Source Code (Use browser search to find items of interest.)

Class Index

kdelibs'KCompletion (./kdelibs/kdecore/kcompletion.h:119)

class KCompletion : public QObject
{
    Q_OBJECT

public:
    /**
     * Constructor, nothing special here :)
     */
    KCompletion();

    // FIXME: copy constructor, assignment constructor...

    /**
     * Destructor, nothing special here, either.
     */
    virtual ~KCompletion();

    /**
     * Attempts to find an item in the list of available completions,
     * that begins with string. Will either return the first (if more than one
     * match) matching item or QString::null, if no match was found. In the
     * latter case, a beep will be issued, depending on @ref isSoundsEnabled().
     * If a match was found, it will also be emitted via the signal
     * @ref match().
     *
     * If this is called twice or more often with the same string while no
     * items were added or removed in the meantime, all available completions
     * will be emitted via the signal @ref matches().
     * This happens only in shell-completion-mode.
     *
     * @returns the matching item, or QString::null if there is no matching
     * item.
     * @see #slotMakeCompletion
     */
    virtual QString makeCompletion( const QString& string );

    /**
     * @returns the next item from the matching-items-list
     * When reaching the beginning, the list is rotated, so it will return
     * the last match. When there is no match, QString::null is returned and
     * a beep will be issued, depending on @ref isSoundsEnabled().
     * @see #slotPreviousMatch
     */
    QString previousMatch();

    /**
     * @returns the previous item from the matching-items-list
     * When reaching the last item, the list is rotated, so it will return
     * the first match. When there is no match, QString::null is returned and
     * a beep will be issued, depending on @ref isSoundsEnabled().
     * @see #slotNextMatch
     */
    QString nextMatch();

    /**
     * @returns the last match. Might be useful if you need to check whether
     * a completion is different from the last one.
     * QString::null is returned when there is no last match.
     */
    virtual const QString& lastMatch() const { return myLastMatch; }


    /**
     * @returns a list of all items inserted into KCompletion. This is useful
     * if you need to save the state of a KCompletion object and restore it
     * later.
     * @see #setItems
     */
    QStringList items() const;


    /**
     * Sets the completion mode to Auto/Manual (see @ref KCompletion
     * documentation), Shell or None.
     * If you don't set the mode explicitly, the global default value
     * KGlobalSettings::completionMode() is used.
     * @ref KGlobalSettings::CompletionNone disables completion.
     * @see #completionMode
     * @see #KGlobalSettings::completionMode
     */
    void setCompletionMode( KGlobalSettings::Completion mode );

    /**
     * @returns the current completion mode.
     * May be different from @ref KGlobalSettings::completionMode(), if you
     * explicitly called @ref setCompletionMode().
     * @see #setCompletionMode
     */
    KGlobalSettings::Completion completionMode() const { return myCompletionMode; }

    /**
     * Setting this to true makes us go into sorted mode (doh).
     * Completion will then always return the alphabetically first match.
     * If set to false, the order is the same as the items were inserted.
     * Note: this only affects new inserted items, already existing items will
     * stay in the current order. So you probably want to call setSorted( true )
     * before inserting items, when you want everything sorted.
     * Default is false, not sorted.
     * @see #isSorted
     */
    void setSorted( bool enable ) { mySorting = enable; }

    /**
     * Setting this to true makes KCompletion behave case insensitively.
     * E.g. makeCompletion( "CA" ); might return "carp@cs.tu-berlin.de".
     * Default is false (case sensitive).
     * @see #ignoreCase
     */
    //  void setIgnoreCase( bool ignoreCase ) { myIgnoreCase = ignoreCase; }

    /**
     * @returns whether KCompletion acts case insensitively or not.
     * Default is false (case sensitive).
     * @see #setIgnoreCase
     */
    //  bool ignoreCase() const { return myIgnoreCase; }

    /**
     * @returns true if the completion-items are alphabetically sorted and
     * false if the order of insertion is used.
     * @see #setSorted
     */
    bool isSorted() const { return mySorting; }

    /**
     * @returns a list of all matching items. Might take some time, when you
     * have LOTS of items.
     */
    QStringList allMatches() { return findAllCompletions( myLastString ); }

    /**
     * Enables playing a sound when
     * @li @ref makeCompletion() can't find a match
     * @li there is a partial completion
     * @li @ref nextMatch() or @ref previousMatch() hit the last possible
     *     match -> rotation
     *
     * @see #disableSounds
     * @see #isSoundEnabled
     */
    void enableSounds() { myBeep = true; }

    /**
     * Disables playing a sound when
     * @li @ref makeCompletion() can't find a match
     * @li there is a partial completion
     *
     * Sounds are only played in shell-completion mode. Default is enabled
     * @see #enableSounds
     * @see #isSoundEnabled
     */
    void disableSounds() { myBeep = false; }

