modernize: Migrate action-related things to PMF connects
[quassel.git] / src / qtui / chatscene.cpp
index 1588f4d..67d1425 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2016 by the Quassel Project                        *
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
+#include "chatscene.h"
+
+#include <utility>
+
 #include <QApplication>
 #include <QClipboard>
 #include <QDesktopServices>
 #include <QDrag>
 #include <QGraphicsSceneMouseEvent>
-#include <QIcon>
 #include <QMenu>
 #include <QMenuBar>
 #include <QMimeData>
 #include <QPersistentModelIndex>
 #include <QUrl>
 
-#ifdef HAVE_KDE4
-#  include <KMenuBar>
-#else
-#  include <QMenuBar>
-#endif
-
 #ifdef HAVE_WEBENGINE
 #  include <QWebEngineView>
 #elif defined HAVE_WEBKIT
 #include "chatitem.h"
 #include "chatline.h"
 #include "chatlinemodelitem.h"
-#include "chatscene.h"
 #include "chatview.h"
+#include "chatviewsettings.h"
 #include "client.h"
 #include "clientbacklogmanager.h"
 #include "columnhandleitem.h"
 #include "contextmenuactionprovider.h"
+#include "icon.h"
 #include "mainwin.h"
 #include "markerlineitem.h"
 #include "messagefilter.h"
 #include "qtui.h"
 #include "qtuistyle.h"
-#include "chatviewsettings.h"
 #include "webpreviewitem.h"
 
 const qreal minContentsWidth = 200;
 
-ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal width, ChatView *parent)
+ChatScene::ChatScene(QAbstractItemModel *model, QString idString, qreal width, ChatView *parent)
     : QGraphicsScene(0, 0, width, 0, (QObject *)parent),
     _chatView(parent),
-    _idString(idString),
+    _idString(std::move(idString)),
     _model(model),
     _singleBufferId(BufferId()),
     _sceneRect(0, 0, width, 0),
@@ -76,20 +73,20 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w
     _markerLineJumpPending(false),
     _cutoffMode(CutoffRight),
     _alwaysBracketSender(false),
-    _selectingItem(0),
+    _selectingItem(nullptr),
     _selectionStart(-1),
     _isSelecting(false),
     _clickMode(NoClick),
     _clickHandled(true),
     _leftButtonPressed(false)
 {
-    MessageFilter *filter = qobject_cast<MessageFilter *>(model);
+    auto *filter = qobject_cast<MessageFilter *>(model);
     if (filter && filter->isSingleBufferFilter()) {
         _singleBufferId = filter->singleBufferId();
     }
 
     addItem(_markerLine);
-    connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _markerLine, SLOT(sceneRectChanged(const QRectF &)));
+    connect(this, &QGraphicsScene::sceneRectChanged, _markerLine, &MarkerLineItem::sceneRectChanged);
 
     ChatViewSettings defaultSettings;
     _defaultFirstColHandlePos = defaultSettings.value("FirstColumnHandlePos", 80).toInt();
@@ -102,32 +99,32 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w
     _firstColHandle = new ColumnHandleItem(QtUi::style()->firstColumnSeparator());
     addItem(_firstColHandle);
     _firstColHandle->setXPos(_firstColHandlePos);
-    connect(_firstColHandle, SIGNAL(positionChanged(qreal)), this, SLOT(firstHandlePositionChanged(qreal)));
-    connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _firstColHandle, SLOT(sceneRectChanged(const QRectF &)));
+    connect(_firstColHandle, &ColumnHandleItem::positionChanged, this, &ChatScene::firstHandlePositionChanged);
+    connect(this, &QGraphicsScene::sceneRectChanged, _firstColHandle, &ColumnHandleItem::sceneRectChanged);
 
     _secondColHandle = new ColumnHandleItem(QtUi::style()->secondColumnSeparator());
     addItem(_secondColHandle);
     _secondColHandle->setXPos(_secondColHandlePos);
-    connect(_secondColHandle, SIGNAL(positionChanged(qreal)), this, SLOT(secondHandlePositionChanged(qreal)));
+    connect(_secondColHandle, &ColumnHandleItem::positionChanged, this, &ChatScene::secondHandlePositionChanged);
 
