cmake: avoid de-duplication of user's CXXFLAGS
[quassel.git] / src / uisupport / multilineedit.cpp
index 2c9d594..3711831 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   Copyright (C) 2005-2022 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -18,6 +18,8 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
+#include "multilineedit.h"
+
 #include <QApplication>
 #include <QMessageBox>
 #include <QScrollBar>
 #include "actioncollection.h"
 #include "bufferview.h"
 #include "graphicalui.h"
-#include "multilineedit.h"
 #include "tabcompleter.h"
 
 const int leftMargin = 3;
 
-MultiLineEdit::MultiLineEdit(QWidget *parent)
-    : MultiLineEditParent(parent),
-    _idx(0),
-    _mode(SingleLine),
-    _singleLine(true),
-    _minHeight(1),
-    _maxHeight(5),
-    _scrollBarsEnabled(true),
-    _pasteProtectionEnabled(true),
-    _emacsMode(false),
-    _completionSpace(0),
-    _lastDocumentHeight(-1)
+MultiLineEdit::MultiLineEdit(QWidget* parent)
+    : MultiLineEditParent(parent)
 {
     document()->setDocumentMargin(0);
 
@@ -62,7 +53,7 @@ MultiLineEdit::MultiLineEdit(QWidget *parent)
     // Prevent QTextHtmlImporter::appendNodeText from eating whitespace
     document()->setDefaultStyleSheet("span { white-space: pre-wrap; }");
 
-    connect(this, SIGNAL(textChanged()), this, SLOT(on_textChanged()));
+    connect(this, &QTextEdit::textChanged, this, &MultiLineEdit::on_textChanged);
 
     _mircColorMap["00"] = "#ffffff";
     _mircColorMap["01"] = "#000000";
@@ -82,18 +73,12 @@ MultiLineEdit::MultiLineEdit(QWidget *parent)
     _mircColorMap["15"] = "#c0c0c0";
 }
 
-
-MultiLineEdit::~MultiLineEdit()
-{
-}
-
 #if defined HAVE_SONNET && !defined HAVE_KDE
-Sonnet::Highlighter *MultiLineEdit::highlighter() const
+Sonnet::HighlighterMultiLineEdit::highlighter() const
 {
     return _spellCheckDecorator->highlighter();
 }
 
-
 void MultiLineEdit::setSpellCheckEnabled(bool enabled)
 {
     highlighter()->setActive(enabled);
@@ -102,15 +87,15 @@ void MultiLineEdit::setSpellCheckEnabled(bool enabled)
     }
 }
 
-void MultiLineEdit::contextMenuEvent(QContextMenuEvent *event)
+void MultiLineEdit::contextMenuEvent(QContextMenuEventevent)
 {
-    QMenu *menu = createStandardContextMenu();
+    QMenumenu = createStandardContextMenu();
     menu->addSeparator();
 
     auto action = menu->addAction(tr("Auto Spell Check"));
     action->setCheckable(true);
     action->setChecked(highlighter()->isActive());
-    connect(action, SIGNAL(toggled(bool)), this, SLOT(setSpellCheckEnabled(bool)));
+    connect(action, &QAction::toggled, this, &MultiLineEdit::setSpellCheckEnabled);
 
     menu->exec(event->globalPos());
     delete menu;
@@ -118,14 +103,12 @@ void MultiLineEdit::contextMenuEvent(QContextMenuEvent *event)
 
 #endif
 
-
-void MultiLineEdit::setCustomFont(const QFont &font)
+void MultiLineEdit::setCustomFont(const QFont& font)
 {
     setFont(font);
     updateSizeHint();
 }
 
-
 void MultiLineEdit::setMode(Mode mode)
 {
     if (mode == _mode)
@@ -134,14 +117,12 @@ void MultiLineEdit::setMode(Mode mode)
     _mode = mode;
 }
 
-
 void MultiLineEdit::setLineWrapEnabled(bool enable)
 {
     setLineWrapMode(enable ? WidgetWidth : NoWrap);
     updateSizeHint();
 }
 
-
 void MultiLineEdit::setMinHeight(int lines)
 {
     if (lines == _minHeight)
@@ -151,7 +132,6 @@ void MultiLineEdit::setMinHeight(int lines)
     updateSizeHint();
 }
 
-
 void MultiLineEdit::setMaxHeight(int lines)
 {
     if (lines == _maxHeight)
@@ -161,7 +141,6 @@ void MultiLineEdit::setMaxHeight(int lines)
     updateSizeHint();
 }
 
-
 void MultiLineEdit::setScrollBarsEnabled(bool enable)
 {
     if (_scrollBarsEnabled == enable)
@@ -171,7 +150,6 @@ void MultiLineEdit::setScrollBarsEnabled(bool enable)
     updateScrollBars();
 }
 
-
 void MultiLineEdit::updateScrollBars()
 {
     QFontMetrics fm(font());
@@ -187,15 +165,13 @@ void MultiLineEdit::updateScrollBars()
         setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
 }
 
-
-void MultiLineEdit::resizeEvent(QResizeEvent *event)
+void MultiLineEdit::resizeEvent(QResizeEvent* event)
 {
     QTextEdit::resizeEvent(event);
     updateSizeHint();
     updateScrollBars();
 }
 
-
 void MultiLineEdit::updateSizeHint()
 {
     QFontMetrics fm(font());
@@ -212,7 +188,7 @@ void MultiLineEdit::updateSizeHint()
     opt.lineWidth = lineWidth();
     opt.midLineWidth = midLineWidth();
     opt.state |= QStyle::State_Sunken;
-    QWidget *widget = this;
+    QWidgetwidget = this;
 #ifdef Q_OS_MAC
     widget = 0;
 #endif
@@ -223,35 +199,30 @@ void MultiLineEdit::updateSizeHint()
     }
 }
 
