/***************************************************************************
- * Copyright (C) 2005-2015 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 <QApplication>
#include <QClipboard>
#include <QDesktopServices>
#include <QDrag>
#include <QGraphicsSceneMouseEvent>
-#include <QIcon>
#include <QMenu>
#include <QMenuBar>
#include <QMimeData>
# include <QMenuBar>
#endif
-#ifdef HAVE_WEBKIT
+#ifdef HAVE_WEBENGINE
+# include <QWebEngineView>
+#elif defined HAVE_WEBKIT
# include <QWebView>
#endif
#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;
_markerLineValid(false),
_markerLineJumpPending(false),
_cutoffMode(CutoffRight),
+ _alwaysBracketSender(false),
_selectingItem(0),
_selectionStart(-1),
_isSelecting(false),
this, SLOT(rowsRemoved()));
connect(model, SIGNAL(dataChanged(QModelIndex, QModelIndex)), SLOT(dataChanged(QModelIndex, QModelIndex)));
-#ifdef HAVE_WEBKIT
+#if defined HAVE_WEBKIT || defined HAVE_WEBENGINE
webPreview.timer.setSingleShot(true);
connect(&webPreview.timer, SIGNAL(timeout()), this, SLOT(webPreviewNextStep()));
#endif
_showWebPreview = defaultSettings.showWebPreview();
defaultSettings.notify("ShowWebPreview", this, SLOT(showWebPreviewChanged()));
+ _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()));
// 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);
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);
}
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::SenderColumn)
- result += _lines[l]->item(ChatLineModel::SenderColumn)->data(MessageModel::DisplayRole).toString() + " ";
- result += _lines[l]->item(ChatLineModel::ContentsColumn)->data(MessageModel::DisplayRole).toString() + "\n";
+ 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 && (_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 {
+ result += item->data(MessageModel::DisplayRole).toString() + " ";
+ }
+ }
+ result += _lines[l]->item(ChatLineModel::ContentsColumn)
+ ->data(MessageModel::DisplayRole).toString() + "\n";
}
return result;
}
// ========================================
-// Webkit Only stuff
+// Webkit/WebEngine Only stuff
// ========================================
-#ifdef HAVE_WEBKIT
+#if defined HAVE_WEBKIT || defined HAVE_WEBENGINE
void ChatScene::loadWebPreview(ChatItem *parentItem, const QUrl &url, const QRectF &urlRect)
{
if (!_showWebPreview)
qWarning() << "removing preview";
if (webPreview.previewItem && webPreview.previewItem->scene())
removeItem(webPreview.previewItem);
- // Fall through to deletion!
+ // Fall through to deletion!
+ [[clang::fallthrough]];
case WebPreview::HidePreview:
if (webPreview.previewItem) {
delete webPreview.previewItem;
if (webPreview.previewItem && webPreview.previewItem->scene())
removeItem(webPreview.previewItem);
}
- // fall through into to set hidden state
+ // fall through into to set hidden state
+ [[clang::fallthrough]];
case WebPreview::DelayPreview:
// we're just loading, so haven't shown the preview yet.
webPreview.previewState = WebPreview::HidePreview;
// end of webkit only
// ========================================
+// Local configuration caching
void ChatScene::showWebPreviewChanged()
{
ChatViewSettings settings;
_showWebPreview = settings.showWebPreview();
}
+
+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);
+ }
+}