diff options
author | mae <qt-info@nokia.com> | 2010-07-02 13:47:14 +0200 |
---|---|---|
committer | mae <qt-info@nokia.com> | 2010-07-02 13:48:57 +0200 |
commit | 6ef602d121bbd32055471cb6ce51c2bf5736ff89 (patch) | |
tree | ece46d0dc38785685d46d905d505233301a6c989 | |
parent | 038d943f9aa3b0fcc6099ba9bc692b9a7fc97a3f (diff) |
add basic support to show refactor markers
See BaseTextEditor::setRefactorMarkers(...). The markers support
a clicked signal via BaseTextEditor and tooltips. They feature
a cursor, but are always positioned at the end of the line (not block!).
As special gimmick they do extend the document width when they
are positioned outside the document area.
-rw-r--r-- | src/plugins/texteditor/basetextdocumentlayout.cpp | 18 | ||||
-rw-r--r-- | src/plugins/texteditor/basetextdocumentlayout.h | 5 | ||||
-rw-r--r-- | src/plugins/texteditor/basetexteditor.cpp | 71 | ||||
-rw-r--r-- | src/plugins/texteditor/basetexteditor.h | 13 | ||||
-rw-r--r-- | src/plugins/texteditor/basetexteditor_p.h | 3 | ||||
-rw-r--r-- | src/plugins/texteditor/images/refactormarker.png | bin | 0 -> 4886 bytes | |||
-rw-r--r-- | src/plugins/texteditor/refactoroverlay.cpp | 76 | ||||
-rw-r--r-- | src/plugins/texteditor/refactoroverlay.h | 51 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.pro | 6 | ||||
-rw-r--r-- | src/plugins/texteditor/texteditor.qrc | 3 |
10 files changed, 230 insertions, 16 deletions
diff --git a/src/plugins/texteditor/basetextdocumentlayout.cpp b/src/plugins/texteditor/basetextdocumentlayout.cpp index 648c0a610e..58427566bb 100644 --- a/src/plugins/texteditor/basetextdocumentlayout.cpp +++ b/src/plugins/texteditor/basetextdocumentlayout.cpp @@ -512,4 +512,22 @@ void BaseTextDocumentLayout::doFoldOrUnfold(const QTextBlock& block, bool unfold setFolded(block, !unfold); } +void BaseTextDocumentLayout::setRequiredWidth(int width) +{ + int oldw = m_requiredWidth; + m_requiredWidth = width; + int dw = QPlainTextDocumentLayout::documentSize().width(); + if (oldw > dw || width > dw) + emitDocumentSizeChanged(); +} + + +QSizeF BaseTextDocumentLayout::documentSize() const +{ + QSizeF size = QPlainTextDocumentLayout::documentSize(); + size.setWidth(qMax((qreal)m_requiredWidth, size.width())); + return size; +} + + diff --git a/src/plugins/texteditor/basetextdocumentlayout.h b/src/plugins/texteditor/basetextdocumentlayout.h index c76a628339..b3b20ce2d4 100644 --- a/src/plugins/texteditor/basetextdocumentlayout.h +++ b/src/plugins/texteditor/basetextdocumentlayout.h @@ -159,6 +159,11 @@ public: void emitDocumentSizeChanged() { emit documentSizeChanged(documentSize()); } int lastSaveRevision; bool hasMarks; + + int m_requiredWidth; + void setRequiredWidth(int width); + + QSizeF documentSize() const; }; } // namespace TextEditor diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp index a543d85d48..12d2c11321 100644 --- a/src/plugins/texteditor/basetexteditor.cpp +++ b/src/plugins/texteditor/basetexteditor.cpp @@ -81,6 +81,8 @@ #include <QtGui/QInputDialog> #include <QtGui/QMenu> +//#define DO_FOO + using namespace TextEditor; using namespace TextEditor::Internal; @@ -189,6 +191,7 @@ BaseTextEditor::BaseTextEditor(QWidget *parent) d->m_overlay = new TextEditorOverlay(this); d->m_snippetOverlay = new TextEditorOverlay(this); d->m_searchResultOverlay = new TextEditorOverlay(this); + d->m_refactorOverlay = new RefactorOverlay(this); d->setupDocumentSignals(d->m_document); d->setupDocumentSignals(d->m_document); @@ -217,6 +220,10 @@ BaseTextEditor::BaseTextEditor(QWidget *parent) // (void) new QShortcut(tr("F9"), this, SLOT(slotToggleMark()), 0, Qt::WidgetShortcut); // (void) new QShortcut(tr("F11"), this, SLOT(slotToggleBlockVisible())); +#ifdef DO_FOO + (void) new QShortcut(tr("CTRL+D"), this, SLOT(doFoo())); +#endif + // parentheses matcher d->m_formatRange = true; @@ -1610,12 +1617,10 @@ void BaseTextEditor::documentAboutToBeReloaded() QPlainTextEdit::setExtraSelections(QList<QTextEdit::ExtraSelection>()); // clear all overlays - if (d->m_overlay) - d->m_overlay->clear(); - if (d->m_snippetOverlay) - d->m_snippetOverlay->clear(); - if (d->m_searchResultOverlay) - d->m_searchResultOverlay->clear(); + d->m_overlay->clear(); + d->m_snippetOverlay->clear(); + d->m_searchResultOverlay->clear(); + d->m_refactorOverlay->clear(); } void BaseTextEditor::documentReloaded() @@ -1867,6 +1872,7 @@ BaseTextEditorPrivate::BaseTextEditorPrivate() m_overlay(0), m_snippetOverlay(0), m_searchResultOverlay(0), + m_refactorOverlay(0), visibleFoldedBlockNumber(-1), suggestedVisibleFoldedBlockNumber(-1), m_mouseOnFoldedMarker(false), @@ -2001,6 +2007,12 @@ bool BaseTextEditor::viewportEvent(QEvent *event) return true; // eat tooltip event when control is pressed const QPoint &pos = he->pos(); + RefactorMarker refactorMarker = d->m_refactorOverlay->markerAt(pos); + if (refactorMarker.isValid() && !refactorMarker.tooltip.isEmpty()) { + QToolTip::showText(he->globalPos(), refactorMarker.tooltip, viewport(), refactorMarker.rect); + return true; + } + // Allow plugins to show tooltips const QTextCursor &c = cursorForPosition(pos); QPoint cursorPos = mapToGlobal(cursorRect(c).bottomRight() + QPoint(1,1)); @@ -2763,10 +2775,10 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) d->m_animator->draw(&painter, cursorRect(cursor).topLeft()); } - if (d->m_overlay && d->m_overlay->isVisible()) + if (d->m_overlay->isVisible()) d->m_overlay->paint(&painter, e->rect()); - if (d->m_snippetOverlay && d->m_snippetOverlay->isVisible()) + if (d->m_snippetOverlay->isVisible()) d->m_snippetOverlay->paint(&painter, e->rect()); if (!d->m_searchResultOverlay->isEmpty()) { @@ -2774,6 +2786,9 @@ void BaseTextEditor::paintEvent(QPaintEvent *e) d->m_searchResultOverlay->clear(); } + if (!d->m_refactorOverlay->isEmpty()) + d->m_refactorOverlay->paint(&painter, e->rect()); + // draw the cursor last, on top of everything if (cursor_layout) { painter.setPen(cursor_pen); @@ -3373,11 +3388,13 @@ void BaseTextEditor::mouseMoveEvent(QMouseEvent *e) d->foldedBlockTimer.start(40, this); } + const RefactorMarker refactorMarker = d->m_refactorOverlay->markerAt(e->pos()); + // Update the mouse cursor - if (collapsedBlock.isValid() && !d->m_mouseOnFoldedMarker) { + if ((collapsedBlock.isValid() || refactorMarker.isValid()) && !d->m_mouseOnFoldedMarker) { d->m_mouseOnFoldedMarker = true; viewport()->setCursor(Qt::PointingHandCursor); - } else if (!collapsedBlock.isValid() && d->m_mouseOnFoldedMarker) { + } else if (!collapsedBlock.isValid() && !refactorMarker.isValid() && d->m_mouseOnFoldedMarker) { d->m_mouseOnFoldedMarker = false; viewport()->setCursor(Qt::IBeamCursor); } @@ -3420,10 +3437,16 @@ void BaseTextEditor::mousePressEvent(QMouseEvent *e) viewport()->setCursor(Qt::IBeamCursor); } - updateLink(e); + RefactorMarker refactorMarker = d->m_refactorOverlay->markerAt(e->pos()); + if (refactorMarker.isValid()) { + qDebug() << "refactorMarkerClicked" << refactorMarker.cursor.position(); + emit refactorMarkerClicked(refactorMarker); + } else { + updateLink(e); - if (d->m_currentLink.isValid()) - d->m_linkPressed = true; + if (d->m_currentLink.isValid()) + d->m_linkPressed = true; + } } #ifdef Q_OS_LINUX @@ -5388,3 +5411,25 @@ QString BaseTextEditorEditable::contextHelpId() const e->textCursor().position()); return m_contextHelpId; } + + +void BaseTextEditor::setRefactorMarkers(const Internal::RefactorMarkers &markers) +{ + foreach (const Internal::RefactorMarker &marker, d->m_refactorOverlay->markers()) + requestBlockUpdate(marker.cursor.block()); + d->m_refactorOverlay->setMarkers(markers); + foreach (const Internal::RefactorMarker &marker, markers) + requestBlockUpdate(marker.cursor.block()); +} + +void BaseTextEditor::doFoo() { +#ifdef DO_FOO + qDebug() << Q_FUNC_INFO; + RefactorMarkers markers = d->m_refactorOverlay->markers(); + RefactorMarker marker; + marker.tooltip = "Hello World"; + marker.cursor = textCursor(); + markers += marker; + setRefactorMarkers(markers); +#endif +} diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h index 1bab6597a7..2f96437f94 100644 --- a/src/plugins/texteditor/basetexteditor.h +++ b/src/plugins/texteditor/basetexteditor.h @@ -51,6 +51,10 @@ namespace TextEditor { namespace Internal { class BaseTextEditorPrivate; class TextEditorOverlay; + class RefactorOverlay; + class RefactorMarker; + typedef QList<RefactorMarker> RefactorMarkers; + } class ITextMarkable; @@ -315,6 +319,7 @@ private: Internal::BaseTextEditorPrivate *d; friend class Internal::BaseTextEditorPrivate; friend class Internal::TextEditorOverlay; + friend class Internal::RefactorOverlay; public: QWidget *extraArea() const; @@ -348,6 +353,13 @@ public: QList<QTextEdit::ExtraSelection> extraSelections(ExtraSelectionKind kind) const; QString extraSelectionTooltip(int pos) const; + + void setRefactorMarkers(const Internal::RefactorMarkers &markers); +signals: + void refactorMarkerClicked(const Internal::RefactorMarker &marker); + +public: + struct BlockRange { BlockRange() : first(0), last(-1) {} @@ -516,6 +528,7 @@ private slots: void _q_highlightBlocks(); void slotSelectionChanged(); void _q_animateUpdate(int position, QPointF lastPos, QRectF rect); + void doFoo(); }; diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h index 9cb7788186..6419976777 100644 --- a/src/plugins/texteditor/basetexteditor_p.h +++ b/src/plugins/texteditor/basetexteditor_p.h @@ -35,6 +35,7 @@ #include "displaysettings.h" #include "texteditoroverlay.h" #include "fontsettings.h" +#include "refactoroverlay.h" #include <utils/changeset.h> @@ -199,6 +200,8 @@ public: QTextCharFormat m_occurrencesFormat; QTextCharFormat m_occurrenceRenameFormat; + RefactorOverlay *m_refactorOverlay; + QBasicTimer foldedBlockTimer; int visibleFoldedBlockNumber; int suggestedVisibleFoldedBlockNumber; diff --git a/src/plugins/texteditor/images/refactormarker.png b/src/plugins/texteditor/images/refactormarker.png Binary files differnew file mode 100644 index 0000000000..dd7d7a2417 --- /dev/null +++ b/src/plugins/texteditor/images/refactormarker.png diff --git a/src/plugins/texteditor/refactoroverlay.cpp b/src/plugins/texteditor/refactoroverlay.cpp new file mode 100644 index 0000000000..006de65023 --- /dev/null +++ b/src/plugins/texteditor/refactoroverlay.cpp @@ -0,0 +1,76 @@ +#include "refactoroverlay.h" +#include <QPainter> +#include <QTextBlock> +#include "basetextdocumentlayout.h" +#include <QDebug> + +using namespace TextEditor::Internal; + +RefactorOverlay::RefactorOverlay(BaseTextEditor *editor) : + QObject(editor), + m_editor(editor), + m_maxWidth(0), + m_icon(":/texteditor/images/refactormarker.png") +{ +} + +void RefactorOverlay::paint(QPainter *painter, const QRect &clip) +{ + QTextBlock lastBlock; + int position = 0; + m_maxWidth = 0; + for (int i = 0; i < m_markers.size(); ++i) { + + // position counts how many refactor markers are in a single block + if (m_markers.at(i).cursor.block() != lastBlock) { + lastBlock = m_markers.at(i).cursor.block(); + position = 0; + } else { + position++; + } + + paintMarker(m_markers.at(i), position, painter, clip); + } + + if (BaseTextDocumentLayout *documentLayout = qobject_cast<BaseTextDocumentLayout*>(m_editor->document()->documentLayout())) { + documentLayout->setRequiredWidth(m_maxWidth); + } + +} + +RefactorMarker RefactorOverlay::markerAt(const QPoint &pos) const +{ + QPointF offset = m_editor->contentOffset(); + foreach(const RefactorMarker &marker, m_markers) { + if (marker.rect.translated(offset.toPoint()).contains(pos)) + return marker; + } + return RefactorMarker(); +} + +void RefactorOverlay::paintMarker(const RefactorMarker& marker, int position, + QPainter *painter, const QRect &clip) +{ + QPointF offset = m_editor->contentOffset(); + QRectF geometry = m_editor->blockBoundingGeometry(marker.cursor.block()).translated(offset); + + if (geometry.top() > clip.bottom() + 10 || geometry.bottom() < clip.top() - 10) + return; // marker not visible + + QTextCursor cursor = marker.cursor; + cursor.movePosition(QTextCursor::EndOfLine); + QRect r = m_editor->cursorRect(cursor); + + QIcon icon = marker.icon; + if (icon.isNull()) + icon = m_icon; + + QSize sz = icon.actualSize(QSize(INT_MAX, r.height())); + + int x = r.right() + position * sz.width(); + marker.rect = QRect(x, r.bottom() - sz.height(), sz.width(), sz.height()).translated(-offset.toPoint()); + icon.paint(painter, marker.rect); + m_maxWidth = qMax((qreal)m_maxWidth, x + sz.width() - offset.x()); +} + + diff --git a/src/plugins/texteditor/refactoroverlay.h b/src/plugins/texteditor/refactoroverlay.h new file mode 100644 index 0000000000..ad44b843c7 --- /dev/null +++ b/src/plugins/texteditor/refactoroverlay.h @@ -0,0 +1,51 @@ +#ifndef REFACTOROVERLAY_H +#define REFACTOROVERLAY_H + +#include "basetexteditor.h" +#include <QTextCursor> +#include <QObject> +#include <QIcon> + +namespace TextEditor { +namespace Internal { + +struct TEXTEDITOR_EXPORT RefactorMarker { + inline bool isValid() const { return !cursor.isNull(); } + QTextCursor cursor; + QString tooltip; + QIcon icon; + mutable QRect rect; // used to cache last drawing positin in document coordinates + QVariant data; +}; + +typedef QList<RefactorMarker> RefactorMarkers; + +class TEXTEDITOR_EXPORT RefactorOverlay : public QObject +{ + Q_OBJECT +public: + explicit RefactorOverlay(BaseTextEditor *editor); + + bool isEmpty() const { return m_markers.isEmpty(); } + void paint(QPainter *painter, const QRect &clip); + + void setMarkers(const RefactorMarkers &markers) { m_markers = markers; } + RefactorMarkers markers() const { return m_markers; } + + void clear() { m_markers.clear(); } + + RefactorMarker markerAt(const QPoint &pos) const; + +private: + void paintMarker(const RefactorMarker& marker, int position, QPainter *painter, const QRect &clip); + RefactorMarkers m_markers; + BaseTextEditor *m_editor; + int m_maxWidth; + QIcon m_icon; + +}; + +} +} + +#endif // REFACTOROVERLAY_H diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index d9eb392805..65bc255c93 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -59,7 +59,8 @@ SOURCES += texteditorplugin.cpp \ generichighlighter/managedefinitionsdialog.cpp \ generichighlighter/highlightdefinitionmetadata.cpp \ generichighlighter/definitiondownloader.cpp \ - refactoringchanges.cpp + refactoringchanges.cpp \ + refactoroverlay.cpp HEADERS += texteditorplugin.h \ textfilewizard.h \ @@ -121,7 +122,8 @@ HEADERS += texteditorplugin.h \ generichighlighter/managedefinitionsdialog.h \ generichighlighter/highlightdefinitionmetadata.h \ generichighlighter/definitiondownloader.h \ - refactoringchanges.h + refactoringchanges.h \ + refactoroverlay.h FORMS += behaviorsettingspage.ui \ displaysettingspage.ui \ diff --git a/src/plugins/texteditor/texteditor.qrc b/src/plugins/texteditor/texteditor.qrc index 191343ce0e..0d131c4f3b 100644 --- a/src/plugins/texteditor/texteditor.qrc +++ b/src/plugins/texteditor/texteditor.qrc @@ -1,7 +1,8 @@ <RCC> - <qresource prefix="/texteditor" > + <qresource prefix="/texteditor"> <file>images/finddocuments.png</file> <file>images/finddirectory.png</file> <file>TextEditor.mimetypes.xml</file> + <file>images/refactormarker.png</file> </qresource> </RCC> |