    /**
     * Tells you whether KCompletion will issue beeps (@ref KApplication::beep())
     * Beeps only in manual-completion mode
     * Default is enabled
     * @see #enableSounds
     * @see #disableSounds
     */
    bool isSoundsEnabled() const { return myBeep; }


public slots:
    /**
     * Attempts to complete "string" and emits the completion via @ref match().
     * Same as @ref makeCompletion() (just as a slot).
     * @see #makeCompletion
     */
    void slotMakeCompletion( const QString& string ) {
	(void) makeCompletion( string );
    }

    /**
     * Searches the previous matching item and emits it via @ref match()
     * Same as @ref previousMatch() (just as a slot).
     * @see #previousMatch
     */
    void slotPreviousMatch() {
	(void) previousMatch();
    }

    /**
     * Searches the next matching item and emits it via @ref match()
     * Same as @ref nextMatch() (just as a slot).
     * @see #nextMatch
     */
    void slotNextMatch() {
	(void) nextMatch();
    }

    /**
     * @returns true when more than one match is found
     * @see #multipleMatches
     */
    bool hasMultipleMatches() const { return myHasMultipleMatches; }

    /**
     * Sets the list of items available for completion. Removes all previous
     * items.
     * @see #items
     */
    void setItems( const QStringList& );

    /**
     * Adds an item to the list of available completions.
     * Resets the current item-state (@ref previousMatch() and @ref nextMatch()
     * won't work anymore).
     */
    void addItem( const QString& );

    /**
     * Removes an item from the list of available completions.
     * Resets the current item-state (@ref previousMatch() and @ref nextMatch()
     * won't work anymore).
     */
    void removeItem( const QString& );

    /**
     * Clears the list of inserted items.
     */
    void clear();


signals:
    /**
     * The matching item. Will be emitted by @ref makeCompletion(),
     * @ref previousMatch() or @ref nextMatch(). May be QString::null if there is
     * no matching item.
     */
    void match( const QString& );

    /**
     * All matching items. Will be emitted by @ref makeCompletion() in shell-
     * completion-mode, when the same string is passed to makeCompletion twice
     * or more often.
     */
    void matches( const QStringList& );

    /**
     * This signal is emitted, when calling @ref makeCompletion() and more than
     * one matching item is found.
     * @see #hasMultipleMatches
     */
    void multipleMatches();

protected:
    /**
     * This method is called after a completion is found and before the
     * matching string is emitted. You can override this method to modify the
     * string that will be emitted.
     * This is necessary e.g. in @ref KURLCompletion, where files with spaces
     * in their names are shown escaped ("filename\ with\ spaces"), but stored
     * unescaped inside KCompletion.
     * Never delete that pointer!
     *
     * Default implementation does nothing.
     * @see #postProcessMatches
     */
    virtual void postProcessMatch( QString * /*match*/ ) {}

    /**
     * This method is called before a list of all available completions is
     * emitted via @ref matches. You can override this method to modify the
     * list which that will be emitted.
     * Never delete that pointer!
     *
     * Default implementation does nothing.
     * @see #postProcessMatch
     */
    virtual void postProcessMatches( QStringList * /*matches*/ ) {}

private:
    void 		addItemInternal( const QString& );
    QString 		findCompletion( const QString& string );
    const QStringList& 	findAllCompletions( const QString& );
    void 		extractStringsFromNode( const KCompTreeNode *,
						const QString& beginning,
						QStringList *matches ) const;

    enum 		BeepMode { NoMatch, PartialMatch, Rotation };
    void 		doBeep( BeepMode );

    QStringList         myMatches;
    KGlobalSettings::Completion myCompletionMode;

    QString             myLastString;
    QString 		myLastMatch;
    QString 		myCurrentMatch;
    KCompTreeNode *     myTreeRoot;
    QStringList 	myRotations;
    bool                mySorting;
    bool                myBeep;
    bool 		myBackwards;
    bool 		myIgnoreCase;
    bool 		myHasMultipleMatches;
    int 		myItemIndex; // FIXME
    uint 		myRotationIndex;

    KCompletionPrivate *d;
};


 /**
 * An abstract base class for adding completion feature
 * into widgets.
 *
 * This is a convienence class that tries to provide
 * the common functions needed to add support for
 * completion into widgets.  Refer to @ref KLineEdit
 * or @ref KComboBox to see how to such support can be
 * added using this base class.
 *
 * NOTE: Do not forget to provide an implementation for
 * the protected pure virtual method @ref connectSignals()
 * if you do not want the class to be abstract.
 *
 * @short An abstract class for using KCompletion in widgets
 * @author Dawit Alemayehu <adawit@earthlink.net>
 */

