/***************************************************************************
- * Copyright (C) 2005-2013 by the Quassel Project *
+ * Copyright (C) 2005-2020 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "tabcompleter.h"
+#include <QRegExp>
+
+#include "action.h"
+#include "actioncollection.h"
#include "buffermodel.h"
#include "client.h"
+#include "graphicalui.h"
#include "ircchannel.h"
#include "ircuser.h"
#include "multilineedit.h"
#include "network.h"
#include "networkmodel.h"
#include "uisettings.h"
-#include "action.h"
-#include "actioncollection.h"
-#include "graphicalui.h"
-#include <QRegExp>
-
-const Network *TabCompleter::_currentNetwork;
+const Network* TabCompleter::_currentNetwork;
BufferId TabCompleter::_currentBufferId;
QString TabCompleter::_currentBufferName;
TabCompleter::Type TabCompleter::_completionType;
-TabCompleter::TabCompleter(MultiLineEdit *_lineEdit)
- : QObject(_lineEdit),
- _lineEdit(_lineEdit),
- _enabled(false),
- _nickSuffix(": ")
+TabCompleter::TabCompleter(MultiLineEdit* _lineEdit)
+ : QObject(_lineEdit)
+ , _lineEdit(_lineEdit)
+ , _enabled(false)
+ , _nickSuffix(": ")
{
- // use both an Action and generic eventFilter, to make the shortcut configurable
- // yet still be able to reset() when required
+ // This Action just serves as a container for the custom shortcut and isn't actually handled;
+ // apparently, using tab as an Action shortcut in an input widget is unreliable on some platforms (e.g. OS/2)
_lineEdit->installEventFilter(this);
- ActionCollection *coll = GraphicalUi::actionCollection("General");
- coll->addAction("TabCompletionKey", new Action(tr("Tab completion"), coll,
- this, SLOT(onTabCompletionKey()), QKeySequence(Qt::Key_Tab)));
+ ActionCollection* coll = GraphicalUi::actionCollection("General");
+ QAction* a = coll->addAction("TabCompletionKey",
+ new Action(tr("Tab completion"), coll, this, &TabCompleter::onTabCompletionKey, QKeySequence(Qt::Key_Tab)));
+ a->setEnabled(false); // avoid catching the shortcut
}
-
void TabCompleter::onTabCompletionKey()
{
- complete();
+ // do nothing; we use the event filter instead
}
-
void TabCompleter::buildCompletionList()
{
// ensure a safe state in case we return early.
if (!_currentNetwork)
return;
- QString tabAbbrev = _lineEdit->text().left(_lineEdit->cursorPosition()).section(QRegExp("[^#\\w\\d-_\\[\\]{}|`^.\\\\]"), -1, -1);
- QRegExp regex(QString("^[-_\\[\\]{}|`^.\\\\]*").append(QRegExp::escape(tabAbbrev)), Qt::CaseInsensitive);
+ 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()) {
+ foreach (IrcChannel* ircChannel, _currentNetwork->ircChannels()) {
if (regex.indexIn(ircChannel->name()) > -1)
_completionMap[ircChannel->name()] = ircChannel->name();
}
// 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);
+ case BufferInfo::ChannelBuffer: { // scope is needed for local var declaration
+ IrcChannel* channel = _currentNetwork->ircChannel(_currentBufferName);
if (!channel)
return;
- foreach(IrcUser *ircUser, channel->ircUsers()) {
+ foreach (IrcUser* ircUser, channel->ircUsers()) {
if (regex.indexIn(ircUser->nick()) > -1)
_completionMap[ircUser->nick().toLower()] = ircUser->nick();
}
- }
- break;
+ } 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();
_lastCompletionLength = tabAbbrev.length();
}
-
void TabCompleter::complete()
{
TabCompletionSettings s;
_lastCompletionLength += _nickSuffix.length();
}
else if (s.addSpaceMidSentence()) {
- _lineEdit->insert(" ");
+ _lineEdit->addCompletionSpace();
_lastCompletionLength++;
}
}
}
-
void TabCompleter::reset()
{
_enabled = false;
}
-
-bool TabCompleter::eventFilter(QObject *obj, QEvent *event)
+bool TabCompleter::eventFilter(QObject* obj, QEvent* event)
{
if (obj != _lineEdit || event->type() != QEvent::KeyPress)
return QObject::eventFilter(obj, event);
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ auto* keyEvent = static_cast<QKeyEvent*>(event);
- if (keyEvent->key() != GraphicalUi::actionCollection("General")->action("TabCompletionKey")->shortcut()) {
+ if (keyEvent->key() == GraphicalUi::actionCollection("General")->action("TabCompletionKey")->shortcut()[0])
+ complete();
+ else
reset();
- }
+
return false;
}
-
// this determines the sort order
-bool TabCompleter::CompletionKey::operator<(const CompletionKey &other) const
+bool TabCompleter::CompletionKey::operator<(const CompletionKey& other) const
{
switch (_completionType) {
- case UserTab:
- {
- IrcUser *thisUser = _currentNetwork->ircUser(this->contents);
+ case UserTab: {
+ IrcUser* thisUser = _currentNetwork->ircUser(this->contents);
if (thisUser && _currentNetwork->isMe(thisUser))
return false;
- IrcUser *thatUser = _currentNetwork->ircUser(other.contents);
+ IrcUser* thatUser = _currentNetwork->ircUser(other.contents);
if (thatUser && _currentNetwork->isMe(thatUser))
return true;
if (thisTime.isValid() || thatTime.isValid())
return thisTime > thatTime;
- }
- break;
+ } break;
case ChannelTab:
if (QString::compare(_currentBufferName, this->contents, Qt::CaseInsensitive) == 0)
return true;