kcompletion.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 00021 #include <tdeapplication.h> 00022 #include <kdebug.h> 00023 #include <tdelocale.h> 00024 #include <knotifyclient.h> 00025 #include <tdeglobal.h> 00026 00027 #include <tqptrvector.h> 00028 00029 #include "kcompletion.h" 00030 #include "kcompletion_private.h" 00031 00032 00033 class TDECompletionPrivate 00034 { 00035 public: 00036 // not a member to avoid #including kcompletion_private.h from kcompletion.h 00037 // list used for nextMatch() and previousMatch() 00038 TDECompletionMatchesWrapper matches; 00039 }; 00040 00041 TDECompletion::TDECompletion() 00042 { 00043 d = new TDECompletionPrivate; 00044 00045 myCompletionMode = TDEGlobalSettings::completionMode(); 00046 myTreeRoot = new TDECompTreeNode; 00047 myBeep = true; 00048 myIgnoreCase = false; 00049 myHasMultipleMatches = false; 00050 myRotationIndex = 0; 00051 setOrder( Insertion ); 00052 } 00053 00054 TDECompletion::~TDECompletion() 00055 { 00056 delete d; 00057 delete myTreeRoot; 00058 } 00059 00060 void TDECompletion::setOrder( CompOrder order ) 00061 { 00062 myOrder = order; 00063 d->matches.setSorting( order == Weighted ); 00064 } 00065 00066 void TDECompletion::setIgnoreCase( bool ignoreCase ) 00067 { 00068 myIgnoreCase = ignoreCase; 00069 } 00070 00071 void TDECompletion::setItems( const TQStringList& items ) 00072 { 00073 clear(); 00074 insertItems( items ); 00075 } 00076 00077 00078 void TDECompletion::insertItems( const TQStringList& items ) 00079 { 00080 bool weighted = (myOrder == Weighted); 00081 TQStringList::ConstIterator it; 00082 if ( weighted ) { // determine weight 00083 for ( it = items.begin(); it != items.end(); ++it ) 00084 addWeightedItem( *it ); 00085 } 00086 else { 00087 for ( it = items.begin(); it != items.end(); ++it ) 00088 addItem( *it, 0 ); 00089 } 00090 } 00091 00092 TQStringList TDECompletion::items() const 00093 { 00094 TDECompletionMatchesWrapper list; // unsorted 00095 bool addWeight = (myOrder == Weighted); 00096 extractStringsFromNode( myTreeRoot, TQString::null, &list, addWeight ); 00097 00098 return list.list(); 00099 } 00100 00101 bool TDECompletion::isEmpty() const 00102 { 00103 return (myTreeRoot->childrenCount() == 0); 00104 } 00105 00106 void TDECompletion::addItem( const TQString& item ) 00107 { 00108 d->matches.clear(); 00109 myRotationIndex = 0; 00110 myLastString = TQString::null; 00111 00112 addItem( item, 0 ); 00113 } 00114 00115 void TDECompletion::addItem( const TQString& item, uint weight ) 00116 { 00117 if ( item.isEmpty() ) 00118 return; 00119 00120 TDECompTreeNode *node = myTreeRoot; 00121 uint len = item.length(); 00122 00123 bool sorted = (myOrder == Sorted); 00124 bool weighted = ((myOrder == Weighted) && weight > 1); 00125 00126 // knowing the weight of an item, we simply add this weight to all of its 00127 // nodes. 00128 00129 for ( uint i = 0; i < len; i++ ) { 00130 node = node->insert( item.at(i), sorted ); 00131 if ( weighted ) 00132 node->confirm( weight -1 ); // node->insert() sets weighting to 1 00133 } 00134 00135 // add 0x0-item as delimiter with evtl. weight 00136 node = node->insert( 0x0, true ); 00137 if ( weighted ) 00138 node->confirm( weight -1 ); 00139 // tqDebug("*** added: %s (%i)", item.latin1(), node->weight()); 00140 } 00141 00142 void TDECompletion::addWeightedItem( const TQString& item ) 00143 { 00144 if ( myOrder != Weighted ) { 00145 addItem( item, 0 ); 00146 return; 00147 } 00148 00149 uint len = item.length(); 00150 uint weight = 0; 00151 00152 // find out the weighting of this item (appended to the string as ":num") 00153 int index = item.findRev(':'); 00154 if ( index > 0 ) { 00155 bool ok; 00156 weight = item.mid( index + 1 ).toUInt( &ok ); 00157 if ( !ok ) 00158 weight = 0; 00159 00160 len = index; // only insert until the ':' 00161 } 00162 00163 addItem( item.left( len ), weight ); 00164 return; 00165 } 00166 00167 00168 void TDECompletion::removeItem( const TQString& item ) 00169 { 00170 d->matches.clear(); 00171 myRotationIndex = 0; 00172 myLastString = TQString::null; 00173 00174 myTreeRoot->remove( item ); 00175 } 00176 00177 00178 void TDECompletion::clear() 00179 { 00180 d->matches.clear(); 00181 myRotationIndex = 0; 00182 myLastString = TQString::null; 00183 00184 delete myTreeRoot; 00185 myTreeRoot = new TDECompTreeNode; 00186 } 00187 00188 00189 TQString TDECompletion::makeCompletion( const TQString& string ) 00190 { 00191 if ( myCompletionMode == TDEGlobalSettings::CompletionNone ) 00192 return TQString::null; 00193 00194 //kdDebug(0) << "TDECompletion: completing: " << string << endl; 00195 00196 d->matches.clear(); 00197 myRotationIndex = 0; 00198 myHasMultipleMatches = false; 00199 myLastMatch = myCurrentMatch; 00200 00201 // in Shell-completion-mode, emit all matches when we get the same 00202 // complete-string twice 00203 if ( myCompletionMode == TDEGlobalSettings::CompletionShell && 00204 string == myLastString ) { 00205 // Don't use d->matches since calling postProcessMatches() 00206 // on d->matches here would interfere with call to 00207 // postProcessMatch() during rotation 00208 00209 findAllCompletions( string, &d->matches, myHasMultipleMatches ); 00210 TQStringList l = d->matches.list(); 00211 postProcessMatches( &l ); 00212 emit matches( l ); 00213 00214 if ( l.isEmpty() ) 00215 doBeep( NoMatch ); 00216 00217 return TQString::null; 00218 } 00219 00220 TQString completion; 00221 // in case-insensitive popup mode, we search all completions at once 00222 if ( myCompletionMode == TDEGlobalSettings::CompletionPopup || 00223 myCompletionMode == TDEGlobalSettings::CompletionPopupAuto ) { 00224 findAllCompletions( string, &d->matches, myHasMultipleMatches ); 00225 if ( !d->matches.isEmpty() ) 00226 completion = d->matches.first(); 00227 } 00228 else 00229 completion = findCompletion( string ); 00230 00231 if ( myHasMultipleMatches ) 00232 emit multipleMatches(); 00233 00234 myLastString = string; 00235 myCurrentMatch = completion; 00236 00237 postProcessMatch( &completion ); 00238 00239 if ( !string.isEmpty() ) { // only emit match when string is not empty 00240 //kdDebug(0) << "TDECompletion: Match: " << completion << endl; 00241 emit match( completion ); 00242 } 00243 00244 if ( completion.isNull() ) 00245 doBeep( NoMatch ); 00246 00247 return completion; 00248 } 00249 00250 00251 TQStringList TDECompletion::substringCompletion( const TQString& string ) const 00252 { 00253 // get all items in the tree, possibly in sorted order 00254 bool sorted = (myOrder == Weighted); 00255 TDECompletionMatchesWrapper allItems( sorted ); 00256 extractStringsFromNode( myTreeRoot, TQString::null, &allItems, false ); 00257 00258 TQStringList list = allItems.list(); 00259 00260 // subStringMatches is invoked manually, via a shortcut, so we should 00261 // beep here, if necessary. 00262 if ( list.isEmpty() ) { 00263 doBeep( NoMatch ); 00264 return list; 00265 } 00266 00267 if ( string.isEmpty() ) { // shortcut 00268 postProcessMatches( &list ); 00269 return list; 00270 } 00271 00272 TQStringList matches; 00273 TQStringList::ConstIterator it = list.begin(); 00274 00275 for( ; it != list.end(); ++it ) { 00276 TQString item = *it; 00277 if ( item.find( string, 0, false ) != -1 ) { // always case insensitive 00278 matches.append( item ); 00279 } 00280 } 00281 00282 postProcessMatches( &matches ); 00283 00284 if ( matches.isEmpty() ) 00285 doBeep( NoMatch ); 00286 00287 return matches; 00288 } 00289 00290 00291 void TDECompletion::setCompletionMode( TDEGlobalSettings::Completion mode ) 00292 { 00293 myCompletionMode = mode; 00294 } 00295 00296 TQStringList TDECompletion::allMatches() 00297 { 00298 // Don't use d->matches since calling postProcessMatches() 00299 // on d->matches here would interfere with call to 00300 // postProcessMatch() during rotation 00301 TDECompletionMatchesWrapper matches( myOrder == Weighted ); 00302 bool dummy; 00303 findAllCompletions( myLastString, &matches, dummy ); 00304 TQStringList l = matches.list(); 00305 postProcessMatches( &l ); 00306 return l; 00307 } 00308 00309 TDECompletionMatches TDECompletion::allWeightedMatches() 00310 { 00311 // Don't use d->matches since calling postProcessMatches() 00312 // on d->matches here would interfere with call to 00313 // postProcessMatch() during rotation 00314 TDECompletionMatchesWrapper matches( myOrder == Weighted ); 00315 bool dummy; 00316 findAllCompletions( myLastString, &matches, dummy ); 00317 TDECompletionMatches ret( matches ); 00318 postProcessMatches( &ret ); 00319 return ret; 00320 } 00321 00322 TQStringList TDECompletion::allMatches( const TQString &string ) 00323 { 00324 TDECompletionMatchesWrapper matches( myOrder == Weighted ); 00325 bool dummy; 00326 findAllCompletions( string, &matches, dummy ); 00327 TQStringList l = matches.list(); 00328 postProcessMatches( &l ); 00329 return l; 00330 } 00331 00332 TDECompletionMatches TDECompletion::allWeightedMatches( const TQString &string ) 00333 { 00334 TDECompletionMatchesWrapper matches( myOrder == Weighted ); 00335 bool dummy; 00336 findAllCompletions( string, &matches, dummy ); 00337 TDECompletionMatches ret( matches ); 00338 postProcessMatches( &ret ); 00339 return ret; 00340 } 00341 00344 00345 00346 TQString TDECompletion::nextMatch() 00347 { 00348 TQString completion; 00349 myLastMatch = myCurrentMatch; 00350 00351 if ( d->matches.isEmpty() ) { 00352 findAllCompletions( myLastString, &d->matches, myHasMultipleMatches ); 00353 completion = d->matches.first(); 00354 myCurrentMatch = completion; 00355 myRotationIndex = 0; 00356 postProcessMatch( &completion ); 00357 emit match( completion ); 00358 return completion; 00359 } 00360 00361 TQStringList matches = d->matches.list(); 00362 myLastMatch = matches[ myRotationIndex++ ]; 00363 00364 if ( myRotationIndex == matches.count() -1 ) 00365 doBeep( Rotation ); // indicate last matching item -> rotating 00366 00367 else if ( myRotationIndex == matches.count() ) 00368 myRotationIndex = 0; 00369 00370 completion = matches[ myRotationIndex ]; 00371 myCurrentMatch = completion; 00372 postProcessMatch( &completion ); 00373 emit match( completion ); 00374 return completion; 00375 } 00376 00377 00378 00379 TQString TDECompletion::previousMatch() 00380 { 00381 TQString completion; 00382 myLastMatch = myCurrentMatch; 00383 00384 if ( d->matches.isEmpty() ) { 00385 findAllCompletions( myLastString, &d->matches, myHasMultipleMatches ); 00386 completion = d->matches.last(); 00387 myCurrentMatch = completion; 00388 myRotationIndex = 0; 00389 postProcessMatch( &completion ); 00390 emit match( completion ); 00391 return completion; 00392 } 00393 00394 TQStringList matches = d->matches.list(); 00395 myLastMatch = matches[ myRotationIndex ]; 00396 if ( myRotationIndex == 1 ) 00397 doBeep( Rotation ); // indicate first item -> rotating 00398 00399 else if ( myRotationIndex == 0 ) 00400 myRotationIndex = matches.count(); 00401 00402 myRotationIndex--; 00403 00404 completion = matches[ myRotationIndex ]; 00405 myCurrentMatch = completion; 00406 postProcessMatch( &completion ); 00407 emit match( completion ); 00408 return completion; 00409 } 00410 00411 00412 00413 // tries to complete "string" from the tree-root 00414 TQString TDECompletion::findCompletion( const TQString& string ) 00415 { 00416 TQChar ch; 00417 TQString completion; 00418 const TDECompTreeNode *node = myTreeRoot; 00419 00420 // start at the tree-root and try to find the search-string 00421 for( uint i = 0; i < string.length(); i++ ) { 00422 ch = string.at( i ); 00423 node = node->find( ch ); 00424 00425 if ( node ) 00426 completion += ch; 00427 else 00428 return TQString::null; // no completion 00429 } 00430 00431 // Now we have the last node of the to be completed string. 00432 // Follow it as long as it has exactly one child (= longest possible 00433 // completion) 00434 00435 while ( node->childrenCount() == 1 ) { 00436 node = node->firstChild(); 00437 if ( !node->isNull() ) 00438 completion += *node; 00439 } 00440 // if multiple matches and auto-completion mode 00441 // -> find the first complete match 00442 if ( node && node->childrenCount() > 1 ) { 00443 myHasMultipleMatches = true; 00444 00445 if ( myCompletionMode == TDEGlobalSettings::CompletionAuto ) { 00446 myRotationIndex = 1; 00447 if (myOrder != Weighted) { 00448 while ( (node = node->firstChild()) ) { 00449 if ( !node->isNull() ) 00450 completion += *node; 00451 else 00452 break; 00453 } 00454 } 00455 else { 00456 // don't just find the "first" match, but the one with the 00457 // highest priority 00458 00459 const TDECompTreeNode* temp_node = 0L; 00460 while(1) { 00461 int count = node->childrenCount(); 00462 temp_node = node->firstChild(); 00463 uint weight = temp_node->weight(); 00464 const TDECompTreeNode* hit = temp_node; 00465 for( int i = 1; i < count; i++ ) { 00466 temp_node = node->childAt(i); 00467 if( temp_node->weight() > weight ) { 00468 hit = temp_node; 00469 weight = hit->weight(); 00470 } 00471 } 00472 // 0x0 has the highest priority -> we have the best match 00473 if ( hit->isNull() ) 00474 break; 00475 00476 node = hit; 00477 completion += *node; 00478 } 00479 } 00480 } 00481 00482 else 00483 doBeep( PartialMatch ); // partial match -> beep 00484 } 00485 00486 return completion; 00487 } 00488 00489 00490 void TDECompletion::findAllCompletions(const TQString& string, 00491 TDECompletionMatchesWrapper *matches, 00492 bool& hasMultipleMatches) const 00493 { 00494 //kdDebug(0) << "*** finding all completions for " << string << endl; 00495 00496 if ( string.isEmpty() ) 00497 return; 00498 00499 if ( myIgnoreCase ) { // case insensitive completion 00500 extractStringsFromNodeCI( myTreeRoot, TQString::null, string, matches ); 00501 hasMultipleMatches = (matches->count() > 1); 00502 return; 00503 } 00504 00505 TQChar ch; 00506 TQString completion; 00507 const TDECompTreeNode *node = myTreeRoot; 00508 00509 // start at the tree-root and try to find the search-string 00510 for( uint i = 0; i < string.length(); i++ ) { 00511 ch = string.at( i ); 00512 node = node->find( ch ); 00513 00514 if ( node ) 00515 completion += ch; 00516 else 00517 return; // no completion -> return empty list 00518 } 00519 00520 // Now we have the last node of the to be completed string. 00521 // Follow it as long as it has exactly one child (= longest possible 00522 // completion) 00523 00524 while ( node->childrenCount() == 1 ) { 00525 node = node->firstChild(); 00526 if ( !node->isNull() ) 00527 completion += *node; 00528 // kdDebug() << completion << node->latin1(); 00529 } 00530 00531 00532 // there is just one single match) 00533 if ( node->childrenCount() == 0 ) 00534 matches->append( node->weight(), completion ); 00535 00536 else { 00537 // node has more than one child 00538 // -> recursively find all remaining completions 00539 hasMultipleMatches = true; 00540 extractStringsFromNode( node, completion, matches ); 00541 } 00542 } 00543 00544 00545 void TDECompletion::extractStringsFromNode( const TDECompTreeNode *node, 00546 const TQString& beginning, 00547 TDECompletionMatchesWrapper *matches, 00548 bool addWeight ) const 00549 { 00550 if ( !node || !matches ) 00551 return; 00552 00553 // kDebug() << "Beginning: " << beginning << endl; 00554 const TDECompTreeChildren *list = node->children(); 00555 TQString string; 00556 TQString w; 00557 00558 // loop thru all children 00559 for ( TDECompTreeNode *cur = list->begin(); cur ; cur = cur->next) { 00560 string = beginning; 00561 node = cur; 00562 if ( !node->isNull() ) 00563 string += *node; 00564 00565 while ( node && node->childrenCount() == 1 ) { 00566 node = node->firstChild(); 00567 if ( node->isNull() ) 00568 break; 00569 string += *node; 00570 } 00571 00572 if ( node && node->isNull() ) { // we found a leaf 00573 if ( addWeight ) { 00574 // add ":num" to the string to store the weighting 00575 string += ':'; 00576 w.setNum( node->weight() ); 00577 string.append( w ); 00578 } 00579 matches->append( node->weight(), string ); 00580 } 00581 00582 // recursively find all other strings. 00583 if ( node && node->childrenCount() > 1 ) 00584 extractStringsFromNode( node, string, matches, addWeight ); 00585 } 00586 } 00587 00588 void TDECompletion::extractStringsFromNodeCI( const TDECompTreeNode *node, 00589 const TQString& beginning, 00590 const TQString& restString, 00591 TDECompletionMatchesWrapper *matches ) const 00592 { 00593 if ( restString.isEmpty() ) { 00594 extractStringsFromNode( node, beginning, matches, false /*noweight*/ ); 00595 return; 00596 } 00597 00598 TQChar ch1 = restString.at(0); 00599 TQString newRest = restString.mid(1); 00600 TDECompTreeNode *child1, *child2; 00601 00602 child1 = node->find( ch1 ); // the correct match 00603 if ( child1 ) 00604 extractStringsFromNodeCI( child1, beginning + *child1, newRest, 00605 matches ); 00606 00607 // append the case insensitive matches, if available 00608 if ( ch1.isLetter() ) { 00609 // find out if we have to lower or upper it. Is there a better way? 00610 TQChar ch2 = ch1.lower(); 00611 if ( ch1 == ch2 ) 00612 ch2 = ch1.upper(); 00613 if ( ch1 != ch2 ) { 00614 child2 = node->find( ch2 ); 00615 if ( child2 ) 00616 extractStringsFromNodeCI( child2, beginning + *child2, newRest, 00617 matches ); 00618 } 00619 } 00620 } 00621 00622 void TDECompletion::doBeep( BeepMode mode ) const 00623 { 00624 if ( !myBeep ) 00625 return; 00626 00627 TQString text, event; 00628 00629 switch ( mode ) { 00630 case Rotation: 00631 event = TQString::fromLatin1("Textcompletion: rotation"); 00632 text = i18n("You reached the end of the list\nof matching items.\n"); 00633 break; 00634 case PartialMatch: 00635 if ( myCompletionMode == TDEGlobalSettings::CompletionShell || 00636 myCompletionMode == TDEGlobalSettings::CompletionMan ) { 00637 event = TQString::fromLatin1("Textcompletion: partial match"); 00638 text = i18n("The completion is ambiguous, more than one\nmatch is available.\n"); 00639 } 00640 break; 00641 case NoMatch: 00642 if ( myCompletionMode == TDEGlobalSettings::CompletionShell ) { 00643 event = TQString::fromLatin1("Textcompletion: no match"); 00644 text = i18n("There is no matching item available.\n"); 00645 } 00646 break; 00647 } 00648 00649 if ( !text.isEmpty() ) 00650 KNotifyClient::event( event, text ); 00651 } 00652 00653 00656 00657 00658 // Implements the tree. Every node is a TQChar and has a list of children, which 00659 // are Nodes as well. 00660 // TQChar( 0x0 ) is used as the delimiter of a string; the last child of each 00661 // inserted string is 0x0. 00662 00663 TDECompTreeNode::~TDECompTreeNode() 00664 { 00665 // delete all children 00666 TDECompTreeNode *cur = myChildren.begin(); 00667 while (cur) { 00668 TDECompTreeNode * next = cur->next; 00669 delete myChildren.remove(cur); 00670 cur = next; 00671 } 00672 } 00673 00674 00675 // Adds a child-node "ch" to this node. If such a node is already existant, 00676 // it will not be created. Returns the new/existing node. 00677 TDECompTreeNode * TDECompTreeNode::insert( const TQChar& ch, bool sorted ) 00678 { 00679 TDECompTreeNode *child = find( ch ); 00680 if ( !child ) { 00681 child = new TDECompTreeNode( ch ); 00682 00683 // FIXME, first (slow) sorted insertion implementation 00684 if ( sorted ) { 00685 TDECompTreeNode * prev = 0; 00686 TDECompTreeNode * cur = myChildren.begin(); 00687 while ( cur ) { 00688 if ( ch > *cur ) { 00689 prev = cur; 00690 cur = cur->next; 00691 } else 00692 break; 00693 } 00694 if (prev) 00695 myChildren.insert( prev, child ); 00696 else 00697 myChildren.prepend(child); 00698 } 00699 00700 else 00701 myChildren.append( child ); 00702 } 00703 00704 // implicit weighting: the more often an item is inserted, the higher 00705 // priority it gets. 00706 child->confirm(); 00707 00708 return child; 00709 } 00710 00711 00712 // Iteratively removes a string from the tree. The nicer recursive 00713 // version apparently was a little memory hungry (see #56757) 00714 void TDECompTreeNode::remove( const TQString& str ) 00715 { 00716 TQString string = str; 00717 string += TQChar(0x0); 00718 00719 TQPtrVector<TDECompTreeNode> deletables( string.length() + 1 ); 00720 00721 TDECompTreeNode *child = 0L; 00722 TDECompTreeNode *parent = this; 00723 deletables.insert( 0, parent ); 00724 00725 uint i = 0; 00726 for ( ; i < string.length(); i++ ) 00727 { 00728 child = parent->find( string.at( i ) ); 00729 if ( child ) 00730 deletables.insert( i + 1, child ); 00731 else 00732 break; 00733 00734 parent = child; 00735 } 00736 00737 for ( ; i >= 1; i-- ) 00738 { 00739 parent = deletables.at( i - 1 ); 00740 child = deletables.at( i ); 00741 if ( child->myChildren.count() == 0 ) 00742 delete parent->myChildren.remove( child ); 00743 } 00744 } 00745 00746 TQStringList TDECompletionMatchesWrapper::list() const 00747 { 00748 if ( sortedList && dirty ) { 00749 sortedList->sort(); 00750 dirty = false; 00751 00752 stringList.clear(); 00753 00754 // high weight == sorted last -> reverse the sorting here 00755 TQValueListConstIterator<KSortableItem<TQString> > it; 00756 for ( it = sortedList->begin(); it != sortedList->end(); ++it ) 00757 stringList.prepend( (*it).value() ); 00758 } 00759 00760 return stringList; 00761 } 00762 00763 TDECompletionMatches::TDECompletionMatches( bool sort_P ) 00764 : _sorting( sort_P ) 00765 { 00766 } 00767 00768 TDECompletionMatches::TDECompletionMatches( const TDECompletionMatchesWrapper& matches ) 00769 : _sorting( matches.sorting()) 00770 { 00771 if( matches.sortedList != 0L ) 00772 TDECompletionMatchesList::operator=( *matches.sortedList ); 00773 else { 00774 TQStringList l = matches.list(); 00775 for( TQStringList::ConstIterator it = l.begin(); 00776 it != l.end(); 00777 ++it ) 00778 prepend( KSortableItem<TQString, int>( 1, *it ) ); 00779 } 00780 } 00781 00782 TDECompletionMatches::~TDECompletionMatches() 00783 { 00784 } 00785 00786 TQStringList TDECompletionMatches::list( bool sort_P ) const 00787 { 00788 if( _sorting && sort_P ) 00789 const_cast< TDECompletionMatches* >( this )->sort(); 00790 TQStringList stringList; 00791 // high weight == sorted last -> reverse the sorting here 00792 for ( ConstIterator it = begin(); it != end(); ++it ) 00793 stringList.prepend( (*it).value() ); 00794 return stringList; 00795 } 00796 00797 void TDECompletionMatches::removeDuplicates() 00798 { 00799 Iterator it1, it2; 00800 for ( it1 = begin(); it1 != end(); ++it1 ) { 00801 for ( (it2 = it1), ++it2; it2 != end();) { 00802 if( (*it1).value() == (*it2).value()) { 00803 // use the max height 00804 (*it1).first = kMax( (*it1).index(), (*it2).index()); 00805 it2 = remove( it2 ); 00806 continue; 00807 } 00808 ++it2; 00809 } 00810 } 00811 } 00812 00813 void TDECompTreeNodeList::append(TDECompTreeNode *item) 00814 { 00815 m_count++; 00816 if (!last) { 00817 last = item; 00818 last->next = 0; 00819 first = item; 00820 return; 00821 } 00822 last->next = item; 00823 item->next = 0; 00824 last = item; 00825 } 00826 00827 void TDECompTreeNodeList::prepend(TDECompTreeNode *item) 00828 { 00829 m_count++; 00830 if (!last) { 00831 last = item; 00832 last->next = 0; 00833 first = item; 00834 return; 00835 } 00836 item->next = first; 00837 first = item; 00838 } 00839 00840 void TDECompTreeNodeList::insert(TDECompTreeNode *after, TDECompTreeNode *item) 00841 { 00842 if (!after) { 00843 append(item); 00844 return; 00845 } 00846 00847 m_count++; 00848 00849 item->next = after->next; 00850 after->next = item; 00851 00852 if (after == last) 00853 last = item; 00854 } 00855 00856 TDECompTreeNode *TDECompTreeNodeList::remove(TDECompTreeNode *item) 00857 { 00858 if (!first || !item) 00859 return 0; 00860 TDECompTreeNode *cur = 0; 00861 00862 if (item == first) 00863 first = first->next; 00864 else { 00865 cur = first; 00866 while (cur && cur->next != item) cur = cur->next; 00867 if (!cur) 00868 return 0; 00869 cur->next = item->next; 00870 } 00871 if (item == last) 00872 last = cur; 00873 m_count--; 00874 return item; 00875 } 00876 00877 TDECompTreeNode *TDECompTreeNodeList::at(uint index) const 00878 { 00879 TDECompTreeNode *cur = first; 00880 while (index-- && cur) cur = cur->next; 00881 return cur; 00882 } 00883 00884 TDEZoneAllocator TDECompTreeNode::alloc(8192); 00885 00886 void TDECompletion::virtual_hook( int, void* ) 00887 { /*BASE::virtual_hook( id, data );*/ } 00888 00889 void TDECompletionBase::virtual_hook( int, void* ) 00890 { /*BASE::virtual_hook( id, data );*/ } 00891 00892 #include "kcompletion.moc"