• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.10.5 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • util
kcompletion.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 */
19 
20 
21 #include "kcompletion.h"
22 #include "kcompletion_p.h"
23 
24 #include <kdebug.h>
25 #include <klocale.h>
26 #include <knotification.h>
27 #include <kglobal.h>
28 #include <kstringhandler.h>
29 #include <QtCore/QMutableVectorIterator>
30 
31 class KCompletionPrivate
32 {
33 public:
34  KCompletionPrivate()
35  : myCompletionMode( KGlobalSettings::completionMode() )
36  , myTreeRoot( new KCompTreeNode )
37  , myBeep( true )
38  , myIgnoreCase( false )
39  , myHasMultipleMatches( false )
40  , myRotationIndex( 0 )
41  {
42  }
43  ~KCompletionPrivate()
44  {
45  delete myTreeRoot;
46  }
47  // list used for nextMatch() and previousMatch()
48  KCompletionMatchesWrapper matches;
49 
50  KGlobalSettings::Completion myCompletionMode;
51 
52  KCompletion::CompOrder myOrder;
53  QString myLastString;
54  QString myLastMatch;
55  QString myCurrentMatch;
56  KCompTreeNode * myTreeRoot;
57  //QStringList myRotations;
58  bool myBeep : 1;
59  bool myIgnoreCase : 1;
60  bool myHasMultipleMatches;
61  int myRotationIndex;
62 };
63 
64 KCompletion::KCompletion()
65  :d(new KCompletionPrivate)
66 {
67  setOrder( Insertion );
68 }
69 
70 KCompletion::~KCompletion()
71 {
72  delete d;
73 }
74 
75 void KCompletion::setOrder( CompOrder order )
76 {
77  d->myOrder = order;
78  d->matches.setSorting( order );
79 }
80 
81 KCompletion::CompOrder KCompletion::order() const
82 {
83  return d->myOrder;
84 }
85 
86 void KCompletion::setIgnoreCase( bool ignoreCase )
87 {
88  d->myIgnoreCase = ignoreCase;
89 }
90 
91 bool KCompletion::ignoreCase() const
92 {
93  return d->myIgnoreCase;
94 }
95 
96 void KCompletion::setItems( const QStringList& items )
97 {
98  clear();
99  insertItems( items );
100 }
101 
102 
103 void KCompletion::insertItems( const QStringList& items )
104 {
105  bool weighted = (d->myOrder == Weighted);
106  QStringList::ConstIterator it;
107  if ( weighted ) { // determine weight
108  for ( it = items.begin(); it != items.end(); ++it )
109  addWeightedItem( *it );
110  }
111  else {
112  for ( it = items.begin(); it != items.end(); ++it )
113  addItem( *it, 0 );
114  }
115 }
116 
117 QStringList KCompletion::items() const
118 {
119  KCompletionMatchesWrapper list; // unsorted
120  bool addWeight = (d->myOrder == Weighted);
121  extractStringsFromNode( d->myTreeRoot, QString(), &list, addWeight );
122 
123  return list.list();
124 }
125 
126 bool KCompletion::isEmpty() const
127 {
128  return (d->myTreeRoot->childrenCount() == 0);
129 }
130 
131 void KCompletion::postProcessMatch( QString * ) const
132 {
133 }
134 
135 void KCompletion::postProcessMatches( QStringList * ) const
136 {
137 }
138 
139 void KCompletion::postProcessMatches( KCompletionMatches * ) const
140 {
141 }
142 
143 void KCompletion::addItem( const QString& item )
144 {
145  d->matches.clear();
146  d->myRotationIndex = 0;
147  d->myLastString.clear();
148 
149  addItem( item, 0 );
150 }
151 
152 void KCompletion::addItem( const QString& item, uint weight )
153 {
154  if ( item.isEmpty() )
155  return;
156 
157  KCompTreeNode *node = d->myTreeRoot;
158  uint len = item.length();
159 
160  bool sorted = (d->myOrder == Sorted);
161  bool weighted = ((d->myOrder == Weighted) && weight > 1);
162 
163  // knowing the weight of an item, we simply add this weight to all of its
164  // nodes.
165 
166  for ( uint i = 0; i < len; i++ ) {
167  node = node->insert( item.at(i), sorted );
168  if ( weighted )
169  node->confirm( weight -1 ); // node->insert() sets weighting to 1
170  }
171 
172  // add 0x0-item as delimiter with evtl. weight
173  node = node->insert( 0x0, true );
174  if ( weighted )
175  node->confirm( weight -1 );
176 // qDebug("*** added: %s (%i)", item.toLatin1().constData(), node->weight());
177 }
178 
179 void KCompletion::addWeightedItem( const QString& item )
180 {
181  if ( d->myOrder != Weighted ) {
182  addItem( item, 0 );
183  return;
184  }
185 
186  uint len = item.length();
187  uint weight = 0;
188 
189  // find out the weighting of this item (appended to the string as ":num")
190  int index = item.lastIndexOf(':');
191  if ( index > 0 ) {
192  bool ok;
193  weight = item.mid( index + 1 ).toUInt( &ok );
194  if ( !ok )
195  weight = 0;
196 
197  len = index; // only insert until the ':'
198  }
199 
200  addItem( item.left( len ), weight );
201  return;
202 }
203 
204 
205 void KCompletion::removeItem( const QString& item )
206 {
207  d->matches.clear();
208  d->myRotationIndex = 0;
209  d->myLastString.clear();
210 
211  d->myTreeRoot->remove( item );
212 }
213 
214 
215 void KCompletion::clear()
216 {
217  d->matches.clear();
218  d->myRotationIndex = 0;
219  d->myLastString.clear();
220 
221  delete d->myTreeRoot;
222  d->myTreeRoot = new KCompTreeNode;
223 }
224 
225 
226 QString KCompletion::makeCompletion( const QString& string )
227 {
228  if ( d->myCompletionMode == KGlobalSettings::CompletionNone )
229  return QString();
230 
231  //kDebug(0) << "KCompletion: completing: " << string;
232 
233  d->matches.clear();
234  d->myRotationIndex = 0;
235  d->myHasMultipleMatches = false;
236  d->myLastMatch = d->myCurrentMatch;
237 
238  // in Shell-completion-mode, emit all matches when we get the same
239  // complete-string twice
240  if ( d->myCompletionMode == KGlobalSettings::CompletionShell &&
241  string == d->myLastString ) {
242  // Don't use d->matches since calling postProcessMatches()
243  // on d->matches here would interfere with call to
244  // postProcessMatch() during rotation
245 
246  findAllCompletions( string, &d->matches, d->myHasMultipleMatches );
247  QStringList l = d->matches.list();
248  postProcessMatches( &l );
249  emit matches( l );
250 
251  if ( l.isEmpty() )
252  doBeep( NoMatch );
253 
254  return QString();
255  }
256 
257  QString completion;
258  // in case-insensitive popup mode, we search all completions at once
259  if ( d->myCompletionMode == KGlobalSettings::CompletionPopup ||
260  d->myCompletionMode == KGlobalSettings::CompletionPopupAuto ) {
261  findAllCompletions( string, &d->matches, d->myHasMultipleMatches );
262  if ( !d->matches.isEmpty() )
263  completion = d->matches.first();
264  }
265  else
266  completion = findCompletion( string );
267 
268  if ( d->myHasMultipleMatches )
269  emit multipleMatches();
270 
271  d->myLastString = string;
272  d->myCurrentMatch = completion;
273 
274  postProcessMatch( &completion );
275 
276  if ( !string.isEmpty() ) { // only emit match when string is not empty
277  //kDebug(0) << "KCompletion: Match: " << completion;
278  emit match( completion );
279  }
280 
281  if ( completion.isNull() )
282  doBeep( NoMatch );
283 
284  return completion;
285 }
286 
287 
288 
289 QStringList KCompletion::substringCompletion( const QString& string ) const
290 {
291  // get all items in the tree, eventually in sorted order
292  KCompletionMatchesWrapper allItems( d->myOrder );
293  extractStringsFromNode( d->myTreeRoot, QString(), &allItems, false );
294 
295  QStringList list = allItems.list();
296 
297  // subStringMatches is invoked manually, via a shortcut, so we should
298  // beep here, if necessary.
299  if ( list.isEmpty() ) {
300  doBeep( NoMatch );
301  return list;
302  }
303 
304  if ( string.isEmpty() ) { // shortcut
305  postProcessMatches( &list );
306  return list;
307  }
308 
309  QStringList matches;
310  QStringList::ConstIterator it = list.constBegin();
311 
312  for( ; it != list.constEnd(); ++it ) {
313  QString item = *it;
314  if ( item.indexOf( string, 0, Qt::CaseInsensitive ) != -1 ) { // always case insensitive
315  postProcessMatch( &item );
316  matches.append( item );
317  }
318  }
319 
320  if ( matches.isEmpty() )
321  doBeep( NoMatch );
322 
323  return matches;
324 }
325 
326 
327 void KCompletion::setCompletionMode( KGlobalSettings::Completion mode )
328 {
329  d->myCompletionMode = mode;
330 }
331 
332 KGlobalSettings::Completion KCompletion::completionMode() const {
333  return d->myCompletionMode;
334 }
335 
336 QStringList KCompletion::allMatches()
337 {
338  // Don't use d->matches since calling postProcessMatches()
339  // on d->matches here would interfere with call to
340  // postProcessMatch() during rotation
341  KCompletionMatchesWrapper matches( d->myOrder );
342  bool dummy;
343  findAllCompletions( d->myLastString, &matches, dummy );
344  QStringList l = matches.list();
345  postProcessMatches( &l );
346  return l;
347 }
348 
349 KCompletionMatches KCompletion::allWeightedMatches()
350 {
351  // Don't use d->matches since calling postProcessMatches()
352  // on d->matches here would interfere with call to
353  // postProcessMatch() during rotation
354  KCompletionMatchesWrapper matches( d->myOrder );
355  bool dummy;
356  findAllCompletions( d->myLastString, &matches, dummy );
357  KCompletionMatches ret( matches );
358  postProcessMatches( &ret );
359  return ret;
360 }
361 
362 QStringList KCompletion::allMatches( const QString &string )
363 {
364  KCompletionMatchesWrapper matches( d->myOrder );
365  bool dummy;
366  findAllCompletions( string, &matches, dummy );
367  QStringList l = matches.list();
368  postProcessMatches( &l );
369  return l;
370 }
371 
372 KCompletionMatches KCompletion::allWeightedMatches( const QString &string )
373 {
374  KCompletionMatchesWrapper matches( d->myOrder );
375  bool dummy;
376  findAllCompletions( string, &matches, dummy );
377  KCompletionMatches ret( matches );
378  postProcessMatches( &ret );
379  return ret;
380 }
381 
382 void KCompletion::setSoundsEnabled( bool enable )
383 {
384  d->myBeep = enable;
385 }
386 
387 bool KCompletion::soundsEnabled() const
388 {
389  return d->myBeep;
390 }
391 
392 bool KCompletion::hasMultipleMatches() const
393 {
394  return d->myHasMultipleMatches;
395 }
396 
399 
400 
401 QString KCompletion::nextMatch()
402 {
403  QString completion;
404  d->myLastMatch = d->myCurrentMatch;
405 
406  if ( d->matches.isEmpty() ) {
407  findAllCompletions( d->myLastString, &d->matches, d->myHasMultipleMatches );
408  if ( !d->matches.isEmpty() )
409  completion = d->matches.first();
410  d->myCurrentMatch = completion;
411  d->myRotationIndex = 0;
412  postProcessMatch( &completion );
413  emit match( completion );
414  return completion;
415  }
416 
417  QStringList matches = d->matches.list();
418  d->myLastMatch = matches[ d->myRotationIndex++ ];
419 
420  if ( d->myRotationIndex == matches.count() -1 )
421  doBeep( Rotation ); // indicate last matching item -> rotating
422 
423  else if ( d->myRotationIndex == matches.count() )
424  d->myRotationIndex = 0;
425 
426  completion = matches[ d->myRotationIndex ];
427  d->myCurrentMatch = completion;
428  postProcessMatch( &completion );
429  emit match( completion );
430  return completion;
431 }
432 
433 const QString& KCompletion::lastMatch() const
434 {
435  return d->myLastMatch;
436 }
437 
438 
439 QString KCompletion::previousMatch()
440 {
441  QString completion;
442  d->myLastMatch = d->myCurrentMatch;
443 
444  if ( d->matches.isEmpty() ) {
445  findAllCompletions( d->myLastString, &d->matches, d->myHasMultipleMatches );
446  if ( !d->matches.isEmpty() )
447  completion = d->matches.last();
448  d->myCurrentMatch = completion;
449  d->myRotationIndex = 0;
450  postProcessMatch( &completion );
451  emit match( completion );
452  return completion;
453  }
454 
455  QStringList matches = d->matches.list();
456  d->myLastMatch = matches[ d->myRotationIndex ];
457  if ( d->myRotationIndex == 1 )
458  doBeep( Rotation ); // indicate first item -> rotating
459 
460  else if ( d->myRotationIndex == 0 )
461  d->myRotationIndex = matches.count();
462 
463  d->myRotationIndex--;
464 
465  completion = matches[ d->myRotationIndex ];
466  d->myCurrentMatch = completion;
467  postProcessMatch( &completion );
468  emit match( completion );
469  return completion;
470 }
471 
472 
473 
474 // tries to complete "string" from the tree-root
475 QString KCompletion::findCompletion( const QString& string )
476 {
477  QChar ch;
478  QString completion;
479  const KCompTreeNode *node = d->myTreeRoot;
480 
481  // start at the tree-root and try to find the search-string
482  for( int i = 0; i < string.length(); i++ ) {
483  ch = string.at( i );
484  node = node->find( ch );
485 
486  if ( node )
487  completion += ch;
488  else
489  return QString(); // no completion
490  }
491 
492  // Now we have the last node of the to be completed string.
493  // Follow it as long as it has exactly one child (= longest possible
494  // completion)
495 
496  while ( node->childrenCount() == 1 ) {
497  node = node->firstChild();
498  if ( !node->isNull() )
499  completion += *node;
500  }
501  // if multiple matches and auto-completion mode
502  // -> find the first complete match
503  if ( node && node->childrenCount() > 1 ) {
504  d->myHasMultipleMatches = true;
505 
506  if ( d->myCompletionMode == KGlobalSettings::CompletionAuto ) {
507  d->myRotationIndex = 1;
508  if (d->myOrder != Weighted) {
509  while ( (node = node->firstChild()) ) {
510  if ( !node->isNull() )
511  completion += *node;
512  else
513  break;
514  }
515  }
516  else {
517  // don't just find the "first" match, but the one with the
518  // highest priority
519 
520  const KCompTreeNode* temp_node = 0L;
521  while(1) {
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 ) {
529  hit = temp_node;
530  weight = hit->weight();
531  }
532  }
533  // 0x0 has the highest priority -> we have the best match
534  if ( hit->isNull() )
535  break;
536 
537  node = hit;
538  completion += *node;
539  }
540  }
541  }
542 
543  else
544  doBeep( PartialMatch ); // partial match -> beep
545  }
546 
547  return completion;
548 }
549 
550 
551 void KCompletion::findAllCompletions(const QString& string,
552  KCompletionMatchesWrapper *matches,
553  bool& hasMultipleMatches) const
554 {
555  //kDebug(0) << "*** finding all completions for " << string;
556 
557  if ( string.isEmpty() )
558  return;
559 
560  if ( d->myIgnoreCase ) { // case insensitive completion
561  extractStringsFromNodeCI( d->myTreeRoot, QString(), string, matches );
562  hasMultipleMatches = (matches->count() > 1);
563  return;
564  }
565 
566  QChar ch;
567  QString completion;
568  const KCompTreeNode *node = d->myTreeRoot;
569 
570  // start at the tree-root and try to find the search-string
571  for( int i = 0; i < string.length(); i++ ) {
572  ch = string.at( i );
573  node = node->find( ch );
574 
575  if ( node )
576  completion += ch;
577  else
578  return; // no completion -> return empty list
579  }
580 
581  // Now we have the last node of the to be completed string.
582  // Follow it as long as it has exactly one child (= longest possible
583  // completion)
584 
585  while ( node->childrenCount() == 1 ) {
586  node = node->firstChild();
587  if ( !node->isNull() )
588  completion += *node;
589  // kDebug() << completion << node->latin1();
590  }
591 
592 
593  // there is just one single match)
594  if ( node->childrenCount() == 0 )
595  matches->append( node->weight(), completion );
596 
597  else {
598  // node has more than one child
599  // -> recursively find all remaining completions
600  hasMultipleMatches = true;
601  extractStringsFromNode( node, completion, matches );
602  }
603 }
604 
605 
606 void KCompletion::extractStringsFromNode( const KCompTreeNode *node,
607  const QString& beginning,
608  KCompletionMatchesWrapper *matches,
609  bool addWeight ) const
610 {
611  if ( !node || !matches )
612  return;
613 
614  // kDebug() << "Beginning: " << beginning;
615  const KCompTreeChildren *list = node->children();
616  QString string;
617  QString w;
618 
619  // loop thru all children
620  for ( KCompTreeNode *cur = list->begin(); cur ; cur = cur->next) {
621  string = beginning;
622  node = cur;
623  if ( !node->isNull() )
624  string += *node;
625 
626  while ( node && node->childrenCount() == 1 ) {
627  node = node->firstChild();
628  if ( node->isNull() )
629  break;
630  string += *node;
631  }
632 
633  if ( node && node->isNull() ) { // we found a leaf
634  if ( addWeight ) {
635  // add ":num" to the string to store the weighting
636  string += ':';
637  w.setNum( node->weight() );
638  string.append( w );
639  }
640  matches->append( node->weight(), string );
641  }
642 
643  // recursively find all other strings.
644  if ( node && node->childrenCount() > 1 )
645  extractStringsFromNode( node, string, matches, addWeight );
646  }
647 }
648 
649 void KCompletion::extractStringsFromNodeCI( const KCompTreeNode *node,
650  const QString& beginning,
651  const QString& restString,
652  KCompletionMatchesWrapper *matches ) const
653 {
654  if ( restString.isEmpty() ) {
655  extractStringsFromNode( node, beginning, matches, false /*noweight*/ );
656  return;
657  }
658 
659  QChar ch1 = restString.at(0);
660  QString newRest = restString.mid(1);
661  KCompTreeNode *child1, *child2;
662 
663  child1 = node->find( ch1 ); // the correct match
664  if ( child1 )
665  extractStringsFromNodeCI( child1, beginning + QChar(*child1), newRest,
666  matches );
667 
668  // append the case insensitive matches, if available
669  if ( ch1.isLetter() ) {
670  // find out if we have to lower or upper it. Is there a better way?
671  QChar ch2 = ch1.toLower();
672  if ( ch1 == ch2 )
673  ch2 = ch1.toUpper();
674  if ( ch1 != ch2 ) {
675  child2 = node->find( ch2 );
676  if ( child2 )
677  extractStringsFromNodeCI( child2, beginning + QChar(*child2), newRest,
678  matches );
679  }
680  }
681 }
682 
683 void KCompletion::doBeep( BeepMode mode ) const
684 {
685  if ( !d->myBeep )
686  return;
687 
688  QString text, event;
689 
690  switch ( mode ) {
691  case Rotation:
692  event = QLatin1String("Textcompletion: rotation");
693  text = i18n("You reached the end of the list\nof matching items.\n");
694  break;
695  case PartialMatch:
696  if ( d->myCompletionMode == KGlobalSettings::CompletionShell ||
697  d->myCompletionMode == KGlobalSettings::CompletionMan ) {
698  event = QLatin1String("Textcompletion: partial match");
699  text = i18n("The completion is ambiguous, more than one\nmatch is available.\n");
700  }
701  break;
702  case NoMatch:
703  if ( d->myCompletionMode == KGlobalSettings::CompletionShell ) {
704  event = QLatin1String("Textcompletion: no match");
705  text = i18n("There is no matching item available.\n");
706  }
707  break;
708  }
709 
710  if ( !text.isEmpty() )
711  {
712  KNotification::event( event, text , QPixmap() , 0L , KNotification::DefaultEvent );
713  }
714 }
715 
716 
719 
720 
721 // Implements the tree. Every node is a QChar and has a list of children, which
722 // are Nodes as well.
723 // QChar( 0x0 ) is used as the delimiter of a string; the last child of each
724 // inserted string is 0x0.
725 
726 KCompTreeNode::~KCompTreeNode()
727 {
728  // delete all children
729  KCompTreeNode *cur = myChildren.begin();
730  while (cur) {
731  KCompTreeNode * next = cur->next;
732  delete myChildren.remove(cur);
733  cur = next;
734  }
735 }
736 
737 
738 // Adds a child-node "ch" to this node. If such a node is already existent,
739 // it will not be created. Returns the new/existing node.
740 KCompTreeNode * KCompTreeNode::insert( const QChar& ch, bool sorted )
741 {
742  KCompTreeNode *child = find( ch );
743  if ( !child ) {
744  child = new KCompTreeNode( ch );
745 
746  // FIXME, first (slow) sorted insertion implementation
747  if ( sorted ) {
748  KCompTreeNode * prev = 0;
749  KCompTreeNode * cur = myChildren.begin();
750  while ( cur ) {
751  if ( ch > *cur ) {
752  prev = cur;
753  cur = cur->next;
754  } else
755  break;
756  }
757  if (prev)
758  myChildren.insert( prev, child );
759  else
760  myChildren.prepend(child);
761  }
762 
763  else
764  myChildren.append( child );
765  }
766 
767  // implicit weighting: the more often an item is inserted, the higher
768  // priority it gets.
769  child->confirm();
770 
771  return child;
772 }
773 
774 
775 // Iteratively removes a string from the tree. The nicer recursive
776 // version apparently was a little memory hungry (see #56757)
777 void KCompTreeNode::remove( const QString& str )
778 {
779  QString string = str;
780  string += QChar(0x0);
781 
782  QVector<KCompTreeNode *> deletables( string.length() + 1 );
783 
784  KCompTreeNode *child = 0L;
785  KCompTreeNode *parent = this;
786  deletables.replace( 0, parent );
787 
788  int i = 0;
789  for ( ; i < string.length(); i++ )
790  {
791  child = parent->find( string.at( i ) );
792  if ( child )
793  deletables.replace( i + 1, child );
794  else
795  break;
796 
797  parent = child;
798  }
799 
800  for ( ; i >= 1; i-- )
801  {
802  parent = deletables.at( i - 1 );
803  child = deletables.at( i );
804  if ( child->myChildren.count() == 0 )
805  delete parent->myChildren.remove( child );
806  }
807 }
808 
809 bool lessThan( const QString &left, const QString &right )
810 {
811  return KStringHandler::naturalCompare( left, right ) < 0;
812 }
813 
814 QStringList KCompletionMatchesWrapper::list() const
815 {
816  if ( sortedList && dirty ) {
817  sortedList->sort();
818  dirty = false;
819 
820  stringList.clear();
821 
822  // high weight == sorted last -> reverse the sorting here
823  QList<KSortableItem<QString> >::const_iterator it;
824  for ( it = sortedList->constBegin(); it != sortedList->constEnd(); ++it )
825  stringList.prepend( (*it).value() );
826  } else if ( compOrder == KCompletion::Sorted ) {
827  qStableSort(stringList.begin(), stringList.end(), lessThan);
828  }
829 
830  return stringList;
831 }
832 
833 class KCompletionMatchesPrivate
834 {
835 public:
836  KCompletionMatchesPrivate( bool sort )
837  : sorting( sort )
838  {}
839  bool sorting;
840 };
841 
842 KCompletionMatches::KCompletionMatches( const KCompletionMatches &o )
843  : KSortableList<QString, int>(),
844  d( new KCompletionMatchesPrivate( o.d->sorting ) )
845 {
846  *this = KCompletionMatches::operator=( o );
847 }
848 
849 KCompletionMatches &KCompletionMatches::operator=( const KCompletionMatches &o )
850 {
851  if( *this == o )
852  return *this;
853  KCompletionMatchesList::operator=( o );
854  d->sorting = o.d->sorting;
855 
856  return *this;
857 }
858 
859 KCompletionMatches::KCompletionMatches( bool sort_P )
860  : d( new KCompletionMatchesPrivate( sort_P ) )
861 {
862 }
863 
864 KCompletionMatches::KCompletionMatches( const KCompletionMatchesWrapper& matches )
865  : d( new KCompletionMatchesPrivate( matches.sorting() ) )
866 {
867  if( matches.sortedList != 0L )
868  KCompletionMatchesList::operator=( *matches.sortedList );
869  else {
870  const QStringList l = matches.list();
871  for( QStringList::ConstIterator it = l.begin();
872  it != l.end();
873  ++it )
874  prepend( KSortableItem<QString, int>( 1, *it ) );
875  }
876 }
877 
878 KCompletionMatches::~KCompletionMatches()
879 {
880  delete d;
881 }
882 
883 QStringList KCompletionMatches::list( bool sort_P ) const
884 {
885  if( d->sorting && sort_P )
886  const_cast< KCompletionMatches* >( this )->sort();
887  QStringList stringList;
888  // high weight == sorted last -> reverse the sorting here
889  for ( ConstIterator it = begin(); it != end(); ++it )
890  stringList.prepend( (*it).value() );
891  return stringList;
892 }
893 
894 bool KCompletionMatches::sorting() const
895 {
896  return d->sorting;
897 }
898 
899 void KCompletionMatches::removeDuplicates()
900 {
901  Iterator it1, it2;
902  for ( it1 = begin(); it1 != end(); ++it1 ) {
903  for ( (it2 = it1), ++it2; it2 != end();) {
904  if( (*it1).value() == (*it2).value()) {
905  // use the max height
906  (*it1).first = qMax( (*it1).key(), (*it2).key());
907  it2 = erase( it2 );
908  continue;
909  }
910  ++it2;
911  }
912  }
913 }
914 
915 void KCompTreeNodeList::append(KCompTreeNode *item)
916 {
917  m_count++;
918  if (!last) {
919  last = item;
920  last->next = 0;
921  first = item;
922  return;
923  }
924  last->next = item;
925  item->next = 0;
926  last = item;
927 }
928 
929 void KCompTreeNodeList::prepend(KCompTreeNode *item)
930 {
931  m_count++;
932  if (!last) {
933  last = item;
934  last->next = 0;
935  first = item;
936  return;
937  }
938  item->next = first;
939  first = item;
940 }
941 
942 void KCompTreeNodeList::insert(KCompTreeNode *after, KCompTreeNode *item)
943 {
944  if (!after) {
945  append(item);
946  return;
947  }
948 
949  m_count++;
950 
951  item->next = after->next;
952  after->next = item;
953 
954  if (after == last)
955  last = item;
956 }
957 
958 KCompTreeNode *KCompTreeNodeList::remove(KCompTreeNode *item)
959 {
960  if (!first || !item)
961  return 0;
962  KCompTreeNode *cur = 0;
963 
964  if (item == first)
965  first = first->next;
966  else {
967  cur = first;
968  while (cur && cur->next != item) cur = cur->next;
969  if (!cur)
970  return 0;
971  cur->next = item->next;
972  }
973  if (item == last)
974  last = cur;
975  m_count--;
976  return item;
977 }
978 
979 KCompTreeNode *KCompTreeNodeList::at(uint index) const
980 {
981  KCompTreeNode *cur = first;
982  while (index-- && cur) cur = cur->next;
983  return cur;
984 }
985 
986 KZoneAllocator KCompTreeNode::alloc(8192);
987 
988 #include "kcompletion.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Tue Jul 23 2013 20:33:52 by doxygen 1.8.1.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.10.5 API Reference

Skip menu "kdelibs-4.10.5 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal