diff options
Diffstat (limited to 'kdecore/kcompletion.cpp')
-rw-r--r-- | kdecore/kcompletion.cpp | 892 |
1 files changed, 0 insertions, 892 deletions
diff --git a/kdecore/kcompletion.cpp b/kdecore/kcompletion.cpp deleted file mode 100644 index 813b56027..000000000 --- a/kdecore/kcompletion.cpp +++ /dev/null @@ -1,892 +0,0 @@ -/* This file is part of the KDE libraries - Copyright (C) 1999,2000,2001 Carsten Pfeiffer <pfeiffer@kde.org> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - - -#include <kapplication.h> -#include <kdebug.h> -#include <klocale.h> -#include <knotifyclient.h> -#include <kglobal.h> - -#include <tqptrvector.h> - -#include "kcompletion.h" -#include "kcompletion_private.h" - - -class KCompletionPrivate -{ -public: - // not a member to avoid #including kcompletion_private.h from kcompletion.h - // list used for nextMatch() and previousMatch() - KCompletionMatchesWrapper matches; -}; - -KCompletion::KCompletion() -{ - d = new KCompletionPrivate; - - myCompletionMode = KGlobalSettings::completionMode(); - myTreeRoot = new KCompTreeNode; - myBeep = true; - myIgnoreCase = false; - myHasMultipleMatches = false; - myRotationIndex = 0; - setOrder( Insertion ); -} - -KCompletion::~KCompletion() -{ - delete d; - delete myTreeRoot; -} - -void KCompletion::setOrder( CompOrder order ) -{ - myOrder = order; - d->matches.setSorting( order == Weighted ); -} - -void KCompletion::setIgnoreCase( bool ignoreCase ) -{ - myIgnoreCase = ignoreCase; -} - -void KCompletion::setItems( const TQStringList& items ) -{ - clear(); - insertItems( items ); -} - - -void KCompletion::insertItems( const TQStringList& items ) -{ - bool weighted = (myOrder == Weighted); - TQStringList::ConstIterator it; - if ( weighted ) { // determine weight - for ( it = items.begin(); it != items.end(); ++it ) - addWeightedItem( *it ); - } - else { - for ( it = items.begin(); it != items.end(); ++it ) - addItem( *it, 0 ); - } -} - -TQStringList KCompletion::items() const -{ - KCompletionMatchesWrapper list; // unsorted - bool addWeight = (myOrder == Weighted); - extractStringsFromNode( myTreeRoot, TQString::null, &list, addWeight ); - - return list.list(); -} - -bool KCompletion::isEmpty() const -{ - return (myTreeRoot->childrenCount() == 0); -} - -void KCompletion::addItem( const TQString& item ) -{ - d->matches.clear(); - myRotationIndex = 0; - myLastString = TQString::null; - - addItem( item, 0 ); -} - -void KCompletion::addItem( const TQString& item, uint weight ) -{ - if ( item.isEmpty() ) - return; - - KCompTreeNode *node = myTreeRoot; - uint len = item.length(); - - bool sorted = (myOrder == Sorted); - bool weighted = ((myOrder == Weighted) && weight > 1); - - // knowing the weight of an item, we simply add this weight to all of its - // nodes. - - for ( uint i = 0; i < len; i++ ) { - node = node->insert( item.tqat(i), sorted ); - if ( weighted ) - node->confirm( weight -1 ); // node->insert() sets weighting to 1 - } - - // add 0x0-item as delimiter with evtl. weight - node = node->insert( 0x0, true ); - if ( weighted ) - node->confirm( weight -1 ); -// qDebug("*** added: %s (%i)", item.latin1(), node->weight()); -} - -void KCompletion::addWeightedItem( const TQString& item ) -{ - if ( myOrder != Weighted ) { - addItem( item, 0 ); - return; - } - - uint len = item.length(); - uint weight = 0; - - // find out the weighting of this item (appended to the string as ":num") - int index = item.findRev(':'); - if ( index > 0 ) { - bool ok; - weight = item.mid( index + 1 ).toUInt( &ok ); - if ( !ok ) - weight = 0; - - len = index; // only insert until the ':' - } - - addItem( item.left( len ), weight ); - return; -} - - -void KCompletion::removeItem( const TQString& item ) -{ - d->matches.clear(); - myRotationIndex = 0; - myLastString = TQString::null; - - myTreeRoot->remove( item ); -} - - -void KCompletion::clear() -{ - d->matches.clear(); - myRotationIndex = 0; - myLastString = TQString::null; - - delete myTreeRoot; - myTreeRoot = new KCompTreeNode; -} - - -TQString KCompletion::makeCompletion( const TQString& string ) -{ - if ( myCompletionMode == KGlobalSettings::CompletionNone ) - return TQString::null; - - //kdDebug(0) << "KCompletion: completing: " << string << endl; - - d->matches.clear(); - myRotationIndex = 0; - myHasMultipleMatches = false; - myLastMatch = myCurrentMatch; - - // in Shell-completion-mode, emit all matches when we get the same - // complete-string twice - if ( myCompletionMode == KGlobalSettings::CompletionShell && - string == myLastString ) { - // Don't use d->matches since calling postProcessMatches() - // on d->matches here would interfere with call to - // postProcessMatch() during rotation - - findAllCompletions( string, &d->matches, myHasMultipleMatches ); - TQStringList l = d->matches.list(); - postProcessMatches( &l ); - emit matches( l ); - - if ( l.isEmpty() ) - doBeep( NoMatch ); - - return TQString::null; - } - - TQString completion; - // in case-insensitive popup mode, we search all completions at once - if ( myCompletionMode == KGlobalSettings::CompletionPopup || - myCompletionMode == KGlobalSettings::CompletionPopupAuto ) { - findAllCompletions( string, &d->matches, myHasMultipleMatches ); - if ( !d->matches.isEmpty() ) - completion = d->matches.first(); - } - else - completion = findCompletion( string ); - - if ( myHasMultipleMatches ) - emit multipleMatches(); - - myLastString = string; - myCurrentMatch = completion; - - postProcessMatch( &completion ); - - if ( !string.isEmpty() ) { // only emit match when string is not empty - //kdDebug(0) << "KCompletion: Match: " << completion << endl; - emit match( completion ); - } - - if ( completion.isNull() ) - doBeep( NoMatch ); - - return completion; -} - - -TQStringList KCompletion::substringCompletion( const TQString& string ) const -{ - // get all items in the tree, possibly in sorted order - bool sorted = (myOrder == Weighted); - KCompletionMatchesWrapper allItems( sorted ); - extractStringsFromNode( myTreeRoot, TQString::null, &allItems, false ); - - TQStringList list = allItems.list(); - - // subStringMatches is invoked manually, via a shortcut, so we should - // beep here, if necessary. - if ( list.isEmpty() ) { - doBeep( NoMatch ); - return list; - } - - if ( string.isEmpty() ) { // shortcut - postProcessMatches( &list ); - return list; - } - - TQStringList matches; - TQStringList::ConstIterator it = list.begin(); - - for( ; it != list.end(); ++it ) { - TQString item = *it; - if ( item.find( string, 0, false ) != -1 ) { // always case insensitive - matches.append( item ); - } - } - - postProcessMatches( &matches ); - - if ( matches.isEmpty() ) - doBeep( NoMatch ); - - return matches; -} - - -void KCompletion::setCompletionMode( KGlobalSettings::Completion mode ) -{ - myCompletionMode = mode; -} - -TQStringList KCompletion::allMatches() -{ - // Don't use d->matches since calling postProcessMatches() - // on d->matches here would interfere with call to - // postProcessMatch() during rotation - KCompletionMatchesWrapper matches( myOrder == Weighted ); - bool dummy; - findAllCompletions( myLastString, &matches, dummy ); - TQStringList l = matches.list(); - postProcessMatches( &l ); - return l; -} - -KCompletionMatches KCompletion::allWeightedMatches() -{ - // Don't use d->matches since calling postProcessMatches() - // on d->matches here would interfere with call to - // postProcessMatch() during rotation - KCompletionMatchesWrapper matches( myOrder == Weighted ); - bool dummy; - findAllCompletions( myLastString, &matches, dummy ); - KCompletionMatches ret( matches ); - postProcessMatches( &ret ); - return ret; -} - -TQStringList KCompletion::allMatches( const TQString &string ) -{ - KCompletionMatchesWrapper matches( myOrder == Weighted ); - bool dummy; - findAllCompletions( string, &matches, dummy ); - TQStringList l = matches.list(); - postProcessMatches( &l ); - return l; -} - -KCompletionMatches KCompletion::allWeightedMatches( const TQString &string ) -{ - KCompletionMatchesWrapper matches( myOrder == Weighted ); - bool dummy; - findAllCompletions( string, &matches, dummy ); - KCompletionMatches ret( matches ); - postProcessMatches( &ret ); - return ret; -} - -///////////////////////////////////////////////////// -///////////////// tree operations /////////////////// - - -TQString KCompletion::nextMatch() -{ - TQString completion; - myLastMatch = myCurrentMatch; - - if ( d->matches.isEmpty() ) { - findAllCompletions( myLastString, &d->matches, myHasMultipleMatches ); - completion = d->matches.first(); - myCurrentMatch = completion; - myRotationIndex = 0; - postProcessMatch( &completion ); - emit match( completion ); - return completion; - } - - TQStringList matches = d->matches.list(); - myLastMatch = matches[ myRotationIndex++ ]; - - if ( myRotationIndex == matches.count() -1 ) - doBeep( Rotation ); // indicate last matching item -> rotating - - else if ( myRotationIndex == matches.count() ) - myRotationIndex = 0; - - completion = matches[ myRotationIndex ]; - myCurrentMatch = completion; - postProcessMatch( &completion ); - emit match( completion ); - return completion; -} - - - -TQString KCompletion::previousMatch() -{ - TQString completion; - myLastMatch = myCurrentMatch; - - if ( d->matches.isEmpty() ) { - findAllCompletions( myLastString, &d->matches, myHasMultipleMatches ); - completion = d->matches.last(); - myCurrentMatch = completion; - myRotationIndex = 0; - postProcessMatch( &completion ); - emit match( completion ); - return completion; - } - - TQStringList matches = d->matches.list(); - myLastMatch = matches[ myRotationIndex ]; - if ( myRotationIndex == 1 ) - doBeep( Rotation ); // indicate first item -> rotating - - else if ( myRotationIndex == 0 ) - myRotationIndex = matches.count(); - - myRotationIndex--; - - completion = matches[ myRotationIndex ]; - myCurrentMatch = completion; - postProcessMatch( &completion ); - emit match( completion ); - return completion; -} - - - -// tries to complete "string" from the tree-root -TQString KCompletion::findCompletion( const TQString& string ) -{ - TQChar ch; - TQString completion; - const KCompTreeNode *node = myTreeRoot; - - // start at the tree-root and try to find the search-string - for( uint i = 0; i < string.length(); i++ ) { - ch = string.tqat( i ); - node = node->find( ch ); - - if ( node ) - completion += ch; - else - return TQString::null; // no completion - } - - // Now we have the last node of the to be completed string. - // Follow it as long as it has exactly one child (= longest possible - // completion) - - while ( node->childrenCount() == 1 ) { - node = node->firstChild(); - if ( !node->isNull() ) - completion += *node; - } - // if multiple matches and auto-completion mode - // -> find the first complete match - if ( node && node->childrenCount() > 1 ) { - myHasMultipleMatches = true; - - if ( myCompletionMode == KGlobalSettings::CompletionAuto ) { - myRotationIndex = 1; - if (myOrder != Weighted) { - while ( (node = node->firstChild()) ) { - if ( !node->isNull() ) - completion += *node; - else - break; - } - } - else { - // don't just find the "first" match, but the one with the - // highest priority - - const KCompTreeNode* temp_node = 0L; - while(1) { - int count = node->childrenCount(); - temp_node = node->firstChild(); - uint weight = temp_node->weight(); - const KCompTreeNode* hit = temp_node; - for( int i = 1; i < count; i++ ) { - temp_node = node->tqchildAt(i); - if( temp_node->weight() > weight ) { - hit = temp_node; - weight = hit->weight(); - } - } - // 0x0 has the highest priority -> we have the best match - if ( hit->isNull() ) - break; - - node = hit; - completion += *node; - } - } - } - - else - doBeep( PartialMatch ); // partial match -> beep - } - - return completion; -} - - -void KCompletion::findAllCompletions(const TQString& string, - KCompletionMatchesWrapper *matches, - bool& hasMultipleMatches) const -{ - //kdDebug(0) << "*** finding all completions for " << string << endl; - - if ( string.isEmpty() ) - return; - - if ( myIgnoreCase ) { // case insensitive completion - extractStringsFromNodeCI( myTreeRoot, TQString::null, string, matches ); - hasMultipleMatches = (matches->count() > 1); - return; - } - - TQChar ch; - TQString completion; - const KCompTreeNode *node = myTreeRoot; - - // start at the tree-root and try to find the search-string - for( uint i = 0; i < string.length(); i++ ) { - ch = string.tqat( i ); - node = node->find( ch ); - - if ( node ) - completion += ch; - else - return; // no completion -> return empty list - } - - // Now we have the last node of the to be completed string. - // Follow it as long as it has exactly one child (= longest possible - // completion) - - while ( node->childrenCount() == 1 ) { - node = node->firstChild(); - if ( !node->isNull() ) - completion += *node; - // kdDebug() << completion << node->latin1(); - } - - - // there is just one single match) - if ( node->childrenCount() == 0 ) - matches->append( node->weight(), completion ); - - else { - // node has more than one child - // -> recursively find all remaining completions - hasMultipleMatches = true; - extractStringsFromNode( node, completion, matches ); - } -} - - -void KCompletion::extractStringsFromNode( const KCompTreeNode *node, - const TQString& beginning, - KCompletionMatchesWrapper *matches, - bool addWeight ) const -{ - if ( !node || !matches ) - return; - - // kDebug() << "Beginning: " << beginning << endl; - const KCompTreeChildren *list = node->children(); - TQString string; - TQString w; - - // loop thru all children - for ( KCompTreeNode *cur = list->begin(); cur ; cur = cur->next) { - string = beginning; - node = cur; - if ( !node->isNull() ) - string += *node; - - while ( node && node->childrenCount() == 1 ) { - node = node->firstChild(); - if ( node->isNull() ) - break; - string += *node; - } - - if ( node && node->isNull() ) { // we found a leaf - if ( addWeight ) { - // add ":num" to the string to store the weighting - string += ':'; - w.setNum( node->weight() ); - string.append( w ); - } - matches->append( node->weight(), string ); - } - - // recursively find all other strings. - if ( node && node->childrenCount() > 1 ) - extractStringsFromNode( node, string, matches, addWeight ); - } -} - -void KCompletion::extractStringsFromNodeCI( const KCompTreeNode *node, - const TQString& beginning, - const TQString& restString, - KCompletionMatchesWrapper *matches ) const -{ - if ( restString.isEmpty() ) { - extractStringsFromNode( node, beginning, matches, false /*noweight*/ ); - return; - } - - TQChar ch1 = restString.tqat(0); - TQString newRest = restString.mid(1); - KCompTreeNode *child1, *child2; - - child1 = node->find( ch1 ); // the correct match - if ( child1 ) - extractStringsFromNodeCI( child1, beginning + *child1, newRest, - matches ); - - // append the case insensitive matches, if available - if ( ch1.isLetter() ) { - // find out if we have to lower or upper it. Is there a better way? - TQChar ch2 = ch1.lower(); - if ( ch1 == ch2 ) - ch2 = ch1.upper(); - if ( ch1 != ch2 ) { - child2 = node->find( ch2 ); - if ( child2 ) - extractStringsFromNodeCI( child2, beginning + *child2, newRest, - matches ); - } - } -} - -void KCompletion::doBeep( BeepMode mode ) const -{ - if ( !myBeep ) - return; - - TQString text, event; - - switch ( mode ) { - case Rotation: - event = TQString::tqfromLatin1("Textcompletion: rotation"); - text = i18n("You reached the end of the list\nof matching items.\n"); - break; - case PartialMatch: - if ( myCompletionMode == KGlobalSettings::CompletionShell || - myCompletionMode == KGlobalSettings::CompletionMan ) { - event = TQString::tqfromLatin1("Textcompletion: partial match"); - text = i18n("The completion is ambiguous, more than one\nmatch is available.\n"); - } - break; - case NoMatch: - if ( myCompletionMode == KGlobalSettings::CompletionShell ) { - event = TQString::tqfromLatin1("Textcompletion: no match"); - text = i18n("There is no matching item available.\n"); - } - break; - } - - if ( !text.isEmpty() ) - KNotifyClient::event( event, text ); -} - - -///////////////////////////////// -///////// - - -// Implements the tree. Every node is a TQChar and has a list of children, which -// are Nodes as well. -// TQChar( 0x0 ) is used as the delimiter of a string; the last child of each -// inserted string is 0x0. - -KCompTreeNode::~KCompTreeNode() -{ - // delete all children - KCompTreeNode *cur = myChildren.begin(); - while (cur) { - KCompTreeNode * next = cur->next; - delete myChildren.remove(cur); - cur = next; - } -} - - -// Adds a child-node "ch" to this node. If such a node is already existant, -// it will not be created. Returns the new/existing node. -KCompTreeNode * KCompTreeNode::insert( const TQChar& ch, bool sorted ) -{ - KCompTreeNode *child = find( ch ); - if ( !child ) { - child = new KCompTreeNode( ch ); - - // FIXME, first (slow) sorted insertion implementation - if ( sorted ) { - KCompTreeNode * prev = 0; - KCompTreeNode * cur = myChildren.begin(); - while ( cur ) { - if ( ch > *cur ) { - prev = cur; - cur = cur->next; - } else - break; - } - if (prev) - myChildren.insert( prev, child ); - else - myChildren.prepend(child); - } - - else - myChildren.append( child ); - } - - // implicit weighting: the more often an item is inserted, the higher - // priority it gets. - child->confirm(); - - return child; -} - - -// Iteratively removes a string from the tree. The nicer recursive -// version apparently was a little memory hungry (see #56757) -void KCompTreeNode::remove( const TQString& str ) -{ - TQString string = str; - string += TQChar(0x0); - - TQPtrVector<KCompTreeNode> deletables( string.length() + 1 ); - - KCompTreeNode *child = 0L; - KCompTreeNode *parent = this; - deletables.insert( 0, parent ); - - uint i = 0; - for ( ; i < string.length(); i++ ) - { - child = parent->find( string.tqat( i ) ); - if ( child ) - deletables.insert( i + 1, child ); - else - break; - - parent = child; - } - - for ( ; i >= 1; i-- ) - { - parent = deletables.tqat( i - 1 ); - child = deletables.tqat( i ); - if ( child->myChildren.count() == 0 ) - delete parent->myChildren.remove( child ); - } -} - -TQStringList KCompletionMatchesWrapper::list() const -{ - if ( sortedList && dirty ) { - sortedList->sort(); - dirty = false; - - stringList.clear(); - - // high weight == sorted last -> reverse the sorting here - TQValueListConstIterator<KSortableItem<TQString> > it; - for ( it = sortedList->begin(); it != sortedList->end(); ++it ) - stringList.prepend( (*it).value() ); - } - - return stringList; -} - -KCompletionMatches::KCompletionMatches( bool sort_P ) - : _sorting( sort_P ) -{ -} - -KCompletionMatches::KCompletionMatches( const KCompletionMatchesWrapper& matches ) - : _sorting( matches.sorting()) -{ - if( matches.sortedList != 0L ) - KCompletionMatchesList::operator=( *matches.sortedList ); - else { - TQStringList l = matches.list(); - for( TQStringList::ConstIterator it = l.begin(); - it != l.end(); - ++it ) - prepend( KSortableItem<TQString, int>( 1, *it ) ); - } -} - -KCompletionMatches::~KCompletionMatches() -{ -} - -TQStringList KCompletionMatches::list( bool sort_P ) const -{ - if( _sorting && sort_P ) - const_cast< KCompletionMatches* >( this )->sort(); - TQStringList stringList; - // high weight == sorted last -> reverse the sorting here - for ( ConstIterator it = begin(); it != end(); ++it ) - stringList.prepend( (*it).value() ); - return stringList; -} - -void KCompletionMatches::removeDuplicates() -{ - Iterator it1, it2; - for ( it1 = begin(); it1 != end(); ++it1 ) { - for ( (it2 = it1), ++it2; it2 != end();) { - if( (*it1).value() == (*it2).value()) { - // use the max height - (*it1).first = kMax( (*it1).index(), (*it2).index()); - it2 = remove( it2 ); - continue; - } - ++it2; - } - } -} - -void KCompTreeNodeList::append(KCompTreeNode *item) -{ - m_count++; - if (!last) { - last = item; - last->next = 0; - first = item; - return; - } - last->next = item; - item->next = 0; - last = item; -} - -void KCompTreeNodeList::prepend(KCompTreeNode *item) -{ - m_count++; - if (!last) { - last = item; - last->next = 0; - first = item; - return; - } - item->next = first; - first = item; -} - -void KCompTreeNodeList::insert(KCompTreeNode *after, KCompTreeNode *item) -{ - if (!after) { - append(item); - return; - } - - m_count++; - - item->next = after->next; - after->next = item; - - if (after == last) - last = item; -} - -KCompTreeNode *KCompTreeNodeList::remove(KCompTreeNode *item) -{ - if (!first || !item) - return 0; - KCompTreeNode *cur = 0; - - if (item == first) - first = first->next; - else { - cur = first; - while (cur && cur->next != item) cur = cur->next; - if (!cur) - return 0; - cur->next = item->next; - } - if (item == last) - last = cur; - m_count--; - return item; -} - -KCompTreeNode *KCompTreeNodeList::tqat(uint index) const -{ - KCompTreeNode *cur = first; - while (index-- && cur) cur = cur->next; - return cur; -} - -KZoneAllocator KCompTreeNode::alloc(8192); - -void KCompletion::virtual_hook( int, void* ) -{ /*BASE::virtual_hook( id, data );*/ } - -void KCompletionBase::virtual_hook( int, void* ) -{ /*BASE::virtual_hook( id, data );*/ } - -#include "kcompletion.moc" |