-    connect(this, SIGNAL(sceneRectChanged(const QRectF &)), _secondColHandle, SLOT(sceneRectChanged(const QRectF &)));
+    connect(this, &QGraphicsScene::sceneRectChanged, _secondColHandle, &ColumnHandleItem::sceneRectChanged);
 
     setHandleXLimits();
 
     if (model->rowCount() > 0)
         rowsInserted(QModelIndex(), 0, model->rowCount() - 1);
 
-    connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
-        this, SLOT(rowsInserted(const QModelIndex &, int, int)));
-    connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
-        this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
-    connect(model, SIGNAL(rowsRemoved(QModelIndex, int, int)),
-        this, SLOT(rowsRemoved()));
-    connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(dataChanged(QModelIndex, QModelIndex)));
+    connect(model, &QAbstractItemModel::rowsInserted,
+        this, &ChatScene::rowsInserted);
+    connect(model, &QAbstractItemModel::rowsAboutToBeRemoved,
+        this, &ChatScene::rowsAboutToBeRemoved);
+    connect(model, &QAbstractItemModel::rowsRemoved,
+        this, &ChatScene::rowsRemoved);
+    connect(model, &QAbstractItemModel::dataChanged, this, &ChatScene::dataChanged);
 
 #if defined HAVE_WEBKIT || defined HAVE_WEBENGINE
     webPreview.timer.setSingleShot(true);
-    connect(&webPreview.timer, SIGNAL(timeout()), this, SLOT(webPreviewNextStep()));
+    connect(&webPreview.timer, &QTimer::timeout, this, &ChatScene::webPreviewNextStep);
 #endif
     _showWebPreview = defaultSettings.showWebPreview();
     defaultSettings.notify("ShowWebPreview", this, SLOT(showWebPreviewChanged()));
@@ -144,17 +141,12 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w
 
     _clickTimer.setInterval(QApplication::doubleClickInterval());
     _clickTimer.setSingleShot(true);
-    connect(&_clickTimer, SIGNAL(timeout()), SLOT(clickTimeout()));
+    connect(&_clickTimer, &QTimer::timeout, this, &ChatScene::clickTimeout);
 
     setItemIndexMethod(QGraphicsScene::NoIndex);
 }
 
 
-ChatScene::~ChatScene()
-{
-}
-
-
 ChatView *ChatScene::chatView() const
 {
     return _chatView;
@@ -187,13 +179,13 @@ void ChatScene::resetColumnWidths()
 ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange) const
 {
     if (!_lines.count())
-        return 0;
+        return nullptr;
 
     QList<ChatLine *>::ConstIterator start = _lines.begin();
     QList<ChatLine *>::ConstIterator end = _lines.end();
     QList<ChatLine *>::ConstIterator middle;
 
-    int n = int(end - start);
+    auto n = int(end - start);
     int half;
 
     while (n > 0) {
@@ -212,10 +204,10 @@ ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange
         return *start;
 
     if (matchExact)
-        return 0;
+        return nullptr;
 
     if (start == _lines.begin()) // not (yet?) in our scene
-        return 0;
+        return nullptr;
 
     // if we didn't find the exact msgId, take the next-lower one (this makes sense for lastSeen)
 
@@ -227,7 +219,7 @@ ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange
             if (_lines.at(i)->msgType() != Message::DayChange)
                 return _lines.at(i);
         }
-        return 0;
+        return nullptr;
     }
 
     // return the next-lower line
@@ -239,24 +231,24 @@ ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange
             return *start;
     }
     while (start != _lines.begin());
