-void TabCompleter::buildCompletionList() {
- completionList.clear();
- nextCompletion = completionList.begin();
- // this is the first time tab is pressed -> build up the completion list and it's iterator
- QModelIndex currentIndex = Client::bufferModel()->currentIndex();
- if(!currentIndex.data(NetworkModel::BufferIdRole).isValid())
- return;
-
- NetworkId networkId = currentIndex.data(NetworkModel::NetworkIdRole).value<NetworkId>();
- QString channelName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
-
- const Network *network = Client::network(networkId);
- if(!network)
- return;
-
- IrcChannel *channel = network->ircChannel(channelName);
- if(!channel)
- return;
-
- // FIXME commented for debugging
- /*
- disconnect(this, SLOT(ircUserJoinedOrParted(IrcUser *)));
- connect(channel, SIGNAL(ircUserJoined(IrcUser *)),
- this, SLOT(ircUserJoinedOrParted(IrcUser *)));
- connect(channel, SIGNAL(ircUserParted(IrcUser *)),
- this, SLOT(ircUserJoinedOrParted(IrcUser *)));
- */
-
- completionList.clear();
- QString tabAbbrev = inputLine->text().left(inputLine->cursorPosition()).section(' ',-1,-1);
- completionList.clear();
- QRegExp regex(QString("^[^a-zA-Z]*").append(tabAbbrev), Qt::CaseInsensitive);
- QMap<QString, QString> sortMap;
-
- foreach(IrcUser *ircUser, channel->ircUsers()) {
- if(regex.indexIn(ircUser->nick()) > -1) {
- sortMap[ircUser->nick().toLower()] = ircUser->nick();
+void TabCompleter::onTabCompletionKey()
+{
+ // do nothing; we use the event filter instead
+}
+
+void TabCompleter::buildCompletionList()
+{
+ // ensure a safe state in case we return early.
+ _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();
+ _currentBufferId = currentIndex.data(NetworkModel::BufferIdRole).value<BufferId>();
+ if (!_currentBufferId.isValid())
+ return;
+
+ NetworkId networkId = currentIndex.data(NetworkModel::NetworkIdRole).value<NetworkId>();
+ _currentBufferName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
+
+ _currentNetwork = Client::network(networkId);
+ if (!_currentNetwork)
+ return;
+
+ QString tabAbbrev = _lineEdit->text().left(_lineEdit->cursorPosition()).section(QRegExp(R"([^#\w\d-_\[\]{}|`^.\\])"), -1, -1);
+ QRegExp regex(QString(R"(^[-_\[\]{}|`^.\\]*)").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;
+ // fallthrough
+ case BufferInfo::StatusBuffer:
+ if (!_currentNetwork->myNick().isEmpty() && regex.indexIn(_currentNetwork->myNick()) > -1)
+ _completionMap[_currentNetwork->myNick().toLower()] = _currentNetwork->myNick();
+ break;
+ default:
+ return;
+ }