22#include "kcompletion_p.h"
29#include <QtCore/QMutableVectorIterator>
31class KCompletionPrivate
36 , myTreeNodeAllocator( KCompTreeNode::allocator() )
37 , myTreeRoot( new KCompTreeNode )
39 , myIgnoreCase( false )
40 , myHasMultipleMatches( false )
41 , myRotationIndex( 0 )
49 KCompletionMatchesWrapper matches;
53 QSharedPointer<KZoneAllocator> myTreeNodeAllocator;
58 QString myCurrentMatch;
59 KCompTreeNode * myTreeRoot;
62 bool myIgnoreCase : 1;
63 bool myHasMultipleMatches;
68 :d(new KCompletionPrivate)
81 d->matches.setSorting( order );
91 d->myIgnoreCase = ignoreCase;
96 return d->myIgnoreCase;
108 bool weighted = (d->myOrder ==
Weighted);
109 QStringList::ConstIterator it;
111 for ( it = items.begin(); it != items.end(); ++it )
112 addWeightedItem( *it );
115 for ( it = items.begin(); it != items.end(); ++it )
122 KCompletionMatchesWrapper list;
123 bool addWeight = (d->myOrder ==
Weighted);
124 extractStringsFromNode( d->myTreeRoot, QString(), &list, addWeight );
131 return (d->myTreeRoot->childrenCount() == 0);
149 d->myRotationIndex = 0;
150 d->myLastString.clear();
157 if ( item.isEmpty() )
160 KCompTreeNode *node = d->myTreeRoot;
161 uint len = item.length();
163 bool sorted = (d->myOrder ==
Sorted);
164 bool weighted = ((d->myOrder ==
Weighted) && weight > 1);
169 for ( uint i = 0; i < len; i++ ) {
170 node = node->insert( item.at(i), sorted );
172 node->confirm( weight -1 );
176 node = node->insert( 0x0,
true );
178 node->confirm( weight -1 );
182void KCompletion::addWeightedItem(
const QString& item )
184 if ( d->myOrder != Weighted ) {
189 uint len = item.length();
193 int index = item.lastIndexOf(
':');
196 weight = item.mid( index + 1 ).toUInt( &ok );
203 addItem( item.left( len ), weight );
211 d->myRotationIndex = 0;
212 d->myLastString.clear();
214 d->myTreeRoot->remove( item );
221 d->myRotationIndex = 0;
222 d->myLastString.clear();
224 delete d->myTreeRoot;
225 d->myTreeRoot =
new KCompTreeNode;
237 d->myRotationIndex = 0;
238 d->myHasMultipleMatches =
false;
239 d->myLastMatch = d->myCurrentMatch;
244 string == d->myLastString ) {
249 findAllCompletions(
string, &d->matches, d->myHasMultipleMatches );
250 QStringList l = d->matches.list();
264 findAllCompletions(
string, &d->matches, d->myHasMultipleMatches );
265 if ( !d->matches.isEmpty() )
266 completion = d->matches.first();
269 completion = findCompletion(
string );
271 if ( d->myHasMultipleMatches )
274 d->myLastString = string;
275 d->myCurrentMatch = completion;
281 emit
match( completion );
284 if ( completion.isNull() )
295 KCompletionMatchesWrapper allItems( d->myOrder );
296 extractStringsFromNode( d->myTreeRoot, QString(), &allItems,
false );
298 QStringList list = allItems.list();
302 if ( list.isEmpty() ) {
313 QStringList::ConstIterator it = list.constBegin();
315 for( ; it != list.constEnd(); ++it ) {
317 if ( item.indexOf(
string, 0, Qt::CaseInsensitive ) != -1 ) {
319 matches.append( item );
323 if ( matches.isEmpty() )
332 d->myCompletionMode = mode;
336 return d->myCompletionMode;
344 KCompletionMatchesWrapper
matches( d->myOrder );
346 findAllCompletions( d->myLastString, &matches, dummy );
347 QStringList l = matches.list();
357 KCompletionMatchesWrapper
matches( d->myOrder );
359 findAllCompletions( d->myLastString, &matches, dummy );
367 KCompletionMatchesWrapper
matches( d->myOrder );
369 findAllCompletions(
string, &matches, dummy );
370 QStringList l = matches.list();
377 KCompletionMatchesWrapper
matches( d->myOrder );
379 findAllCompletions(
string, &matches, dummy );
397 return d->myHasMultipleMatches;
407 d->myLastMatch = d->myCurrentMatch;
409 if ( d->matches.isEmpty() ) {
410 findAllCompletions( d->myLastString, &d->matches, d->myHasMultipleMatches );
411 if ( !d->matches.isEmpty() )
412 completion = d->matches.first();
413 d->myCurrentMatch = completion;
414 d->myRotationIndex = 0;
416 emit
match( completion );
420 QStringList
matches = d->matches.list();
421 d->myLastMatch = matches[ d->myRotationIndex++ ];
423 if ( d->myRotationIndex == matches.count() -1 )
426 else if ( d->myRotationIndex == matches.count() )
427 d->myRotationIndex = 0;
429 completion = matches[ d->myRotationIndex ];
430 d->myCurrentMatch = completion;
432 emit
match( completion );
438 return d->myLastMatch;
445 d->myLastMatch = d->myCurrentMatch;
447 if ( d->matches.isEmpty() ) {
448 findAllCompletions( d->myLastString, &d->matches, d->myHasMultipleMatches );
449 if ( !d->matches.isEmpty() )
450 completion = d->matches.last();
451 d->myCurrentMatch = completion;
452 d->myRotationIndex = 0;
454 emit
match( completion );
458 QStringList
matches = d->matches.list();
459 d->myLastMatch = matches[ d->myRotationIndex ];
460 if ( d->myRotationIndex == 1 )
463 else if ( d->myRotationIndex == 0 )
464 d->myRotationIndex = matches.count();
466 d->myRotationIndex--;
468 completion = matches[ d->myRotationIndex ];
469 d->myCurrentMatch = completion;
471 emit
match( completion );
478QString KCompletion::findCompletion(
const QString&
string )
482 const KCompTreeNode *node = d->myTreeRoot;
485 for(
int i = 0; i <
string.length(); i++ ) {
487 node = node->find( ch );
499 while ( node->childrenCount() == 1 ) {
500 node = node->firstChild();
501 if ( !node->isNull() )
506 if ( node && node->childrenCount() > 1 ) {
507 d->myHasMultipleMatches =
true;
510 d->myRotationIndex = 1;
511 if (d->myOrder != Weighted) {
512 while ( (node = node->firstChild()) ) {
513 if ( !node->isNull() )
523 const KCompTreeNode* temp_node = 0L;
525 int count = node->childrenCount();
526 temp_node = node->firstChild();
527 uint weight = temp_node->weight();
528 const KCompTreeNode* hit = temp_node;
529 for(
int i = 1; i < count; i++ ) {
530 temp_node = node->childAt(i);
531 if( temp_node->weight() > weight ) {
533 weight = hit->weight();
547 doBeep( PartialMatch );
554void KCompletion::findAllCompletions(
const QString&
string,
555 KCompletionMatchesWrapper *matches,
556 bool& hasMultipleMatches)
const
563 if ( d->myIgnoreCase ) {
564 extractStringsFromNodeCI( d->myTreeRoot, QString(),
string, matches );
565 hasMultipleMatches = (matches->count() > 1);
571 const KCompTreeNode *node = d->myTreeRoot;
574 for(
int i = 0; i <
string.length(); i++ ) {
576 node = node->find( ch );
588 while ( node->childrenCount() == 1 ) {
589 node = node->firstChild();
590 if ( !node->isNull() )
597 if ( node->childrenCount() == 0 )
598 matches->append( node->weight(),
completion );
603 hasMultipleMatches =
true;
604 extractStringsFromNode( node, completion, matches );
609void KCompletion::extractStringsFromNode(
const KCompTreeNode *node,
610 const QString& beginning,
611 KCompletionMatchesWrapper *matches,
612 bool addWeight )
const
614 if ( !node || !matches )
618 const KCompTreeChildren *list = node->children();
623 for ( KCompTreeNode *cur = list->begin(); cur ; cur = cur->next) {
626 if ( !node->isNull() )
629 while ( node && node->childrenCount() == 1 ) {
630 node = node->firstChild();
631 if ( node->isNull() )
636 if ( node && node->isNull() ) {
640 w.setNum( node->weight() );
643 matches->append( node->weight(),
string );
647 if ( node && node->childrenCount() > 1 )
648 extractStringsFromNode( node,
string, matches, addWeight );
652void KCompletion::extractStringsFromNodeCI(
const KCompTreeNode *node,
653 const QString& beginning,
654 const QString& restString,
655 KCompletionMatchesWrapper *matches )
const
657 if ( restString.isEmpty() ) {
658 extractStringsFromNode( node, beginning, matches,
false );
662 QChar ch1 = restString.at(0);
663 QString newRest = restString.mid(1);
664 KCompTreeNode *child1, *child2;
666 child1 = node->find( ch1 );
668 extractStringsFromNodeCI( child1, beginning + QChar(*child1), newRest,
672 if ( ch1.isLetter() ) {
674 QChar ch2 = ch1.toLower();
678 child2 = node->find( ch2 );
680 extractStringsFromNodeCI( child2, beginning + QChar(*child2), newRest,
686void KCompletion::doBeep( BeepMode mode )
const
695 event = QLatin1String(
"Textcompletion: rotation");
696 text =
i18n(
"You reached the end of the list\nof matching items.\n");
701 event = QLatin1String(
"Textcompletion: partial match");
702 text =
i18n(
"The completion is ambiguous, more than one\nmatch is available.\n");
707 event = QLatin1String(
"Textcompletion: no match");
708 text =
i18n(
"There is no matching item available.\n");
713 if ( !text.isEmpty() )
729KCompTreeNode::~KCompTreeNode()
732 KCompTreeNode *cur = myChildren.begin();
734 KCompTreeNode *
next = cur->next;
735 delete myChildren.remove(cur);
743KCompTreeNode * KCompTreeNode::insert(
const QChar& ch,
bool sorted )
745 KCompTreeNode *child =
find( ch );
747 child =
new KCompTreeNode( ch );
751 KCompTreeNode * prev = 0;
752 KCompTreeNode * cur = myChildren.begin();
761 myChildren.insert( prev, child );
763 myChildren.prepend(child);
767 myChildren.append( child );
780void KCompTreeNode::remove(
const QString& str )
782 QString
string = str;
783 string += QChar(0x0);
785 QVector<KCompTreeNode *> deletables(
string.length() + 1 );
787 KCompTreeNode *child = 0L;
788 KCompTreeNode *parent =
this;
789 deletables.replace( 0, parent );
792 for ( ; i <
string.length(); i++ )
794 child = parent->find(
string.at( i ) );
796 deletables.replace( i + 1, child );
803 for ( ; i >= 1; i-- )
805 parent = deletables.at( i - 1 );
806 child = deletables.at( i );
807 if ( child->myChildren.count() == 0 )
808 delete parent->myChildren.remove( child );
812bool lessThan(
const QString &left,
const QString &right )
817QStringList KCompletionMatchesWrapper::list()
const
819 if ( sortedList && dirty ) {
827 for ( it = sortedList->constBegin(); it != sortedList->constEnd(); ++it )
828 stringList.prepend( (*it).value() );
830 qStableSort(stringList.begin(), stringList.end(),
lessThan);
836class KCompletionMatchesPrivate
839 KCompletionMatchesPrivate(
bool sort )
847 d( new KCompletionMatchesPrivate( o.d->sorting ) )
856 KCompletionMatchesList::operator=( o );
857 d->sorting = o.d->sorting;
863 : d( new KCompletionMatchesPrivate( sort_P ) )
868 : d( new KCompletionMatchesPrivate( matches.sorting() ) )
870 if( matches.sortedList != 0L )
871 KCompletionMatchesList::operator=( *matches.sortedList );
873 const QStringList l = matches.list();
874 for( QStringList::ConstIterator it = l.begin();
888 if( d->sorting && sort_P )
890 QStringList stringList;
892 for ( ConstIterator it = begin(); it != end(); ++it )
893 stringList.prepend( (*it).value() );
905 for ( it1 = begin(); it1 != end(); ++it1 ) {
906 for ( (it2 = it1), ++it2; it2 != end();) {
907 if( (*it1).value() == (*it2).value()) {
909 (*it1).first = qMax( (*it1).key(), (*it2).key());
918void KCompTreeNodeList::append(KCompTreeNode *item)
932void KCompTreeNodeList::prepend(KCompTreeNode *item)
945void KCompTreeNodeList::insert(KCompTreeNode *after, KCompTreeNode *item)
954 item->next = after->next;
961KCompTreeNode *KCompTreeNodeList::remove(KCompTreeNode *item)
965 KCompTreeNode *cur = 0;
971 while (cur && cur->next != item) cur = cur->next;
974 cur->next = item->next;
982KCompTreeNode *KCompTreeNodeList::at(uint index)
const
984 KCompTreeNode *cur = first;
985 while (index-- && cur) cur = cur->next;
989QSharedPointer<KZoneAllocator> KCompTreeNode::alloc(
new KZoneAllocator(8*1024));
991#include "kcompletion.moc"
This structure is returned by KCompletion::allWeightedMatches .
KCompletionMatches(bool sort)
Default constructor.
QStringList list(bool sort=true) const
Returns the matches as a QStringList.
void removeDuplicates()
Removes duplicate matches.
bool sorting() const
If sorting() returns false, the matches aren't sorted by their weight, even if true is passed to list...
~KCompletionMatches()
default destructor.
KCompletionMatches & operator=(const KCompletionMatches &)
assignment operator.
virtual void setItems(const QStringList &list)
Sets the list of items available for completion.
QString nextMatch()
Returns the next item from the matching-items-list.
void insertItems(const QStringList &items)
Inserts items into the list of possible completions.
KGlobalSettings::Completion completionMode() const
Return the current completion mode.
void removeItem(const QString &item)
Removes an item from the list of available completions.
void multipleMatches()
This signal is emitted, when calling makeCompletion() and more than one matching item is found.
virtual QString makeCompletion(const QString &string)
Attempts to find an item in the list of available completions, that begins with string.
bool soundsEnabled() const
Tells you whether KCompletion will play sounds on certain occasions.
bool isEmpty() const
Returns true when the completion object contains no entries.
void matches(const QStringList &matchlist)
All matching items.
QStringList allMatches()
Returns a list of all items matching the last completed string.
KCompletion()
Constructor, nothing special here :)
virtual void setOrder(CompOrder order)
KCompletion offers three different ways in which it offers its items:
virtual void setSoundsEnabled(bool enable)
Enables/disables playing a sound when.
CompOrder
Constants that represent the order in which KCompletion performs completion-lookups.
@ Insertion
Use order of insertion.
@ Weighted
Use weighted order.
@ Sorted
Use alphabetically sorted order.
QStringList substringCompletion(const QString &string) const
Returns a list of all completion items that contain the given string.
virtual void setIgnoreCase(bool ignoreCase)
Setting this to true makes KCompletion behave case insensitively.
QString previousMatch()
Returns the next item from the matching-items-list.
virtual void clear()
Removes all inserted items.
void match(const QString &item)
The matching item.
virtual void setCompletionMode(KGlobalSettings::Completion mode)
Sets the completion mode to Auto/Manual, Shell or None.
void addItem(const QString &item)
Adds an item to the list of available completions.
bool hasMultipleMatches() const
Returns true when more than one match is found.
virtual void postProcessMatch(QString *pMatch) const
This method is called after a completion is found and before the matching string is emitted.
virtual const QString & lastMatch() const
Returns the last match.
KCompletionMatches allWeightedMatches()
Returns a list of all items matching the last completed string.
virtual void postProcessMatches(QStringList *pMatches) const
This method is called before a list of all available completions is emitted via #matches.
virtual ~KCompletion()
Destructor, nothing special here, either.
Access the KDE global configuration.
Completion
This enum describes the completion mode used for by the KCompletion class.
@ CompletionPopup
Lists all possible matches in a popup list-box to choose from.
@ CompletionShell
Complete text much in the same way as a typical *nix shell would.
@ CompletionMan
Same as automatic except shortest match is used for completion.
@ CompletionAuto
Text is automatically filled in whenever possible.
@ CompletionNone
No completion is used.
@ CompletionPopupAuto
Lists all possible matches in a popup list-box to choose from, and automatically fill the result when...
static KNotification * event(const QString &eventId, const QString &title, const QString &text, const QPixmap &pixmap=QPixmap(), QWidget *widget=0L, const NotificationFlags &flags=CloseOnTimeout, const KComponentData &componentData=KComponentData())
emit an event
bool lessThan(const QString &left, const QString &right)
QString i18n(const char *text)
KAction * next(const QObject *recvr, const char *slot, QObject *parent)
Scroll down one page.
KAction * find(const QObject *recvr, const char *slot, QObject *parent)
Initiate a 'find' request in the current document.
KGuiItem ok()
Returns the 'Ok' gui item.
const KShortcut & completion()
Complete text in input widgets.
int naturalCompare(const QString &a, const QString &b, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)