/* Copyright 2003 Rikard Björklind, Arsenij Vodjanov, Mikael Gransell This file is part of dc-qt. dc-qt is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. dc-qt 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 General Public License for more details. You should have received a copy of the GNU General Public License along with dc-qt; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "chatedit.h" ChatEdit::ChatEdit( QWidget *parent, const char *name ) : QLineEdit(parent, name) { completions = StrStrVec ( 256 ); lastindex = 0; tabs = 0; } ChatEdit::~ ChatEdit() { clearCompletions(); } void ChatEdit::keyPressEvent( QKeyEvent *e ) { // keypress behaviour: // reset tab counter tabs = 0; QLineEdit::keyPressEvent( e ); } void ChatEdit::focusOutEvent( QFocusEvent *e ) { // exit if this event is not a TAB-focus change if (e->reason() != QFocusEvent::Tab) { /* if (e->reason() == QFocusEvent::Other) tabs = 0; */ QLineEdit::focusOutEvent(e); return; } tabs++; // behaviour on first tab press: // if one match exists, then autocomplete // if several matches exist, then display list of all matches // behaviour on following tab presses (tab counter >= 2): // if any matches exist, then autocomplete 1st match // if no matches exist, then execute default behaviour and reset tab counter int fromPos; // a stringlist of all matching strings QStringList matches; if (cursorPosition() > 0) { QChar lastchar = text().at( cursorPosition()-1 ); // proceed if last entered character is NOT some sort of separator if ( ! ( lastchar.isSpace() || lastchar.isNull() ) ) { // starting from last character, search backwards until a separator character is found for ( fromPos = cursorPosition()-1; fromPos>=0; fromPos--) { QChar c = text().at(fromPos); if ( c.isSpace() || c.isNull() ) break; } fromPos++; QString str = text().mid(fromPos, cursorPosition() - fromPos); if (!str.isEmpty()) { QChar c = str.at(0).lower(); if (cindex[c] < lastindex) { StrVec &ssv = completions[ cindex[c] ]; for ( unsigned int k = 0; k= 2) { #ifdef _DEBUG printf("Gave up focus!\n"); #endif tabs = 0; QLineEdit::focusOutEvent(e); return; } // here we have found one or more matches if ((matches.count()==1) || (matches.count() > 0 && tabs>=2)) { // if only one match exists, // or several matches exist and tab has been pressed more than once, // then complete with first match tabs = 0; setText( text().left( fromPos ) + matches[0] + ": " ); // replace incomplete string with full completion moveCompletionToFront(matches[0]); // relocate this completion in list } else { // else if we have any matches, and tab has only been pressed once, display list of matches if (matches.count()>0 && tabs < 2) { if (matches.count()<8) emit messageStr( QString("<-----> ") + matches.join(" ") + " "); else emit messageStr( QString("<-----> ") + matches[0] + " " + matches[1] + " " + matches[2] + " " + matches[3] + QString(" ... %1 possible completions").arg(matches.count()) ); } } matches.clear(); setFocus(); end(false); // move cursor to end and deselect all } void ChatEdit::addCompletion( const QString &str ) { if (str.isEmpty()) return; QChar c = str.at(0).lower(); if (cindex.find(c) == cindex.end()) cindex[c] = lastindex++; if (lastindex>=completions.count()) completions.resize(lastindex * 2); completions[ cindex[c] ].push_back( str ); #ifdef _DEBUG printf("addCompletion: \"%s\" -> \'%c\' (%u)\n", str.ascii(), c.latin1(), cindex[c]); #endif } void ChatEdit::removeCompletion( const QString &str ) { if (str.isEmpty()) return; QChar c = str.at(0).lower(); if (cindex[c] >= lastindex) return; #ifdef _DEBUG printf("removeCompletion: \"%s\" -> \'%c\' (%u)\n", str.ascii(), c.latin1(), cindex[c]); #endif StrVec &ssv = completions[ cindex[c] ]; StrVec::iterator i = ssv.begin(); while( i != ssv.end() ) { if (*i == str) { ssv.erase(i); return; } else i++; } } void ChatEdit::clearCompletions() { completions.clear(); cindex.clear(); completions = StrStrVec ( 256 ); lastindex = 0; tabs = 0; } void ChatEdit::moveCompletionToFront( const QString &str ) { if (str.isEmpty()) return; QChar c = str.at(0).lower(); if (cindex[c] >= lastindex) return; StrVec &ssv = completions[ cindex[c] ]; for ( unsigned int i = 0; i