kdelibs'KCompletion::KCompletion() (./kdelibs/kdecore/kcompletion.cpp:29)

KCompletion::KCompletion()
{
    myCompletionMode = KGlobalSettings::completionMode();
    myTreeRoot = new KCompTreeNode;
    mySorting    = false;
    myBeep       = true;
    myIgnoreCase = false;
    myRotationIndex = 0;
}


kdelibs'KCompletion::~KCompletion() (./kdelibs/kdecore/kcompletion.cpp:39)

KCompletion::~KCompletion()
{
    delete myTreeRoot;
}



kdelibs'KCompletion::setItems() (./kdelibs/kdecore/kcompletion.cpp:45)

void KCompletion::setItems( const QStringList& items )
{
    myMatches.clear();
    myRotationIndex = 0;
    myLastString = QString::null;

    QStringList::ConstIterator it;
    for ( it = items.begin(); it != items.end(); ++it )
        addItemInternal( *it );
}



kdelibs'KCompletion::items() (./kdelibs/kdecore/kcompletion.cpp:57)

QStringList KCompletion::items() const
{
    QStringList list;
    extractStringsFromNode( myTreeRoot, QString::null, &list );

    return list;
}



kdelibs'KCompletion::addItem() (./kdelibs/kdecore/kcompletion.cpp:66)

void KCompletion::addItem( const QString& item )
{
    myMatches.clear();
    myRotationIndex = 0;
    myLastString = QString::null;

    addItemInternal( item );
}



kdelibs'KCompletion::addItemInternal() (./kdelibs/kdecore/kcompletion.cpp:76)

void KCompletion::addItemInternal( const QString& item )
{
    QChar ch;
    KCompTreeNode *node = myTreeRoot;

    for ( uint i = 0; i < item.length(); i++ ) {
        ch = item.at( i );
	node = node->insert( ch, mySorting );
    }

    node->insert( 0x0, true ); // add 0x0-item as delimiter
}



kdelibs'KCompletion::removeItem() (./kdelibs/kdecore/kcompletion.cpp:90)

void KCompletion::removeItem( const QString& item )
{
    myMatches.clear();
    myRotationIndex = 0;
    myLastString = QString::null;

    myTreeRoot->remove( item );
}



kdelibs'KCompletion::clear() (./kdelibs/kdecore/kcompletion.cpp:100)

void KCompletion::clear()
{
    myMatches.clear();
    myRotationIndex = 0;
    myLastString = QString::null;

    delete myTreeRoot;
    myTreeRoot = new KCompTreeNode;
}



kdelibs'KCompletion::makeCompletion() (./kdelibs/kdecore/kcompletion.cpp:111)

QString KCompletion::makeCompletion( const QString& string )
{
    if ( myCompletionMode == KGlobalSettings::CompletionNone )
        return QString::null;

    kdDebug(0) << "KCompletion: completing: " << debugString( string ) << endl;

    myMatches.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 ) {
        myMatches = findAllCompletions( string );
	postProcessMatches( &myMatches );
	emit matches( myMatches );
    }

    QString completion = findCompletion( string );
    if ( myHasMultipleMatches )
        emit multipleMatches();

    myLastString = string;
    myCurrentMatch = completion;

    if ( !string.isEmpty() ) { // only emit match when string != ""
	kdDebug(0) << "KCompletion: Match: " << completion;

	postProcessMatch( &completion );
        emit match( completion );
    }
	else
        postProcessMatch( &completion );

    if ( completion.isNull() )
        doBeep( NoMatch );

    return completion;
}



kdelibs'KCompletion::setCompletionMode() (./kdelibs/kdecore/kcompletion.cpp:155)

void KCompletion::setCompletionMode( KGlobalSettings::Completion mode )
{
    myCompletionMode = mode;
}



/////////////////////////////////////////////////////
///////////////// tree operations ///////////////////



kdelibs'KCompletion::nextMatch() (./kdelibs/kdecore/kcompletion.cpp:166)

QString KCompletion::nextMatch()
{
    QString completion;
    myLastMatch = myCurrentMatch;

    if ( myMatches.isEmpty() ) {
	myMatches = findAllCompletions( myLastString );
	completion = myMatches.first();
	myCurrentMatch = completion;
	postProcessMatch( &completion );
	emit match( completion );
	return completion;
    }

    myLastMatch = myMatches[ myRotationIndex++ ];

    if ( myRotationIndex == myMatches.count() -1 )
	doBeep( Rotation ); // indicate last matching item -> rotating

    else if ( myRotationIndex == myMatches.count() )
	myRotationIndex = 0;

    completion = myMatches[ myRotationIndex ];
    myCurrentMatch = completion;
    postProcessMatch( &completion );
    emit match( completion );
    return completion;
}




