Commit 3a684586 authored by Leandro Melo's avatar Leandro Melo

Editors: Refactor indenters out of the editors for better reusability.

Reviewed-by: ckamm
parent 1afea78c
......@@ -35,6 +35,7 @@
#include "cppquickfix.h"
#include "cpplocalsymbols.h"
#include "cppquickfixcollector.h"
#include "cppqtstyleindenter.h"
#include <AST.h>
#include <Control.h>
......@@ -414,6 +415,7 @@ CPPEditor::CPPEditor(QWidget *parent)
setMarksVisible(true);
setCodeFoldingSupported(true);
setCodeFoldingVisible(true);
setIndenter(new CppQtStyleIndenter);
baseTextDocument()->setSyntaxHighlighter(new CppHighlighter);
m_modelManager = CppTools::CppModelManagerInterface::instance();
......@@ -1405,17 +1407,6 @@ QModelIndex CPPEditor::outlineModelIndex()
return m_outlineModelIndex;
}
bool CPPEditor::isElectricCharacter(QChar ch) const
{
if (ch == QLatin1Char('{') ||
ch == QLatin1Char('}') ||
ch == QLatin1Char(':') ||
ch == QLatin1Char('#')) {
return true;
}
return false;
}
QString CPPEditor::insertMatchingBrace(const QTextCursor &tc, const QString &text,
QChar la, int *skippedChars) const
{
......@@ -1500,61 +1491,6 @@ bool CPPEditor::isInComment(const QTextCursor &cursor) const
return false;
}
void CPPEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
{
Q_UNUSED(doc)
const TabSettings &ts = tabSettings();
CppTools::QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block);
int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
// only reindent the current line when typing electric characters if the
// indent is the same it would be if the line were empty
if (isElectricCharacter(typedChar)) {
int newlineIndent;
int newlinePadding;
codeFormatter.indentForNewLineAfter(block.previous(), &newlineIndent, &newlinePadding);
if (ts.indentationColumn(block.text()) != newlineIndent + newlinePadding)
return;
}
ts.indentLine(block, indent + padding, padding);
}
void CPPEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
{
Q_UNUSED(doc)
Q_UNUSED(typedChar)
maybeClearSomeExtraSelections(cursor);
if (cursor.hasSelection()) {
QTextBlock block = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
const TabSettings &ts = tabSettings();
CppTools::QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block);
QTextCursor tc = textCursor();
tc.beginEditBlock();
do {
int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
ts.indentLine(block, indent + padding, padding);
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
tc.endEditBlock();
} else {
indentBlock(doc, cursor.block(), typedChar);
}
}
bool CPPEditor::event(QEvent *e)
{
switch (e->type()) {
......
......@@ -207,9 +207,6 @@ protected:
TextEditor::BaseTextEditorEditable *createEditableInterface();
// These override BaseTextEditor
virtual bool isElectricCharacter(QChar ch) const;
virtual QString insertMatchingBrace(const QTextCursor &tc, const QString &text,
QChar la, int *skippedChars) const;
......@@ -252,8 +249,6 @@ private:
void markSymbols(const QTextCursor &tc, const SemanticInfo &info);
bool sortedOutline() const;
CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar);
TextEditor::ITextEditor *openCppEditorAt(const QString &fileName, int line,
int column = 0);
......
......@@ -22,7 +22,8 @@ HEADERS += cppplugin.h \
cpplocalsymbols.h \
cpptypehierarchy.h \
cppelementevaluator.h \
cppquickfixcollector.h
cppquickfixcollector.h \
cppqtstyleindenter.h
SOURCES += cppplugin.cpp \
cppeditor.cpp \
cpphighlighter.cpp \
......@@ -38,6 +39,7 @@ SOURCES += cppplugin.cpp \
cpplocalsymbols.cpp \
cpptypehierarchy.cpp \
cppelementevaluator.cpp \
cppquickfixcollector.cpp
cppquickfixcollector.cpp \
cppqtstyleindenter.cpp
RESOURCES += cppeditor.qrc
OTHER_FILES += CppEditor.mimetypes.xml
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "cppqtstyleindenter.h"
#include <cpptools/cppcodeformatter.h>
#include <texteditor/basetexteditor.h>
#include <texteditor/tabsettings.h>
#include <QtCore/QChar>
#include <QtGui/QTextDocument>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
using namespace CppEditor;
using namespace Internal;
CppQtStyleIndenter::CppQtStyleIndenter()
{}
CppQtStyleIndenter::~CppQtStyleIndenter()
{}
bool CppQtStyleIndenter::doIsElectricalCharacter(const QChar &ch) const
{
if (ch == QLatin1Char('{') ||
ch == QLatin1Char('}') ||
ch == QLatin1Char(':') ||
ch == QLatin1Char('#')) {
return true;
}
return false;
}
void CppQtStyleIndenter::doIndentBlock(QTextDocument *doc,
const QTextBlock &block,
const QChar &typedChar,
TextEditor::BaseTextEditor *editor)
{
Q_UNUSED(doc)
const TextEditor::TabSettings &ts = editor->tabSettings();
CppTools::QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block);
int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
// only reindent the current line when typing electric characters if the
// indent is the same it would be if the line were empty
if (isElectricCharacter(typedChar)) {
int newlineIndent;
int newlinePadding;
codeFormatter.indentForNewLineAfter(block.previous(), &newlineIndent, &newlinePadding);
if (ts.indentationColumn(block.text()) != newlineIndent + newlinePadding)
return;
}
ts.indentLine(block, indent + padding, padding);
}
void CppQtStyleIndenter::doIndent(QTextDocument *doc,
const QTextCursor &cursor,
const QChar &typedChar,
TextEditor::BaseTextEditor *editor)
{
if (cursor.hasSelection()) {
QTextBlock block = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
const TextEditor::TabSettings &ts = editor->tabSettings();
CppTools::QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block);
QTextCursor tc = editor->textCursor();
tc.beginEditBlock();
do {
int indent;
int padding;
codeFormatter.indentFor(block, &indent, &padding);
ts.indentLine(block, indent + padding, padding);
codeFormatter.updateLineStateChange(block);
block = block.next();
} while (block.isValid() && block != end);
tc.endEditBlock();
} else {
indentBlock(doc, cursor.block(), typedChar, editor);
}
}
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef CPPQTSTYLEINDENTER_H
#define CPPQTSTYLEINDENTER_H
#include <texteditor/indenter.h>
namespace CppEditor {
namespace Internal {
class CppQtStyleIndenter : public TextEditor::Indenter
{
public:
CppQtStyleIndenter();
virtual ~CppQtStyleIndenter();
private:
virtual bool doIsElectricalCharacter(const QChar &ch) const;
virtual void doIndentBlock(QTextDocument *doc,
const QTextBlock &block,
const QChar &typedChar,
TextEditor::BaseTextEditor *editor);
virtual void doIndent(QTextDocument *doc,
const QTextCursor &cursor,
const QChar &typedChar,
TextEditor::BaseTextEditor *editor);
};
} // Internal
} // CppEditor
#endif // CPPQTSTYLEINDENTER_H
......@@ -38,6 +38,7 @@
#include "qmloutlinemodel.h"
#include "qmljsfindreferences.h"
#include "qmljssemantichighlighter.h"
#include "qmljsindenter.h"
#include <qmljs/qmljsbind.h>
#include <qmljs/qmljsdocument.h>
......@@ -645,6 +646,7 @@ QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
setMarksVisible(true);
setCodeFoldingSupported(true);
setCodeFoldingVisible(true);
setIndenter(new Indenter);
m_updateDocumentTimer = new QTimer(this);
m_updateDocumentTimer->setInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL);
......@@ -1262,15 +1264,6 @@ QString QmlJSTextEditor::wordUnderCursor() const
return word;
}
bool QmlJSTextEditor::isElectricCharacter(QChar ch) const
{
if (ch == QLatin1Char('}')
|| ch == QLatin1Char(']')
|| ch == QLatin1Char(':'))
return true;
return false;
}
bool QmlJSTextEditor::isClosingBrace(const QList<Token> &tokens) const
{
......@@ -1283,19 +1276,6 @@ bool QmlJSTextEditor::isClosingBrace(const QList<Token> &tokens) const
return false;
}
void QmlJSTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
{
Q_UNUSED(doc)
Q_UNUSED(typedChar)
const TextEditor::TabSettings &ts = tabSettings();
QmlJSEditor::QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block);
const int depth = codeFormatter.indentFor(block);
ts.indentLine(block, depth);
}
TextEditor::BaseTextEditorEditable *QmlJSTextEditor::createEditableInterface()
{
QmlJSEditorEditable *editable = new QmlJSEditorEditable(this);
......
......@@ -210,8 +210,6 @@ protected:
virtual QString insertParagraphSeparator(const QTextCursor &tc) const;
private:
virtual bool isElectricCharacter(QChar ch) const;
virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
bool isClosingBrace(const QList<QmlJS::Token> &tokens) const;
void setSelectedElements();
......
......@@ -34,7 +34,8 @@ HEADERS += \
qmljscomponentnamedialog.h \
qmljsfindreferences.h \
qmljseditoreditable.h \
qmljssemantichighlighter.h
qmljssemantichighlighter.h \
qmljsindenter.h
SOURCES += \
qmljscodecompletion.cpp \
......@@ -62,7 +63,8 @@ SOURCES += \
qmljscomponentnamedialog.cpp \
qmljsfindreferences.cpp \
qmljseditoreditable.cpp \
qmljssemantichighlighter.cpp
qmljssemantichighlighter.cpp \
qmljsindenter.cpp
RESOURCES += qmljseditor.qrc
OTHER_FILES += QmlJSEditor.mimetypes.xml
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#include "qmljsindenter.h"
#include "qmljseditorcodeformatter.h"
#include <texteditor/basetexteditor.h>
#include <texteditor/tabsettings.h>
#include <QtCore/QChar>
#include <QtGui/QTextDocument>
#include <QtGui/QTextBlock>
#include <QtGui/QTextCursor>
using namespace QmlJSEditor;
using namespace Internal;
Indenter::Indenter()
{}
Indenter::~Indenter()
{}
bool Indenter::doIsElectricalCharacter(const QChar &ch) const
{
if (ch == QLatin1Char('}')
|| ch == QLatin1Char(']')
|| ch == QLatin1Char(':'))
return true;
return false;
}
void Indenter::doIndentBlock(QTextDocument *doc,
const QTextBlock &block,
const QChar &typedChar,
TextEditor::BaseTextEditor *editor)
{
Q_UNUSED(doc)
Q_UNUSED(typedChar)
Q_UNUSED(editor)
const TextEditor::TabSettings &ts = editor->tabSettings();
QtStyleCodeFormatter codeFormatter(ts);
codeFormatter.updateStateUntil(block);
const int depth = codeFormatter.indentFor(block);
ts.indentLine(block, depth);
}
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/
#ifndef QMLJSINDENTER_H
#define QMLJSINDENTER_H
#include <texteditor/indenter.h>
namespace QmlJSEditor {
namespace Internal {
class Indenter : public TextEditor::Indenter
{
public:
Indenter();
virtual ~Indenter();
private:
virtual bool doIsElectricalCharacter(const QChar &ch) const;
virtual void doIndentBlock(QTextDocument *doc,
const QTextBlock &block,
const QChar &typedChar,
TextEditor::BaseTextEditor *editor);
};
} // Internal
} // QmlJSEditor
#endif // QMLJSINDENTER_H
......@@ -42,6 +42,7 @@
#include "syntaxhighlighter.h"
#include "tooltip.h"
#include "tipcontents.h"
#include "indenter.h"
#include <aggregation/aggregate.h>
#include <coreplugin/actionmanager/actionmanager.h>
......@@ -1877,6 +1878,17 @@ int BaseTextEditor::visibleWrapColumn() const
return d->m_visibleWrapColumn;
}
void BaseTextEditor::setIndenter(Indenter *indenter)
{
// clear out existing code formatter data
for (QTextBlock it = document()->begin(); it.isValid(); it = it.next()) {
TextEditor::TextBlockUserData *userData = BaseTextDocumentLayout::testUserData(it);
if (userData)
userData->setCodeFormatterData(0);
}
d->m_indenter.reset(indenter);
}
//--------- BaseTextEditorPrivate -----------
BaseTextEditorPrivate::BaseTextEditorPrivate()
......@@ -3995,8 +4007,10 @@ void BaseTextEditor::zoomReset()
emit requestZoomReset();
}
bool BaseTextEditor::isElectricCharacter(QChar) const
bool BaseTextEditor::isElectricCharacter(QChar ch) const
{
if (!d->m_indenter.isNull())
return d->m_indenter->isElectricCharacter(ch);
return false;
}
......@@ -4256,59 +4270,26 @@ int BaseTextEditor::paragraphSeparatorAboutToBeInserted(QTextCursor &cursor)
return 1;
}
void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar)
void BaseTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar ch)
{
if (!d->m_indenter.isNull())
d->m_indenter->indentBlock(doc, block, ch, this);
}
void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
{
maybeClearSomeExtraSelections(cursor);
if (cursor.hasSelection()) {
QTextBlock block = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
do {
indentBlock(doc, block, typedChar);
block = block.next();
} while (block.isValid() && block != end);
} else {
indentBlock(doc, cursor.block(), typedChar);
}
if (!d->m_indenter.isNull())
d->m_indenter->indent(doc, cursor, typedChar, this);
}
void BaseTextEditor::reindent(QTextDocument *doc, const QTextCursor &cursor)
{
maybeClearSomeExtraSelections(cursor);
if (cursor.hasSelection()) {
QTextBlock block = doc->findBlock(cursor.selectionStart());
const QTextBlock end = doc->findBlock(cursor.selectionEnd()).next();
const TabSettings &ts = d->m_document->tabSettings();
// skip empty blocks
while (block.isValid() && block != end) {
QString bt = block.text();
if (ts.firstNonSpace(bt) < bt.size())
break;
indentBlock(doc, block, QChar::Null);
block = block.next();
}
int previousIndentation = ts.indentationColumn(block.text());
indentBlock(doc, block, QChar::Null);
int currentIndentation = ts.indentationColumn(block.text());
int delta = currentIndentation - previousIndentation;
block = block.next();
while (block.isValid() && block != end) {
ts.reindentLine(block, delta);
block = block.next();
}
} else {
indentBlock(doc, cursor.block(), QChar::Null);
}
if (!d->m_indenter.isNull())
d->m_indenter->reindent(doc, cursor, this);
}
BaseTextEditor::Link BaseTextEditor::findLinkAt(const QTextCursor &, bool)
{
return Link();
......
......@@ -68,6 +68,7 @@ class BehaviorSettings;
class CompletionSettings;
class DisplaySettings;
class StorageSettings;