#include "tabcompleter.h"
-#include "inputline.h"
-#include "client.h"
#include "buffermodel.h"
-#include "networkmodel.h"
-#include "network.h"
+#include "client.h"
#include "ircchannel.h"
#include "ircuser.h"
+#include "multilineedit.h"
+#include "network.h"
+#include "networkmodel.h"
#include "uisettings.h"
#include <QRegExp>
const Network *TabCompleter::_currentNetwork;
BufferId TabCompleter::_currentBufferId;
-
-TabCompleter::TabCompleter(InputLine *inputLine_)
- : QObject(inputLine_),
- inputLine(inputLine_),
- enabled(false),
- nickSuffix(": ")
+QString TabCompleter::_currentBufferName;
+TabCompleter::Type TabCompleter::_completionType;
+
+TabCompleter::TabCompleter(MultiLineEdit *_lineEdit)
+ : QObject(_lineEdit),
+ _lineEdit(_lineEdit),
+ _enabled(false),
+ _nickSuffix(": ")
{
- inputLine->installEventFilter(this);
+ _lineEdit->installEventFilter(this);
}
void TabCompleter::buildCompletionList() {
// ensure a safe state in case we return early.
- completionMap.clear();
- nextCompletion = completionMap.begin();
+ _completionMap.clear();
+ _nextCompletion = _completionMap.begin();
// this is the first time tab is pressed -> build up the completion list and it's iterator
QModelIndex currentIndex = Client::bufferModel()->currentIndex();
return;
NetworkId networkId = currentIndex.data(NetworkModel::NetworkIdRole).value<NetworkId>();
- QString bufferName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
+ _currentBufferName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
_currentNetwork = Client::network(networkId);
if(!_currentNetwork)
return;
- QString tabAbbrev = inputLine->text().left(inputLine->cursorPosition()).section(' ',-1,-1);
- QRegExp regex(QString("^[^a-zA-Z]*").append(QRegExp::escape(tabAbbrev)), Qt::CaseInsensitive);
-
- switch(static_cast<BufferInfo::Type>(currentIndex.data(NetworkModel::BufferTypeRole).toInt())) {
- case BufferInfo::ChannelBuffer:
- { // scope is needed for local var declaration
- IrcChannel *channel = _currentNetwork->ircChannel(bufferName);
- if(!channel)
- return;
- foreach(IrcUser *ircUser, channel->ircUsers()) {
- if(regex.indexIn(ircUser->nick()) > -1)
- completionMap[ircUser->nick().toLower()] = ircUser->nick();
+ QString tabAbbrev = _lineEdit->text().left(_lineEdit->cursorPosition()).section(QRegExp("[^#\\w\\d-_\\[\\]{}|`^.\\\\]"),-1,-1);
+ QRegExp regex(QString("^[-_\\[\\]{}|`^.\\\\]*").append(QRegExp::escape(tabAbbrev)), Qt::CaseInsensitive);
+
+ // channel completion - add all channels of the current network to the map
+ if(tabAbbrev.startsWith('#')) {
+ _completionType = ChannelTab;
+ foreach(IrcChannel *ircChannel, _currentNetwork->ircChannels()) {
+ if(regex.indexIn(ircChannel->name()) > -1)
+ _completionMap[ircChannel->name()] = ircChannel->name();
+ }
+ } else {
+ // user completion
+ _completionType = UserTab;
+ switch(static_cast<BufferInfo::Type>(currentIndex.data(NetworkModel::BufferTypeRole).toInt())) {
+ case BufferInfo::ChannelBuffer:
+ { // scope is needed for local var declaration
+ IrcChannel *channel = _currentNetwork->ircChannel(_currentBufferName);
+ if(!channel)
+ return;
+ foreach(IrcUser *ircUser, channel->ircUsers()) {
+ if(regex.indexIn(ircUser->nick()) > -1)
+ _completionMap[ircUser->nick().toLower()] = ircUser->nick();
+ }
}
+ break;
+ case BufferInfo::QueryBuffer:
+ if(regex.indexIn(_currentBufferName) > -1)
+ _completionMap[_currentBufferName.toLower()] = _currentBufferName;
+ case BufferInfo::StatusBuffer:
+ if(!_currentNetwork->myNick().isEmpty() && regex.indexIn(_currentNetwork->myNick()) > -1)
+ _completionMap[_currentNetwork->myNick().toLower()] = _currentNetwork->myNick();
+ break;
+ default:
+ return;
}
- break;
- case BufferInfo::QueryBuffer:
- if(regex.indexIn(bufferName) > -1)
- completionMap[bufferName.toLower()] = bufferName;
- case BufferInfo::StatusBuffer:
- if(!_currentNetwork->myNick().isEmpty() && regex.indexIn(_currentNetwork->myNick()) > -1)
- completionMap[_currentNetwork->myNick().toLower()] = _currentNetwork->myNick();
- break;
- default:
- return;
}
- nextCompletion = completionMap.begin();
- lastCompletionLength = tabAbbrev.length();
+ _nextCompletion = _completionMap.begin();
+ _lastCompletionLength = tabAbbrev.length();
}
void TabCompleter::complete() {
- NickCompletionSettings s;
- nickSuffix = s.completionSuffix();
+ TabCompletionSettings s;
+ _nickSuffix = s.completionSuffix();
- if(!enabled) {
+ if(!_enabled) {
buildCompletionList();
- enabled = true;
+ _enabled = true;
}
- if (nextCompletion != completionMap.end()) {
+ if (_nextCompletion != _completionMap.end()) {
// clear previous completion
- for (int i = 0; i < lastCompletionLength; i++) {
- inputLine->backspace();
+ for (int i = 0; i < _lastCompletionLength; i++) {
+ _lineEdit->backspace();
}
// insert completion
- inputLine->insert(*nextCompletion);
+ _lineEdit->insert(*_nextCompletion);
// remember charcount to delete next time and advance to next completion
- lastCompletionLength = nextCompletion->length();
- nextCompletion++;
+ _lastCompletionLength = _nextCompletion->length();
+ _nextCompletion++;
// we're completing the first word of the line
- if(inputLine->cursorPosition() == lastCompletionLength) {
- inputLine->insert(nickSuffix);
- lastCompletionLength += nickSuffix.length();
+ if(_completionType == UserTab && _lineEdit->cursorPosition() == _lastCompletionLength) {
+ _lineEdit->insert(_nickSuffix);
+ _lastCompletionLength += _nickSuffix.length();
}
// we're at the end of the list -> start over again
} else {
- if(!completionMap.isEmpty()) {
- nextCompletion = completionMap.begin();
+ if(!_completionMap.isEmpty()) {
+ _nextCompletion = _completionMap.begin();
complete();
}
}
}
void TabCompleter::reset() {
- enabled = false;
+ _enabled = false;
}
bool TabCompleter::eventFilter(QObject *obj, QEvent *event) {
- if(obj != inputLine || event->type() != QEvent::KeyPress)
+ if(obj != _lineEdit || event->type() != QEvent::KeyPress)
return QObject::eventFilter(obj, event);
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
// this determines the sort order
bool TabCompleter::CompletionKey::operator<(const CompletionKey &other) const {
- IrcUser *thisUser = _currentNetwork->ircUser(this->nick);
- if(thisUser && _currentNetwork->isMe(thisUser))
- return false;
+ switch(_completionType) {
+ case UserTab:
+ {
+ IrcUser *thisUser = _currentNetwork->ircUser(this->contents);
+ if(thisUser && _currentNetwork->isMe(thisUser))
+ return false;
- IrcUser *thatUser = _currentNetwork->ircUser(other.nick);
- if(thatUser && _currentNetwork->isMe(thatUser))
- return true;
+ IrcUser *thatUser = _currentNetwork->ircUser(other.contents);
+ if(thatUser && _currentNetwork->isMe(thatUser))
+ return true;
- if(!thisUser || !thatUser)
- return QString::localeAwareCompare(this->nick, other.nick) < 0;
+ if(!thisUser || !thatUser)
+ return QString::localeAwareCompare(this->contents, other.contents) < 0;
- QDateTime thisSpokenTo = thisUser->lastSpokenTo(_currentBufferId);
- QDateTime thatSpokenTo = thatUser->lastSpokenTo(_currentBufferId);
+ QDateTime thisSpokenTo = thisUser->lastSpokenTo(_currentBufferId);
+ QDateTime thatSpokenTo = thatUser->lastSpokenTo(_currentBufferId);
- if(thisSpokenTo.isValid() || thatSpokenTo.isValid())
- return thisSpokenTo > thatSpokenTo;
+ if(thisSpokenTo.isValid() || thatSpokenTo.isValid())
+ return thisSpokenTo > thatSpokenTo;
- QDateTime thisTime = thisUser->lastChannelActivity(_currentBufferId);
- QDateTime thatTime = thatUser->lastChannelActivity(_currentBufferId);
+ QDateTime thisTime = thisUser->lastChannelActivity(_currentBufferId);
+ QDateTime thatTime = thatUser->lastChannelActivity(_currentBufferId);
- if(thisTime.isValid() || thatTime.isValid())
- return thisTime > thatTime;
+ if(thisTime.isValid() || thatTime.isValid())
+ return thisTime > thatTime;
+ }
+ break;
+ case ChannelTab:
+ if(QString::compare(_currentBufferName, this->contents, Qt::CaseInsensitive) == 0)
+ return true;
+
+ if(QString::compare(_currentBufferName, other.contents, Qt::CaseInsensitive) == 0)
+ return false;
+ break;
+ default:
+ break;
+ }
- return QString::localeAwareCompare(this->nick, other.nick) < 0;
+ return QString::localeAwareCompare(this->contents, other.contents) < 0;
}