22 #include "kcompletion_p.h"
29 #include <QtCore/QMutableVectorIterator>
31 class KCompletionPrivate
36 , myTreeRoot( new KCompTreeNode )
38 , myIgnoreCase( false )
39 , myHasMultipleMatches( false )
40 , myRotationIndex( 0 )
48 KCompletionMatchesWrapper matches;
56 KCompTreeNode * myTreeRoot;
59 bool myIgnoreCase : 1;
60 bool myHasMultipleMatches;
65 :d(new KCompletionPrivate)
78 d->matches.setSorting( order );
93 return d->myIgnoreCase;
105 bool weighted = (d->myOrder ==
Weighted);
106 QStringList::ConstIterator it;
108 for ( it = items.begin(); it != items.end(); ++it )
109 addWeightedItem( *it );
112 for ( it = items.begin(); it != items.end(); ++it )
119 KCompletionMatchesWrapper list;
120 bool addWeight = (d->myOrder ==
Weighted);
121 extractStringsFromNode( d->myTreeRoot,
QString(), &list, addWeight );
128 return (d->myTreeRoot->childrenCount() == 0);
146 d->myRotationIndex = 0;
147 d->myLastString.clear();
154 if ( item.isEmpty() )
157 KCompTreeNode *node = d->myTreeRoot;
158 uint len = item.length();
160 bool sorted = (d->myOrder ==
Sorted);
161 bool weighted = ((d->myOrder ==
Weighted) && weight > 1);
166 for ( uint i = 0; i < len; i++ ) {
167 node = node->insert( item.at(i), sorted );
169 node->confirm( weight -1 );
173 node = node->insert( 0x0,
true );
175 node->confirm( weight -1 );
179 void KCompletion::addWeightedItem(
const QString& item )
186 uint len = item.length();
190 int index = item.lastIndexOf(
':');
193 weight = item.mid( index + 1 ).toUInt( &ok );
200 addItem( item.left( len ), weight );
208 d->myRotationIndex = 0;
209 d->myLastString.clear();
211 d->myTreeRoot->remove( item );
218 d->myRotationIndex = 0;
219 d->myLastString.clear();
221 delete d->myTreeRoot;
222 d->myTreeRoot =
new KCompTreeNode;
234 d->myRotationIndex = 0;
235 d->myHasMultipleMatches =
false;
236 d->myLastMatch = d->myCurrentMatch;
241 string == d->myLastString ) {
246 findAllCompletions(
string, &d->matches, d->myHasMultipleMatches );
261 findAllCompletions(
string, &d->matches, d->myHasMultipleMatches );
262 if ( !d->matches.isEmpty() )
263 completion = d->matches.first();
266 completion = findCompletion(
string );
268 if ( d->myHasMultipleMatches )
271 d->myLastString = string;
278 emit
match( completion );
281 if ( completion.isNull() )
292 KCompletionMatchesWrapper allItems( d->myOrder );
293 extractStringsFromNode( d->myTreeRoot,
QString(), &allItems,
false );
299 if ( list.isEmpty() ) {
310 QStringList::ConstIterator it = list.constBegin();
312 for( ; it != list.constEnd(); ++it ) {
314 if ( item.indexOf(
string, 0, Qt::CaseInsensitive ) != -1 ) {
316 matches.append( item );
320 if ( matches.isEmpty() )
329 d->myCompletionMode = mode;
333 return d->myCompletionMode;
341 KCompletionMatchesWrapper
matches( d->myOrder );
343 findAllCompletions( d->myLastString, &matches, dummy );
354 KCompletionMatchesWrapper
matches( d->myOrder );
356 findAllCompletions( d->myLastString, &matches, dummy );
364 KCompletionMatchesWrapper
matches( d->myOrder );
366 findAllCompletions(
string, &matches, dummy );
374 KCompletionMatchesWrapper
matches( d->myOrder );
376 findAllCompletions(
string, &matches, dummy );
394 return d->myHasMultipleMatches;
404 d->myLastMatch = d->myCurrentMatch;
406 if ( d->matches.isEmpty() ) {
407 findAllCompletions( d->myLastString, &d->matches, d->myHasMultipleMatches );
408 if ( !d->matches.isEmpty() )
409 completion = d->matches.first();
411 d->myRotationIndex = 0;
413 emit
match( completion );
418 d->myLastMatch = matches[ d->myRotationIndex++ ];
420 if ( d->myRotationIndex == matches.count() -1 )
423 else if ( d->myRotationIndex == matches.count() )
424 d->myRotationIndex = 0;
426 completion = matches[ d->myRotationIndex ];
427 d->myCurrentMatch = completion;
429 emit
match( completion );
435 return d->myLastMatch;
442 d->myLastMatch = d->myCurrentMatch;
444 if ( d->matches.isEmpty() ) {
445 findAllCompletions( d->myLastString, &d->matches, d->myHasMultipleMatches );
446 if ( !d->matches.isEmpty() )
447 completion = d->matches.last();
449 d->myRotationIndex = 0;
451 emit
match( completion );
456 d->myLastMatch = matches[ d->myRotationIndex ];
457 if ( d->myRotationIndex == 1 )
460 else if ( d->myRotationIndex == 0 )
461 d->myRotationIndex = matches.count();
463 d->myRotationIndex--;
465 completion = matches[ d->myRotationIndex ];
468 emit
match( completion );
479 const KCompTreeNode *node = d->myTreeRoot;
482 for(
int i = 0; i <
string.length(); i++ ) {
484 node = node->find( ch );
496 while ( node->childrenCount() == 1 ) {
497 node = node->firstChild();
498 if ( !node->isNull() )
503 if ( node && node->childrenCount() > 1 ) {
504 d->myHasMultipleMatches =
true;
507 d->myRotationIndex = 1;
509 while ( (node = node->firstChild()) ) {
510 if ( !node->isNull() )
520 const KCompTreeNode* temp_node = 0L;
522 int count = node->childrenCount();
523 temp_node = node->firstChild();
524 uint weight = temp_node->weight();
525 const KCompTreeNode* hit = temp_node;
526 for(
int i = 1; i < count; i++ ) {
527 temp_node = node->childAt(i);
528 if( temp_node->weight() > weight ) {
530 weight = hit->weight();
544 doBeep( PartialMatch );
551 void KCompletion::findAllCompletions(
const QString&
string,
552 KCompletionMatchesWrapper *matches,
553 bool& hasMultipleMatches)
const
560 if ( d->myIgnoreCase ) {
561 extractStringsFromNodeCI( d->myTreeRoot,
QString(),
string, matches );
562 hasMultipleMatches = (matches->count() > 1);
568 const KCompTreeNode *node = d->myTreeRoot;
571 for(
int i = 0; i <
string.length(); i++ ) {
573 node = node->find( ch );
585 while ( node->childrenCount() == 1 ) {
586 node = node->firstChild();
587 if ( !node->isNull() )
594 if ( node->childrenCount() == 0 )
595 matches->append( node->weight(),
completion );
600 hasMultipleMatches =
true;
601 extractStringsFromNode( node, completion, matches );
606 void KCompletion::extractStringsFromNode(
const KCompTreeNode *node,
608 KCompletionMatchesWrapper *matches,
609 bool addWeight )
const
611 if ( !node || !matches )
615 const KCompTreeChildren *list = node->children();
620 for ( KCompTreeNode *cur = list->begin(); cur ; cur = cur->next) {
623 if ( !node->isNull() )
626 while ( node && node->childrenCount() == 1 ) {
627 node = node->firstChild();
628 if ( node->isNull() )
633 if ( node && node->isNull() ) {
637 w.setNum( node->weight() );
640 matches->append( node->weight(), string );
644 if ( node && node->childrenCount() > 1 )
645 extractStringsFromNode( node,
string, matches, addWeight );
649 void KCompletion::extractStringsFromNodeCI(
const KCompTreeNode *node,
652 KCompletionMatchesWrapper *matches )
const
654 if ( restString.isEmpty() ) {
655 extractStringsFromNode( node, beginning, matches,
false );
659 QChar ch1 = restString.at(0);
660 QString newRest = restString.mid(1);
661 KCompTreeNode *child1, *child2;
663 child1 = node->find( ch1 );
665 extractStringsFromNodeCI( child1, beginning + QChar(*child1), newRest,
669 if ( ch1.isLetter() ) {
671 QChar ch2 = ch1.toLower();
675 child2 = node->find( ch2 );
677 extractStringsFromNodeCI( child2, beginning + QChar(*child2), newRest,
683 void KCompletion::doBeep( BeepMode mode )
const
692 event = QLatin1String(
"Textcompletion: rotation");
693 text =
i18n(
"You reached the end of the list\nof matching items.\n");
698 event = QLatin1String(
"Textcompletion: partial match");
699 text =
i18n(
"The completion is ambiguous, more than one\nmatch is available.\n");
704 event = QLatin1String(
"Textcompletion: no match");
705 text =
i18n(
"There is no matching item available.\n");
710 if ( !text.isEmpty() )
726 KCompTreeNode::~KCompTreeNode()
729 KCompTreeNode *cur = myChildren.begin();
731 KCompTreeNode *
next = cur->next;
732 delete myChildren.remove(cur);
742 KCompTreeNode *child =
find( ch );
744 child =
new KCompTreeNode( ch );
748 KCompTreeNode * prev = 0;
749 KCompTreeNode * cur = myChildren.begin();
758 myChildren.insert( prev, child );
760 myChildren.prepend(child);
764 myChildren.append( child );
780 string += QChar(0x0);
782 QVector<KCompTreeNode *> deletables(
string.length() + 1 );
784 KCompTreeNode *child = 0L;
785 KCompTreeNode *parent =
this;
786 deletables.replace( 0, parent );
789 for ( ; i <
string.length(); i++ )
791 child = parent->find(
string.at( i ) );
793 deletables.replace( i + 1, child );
800 for ( ; i >= 1; i-- )
802 parent = deletables.at( i - 1 );
803 child = deletables.at( i );
804 if ( child->myChildren.count() == 0 )
805 delete parent->myChildren.remove( child );
814 QStringList KCompletionMatchesWrapper::list()
const
816 if ( sortedList && dirty ) {
823 QList<KSortableItem<QString> >::const_iterator it;
824 for ( it = sortedList->constBegin(); it != sortedList->constEnd(); ++it )
825 stringList.prepend( (*it).value() );
827 qStableSort(stringList.begin(), stringList.end(),
lessThan);
833 class KCompletionMatchesPrivate
836 KCompletionMatchesPrivate(
bool sort )
844 d( new KCompletionMatchesPrivate( o.d->sorting ) )
854 d->sorting = o.d->sorting;
860 : d( new KCompletionMatchesPrivate( sort_P ) )
865 : d( new KCompletionMatchesPrivate( matches.sorting() ) )
867 if( matches.sortedList != 0L )
871 for( QStringList::ConstIterator it = l.begin();
885 if( d->sorting && sort_P )
889 for ( ConstIterator it =
begin(); it !=
end(); ++it )
890 stringList.prepend( (*it).value() );
902 for ( it1 =
begin(); it1 !=
end(); ++it1 ) {
903 for ( (it2 = it1), ++it2; it2 !=
end();) {
904 if( (*it1).value() == (*it2).value()) {
906 (*it1).first = qMax( (*it1).key(), (*it2).key());
915 void KCompTreeNodeList::append(KCompTreeNode *item)
929 void KCompTreeNodeList::prepend(KCompTreeNode *item)
951 item->next = after->next;
962 KCompTreeNode *cur = 0;
968 while (cur && cur->next != item) cur = cur->next;
971 cur->next = item->next;
979 KCompTreeNode *KCompTreeNodeList::at(uint index)
const
981 KCompTreeNode *cur = first;
982 while (index-- && cur) cur = cur->next;
988 #include "kcompletion.moc"