-
 QSize MultiLineEdit::sizeHint() const
 {
     if (!_sizeHint.isValid()) {
-        MultiLineEdit *that = const_cast<MultiLineEdit *>(this);
+        auto* that = const_cast<MultiLineEdit*>(this);
         that->updateSizeHint();
     }
     return _sizeHint;
 }
 
-
 QSize MultiLineEdit::minimumSizeHint() const
 {
     return sizeHint();
 }
 
-
 void MultiLineEdit::setEmacsMode(bool enable)
 {
     _emacsMode = enable;
 }
 
-
-void MultiLineEdit::setPasteProtectionEnabled(bool enable, QWidget *)
+void MultiLineEdit::setPasteProtectionEnabled(bool enable, QWidget*)
 {
     _pasteProtectionEnabled = enable;
 }
 
-
 void MultiLineEdit::historyMoveBack()
 {
     addToHistory(convertRichtextToMircCodes(), true);
@@ -262,17 +233,16 @@ void MultiLineEdit::historyMoveBack()
     }
 }
 
-
 void MultiLineEdit::historyMoveForward()
 {
     addToHistory(convertRichtextToMircCodes(), true);
 
     if (_idx < _history.count()) {
         _idx++;
-        if (_idx < _history.count() || _tempHistory.contains(_idx)) // tempHistory might have an entry for idx == history.count() + 1
+        if (_idx < _history.count() || _tempHistory.contains(_idx))  // tempHistory might have an entry for idx == history.count() + 1
             showHistoryEntry();
         else
-            reset();        // equals clear() in this case
+            reset();  // equals clear() in this case
     }
     else {
         addToHistory(convertRichtextToMircCodes());
@@ -280,8 +250,7 @@ void MultiLineEdit::historyMoveForward()
     }
 }
 
-
-bool MultiLineEdit::addToHistory(const QString &text, bool temporary)
+bool MultiLineEdit::addToHistory(const QString& text, bool temporary)
 {
     if (text.isEmpty())
         return false;
@@ -307,14 +276,13 @@ bool MultiLineEdit::addToHistory(const QString &text, bool temporary)
     return false;
 }
 
