X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fqtui%2Fchatscene.cpp;h=78c33c88060c7cfc075410849f8ad022dff9a621;hp=96546261d818117b412bdd6e395824a65f5fac80;hb=3a3e844f9fcfd12235a0086af75ecd503b621ef4;hpb=b82e9603ab7ce1164e8f550132f0c649653ad8ab diff --git a/src/qtui/chatscene.cpp b/src/qtui/chatscene.cpp index 96546261..78c33c88 100644 --- a/src/qtui/chatscene.cpp +++ b/src/qtui/chatscene.cpp @@ -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 * @@ -18,24 +18,21 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include "chatscene.h" + +#include + #include #include #include #include #include -#include #include #include #include #include #include -#ifdef HAVE_KDE4 -# include -#else -# include -#endif - #ifdef HAVE_WEBENGINE # include #elif defined HAVE_WEBKIT @@ -45,26 +42,26 @@ #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), @@ -75,7 +72,8 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w _markerLineValid(false), _markerLineJumpPending(false), _cutoffMode(CutoffRight), - _selectingItem(0), + _alwaysBracketSender(false), + _selectingItem(nullptr), _selectionStart(-1), _isSelecting(false), _clickMode(NoClick), @@ -134,6 +132,13 @@ ChatScene::ChatScene(QAbstractItemModel *model, const QString &idString, qreal w _showSenderBrackets = defaultSettings.showSenderBrackets(); defaultSettings.notify("ShowSenderBrackets", this, SLOT(showSenderBracketsChanged())); + _useCustomTimestampFormat = defaultSettings.useCustomTimestampFormat(); + defaultSettings.notify("UseCustomTimestampFormat", this, SLOT(useCustomTimestampFormatChanged())); + + _timestampFormatString = defaultSettings.timestampFormatString(); + defaultSettings.notify("TimestampFormat", this, SLOT(timestampFormatStringChanged())); + updateTimestampHasBrackets(); + _clickTimer.setInterval(QApplication::doubleClickInterval()); _clickTimer.setSingleShot(true); connect(&_clickTimer, SIGNAL(timeout()), SLOT(clickTimeout())); @@ -179,7 +184,7 @@ void ChatScene::resetColumnWidths() ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange) const { if (!_lines.count()) - return 0; + return nullptr; QList::ConstIterator start = _lines.begin(); QList::ConstIterator end = _lines.end(); @@ -204,10 +209,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) @@ -219,7 +224,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 @@ -231,7 +236,7 @@ ChatLine *ChatScene::chatLine(MsgId msgId, bool matchExact, bool ignoreDayChange return *start; } while (start != _lines.begin()); - return 0; + return nullptr; } @@ -242,7 +247,7 @@ ChatItem *ChatScene::chatItemAt(const QPointF &scenePos) const if (line) return line->itemAt(line->mapFromScene(scenePos)); } - return 0; + return nullptr; } @@ -416,7 +421,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); @@ -481,7 +486,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 @@ -489,7 +494,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); @@ -531,7 +536,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); @@ -828,7 +833,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, + QAction *act = new Action(icon::get("edit-copy"), tr("Copy Selection"), &menu, this, SLOT(selectionToClipboard()), QKeySequence::Copy); menu.insertAction(sep, act); @@ -837,7 +842,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, SLOT(webSearchOnSelection())); menu.insertAction(sep, webSearchAction); } @@ -1026,14 +1031,31 @@ QString ChatScene::selection() const return QString(); } QString result; + for (int l = start; l <= end; l++) { - if (_selectionMinCol == ChatLineModel::TimestampColumn) - result += _lines[l]->item(ChatLineModel::TimestampColumn)->data(MessageModel::DisplayRole).toString() + " "; + if (_selectionMinCol == ChatLineModel::TimestampColumn) { + ChatItem *item = _lines[l]->item(ChatLineModel::TimestampColumn); + if (!_showSenderBrackets && !_timestampHasBrackets) { + // Only re-add brackets if the current timestamp format does not include them + // -and- sender brackets are disabled. Don't filter on Message::Plain as + // timestamp brackets affect all types of messages. + // Remove any spaces before and after, otherwise it may look weird. + result += QString("[%1] ").arg(item->data(MessageModel::DisplayRole) + .toString().trimmed()); + } else { + result += item->data(MessageModel::DisplayRole).toString() + " "; + } + } if (_selectionMinCol <= ChatLineModel::SenderColumn) { ChatItem *item = _lines[l]->item(ChatLineModel::SenderColumn); - if (!_showSenderBrackets && item->chatLine()->msgType() == Message::Plain) { - // Copying to plain-text. Only re-add the sender brackets if they're normally - // hidden. + if (!_showSenderBrackets && (_alwaysBracketSender + || item->chatLine()->msgType() == Message::Plain)) { + // Copying to plain-text. Re-add the sender brackets if they're normally hidden + // for... + // * Plain messages + // * All messages in the Chat Monitor + // + // The Chat Monitor sets alwaysBracketSender() to true. result += QString("<%1> ").arg(item->data(MessageModel::DisplayRole) .toString()); } else { @@ -1207,7 +1229,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; } @@ -1268,15 +1290,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! + } + + // 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; @@ -1293,11 +1318,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 + + // Intentional fallthrough + case WebPreview::DelayPreview: // we're just loading, so haven't shown the preview yet. webPreview.previewState = WebPreview::HidePreview; @@ -1329,3 +1356,48 @@ void ChatScene::showSenderBracketsChanged() ChatViewSettings settings; _showSenderBrackets = settings.showSenderBrackets(); } + +void ChatScene::useCustomTimestampFormatChanged() +{ + ChatViewSettings settings; + _useCustomTimestampFormat = settings.useCustomTimestampFormat(); + updateTimestampHasBrackets(); +} + +void ChatScene::timestampFormatStringChanged() +{ + ChatViewSettings settings; + _timestampFormatString = settings.timestampFormatString(); + updateTimestampHasBrackets(); +} + +void ChatScene::updateTimestampHasBrackets() +{ + // Calculate these parameters only as needed, rather than on-demand + + if (!_useCustomTimestampFormat) { + // The default timestamp format string does not have brackets, no need to check. + // If UiStyle::updateSystemTimestampFormat() has brackets added, change this, too. + _timestampHasBrackets = false; + } else { + // Does the timestamp format contain brackets? For example: + // Classic: "[hh:mm:ss]" + // Modern: " hh:mm:ss" + // + // Match groups of any opening or closing brackets - (), {}, [], <>, (>, {], etc: + // ^\s*[({[<].+[)}\]>]\s*$ + // [...] is a character group containing ... + // ^ matches start of string + // \s* matches any amount of whitespace + // [({[<] matches (, {, [, or < + // .+ matches one or more characters + // [)}\]>] matches ), }, ], or >, escaping the ] + // $ matches end of string + // Alternatively, if opening and closing brackets must be in pairs, use this: + // (^\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*$"); + _timestampHasBrackets = regExpMatchBrackets.exactMatch(_timestampFormatString); + } +}