From 61ed06d58e137c3daf49f3011d1124c948a5c795 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B8rn=20Lindeijer?= <thorbjorn.lindeijer@nokia.com> Date: Tue, 8 Sep 2009 13:03:24 +0200 Subject: [PATCH] Moved mouse navigation into BaseTextEditor so that it can be reused For implementing mouse navigation in the QML editor. --- src/plugins/cppeditor/cppeditor.cpp | 100 +---------------- src/plugins/cppeditor/cppeditor.h | 36 +------ src/plugins/texteditor/basetexteditor.cpp | 125 +++++++++++++++++++++- src/plugins/texteditor/basetexteditor.h | 50 ++++++++- src/plugins/texteditor/basetexteditor_p.h | 6 +- 5 files changed, 179 insertions(+), 138 deletions(-) diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 5bea06a0453..597a2769e85 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -527,8 +527,6 @@ CPPEditorEditable::CPPEditorEditable(CPPEditor *editor) CPPEditor::CPPEditor(QWidget *parent) : TextEditor::BaseTextEditor(parent) - , m_mouseNavigationEnabled(true) - , m_showingLink(false) , m_currentRenameSelection(-1) , m_inRename(false) { @@ -1073,7 +1071,7 @@ void CPPEditor::switchDeclarationDefinition() } CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, - bool lookupDefinition) + bool resolveTarget) { Link link; @@ -1153,7 +1151,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, if (Symbol *symbol = result.second) { Symbol *def = 0; - if (lookupDefinition && !lastSymbol->isFunction()) + if (resolveTarget && !lastSymbol->isFunction()) def = findDefinition(symbol); link = linkToSymbol(def ? def : symbol); @@ -1190,7 +1188,7 @@ CPPEditor::Link CPPEditor::findLinkAt(const QTextCursor &cursor, void CPPEditor::jumpToDefinition() { - openCppEditorAt(findLinkAt(textCursor())); + openLink(findLinkAt(textCursor())); } Symbol *CPPEditor::findDefinition(Symbol *symbol) @@ -1342,68 +1340,6 @@ void CPPEditor::contextMenuEvent(QContextMenuEvent *e) delete menu; } -void CPPEditor::mouseMoveEvent(QMouseEvent *e) -{ - bool linkFound = false; - - if (m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier) { - // Link emulation behaviour for 'go to definition' - const QTextCursor cursor = cursorForPosition(e->pos()); - - // Check that the mouse was actually on the text somewhere - bool onText = cursorRect(cursor).right() >= e->x(); - if (!onText) { - QTextCursor nextPos = cursor; - nextPos.movePosition(QTextCursor::Right); - onText = cursorRect(nextPos).right() >= e->x(); - } - - const Link link = findLinkAt(cursor, false); - - if (onText && !link.fileName.isEmpty()) { - showLink(link); - linkFound = true; - } - } - - if (!linkFound) - clearLink(); - - TextEditor::BaseTextEditor::mouseMoveEvent(e); -} - -void CPPEditor::mouseReleaseEvent(QMouseEvent *e) -{ - if (m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier - && !(e->modifiers() & Qt::ShiftModifier) - && e->button() == Qt::LeftButton) { - - const QTextCursor cursor = cursorForPosition(e->pos()); - if (openCppEditorAt(findLinkAt(cursor))) { - clearLink(); - e->accept(); - return; - } - } - - TextEditor::BaseTextEditor::mouseReleaseEvent(e); -} - -void CPPEditor::leaveEvent(QEvent *e) -{ - clearLink(); - TextEditor::BaseTextEditor::leaveEvent(e); -} - -void CPPEditor::keyReleaseEvent(QKeyEvent *e) -{ - // Clear link emulation when Ctrl is released - if (e->key() == Qt::Key_Control) - clearLink(); - - TextEditor::BaseTextEditor::keyReleaseEvent(e); -} - void CPPEditor::keyPressEvent(QKeyEvent *e) { if (m_currentRenameSelection == -1) { @@ -1491,29 +1427,6 @@ void CPPEditor::keyPressEvent(QKeyEvent *e) TextEditor::BaseTextEditor::keyPressEvent(e); } -void CPPEditor::showLink(const Link &link) -{ - QTextEdit::ExtraSelection sel; - sel.cursor = textCursor(); - sel.cursor.setPosition(link.pos); - sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); - sel.format = m_linkFormat; - sel.format.setFontUnderline(true); - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); - viewport()->setCursor(Qt::PointingHandCursor); - m_showingLink = true; -} - -void CPPEditor::clearLink() -{ - if (!m_showingLink) - return; - - setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); - viewport()->setCursor(Qt::IBeamCursor); - m_showingLink = false; -} - QList<int> CPPEditorEditable::context() const { return m_context; @@ -1557,17 +1470,10 @@ void CPPEditor::setFontSettings(const TextEditor::FontSettings &fs) highlighter->setFormats(formats.constBegin(), formats.constEnd()); highlighter->rehighlight(); - m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); m_occurrencesFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES)); m_occurrenceRenameFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_OCCURRENCES_RENAME)); } -void CPPEditor::setDisplaySettings(const TextEditor::DisplaySettings &ds) -{ - TextEditor::BaseTextEditor::setDisplaySettings(ds); - m_mouseNavigationEnabled = ds.m_mouseNavigation; -} - void CPPEditor::unCommentSelection() { Core::Utils::unCommentSelection(this); diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 27991a550f3..40e2e71972f 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -193,7 +193,6 @@ public: public Q_SLOTS: virtual void setFontSettings(const TextEditor::FontSettings &); - virtual void setDisplaySettings(const TextEditor::DisplaySettings &); void setSortedMethodOverview(bool sort); void switchDeclarationDefinition(); void jumpToDefinition(); @@ -208,10 +207,6 @@ public Q_SLOTS: protected: bool event(QEvent *e); void contextMenuEvent(QContextMenuEvent *); - void mouseMoveEvent(QMouseEvent *); - void mouseReleaseEvent(QMouseEvent *); - void leaveEvent(QEvent *); - void keyReleaseEvent(QKeyEvent *); void keyPressEvent(QKeyEvent *); TextEditor::BaseTextEditorEditable *createEditableInterface(); @@ -261,36 +256,11 @@ private: const QString &text = QString()); void abortRename(); - struct Link - { - Link(const QString &fileName = QString(), - int line = 0, - int column = 0) - : pos(-1) - , length(-1) - , fileName(fileName) - , line(line) - , column(column) - {} - - int pos; // Link position - int length; // Link length - - QString fileName; // Target file - int line; // Target line - int column; // Target column - }; - - void showLink(const Link &); - void clearLink(); - - Link findLinkAt(const QTextCursor &, bool lookupDefinition = true); - static Link linkToSymbol(CPlusPlus::Symbol *symbol); + Link findLinkAt(const QTextCursor &, bool resolveTarget = true); + bool openLink(const Link &link) { return openCppEditorAt(link); } bool openCppEditorAt(const Link &); - bool m_mouseNavigationEnabled; - bool m_showingLink; - QTextCharFormat m_linkFormat; + static Link linkToSymbol(CPlusPlus::Symbol *symbol); CppTools::CppModelManagerInterface *m_modelManager; diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index 80a1f0268cc..59c55fcb2d4 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -1337,6 +1337,16 @@ bool BaseTextEditor::codeFoldingSupported() const return d->m_codeFoldingSupported; } +void BaseTextEditor::setMouseNavigationEnabled(bool b) +{ + d->m_mouseNavigationEnabled = b; +} + +bool BaseTextEditor::mouseNavigationEnabled() const +{ + return d->m_mouseNavigationEnabled; +} + void BaseTextEditor::setRevisionsVisible(bool b) { d->m_revisionsVisible = b; @@ -1372,12 +1382,14 @@ BaseTextEditorPrivate::BaseTextEditorPrivate() m_marksVisible(false), m_codeFoldingVisible(false), m_codeFoldingSupported(false), + m_mouseNavigationEnabled(true), m_revisionsVisible(false), m_lineNumbersVisible(true), m_highlightCurrentLine(true), m_requestMarkEnabled(true), m_lineSeparatorsAllowed(false), m_visibleWrapColumn(0), + m_showingLink(false), m_editable(0), m_actionHack(0), m_inBlockSelectionMode(false), @@ -2721,6 +2733,32 @@ void BaseTextEditorPrivate::clearVisibleCollapsedBlock() void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) { d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier); + + bool linkFound = false; + + if (d->m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier) { + // Link emulation behaviour for 'go to definition' + const QTextCursor cursor = cursorForPosition(e->pos()); + + // Check that the mouse was actually on the text somewhere + bool onText = cursorRect(cursor).right() >= e->x(); + if (!onText) { + QTextCursor nextPos = cursor; + nextPos.movePosition(QTextCursor::Right); + onText = cursorRect(nextPos).right() >= e->x(); + } + + const Link link = findLinkAt(cursor, false); + + if (onText && link.isValid()) { + showLink(link); + linkFound = true; + } + } + + if (!linkFound) + clearLink(); + if (e->buttons() == Qt::NoButton) { const QTextBlock collapsedBlock = collapsedBlockAt(e->pos()); const int blockNumber = collapsedBlock.next().blockNumber(); @@ -2767,6 +2805,38 @@ void BaseTextEditor::mousePressEvent(QMouseEvent *e) QPlainTextEdit::mousePressEvent(e); } +void BaseTextEditor::mouseReleaseEvent(QMouseEvent *e) +{ + if (d->m_mouseNavigationEnabled && e->modifiers() & Qt::ControlModifier + && !(e->modifiers() & Qt::ShiftModifier) + && e->button() == Qt::LeftButton) { + + const QTextCursor cursor = cursorForPosition(e->pos()); + if (openLink(findLinkAt(cursor))) { + clearLink(); + return; + } + } + + QPlainTextEdit::mouseReleaseEvent(e); +} + +void BaseTextEditor::leaveEvent(QEvent *e) +{ + // Clear link emulation when the mouse leaves the editor + clearLink(); + QPlainTextEdit::leaveEvent(e); +} + +void BaseTextEditor::keyReleaseEvent(QKeyEvent *e) +{ + // Clear link emulation when Ctrl is released + if (e->key() == Qt::Key_Control) + clearLink(); + + QPlainTextEdit::keyReleaseEvent(e); +} + void BaseTextEditor::extraAreaLeaveEvent(QEvent *) { // fake missing mouse move event from Qt @@ -3186,6 +3256,50 @@ void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar } } +BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool) +{ + return Link(); +} + +bool BaseTextEditor::openLink(const Link &link) +{ + if (link.fileName.isEmpty()) + return false; + + if (baseTextDocument()->fileName() == link.fileName) { + Core::EditorManager *editorManager = Core::EditorManager::instance(); + editorManager->addCurrentPositionToNavigationHistory(); + gotoLine(link.line, link.column); + setFocus(); + return true; + } + + return openEditorAt(link.fileName, link.line, link.column); +} + +void BaseTextEditor::showLink(const Link &link) +{ + QTextEdit::ExtraSelection sel; + sel.cursor = textCursor(); + sel.cursor.setPosition(link.pos); + sel.cursor.setPosition(link.pos + link.length, QTextCursor::KeepAnchor); + sel.format = d->m_linkFormat; + sel.format.setFontUnderline(true); + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>() << sel); + viewport()->setCursor(Qt::PointingHandCursor); + d->m_showingLink = true; +} + +void BaseTextEditor::clearLink() +{ + if (!d->m_showingLink) + return; + + setExtraSelections(OtherSelection, QList<QTextEdit::ExtraSelection>()); + viewport()->setCursor(Qt::IBeamCursor); + d->m_showingLink = false; +} + void BaseTextEditorPrivate::updateMarksBlock(const QTextBlock &block) { if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block)) @@ -4005,8 +4119,8 @@ void BaseTextEditor::unCommentSelection() void BaseTextEditor::showEvent(QShowEvent* e) { if (!d->m_fontSettings.isEmpty()) { - setFontSettings(d->m_fontSettings); - d->m_fontSettings.clear(); + setFontSettings(d->m_fontSettings); + d->m_fontSettings.clear(); } QPlainTextEdit::showEvent(e); } @@ -4015,11 +4129,12 @@ void BaseTextEditor::showEvent(QShowEvent* e) void BaseTextEditor::setFontSettingsIfVisible(const TextEditor::FontSettings &fs) { if (!isVisible()) { - d->m_fontSettings = fs; - return; + d->m_fontSettings = fs; + return; } setFontSettings(fs); } + void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs) { const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT)); @@ -4030,6 +4145,7 @@ void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs) const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES)); d->m_currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE)); d->m_currentLineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE_NUMBER)); + d->m_linkFormat = fs.toTextCharFormat(QLatin1String(TextEditor::Constants::C_LINK)); d->m_ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE)); QFont font(textFormat.font()); @@ -4082,6 +4198,7 @@ void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds) setCodeFoldingVisible(ds.m_displayFoldingMarkers); setHighlightCurrentLine(ds.m_highlightCurrentLine); setRevisionsVisible(ds.m_markTextChanges); + setMouseNavigationEnabled(ds.m_mouseNavigation); if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) { if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter()) diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 34554082925..17a67d3b0a9 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -274,8 +274,7 @@ private: }; -class TEXTEDITOR_EXPORT BaseTextEditor - : public QPlainTextEdit +class TEXTEDITOR_EXPORT BaseTextEditor : public QPlainTextEdit { Q_OBJECT @@ -345,6 +344,9 @@ public: void setCodeFoldingSupported(bool b); bool codeFoldingSupported() const; + void setMouseNavigationEnabled(bool b); + bool mouseNavigationEnabled() const; + void setRevisionsVisible(bool b); bool revisionsVisible() const; @@ -496,14 +498,54 @@ protected: void timerEvent(QTimerEvent *); void mouseMoveEvent(QMouseEvent *); void mousePressEvent(QMouseEvent *); + void mouseReleaseEvent(QMouseEvent *); + void leaveEvent(QEvent *); + void keyReleaseEvent(QKeyEvent *); - // Rertuns true if key triggers an indent. + // Returns true if key triggers an indent. virtual bool isElectricCharacter(const QChar &ch) const; // Indent a text block based on previous line. Default does nothing virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar); // Indent at cursor. Calls indentBlock for selection or current line. virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar); + struct Link + { + Link(const QString &fileName = QString(), + int line = 0, + int column = 0) + : pos(-1) + , length(-1) + , fileName(fileName) + , line(line) + , column(column) + {} + + bool isValid() const + { return !(pos == -1 || length == -1); } + + int pos; // Link position + int length; // Link length + + QString fileName; // Target file + int line; // Target line + int column; // Target column + }; + + /*! + Reimplement this function to enable code navigation. + + \a resolveTarget is set to true when the target of the link is relevant + (it isn't until the link is used). + */ + virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true); + + /*! + Reimplement this function if you want to customize the way a link is + opened. Returns whether the link was opened succesfully. + */ + virtual bool openLink(const Link &link); + protected slots: virtual void slotUpdateExtraAreaWidth(); virtual void slotModificationChanged(bool); @@ -537,6 +579,8 @@ private: QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const; + void showLink(const Link &); + void clearLink(); // parentheses matcher private slots: diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index dbf5b66d1e8..1956f858800 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -194,6 +194,7 @@ public: uint m_marksVisible : 1; uint m_codeFoldingVisible : 1; uint m_codeFoldingSupported : 1; + uint m_mouseNavigationEnabled : 1; uint m_revisionsVisible : 1; uint m_lineNumbersVisible : 1; uint m_highlightCurrentLine : 1; @@ -201,6 +202,9 @@ public: uint m_lineSeparatorsAllowed : 1; int m_visibleWrapColumn; + QTextCharFormat m_linkFormat; + bool m_showingLink; + QTextCharFormat m_ifdefedOutFormat; QRegExp m_searchExpr; @@ -226,7 +230,7 @@ public: QString copyBlockSelection(); void removeBlockSelection(const QString &text = QString()); bool m_moveLineUndoHack; - + QTextCursor m_findScope; QTextCursor m_selectBlockAnchor; -- GitLab