-
-bool MultiLineEdit::event(QEvent *e)
+bool MultiLineEdit::event(QEvent* e)
 {
     // We need to make sure that global shortcuts aren't eaten
     if (e->type() == QEvent::ShortcutOverride) {
-        QKeyEvent *event = static_cast<QKeyEvent *>(e);
+        auto* event = static_cast<QKeyEvent*>(e);
         QKeySequence key = QKeySequence(event->key() | event->modifiers());
-        foreach(QAction *action, GraphicalUi::actionCollection()->actions()) {
+        foreach (QAction* action, GraphicalUi::actionCollection()->actions()) {
             if (action->shortcuts().contains(key)) {
                 e->ignore();
                 return false;
@@ -325,8 +293,7 @@ bool MultiLineEdit::event(QEvent *e)
     return MultiLineEditParent::event(e);
 }
 
-
-void MultiLineEdit::keyPressEvent(QKeyEvent *event)
+void MultiLineEdit::keyPressEvent(QKeyEvent* event)
 {
     if (event == QKeySequence::InsertLineSeparator) {
         if (_mode == SingleLine) {
@@ -347,7 +314,7 @@ void MultiLineEdit::keyPressEvent(QKeyEvent *event)
             if (!(event->modifiers() & Qt::ControlModifier)) {
                 int pos = textCursor().position();
                 moveCursor(QTextCursor::Up);
-                if (pos == textCursor().position()) // already on top line -> history
+                if (pos == textCursor().position())  // already on top line -> history
                     historyMoveBack();
             }
             else
@@ -363,7 +330,7 @@ void MultiLineEdit::keyPressEvent(QKeyEvent *event)
             if (!(event->modifiers() & Qt::ControlModifier)) {
                 int pos = textCursor().position();
                 moveCursor(QTextCursor::Down);
-                if (pos == textCursor().position()) // already on bottom line -> history
+                if (pos == textCursor().position())  // already on bottom line -> history
                     historyMoveForward();
             }
             else
@@ -417,9 +384,7 @@ void MultiLineEdit::keyPressEvent(QKeyEvent *event)
                 break;
             }
         }
-        else if (event->modifiers() & Qt::MetaModifier ||
-                 event->modifiers() & Qt::AltModifier)
-        {
+        else if (event->modifiers() & Qt::MetaModifier || event->modifiers() & Qt::AltModifier) {
             switch (event->key()) {
             case Qt::Key_Right:
                 moveCursor(QTextCursor::WordRight);
@@ -446,26 +411,24 @@ void MultiLineEdit::keyPressEvent(QKeyEvent *event)
                 cut();
                 return;
 
-            case Qt::Key_U: // uppercase word
+            case Qt::Key_U:  // uppercase word
                 moveCursor(QTextCursor::WordRight, QTextCursor::KeepAnchor);
                 textCursor().insertText(textCursor().selectedText().toUpper());
                 return;
 
-            case Qt::Key_L: // lowercase word
+            case Qt::Key_L:  // lowercase word
                 moveCursor(QTextCursor::WordRight, QTextCursor::KeepAnchor);
                 textCursor().insertText(textCursor().selectedText().toLower());
                 return;
 
-            case Qt::Key_C:
-            {           // capitalize word
+            case Qt::Key_C: {  // capitalize word
                 moveCursor(QTextCursor::WordRight, QTextCursor::KeepAnchor);
                 QString const text = textCursor().selectedText();
                 textCursor().insertText(text.left(1).toUpper() + text.mid(1).toLower());
                 return;
             }
 
-            case Qt::Key_T:
-            {           // transpose words
+            case Qt::Key_T: {  // transpose words
                 moveCursor(QTextCursor::StartOfWord);
                 moveCursor(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
                 QString const word1 = textCursor().selectedText();
@@ -498,16 +461,15 @@ void MultiLineEdit::keyPressEvent(QKeyEvent *event)
 #endif
 }
 
-
 QString MultiLineEdit::convertRichtextToMircCodes()
 {
-    bool underline, bold, italic, color;
+    bool underline, bold, italic, color, strikethrough;
     QString mircText, mircFgColor, mircBgColor;
     QTextCursor cursor = textCursor();
     QTextCursor peekcursor = textCursor();
     cursor.movePosition(QTextCursor::Start);
 
-    underline = bold = italic = color = false;
+    underline = bold = italic = color = strikethrough = false;
 
     while (cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor)) {
         if (cursor.selectedText() == QString(QChar(QChar::LineSeparator))
@@ -528,6 +490,10 @@ QString MultiLineEdit::convertRichtextToMircCodes()
                 bold = false;
                 mircText.append('\x02');
             }
+            if (strikethrough) {
+                strikethrough = false;
+                mircText.append('\x1E');
+            }
             mircText.append('\n');
         }
         else {
@@ -543,6 +509,10 @@ QString MultiLineEdit::convertRichtextToMircCodes()
                 underline = true;
                 mircText.append('\x1f');
             }
+            if (!strikethrough && cursor.charFormat().fontStrikeOut()) {
+                strikethrough = true;
+                mircText.append('\x1E');
+            }
             if (!color && (cursor.charFormat().foreground().isOpaque() || cursor.charFormat().background().isOpaque())) {
                 color = true;
                 mircText.append('\x03');
@@ -550,7 +520,7 @@ QString MultiLineEdit::convertRichtextToMircCodes()
                 mircBgColor = _mircColorMap.key(cursor.charFormat().background().color().name());
 
                 if (mircFgColor.isEmpty()) {
-                    mircFgColor = "01"; //use black if the current foreground color can't be converted
+                    mircFgColor = "01";  // use black if the current foreground color can't be converted
                 }
 
                 mircText.append(mircFgColor);
@@ -580,6 +550,10 @@ QString MultiLineEdit::convertRichtextToMircCodes()
                     bold = false;
                     mircText.append('\x02');
                 }
+                if (strikethrough) {
+                    strikethrough = false;
+                    mircText.append('\x1E');
+                }
             }
         }
 
@@ -598,11 +572,13 @@ QString MultiLineEdit::convertRichtextToMircCodes()
     if (bold)
         mircText.append('\x02');
 
+    if (strikethrough)
+        mircText.append('\x1E');
+
     return mircText;
 }
 
-
-bool MultiLineEdit::mircCodesChanged(QTextCursor &cursor, QTextCursor &peekcursor)
+bool MultiLineEdit::mircCodesChanged(QTextCursor& cursor, QTextCursor& peekcursor)
 {
     bool changed = false;
     if (cursor.charFormat().font().bold() != peekcursor.charFormat().font().bold())
@@ -611,6 +587,8 @@ bool MultiLineEdit::mircCodesChanged(QTextCursor &cursor, QTextCursor &peekcurso
         changed = true;
     if (cursor.charFormat().fontUnderline() != peekcursor.charFormat().fontUnderline())
         changed = true;
+    if (cursor.charFormat().fontStrikeOut() != peekcursor.charFormat().fontStrikeOut())
+        changed = true;
     if (cursor.charFormat().foreground().color() != peekcursor.charFormat().foreground().color())
         changed = true;
     if (cursor.charFormat().background().color() != peekcursor.charFormat().background().color())
@@ -618,11 +596,10 @@ bool MultiLineEdit::mircCodesChanged(QTextCursor &cursor, QTextCursor &peekcurso
     return changed;
 }
 
-
-QString MultiLineEdit::convertMircCodesToHtml(const QString &text)
+QString MultiLineEdit::convertMircCodesToHtml(const QString& text)
 {
     QStringList words;
-    QRegExp mircCode = QRegExp("(\ 2|\1d|\1f|\ 3)", Qt::CaseSensitive);
+    QRegExp mircCode = QRegExp("(\x02|\x1d|\x1f|\x03|\x1E)", Qt::CaseSensitive);
 
     int posLeft = 0;
     int posRight = 0;
@@ -632,7 +609,7 @@ QString MultiLineEdit::convertMircCodesToHtml(const QString &text)
 
         if (posRight < 0) {
             words << text.mid(posLeft);
-            break; // no more mirc color codes
+            break;  // no more mirc color codes
         }
 
         if (posLeft < posRight) {
@@ -641,6 +618,10 @@ QString MultiLineEdit::convertMircCodesToHtml(const QString &text)
         }
 
         posRight = text.indexOf(mircCode.cap(), posRight + 1);
+        if (posRight == -1) {
+            words << text.mid(posLeft);
+            break;  // unclosed color code; can't process
+        }
         words << text.mid(posLeft, posRight + 1 - posLeft);
         posLeft = posRight + 1;
     }
@@ -659,13 +640,17 @@ QString MultiLineEdit::convertMircCodesToHtml(const QString &text)
             style.append(" text-decoration: underline;");
             words[i].replace('\x1f', "");
         }
+        if (words[i].contains('\x1E')) {
+            style.append(" text-decoration: line-through;");
+            words[i].replace('\x1E', "");
+        }
         if (words[i].contains('\x03')) {
             int pos = words[i].indexOf('\x03');
             int len = 3;
             QString fg = words[i].mid(pos + 1, 2);
             QString bg;
-            if (words[i][pos+3] == ',')
-                bg = words[i].mid(pos+4, 2);
+            if (words[i][pos + 3] == ',')
+                bg = words[i].mid(pos + 4, 2);
 
             style.append(" color:");
             style.append(_mircColorMap[fg]);
@@ -694,13 +679,11 @@ QString MultiLineEdit::convertMircCodesToHtml(const QString &text)
     return words.join("").replace("\n", "<br />");
 }
 
-
 void MultiLineEdit::on_returnPressed()
 {
     on_returnPressed(convertRichtextToMircCodes());
 }
 
-
 void MultiLineEdit::on_returnPressed(QString text)
 {
     if (_completionSpace && text.endsWith(" ")) {
@@ -708,7 +691,7 @@ void MultiLineEdit::on_returnPressed(QString text)
     }
 
     if (!text.isEmpty()) {
-        foreach(const QString &line, text.split('\n', QString::SkipEmptyParts)) {
+        foreach (const QString& line, text.split('\n', QString::SkipEmptyParts)) {
             if (line.isEmpty())
                 continue;
             addToHistory(line);
@@ -722,7 +705,6 @@ void MultiLineEdit::on_returnPressed(QString text)
     }
 }
 
-
 void MultiLineEdit::on_textChanged()
 {
     _completionSpace = qMax(_completionSpace - 1, 0);
@@ -747,7 +729,7 @@ void MultiLineEdit::on_textChanged()
                     msg += "<br />";
                 }
                 msg += "...</p>";
-                QMessageBox question(QMessageBox::NoIcon, tr("Paste Protection"), msg, QMessageBox::Yes|QMessageBox::No);
+                QMessageBox question(QMessageBox::NoIcon, tr("Paste Protection"), msg, QMessageBox::Yes | QMessageBox::No);
                 question.setDefaultButton(QMessageBox::No);
 #ifdef Q_OS_MAC
                 question.setWindowFlags(question.windowFlags() | Qt::Sheet);
@@ -756,7 +738,7 @@ void MultiLineEdit::on_textChanged()
                     return;
             }
 
-            foreach(QString line, lines) {
+            foreach (QString line, lines) {
                 clear();
                 insert(line);
                 on_returnPressed();
@@ -774,43 +756,38 @@ void MultiLineEdit::on_textChanged()
     ensureCursorVisible();
 }
 
-
 void MultiLineEdit::on_documentHeightChanged(qreal)
 {
     updateScrollBars();
 }
 
-
 void MultiLineEdit::reset()
 {
     // every time the MultiLineEdit is cleared we also reset history index
     _idx = _history.count();
     clear();
     QTextBlockFormat format = textCursor().blockFormat();
-    format.setLeftMargin(leftMargin); // we want a little space between the frame and the contents
+    format.setLeftMargin(leftMargin);  // we want a little space between the frame and the contents
     textCursor().setBlockFormat(format);
     updateScrollBars();
 }
 
-
 void MultiLineEdit::showHistoryEntry()
 {
     // if the user changed the history, display the changed line
     setHtml(convertMircCodesToHtml(_tempHistory.contains(_idx) ? _tempHistory[_idx] : _history[_idx]));
     QTextCursor cursor = textCursor();
     QTextBlockFormat format = cursor.blockFormat();
-    format.setLeftMargin(leftMargin); // we want a little space between the frame and the contents
+    format.setLeftMargin(leftMargin);  // we want a little space between the frame and the contents
     cursor.setBlockFormat(format);
     cursor.movePosition(QTextCursor::End);
     setTextCursor(cursor);
     updateScrollBars();
 }
 
-
 void MultiLineEdit::addCompletionSpace()
 {
     // Inserting the space emits textChanged, which should not disable removal
     _completionSpace = 2;
     insertPlainText(" ");
 }
-