-    return 0;
+    return nullptr;
 }
 
 
 ChatItem *ChatScene::chatItemAt(const QPointF &scenePos) const
 {
     foreach(QGraphicsItem *item, items(scenePos, Qt::IntersectsItemBoundingRect, Qt::AscendingOrder)) {
-        ChatLine *line = qgraphicsitem_cast<ChatLine *>(item);
+        auto *line = qgraphicsitem_cast<ChatLine *>(item);
         if (line)
             return line->itemAt(line->mapFromScene(scenePos));
     }
-    return 0;
+    return nullptr;
 }
 
 
 bool ChatScene::containsBuffer(const BufferId &id) const
 {
-    MessageFilter *filter = qobject_cast<MessageFilter *>(model());
+    auto *filter = qobject_cast<MessageFilter *>(model());
     if (filter)
         return filter->containsBuffer(id);
     else
@@ -378,7 +370,7 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end)
 
     if (atTop) {
         for (int i = end; i >= start; i--) {
-            ChatLine *line = new ChatLine(i, model(),
+            auto *line = new ChatLine(i, model(),
                 width,
                 timestampWidth, senderWidth, contentsWidth,
                 senderPos, contentsPos);
@@ -390,7 +382,7 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end)
     }
     else {
         for (int i = start; i <= end; i++) {
-            ChatLine *line = new ChatLine(i, model(),
+            auto *line = new ChatLine(i, model(),
                 width,
                 timestampWidth, senderWidth, contentsWidth,
                 senderPos, contentsPos);
@@ -424,7 +416,7 @@ void ChatScene::rowsInserted(const QModelIndex &index, int start, int end)
 
     // neither pre- or append means we have to do dirty work: move items...
     if (!(atTop || atBottom)) {
-        ChatLine *line = 0;
+        ChatLine *line = nullptr;
         for (int i = 0; i <= end; i++) {
             line = _lines.at(i);
             line->setPos(0, line->pos().y() - h);
@@ -489,7 +481,7 @@ void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e
     if (_selectingItem) {
         int row = _selectingItem->row();
         if (row >= start && row <= end)
-            setSelectingItem(0);
+            setSelectingItem(nullptr);
     }
 
     // remove items from scene
@@ -497,7 +489,7 @@ void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e
     int lineCount = start;
     while (lineIter != _lines.end() && lineCount <= end) {
         if ((*lineIter) == markerLine()->chatLine())
-            markerLine()->setChatLine(0);
+            markerLine()->setChatLine(nullptr);
         h += (*lineIter)->height();
         delete *lineIter;
         lineIter = _lines.erase(lineIter);
@@ -539,7 +531,7 @@ void ChatScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int e
             moveStart = start;
             offset = -offset;
         }
-        ChatLine *line = 0;
+        ChatLine *line = nullptr;
         for (int i = moveStart; i <= moveEnd; i++) {
             line = _lines.at(i);
             line->setPos(0, line->pos().y() + offset);
@@ -743,8 +735,8 @@ void ChatScene::updateSelection(const QPointF &pos)
 {
     int curRow = rowByScenePos(pos);
     if (curRow < 0) return;
-    int curColumn = (int)columnByScenePos(pos);
-    ChatLineModel::ColumnType minColumn = (ChatLineModel::ColumnType)qMin(curColumn, _selectionStartCol);
+    auto curColumn = (int)columnByScenePos(pos);
+    auto minColumn = (ChatLineModel::ColumnType)qMin(curColumn, _selectionStartCol);
     if (minColumn != _selectionMinCol) {
         _selectionMinCol = minColumn;
         for (int l = qMin(_selectionStart, _selectionEnd); l <= qMax(_selectionStart, _selectionEnd); l++) {
@@ -836,8 +828,7 @@ void ChatScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
     // If we have text selected, insert the Copy Selection as first item
     if (isPosOverSelection(pos)) {
         QAction *sep = menu.insertSeparator(menu.actions().first());
-        QAction *act = new Action(QIcon::fromTheme("edit-copy"), tr("Copy Selection"), &menu, this,
-            SLOT(selectionToClipboard()), QKeySequence::Copy);
+        QAction *act = new Action(icon::get("edit-copy"), tr("Copy Selection"), &menu, this, [this]() { selectionToClipboard(); }, QKeySequence::Copy);
         menu.insertAction(sep, act);
 
         QString searchSelectionText = selection();
@@ -845,7 +836,7 @@ void ChatScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
             searchSelectionText = searchSelectionText.left(_webSearchSelectionTextMaxVisible).append(QString::fromUtf8("…"));
         searchSelectionText = tr("Search '%1'").arg(searchSelectionText);
 
-        QAction *webSearchAction = new Action(QIcon::fromTheme("edit-find"), searchSelectionText, &menu, this, SLOT(webSearchOnSelection()));
+        QAction *webSearchAction = new Action(icon::get("edit-find"), searchSelectionText, &menu, this, &ChatScene::webSearchOnSelection);
         menu.insertAction(sep, webSearchAction);
     }
 
@@ -855,7 +846,7 @@ void ChatScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
     // show column reset action if columns have been resized in this session or there is at least one very narrow column
     if ((_firstColHandlePos != _defaultFirstColHandlePos) || (_secondColHandlePos != _defaultSecondColHandlePos) ||
         (_firstColHandlePos <= 10) || (_secondColHandlePos - _firstColHandlePos <= 10))
-        menu.addAction(new Action(tr("Reset Column Widths"), &menu, this, SLOT(resetColumnWidths()), 0));
+        menu.addAction(new Action(tr("Reset Column Widths"), &menu, this, &ChatScene::resetColumnWidths));
 
     menu.exec(event->screenPos());
 }
@@ -981,8 +972,8 @@ void ChatScene::handleClick(Qt::MouseButton button, const QPointF &scenePos)
 
 void ChatScene::initiateDrag(QWidget *source)
 {
-    QDrag *drag = new QDrag(source);
-    QMimeData *mimeData = new QMimeData;
+    auto *drag = new QDrag(source);
+    auto *mimeData = new QMimeData;
     mimeData->setText(selection());
     drag->setMimeData(mimeData);
 
@@ -1132,7 +1123,7 @@ void ChatScene::webSearchOnSelection()
 
 void ChatScene::requestBacklog()
 {
-    MessageFilter *filter = qobject_cast<MessageFilter *>(model());
+    auto *filter = qobject_cast<MessageFilter *>(model());
     if (filter)
         return filter->requestBacklog();
     return;
@@ -1156,7 +1147,7 @@ int ChatScene::rowByScenePos(qreal y) const
 
     // ChatLine should be at the bottom of the list
     for (int i = itemList.count()-1; i >= 0; i--) {
-        ChatLine *line = qgraphicsitem_cast<ChatLine *>(itemList.at(i));
+        auto *line = qgraphicsitem_cast<ChatLine *>(itemList.at(i));
         if (line)
             return line->row();
     }
@@ -1232,7 +1223,7 @@ void ChatScene::loadWebPreview(ChatItem *parentItem, const QUrl &url, const QRec
             if (webPreview.previewItem->scene())
                 removeItem(webPreview.previewItem);
             delete webPreview.previewItem;
-            webPreview.previewItem = 0;
+            webPreview.previewItem = nullptr;
         }
         webPreview.previewState = WebPreview::NoPreview;
     }
@@ -1293,16 +1284,18 @@ void ChatScene::webPreviewNextStep()
     case WebPreview::ShowPreview:
         qWarning() << "ChatScene::webPreviewNextStep() called while in ShowPreview Step!";
         qWarning() << "removing preview";
-        if (webPreview.previewItem && webPreview.previewItem->scene())
+        if (webPreview.previewItem && webPreview.previewItem->scene()) {
             removeItem(webPreview.previewItem);
-    // Fall through to deletion!
-    [[fallthrough]];
+        }
+
+        // Intentional fallthrough
+
     case WebPreview::HidePreview:
         if (webPreview.previewItem) {
             delete webPreview.previewItem;
-            webPreview.previewItem = 0;
+            webPreview.previewItem = nullptr;
         }
-        webPreview.parentItem = 0;
+        webPreview.parentItem = nullptr;
         webPreview.url = QUrl();
         webPreview.urlRect = QRectF();
         webPreview.previewState = WebPreview::NoPreview;
@@ -1319,12 +1312,13 @@ void ChatScene::clearWebPreview(ChatItem *parentItem)
         webPreview.previewState = WebPreview::NoPreview; // we haven't loaded anything yet
         break;
     case WebPreview::ShowPreview:
-        if (parentItem == 0 || webPreview.parentItem == parentItem) {
+        if (parentItem == nullptr || webPreview.parentItem == parentItem) {
             if (webPreview.previewItem && webPreview.previewItem->scene())
                 removeItem(webPreview.previewItem);
         }
-    // fall through into to set hidden state
-    [[fallthrough]];
+
+        // Intentional fallthrough
+
     case WebPreview::DelayPreview:
         // we're just loading, so haven't shown the preview yet.
         webPreview.previewState = WebPreview::HidePreview;
@@ -1397,7 +1391,7 @@ void ChatScene::updateTimestampHasBrackets()
         //   (^\s*\(.+\)\s*$)|(^\s*\{.+\}\s*$)|(^\s*\[.+\]\s*$)|(^\s*<.+>\s*$)
         // Note that '\' must be escaped as '\\'
         // Helpful interactive website for debugging and explaining:  https://regex101.com/
-        const QRegExp regExpMatchBrackets("^\\s*[({[<].+[)}\\]>]\\s*$");
+        const QRegExp regExpMatchBrackets(R"(^\s*[({[<].+[)}\]>]\s*$)");
         _timestampHasBrackets = regExpMatchBrackets.exactMatch(_timestampFormatString);
     }
 }