Commit 61ed06d5 authored by Thorbjørn Lindeijer's avatar Thorbjørn Lindeijer

Moved mouse navigation into BaseTextEditor so that it can be reused

For implementing mouse navigation in the QML editor.
parent 1b4d1f1f
......@@ -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);
......
......@@ -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;
......
......@@ -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())
......
......@@ -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:
......
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment