X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fuisupport%2Fmultilineedit.cpp;h=a9a2ae248a75532ed3594a25d225d628cef30bbf;hp=7e89f499ae35cc0d322271e8aa0bc932f6f5a1c1;hb=b359cfe9fdd2427993dc0b2f3f605fd69bbe6bd2;hpb=5748fecfcb2cf979fe5f787a6e5245a29f12ac29 diff --git a/src/uisupport/multilineedit.cpp b/src/uisupport/multilineedit.cpp index 7e89f499..a9a2ae24 100644 --- a/src/uisupport/multilineedit.cpp +++ b/src/uisupport/multilineedit.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2015 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -18,31 +18,21 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ +#include "multilineedit.h" + #include -#include #include #include #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); @@ -51,11 +41,19 @@ MultiLineEdit::MultiLineEdit(QWidget *parent) enableFindReplace(false); #endif +#if defined HAVE_SONNET && !defined HAVE_KDE + _spellCheckDecorator = new Sonnet::SpellCheckDecorator(this); + highlighter()->setActive(highlighter()->checkerEnabledByDefault()); +#endif + setMode(SingleLine); setLineWrapEnabled(false); reset(); - connect(this, SIGNAL(textChanged()), this, SLOT(on_textChanged())); + // Prevent QTextHtmlImporter::appendNodeText from eating whitespace + document()->setDefaultStyleSheet("span { white-space: pre-wrap; }"); + + connect(this, &QTextEdit::textChanged, this, &MultiLineEdit::on_textChanged); _mircColorMap["00"] = "#ffffff"; _mircColorMap["01"] = "#000000"; @@ -75,19 +73,42 @@ MultiLineEdit::MultiLineEdit(QWidget *parent) _mircColorMap["15"] = "#c0c0c0"; } +#if defined HAVE_SONNET && !defined HAVE_KDE +Sonnet::Highlighter* MultiLineEdit::highlighter() const +{ + return _spellCheckDecorator->highlighter(); +} -MultiLineEdit::~MultiLineEdit() +void MultiLineEdit::setSpellCheckEnabled(bool enabled) { + highlighter()->setActive(enabled); + if (enabled) { + highlighter()->slotRehighlight(); + } } +void MultiLineEdit::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu* menu = createStandardContextMenu(); + menu->addSeparator(); + + auto action = menu->addAction(tr("Auto Spell Check")); + action->setCheckable(true); + action->setChecked(highlighter()->isActive()); + connect(action, &QAction::toggled, this, &MultiLineEdit::setSpellCheckEnabled); + + menu->exec(event->globalPos()); + delete menu; +} + +#endif -void MultiLineEdit::setCustomFont(const QFont &font) +void MultiLineEdit::setCustomFont(const QFont& font) { setFont(font); updateSizeHint(); } - void MultiLineEdit::setMode(Mode mode) { if (mode == _mode) @@ -96,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) @@ -113,7 +132,6 @@ void MultiLineEdit::setMinHeight(int lines) updateSizeHint(); } - void MultiLineEdit::setMaxHeight(int lines) { if (lines == _maxHeight) @@ -123,7 +141,6 @@ void MultiLineEdit::setMaxHeight(int lines) updateSizeHint(); } - void MultiLineEdit::setScrollBarsEnabled(bool enable) { if (_scrollBarsEnabled == enable) @@ -133,7 +150,6 @@ void MultiLineEdit::setScrollBarsEnabled(bool enable) updateScrollBars(); } - void MultiLineEdit::updateScrollBars() { QFontMetrics fm(font()); @@ -149,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()); @@ -167,58 +181,48 @@ void MultiLineEdit::updateSizeHint() // use the style to determine a decent size int h = qMin(qMax((int)document()->size().height() + scrollBarHeight, minPixelHeight), maxPixelHeight) + 2 * frameWidth(); - QStyleOptionFrameV2 opt; + + QStyleOptionFrame opt; opt.initFrom(this); opt.rect = QRect(0, 0, 100, h); opt.lineWidth = lineWidth(); opt.midLineWidth = midLineWidth(); opt.state |= QStyle::State_Sunken; - QSize s = style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(100, h).expandedTo(QApplication::globalStrut()), this); + QWidget* widget = this; +#ifdef Q_OS_MAC + widget = 0; +#endif + QSize s = style()->sizeFromContents(QStyle::CT_LineEdit, &opt, QSize(100, h).expandedTo(QApplication::globalStrut()), widget); if (s != _sizeHint) { _sizeHint = s; updateGeometry(); } } - QSize MultiLineEdit::sizeHint() const { if (!_sizeHint.isValid()) { - MultiLineEdit *that = const_cast(this); + auto* that = const_cast(this); that->updateSizeHint(); } return _sizeHint; } - QSize MultiLineEdit::minimumSizeHint() const { return sizeHint(); } - void MultiLineEdit::setEmacsMode(bool enable) { _emacsMode = enable; } - -void MultiLineEdit::setSpellCheckEnabled(bool enable) -{ -#ifdef HAVE_KDE - setCheckSpellingEnabled(enable); -#else - Q_UNUSED(enable) -#endif -} - - -void MultiLineEdit::setPasteProtectionEnabled(bool enable, QWidget *) +void MultiLineEdit::setPasteProtectionEnabled(bool enable, QWidget*) { _pasteProtectionEnabled = enable; } - void MultiLineEdit::historyMoveBack() { addToHistory(convertRichtextToMircCodes(), true); @@ -229,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()); @@ -247,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; @@ -274,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(e); + auto* event = static_cast(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; @@ -292,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) { @@ -314,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 @@ -330,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 @@ -384,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); @@ -413,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(); @@ -465,7 +461,6 @@ void MultiLineEdit::keyPressEvent(QKeyEvent *event) #endif } - QString MultiLineEdit::convertRichtextToMircCodes() { bool underline, bold, italic, color; @@ -517,7 +512,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); @@ -568,8 +563,7 @@ QString MultiLineEdit::convertRichtextToMircCodes() 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()) @@ -585,8 +579,7 @@ 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("(|||)", Qt::CaseSensitive); @@ -599,7 +592,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) { @@ -608,6 +601,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; } @@ -631,8 +628,8 @@ QString MultiLineEdit::convertMircCodesToHtml(const QString &text) 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]); @@ -661,13 +658,11 @@ QString MultiLineEdit::convertMircCodesToHtml(const QString &text) return words.join("").replace("\n", "
"); } - void MultiLineEdit::on_returnPressed() { on_returnPressed(convertRichtextToMircCodes()); } - void MultiLineEdit::on_returnPressed(QString text) { if (_completionSpace && text.endsWith(" ")) { @@ -675,7 +670,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); @@ -689,7 +684,6 @@ void MultiLineEdit::on_returnPressed(QString text) } } - void MultiLineEdit::on_textChanged() { _completionSpace = qMax(_completionSpace - 1, 0); @@ -708,17 +702,13 @@ void MultiLineEdit::on_textChanged() QString msg = tr("Do you really want to paste %n line(s)?", "", lines.count()); msg += "

"; for (int i = 0; i < 4; i++) { -#if QT_VERSION < 0x050000 - msg += Qt::escape(lines[i].left(40)); -#else msg += lines[i].left(40).toHtmlEscaped(); -#endif if (lines[i].count() > 40) msg += "..."; msg += "
"; } msg += "...

"; - 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); @@ -727,7 +717,7 @@ void MultiLineEdit::on_textChanged() return; } - foreach(QString line, lines) { + foreach (QString line, lines) { clear(); insert(line); on_returnPressed(); @@ -745,43 +735,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(" "); } -