kdelibs'KCompletion::previousMatch() (./kdelibs/kdecore/kcompletion.cpp:197)

QString KCompletion::previousMatch()
{
    QString completion;
    myLastMatch = myCurrentMatch;

    if ( myMatches.isEmpty() ) {
	myMatches = findAllCompletions( myLastString );
	completion = myMatches.last();
	myCurrentMatch = completion;
	postProcessMatch( &completion );
	emit match( completion );
	return completion;
    }

    myLastMatch = myMatches[ myRotationIndex ];
    if ( myRotationIndex == 1 )
	doBeep( Rotation ); // indicate first item -> rotating

    else if ( myRotationIndex == 0 )
	myRotationIndex = myMatches.count();

    myRotationIndex--;

    completion = myMatches[ myRotationIndex ];
    myCurrentMatch = completion;
    postProcessMatch( &completion );
    emit match( completion );
    return completion;
}



// tries to complete "string" from the tree-root

kdelibs'KCompletion::findCompletion() (./kdelibs/kdecore/kcompletion.cpp:230)

QString KCompletion::findCompletion( const QString& string )
{
    QChar ch;
    QString 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.at( i );
	node = node->find( ch, myIgnoreCase );

	if ( node )
	    completion += ch;
	else
	    return QString::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 ||
	     myCompletionMode == KGlobalSettings::CompletionMan ) {

	    myRotationIndex = 1;
	    while ( (node = node->firstChild()) ) {
		if ( !node->isNull() )
		    completion += *node;
		else
		    break;
	    }
	}

	else
	    doBeep( PartialMatch ); // partial match -> beep
    }

    return completion;
}



kdelibs'KCompletion::findAllCompletions() (./kdelibs/kdecore/kcompletion.cpp:282)

const QStringList& KCompletion::findAllCompletions( const QString& string )
{
    kdDebug(0) << "*** finding all completions for " << string << endl;
    myMatches.clear();
    myRotationIndex = 0;

    if ( string.isEmpty() )
        return myMatches;

    QChar ch;
    QString 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.at( i );
	node = node->find( ch, myIgnoreCase );

	if ( node )
	    completion += ch;
	else
	    return myMatches; // 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;
	// debug("-> %s, %c", completion.ascii(), node->latin1());
    }


    // there is just one single match)
    if ( node->childrenCount() == 0 )
        myMatches.append( completion );

    else {
        // node has more than one child
        // -> recursively find all remaining completions
	myHasMultipleMatches = true;
        extractStringsFromNode( node, completion, &myMatches );
    }

    return myMatches;
}



kdelibs'KCompletion::extractStringsFromNode() (./kdelibs/kdecore/kcompletion.cpp:333)

void KCompletion::extractStringsFromNode( const KCompTreeNode *node,
					  const QString& beginning,
					  QStringList *matches ) const
{
    if ( !node || !matches )
        return;

    // debug("Beginning: %s", beginning.ascii());
    KCompTreeChildren::ConstIterator it;
    const KCompTreeChildren *list = node->children();
    QString string;

    // loop thru all children
    for ( it = list->begin(); it != list->end(); ++it ) {
        string = beginning;
        node = *it;
	string += *node;

	while ( node && node->childrenCount() == 1 ) {
	    node = node->firstChild();

	    if ( !node->isNull() )
	        string += *node;

	    else { // we found a leaf
	        matches->append( string );
		// debug( " -> found match: %s", debugString( string ));
	    }
	}

	// recursively find all other strings.
	if ( node && node->childrenCount() > 1 )
	    extractStringsFromNode( node, string, matches );
    }
}



kdelibs'KCompletion::doBeep() (./kdelibs/kdecore/kcompletion.cpp:370)

void KCompletion::doBeep( BeepMode mode )
{
    if ( !myBeep )
	return;

    QString text, event;
    
    switch ( mode ) {
    case Rotation:
	event = QString::fromLatin1("KCompletion: rotation");
	text = i18n("You reached the end of the list\nof matching items.\n");
	break;
    case PartialMatch:
	if ( myCompletionMode == KGlobalSettings::CompletionShell ) {
	    event = QString::fromLatin1("KCompletion: partial match");
	    text = i18n("The completion is ambiguous, more than one\nmatch is available.\n");
	}
	break;
    case NoMatch:
	if ( myCompletionMode == KGlobalSettings::CompletionShell ||
	     myCompletionMode == KGlobalSettings::CompletionMan ) {
	    event = QString::fromLatin1("KCompletion: 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 QChar and has a list of children, which
// are Nodes as well.
// QChar( 0x0 ) is used as the delimiter of a string; the last child of each
// inserted string is 0x0.