From 297b281cede2a1c5cdac4ca7512273774f1eee2a Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 14 Jun 2010 14:52:43 +0200 Subject: [PATCH] Added infrastructure to change multiple files at once. --- src/plugins/cppeditor/cppeditor.cpp | 5 + src/plugins/cppeditor/cppeditor.h | 2 + src/plugins/cppeditor/cppeditor.pro | 2 + src/plugins/cppeditor/cppquickfix.cpp | 39 ++-- src/plugins/cppeditor/cppquickfix.h | 9 +- .../cpptools/cpprefactoringchanges.cpp | 75 +++++++ src/plugins/cpptools/cpprefactoringchanges.h | 62 ++++++ src/plugins/cpptools/cpptools.pro | 6 +- src/plugins/qmljseditor/qmljseditor.cpp | 2 +- src/plugins/qmljseditor/qmljseditor.pro | 6 +- src/plugins/qmljseditor/qmljsquickfix.cpp | 39 +++- src/plugins/qmljseditor/qmljsquickfix.h | 7 + .../qmljseditor/qmljsrefactoringchanges.cpp | 50 +++++ .../qmljseditor/qmljsrefactoringchanges.h | 58 ++++++ src/plugins/texteditor/basefilefind.h | 1 + src/plugins/texteditor/quickfix.cpp | 49 ++--- src/plugins/texteditor/quickfix.h | 23 +-- src/plugins/texteditor/refactoringchanges.cpp | 191 ++++++++++++++++++ src/plugins/texteditor/refactoringchanges.h | 89 ++++++++ src/plugins/texteditor/texteditor.pro | 7 +- 20 files changed, 638 insertions(+), 84 deletions(-) create mode 100644 src/plugins/cpptools/cpprefactoringchanges.cpp create mode 100644 src/plugins/cpptools/cpprefactoringchanges.h create mode 100644 src/plugins/qmljseditor/qmljsrefactoringchanges.cpp create mode 100644 src/plugins/qmljseditor/qmljsrefactoringchanges.h create mode 100644 src/plugins/texteditor/refactoringchanges.cpp create mode 100644 src/plugins/texteditor/refactoringchanges.h diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index 59d6e7383c5..148596996c7 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -733,6 +733,11 @@ TokenCache *CPPEditor::tokenCache() const return m_modelManager->tokenCache(editableInterface()); } +CppTools::CppModelManagerInterface *CPPEditor::modelManager() const +{ + return m_modelManager; +} + void CPPEditor::startRename() { m_inRenameChanged = false; diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 35fd20127cf..bb733991c61 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -201,6 +201,8 @@ public: CPlusPlus::TokenCache *tokenCache() const; + CppTools::CppModelManagerInterface *modelManager() const; + public Q_SLOTS: virtual void setFontSettings(const TextEditor::FontSettings &); void setSortedMethodOverview(bool sort); diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index e9f4f0d0f4d..bd24c10b202 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -15,6 +15,7 @@ HEADERS += cppplugin.h \ cppeditor_global.h \ cppclasswizard.h \ cppquickfix.h + SOURCES += cppplugin.cpp \ cppeditor.cpp \ cpphighlighter.cpp \ @@ -22,6 +23,7 @@ SOURCES += cppplugin.cpp \ cppfilewizard.cpp \ cppclasswizard.cpp \ cppquickfix.cpp + RESOURCES += cppeditor.qrc OTHER_FILES += CppEditor.pluginspec CppEditor.mimetypes.xml diff --git a/src/plugins/cppeditor/cppquickfix.cpp b/src/plugins/cppeditor/cppquickfix.cpp index e1adf2d64e1..ea809580a83 100644 --- a/src/plugins/cppeditor/cppquickfix.cpp +++ b/src/plugins/cppeditor/cppquickfix.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include @@ -864,28 +865,39 @@ private: CppQuickFixOperation::CppQuickFixOperation(TextEditor::BaseTextEditor *editor) - : TextEditor::QuickFixOperation(editor), _topLevelNode(0) + : TextEditor::QuickFixOperation(editor) + , _refactoringChanges(0) + , _topLevelNode(0) { } CppQuickFixOperation::~CppQuickFixOperation() -{ } - -CppQuickFixOperation::Range CppQuickFixOperation::topLevelRange() const { - if (topLevelNode()) - return createRange(topLevelNode()); - - return Range(); + if (_refactoringChanges) + delete _refactoringChanges; } int CppQuickFixOperation::match(TextEditor::QuickFixState *state) { CppQuickFixState *s = static_cast(state); _document = s->info.doc; - _snapshot = s->info.snapshot; + if (_refactoringChanges) + delete _refactoringChanges; + CPPEditor *cppEditor = qobject_cast(editor()); + _refactoringChanges = new CppTools::CppRefactoringChanges(s->info.snapshot, cppEditor->modelManager()); return match(s->path); } +void CppQuickFixOperation::apply() +{ + cppRefactoringChanges()->apply(); +} + +CppTools::CppRefactoringChanges *CppQuickFixOperation::cppRefactoringChanges() const +{ return _refactoringChanges; } + +TextEditor::RefactoringChanges *CppQuickFixOperation::refactoringChanges() const +{ return cppRefactoringChanges(); } + CPlusPlus::AST *CppQuickFixOperation::topLevelNode() const { return _topLevelNode; } @@ -896,7 +908,9 @@ Document::Ptr CppQuickFixOperation::document() const { return _document; } const Snapshot &CppQuickFixOperation::snapshot() const -{ return _snapshot; } +{ + return _refactoringChanges->snapshot(); +} const CPlusPlus::Token &CppQuickFixOperation::tokenAt(unsigned index) const { return _document->translationUnit()->tokenAt(index); } @@ -965,11 +979,6 @@ bool CppQuickFixOperation::isCursorOn(const CPlusPlus::AST *ast) const return false; } -CppQuickFixOperation::Range CppQuickFixOperation::createRange(AST *ast) const -{ - return range(startOf(ast), endOf(ast)); -} - void CppQuickFixOperation::move(unsigned tokenIndex, int to) { int start, end; diff --git a/src/plugins/cppeditor/cppquickfix.h b/src/plugins/cppeditor/cppquickfix.h index 673e50ffe5d..a16562523a7 100644 --- a/src/plugins/cppeditor/cppquickfix.h +++ b/src/plugins/cppeditor/cppquickfix.h @@ -43,6 +43,7 @@ namespace CppTools { class CppModelManagerInterface; + class CppRefactoringChanges; } // end of namespace CppTools namespace CppEditor { @@ -61,10 +62,13 @@ public: CPlusPlus::Document::Ptr document() const; const CPlusPlus::Snapshot &snapshot() const; - virtual Range topLevelRange() const; virtual int match(TextEditor::QuickFixState *state); protected: + virtual void apply(); + virtual CppTools::CppRefactoringChanges *cppRefactoringChanges() const; + virtual TextEditor::RefactoringChanges *refactoringChanges() const; + CPlusPlus::AST *topLevelNode() const; void setTopLevelNode(CPlusPlus::AST *topLevelNode); @@ -100,11 +104,10 @@ protected: void copy(const CPlusPlus::AST *ast, int to); QString textOf(const CPlusPlus::AST *ast) const; - Range createRange(CPlusPlus::AST *ast) const; // ### rename me private: + CppTools::CppRefactoringChanges *_refactoringChanges; CPlusPlus::Document::Ptr _document; - CPlusPlus::Snapshot _snapshot; CPlusPlus::AST *_topLevelNode; }; diff --git a/src/plugins/cpptools/cpprefactoringchanges.cpp b/src/plugins/cpptools/cpprefactoringchanges.cpp new file mode 100644 index 00000000000..f6e4766c8aa --- /dev/null +++ b/src/plugins/cpptools/cpprefactoringchanges.cpp @@ -0,0 +1,75 @@ +/************************************************************************** +** +** 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 "cpprefactoringchanges.h" + +using namespace CPlusPlus; +using namespace CppTools; +using namespace TextEditor; + +CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot, + CppModelManagerInterface *modelManager) + : m_snapshot(snapshot) + , m_modelManager(modelManager) + , m_workingCopy(modelManager->workingCopy()) +{ + Q_ASSERT(modelManager); +} + +QStringList CppRefactoringChanges::apply() +{ + const QStringList changedFiles = TextEditor::RefactoringChanges::apply(); + m_modelManager->updateSourceFiles(changedFiles); + return changedFiles; +} + +Document::Ptr CppRefactoringChanges::parsedDocumentForFile(const QString &fileName) const +{ + Document::Ptr doc = m_snapshot.document(fileName); + + QString source; + if (m_workingCopy.contains(fileName)) { + QPair workingCopy = m_workingCopy.get(fileName); + if (doc && doc->editorRevision() == workingCopy.second) + return doc; + else + source = workingCopy.first; + } else { + QFile file(fileName); + if (! file.open(QFile::ReadOnly)) + return Document::Ptr(); + + source = QTextStream(&file).readAll(); // ### FIXME read bytes, and remove the convert below + file.close(); + } + + doc = m_snapshot.documentFromSource(source.toLatin1(), fileName); + doc->check(); + return doc; +} diff --git a/src/plugins/cpptools/cpprefactoringchanges.h b/src/plugins/cpptools/cpprefactoringchanges.h new file mode 100644 index 00000000000..5056a573968 --- /dev/null +++ b/src/plugins/cpptools/cpprefactoringchanges.h @@ -0,0 +1,62 @@ +/************************************************************************** +** +** 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 CPPREFACTORINGCHANGES_H +#define CPPREFACTORINGCHANGES_H + +#include + +#include +#include + +#include + +namespace CppTools { + +class CPPTOOLS_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChanges +{ +public: + CppRefactoringChanges(const CPlusPlus::Snapshot &snapshot, CppModelManagerInterface *modelManager); + + virtual QStringList apply(); + + const CPlusPlus::Snapshot &snapshot() const + { return m_snapshot; } + + CPlusPlus::Document::Ptr parsedDocumentForFile(const QString &fileName) const; + +private: + CPlusPlus::Snapshot m_snapshot; + CppModelManagerInterface *m_modelManager; + CppModelManagerInterface::WorkingCopy m_workingCopy; +}; + +} // namespace CppTools + +#endif // CPPREFACTORINGCHANGES_H diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index de7adcd66f6..1f5e09d0c3f 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -23,7 +23,8 @@ HEADERS += completionsettingspage.h \ searchsymbols.h \ cppdoxygen.h \ cppfilesettingspage.h \ - cppfindreferences.h + cppfindreferences.h \ + cpprefactoringchanges.h SOURCES += completionsettingspage.cpp \ cppclassesfilter.cpp \ @@ -38,7 +39,8 @@ SOURCES += completionsettingspage.cpp \ cppdoxygen.cpp \ cppfilesettingspage.cpp \ abstracteditorsupport.cpp \ - cppfindreferences.cpp + cppfindreferences.cpp \ + cpprefactoringchanges.cpp FORMS += completionsettingspage.ui \ cppfilesettingspage.ui diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index 5f2e4306702..099ebed95da 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -436,7 +436,7 @@ protected: range.ast = member; range.begin = QTextCursor(_textDocument); - range.begin.setPosition(ast->lbraceToken.begin()); + range.begin.setPosition(member->firstSourceLocation().begin()); range.end = QTextCursor(_textDocument); range.end.setPosition(ast->rbraceToken.end()); diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro index 0058d8b9bb9..cf715dfe2b5 100644 --- a/src/plugins/qmljseditor/qmljseditor.pro +++ b/src/plugins/qmljseditor/qmljseditor.pro @@ -21,7 +21,8 @@ HEADERS += \ qmljshoverhandler.h \ qmljsmodelmanager.h \ qmljspreviewrunner.h \ - qmljsquickfix.h + qmljsquickfix.h \ + qmljsrefactoringchanges.h SOURCES += \ qmljscodecompletion.cpp \ @@ -35,7 +36,8 @@ SOURCES += \ qmljshoverhandler.cpp \ qmljsmodelmanager.cpp \ qmljspreviewrunner.cpp \ - qmljsquickfix.cpp + qmljsquickfix.cpp \ + qmljsrefactoringchanges.cpp RESOURCES += qmljseditor.qrc OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml diff --git a/src/plugins/qmljseditor/qmljsquickfix.cpp b/src/plugins/qmljseditor/qmljsquickfix.cpp index b15839387f1..b7ab218e1bd 100644 --- a/src/plugins/qmljseditor/qmljsquickfix.cpp +++ b/src/plugins/qmljseditor/qmljsquickfix.cpp @@ -29,11 +29,19 @@ #include "qmljsquickfix.h" #include "qmljseditor.h" +#include "qmljsrefactoringchanges.h" #include "qmljs/parser/qmljsast_p.h" + +#include + +#include + #include #include +using namespace QmlJSEditor; using namespace QmlJSEditor::Internal; +using TextEditor::RefactoringChanges; class QmlJSQuickFixState: public TextEditor::QuickFixState { @@ -54,14 +62,6 @@ public: return QApplication::translate("QmlJSEditor::QuickFix", "Split initializer"); } - virtual Range topLevelRange() const - { - Q_ASSERT(_objectInitializer); - - return range(position(_objectInitializer->lbraceToken), - position(_objectInitializer->rbraceToken)); - } - virtual void createChangeSet() { Q_ASSERT(_objectInitializer != 0); @@ -77,6 +77,10 @@ public: // insert a newline before the closing brace insert(position(_objectInitializer->rbraceToken), QLatin1String("\n")); + + reindent(RefactoringChanges::Range(position(_objectInitializer->lbraceToken), + position(_objectInitializer->rbraceToken))); + } virtual int check() @@ -112,11 +116,14 @@ private: QmlJSQuickFixOperation::QmlJSQuickFixOperation(TextEditor::BaseTextEditor *editor) : TextEditor::QuickFixOperation(editor) + , _refactoringChanges(0) { } QmlJSQuickFixOperation::~QmlJSQuickFixOperation() { + if (_refactoringChanges) + delete _refactoringChanges; } QmlJS::Document::Ptr QmlJSQuickFixOperation::document() const @@ -136,11 +143,27 @@ const SemanticInfo &QmlJSQuickFixOperation::semanticInfo() const int QmlJSQuickFixOperation::match(TextEditor::QuickFixState *state) { + QmlJS::ModelManagerInterface *modelManager = ExtensionSystem::PluginManager::instance()->getObject(); QmlJSQuickFixState *s = static_cast(state); _semanticInfo = s->semanticInfo; + if (_refactoringChanges) { + delete _refactoringChanges; + } + _refactoringChanges = new QmlJSRefactoringChanges(modelManager, _semanticInfo.snapshot); return check(); } +void QmlJSQuickFixOperation::apply() +{ + _refactoringChanges->apply(); +} + +QmlJSRefactoringChanges *QmlJSQuickFixOperation::qmljsRefactoringChanges() const +{ return _refactoringChanges; } + +RefactoringChanges *QmlJSQuickFixOperation::refactoringChanges() const +{ return qmljsRefactoringChanges(); } + unsigned QmlJSQuickFixOperation::position(const QmlJS::AST::SourceLocation &loc) const { return position(loc.startLine, loc.startColumn); diff --git a/src/plugins/qmljseditor/qmljsquickfix.h b/src/plugins/qmljseditor/qmljsquickfix.h index 998c35fdc64..302f9c666d2 100644 --- a/src/plugins/qmljseditor/qmljsquickfix.h +++ b/src/plugins/qmljseditor/qmljsquickfix.h @@ -31,6 +31,7 @@ #define QMLJSQUICKFIX_H #include "qmljseditor.h" + #include #include #include @@ -40,6 +41,7 @@ namespace QmlJS { } namespace QmlJSEditor { +class QmlJSRefactoringChanges; namespace Internal { @@ -69,6 +71,10 @@ protected: using TextEditor::QuickFixOperation::charAt; using TextEditor::QuickFixOperation::position; + virtual void apply(); + QmlJSRefactoringChanges *qmljsRefactoringChanges() const; + virtual TextEditor::RefactoringChanges *refactoringChanges() const; + unsigned position(const QmlJS::AST::SourceLocation &loc) const; // token based operations @@ -79,6 +85,7 @@ protected: private: SemanticInfo _semanticInfo; + QmlJSRefactoringChanges *_refactoringChanges; }; class QmlJSQuickFixCollector: public TextEditor::QuickFixCollector diff --git a/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp b/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp new file mode 100644 index 00000000000..c8a478eba97 --- /dev/null +++ b/src/plugins/qmljseditor/qmljsrefactoringchanges.cpp @@ -0,0 +1,50 @@ +/************************************************************************** +** +** 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 "qmljsrefactoringchanges.h" + +#include + +using namespace QmlJS; +using namespace QmlJSEditor; + +QmlJSRefactoringChanges::QmlJSRefactoringChanges(ModelManagerInterface *modelManager, + const Snapshot &snapshot) + : m_modelManager(modelManager) + , m_snapshot(snapshot) +{ + Q_ASSERT(modelManager); +} + +QStringList QmlJSRefactoringChanges::apply() +{ + const QStringList changedFiles = TextEditor::RefactoringChanges::apply(); + m_modelManager->updateSourceFiles(changedFiles, true); + return changedFiles; +} diff --git a/src/plugins/qmljseditor/qmljsrefactoringchanges.h b/src/plugins/qmljseditor/qmljsrefactoringchanges.h new file mode 100644 index 00000000000..3a4198743dd --- /dev/null +++ b/src/plugins/qmljseditor/qmljsrefactoringchanges.h @@ -0,0 +1,58 @@ +/************************************************************************** +** +** 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 QMLREFACTORINGCHANGES_H +#define QMLREFACTORINGCHANGES_H + +#include + +#include + +namespace QmlJS { +class ModelManagerInterface; +} // namespace QmlJS + +namespace QmlJSEditor { + +class QmlJSRefactoringChanges: public TextEditor::RefactoringChanges +{ +public: + QmlJSRefactoringChanges(QmlJS::ModelManagerInterface *modelManager, + const QmlJS::Snapshot &snapshot); + + virtual QStringList apply(); + +private: + QmlJS::ModelManagerInterface *m_modelManager; + QmlJS::Snapshot m_snapshot; +}; + +} // namespace QmlJSEditor + +#endif // QMLREFACTORINGCHANGES_H diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h index fdeb19fcaa1..c0fdaa82f61 100644 --- a/src/plugins/texteditor/basefilefind.h +++ b/src/plugins/texteditor/basefilefind.h @@ -69,6 +69,7 @@ public: /* returns the list of unique files that were passed in items */ static QStringList replaceAll(const QString &txt, const QList &items); + protected: virtual QStringList files() = 0; void writeCommonSettings(QSettings *settings); diff --git a/src/plugins/texteditor/quickfix.cpp b/src/plugins/texteditor/quickfix.cpp index 7fdb31c581f..8e65cd4fbf7 100644 --- a/src/plugins/texteditor/quickfix.cpp +++ b/src/plugins/texteditor/quickfix.cpp @@ -30,11 +30,14 @@ #include "quickfix.h" #include "basetexteditor.h" +#include + #include #include #include +using TextEditor::RefactoringChanges; using TextEditor::QuickFixOperation; using TextEditor::QuickFixCollector; @@ -72,49 +75,16 @@ int QuickFixOperation::selectionEnd() const return _textCursor.selectionEnd(); } -const Utils::ChangeSet &QuickFixOperation::changeSet() const -{ - return _changeSet; -} - -void QuickFixOperation::apply() -{ - const Range r = topLevelRange(); - - _textCursor.beginEditBlock(); - _changeSet.apply(&_textCursor); - reindent(r); - _textCursor.endEditBlock(); -} - -QuickFixOperation::Range QuickFixOperation::range(int from, int to) const -{ - QTextDocument *doc = editor()->document(); - - QTextCursor begin(doc); - begin.setPosition(from); - - QTextCursor end(doc); - end.setPosition(to); - - Range range; - range.begin = begin; - range.end = end; - return range; -} - int QuickFixOperation::position(int line, int column) const { QTextDocument *doc = editor()->document(); return doc->findBlockByNumber(line - 1).position() + column - 1; } -void QuickFixOperation::reindent(const Range &range) +void QuickFixOperation::reindent(const RefactoringChanges::Range &range) { if (! range.isNull()) { - QTextCursor tc = range.begin; - tc.setPosition(range.end.position(), QTextCursor::KeepAnchor); - editor()->indentInsertedText(tc); + refactoringChanges()->reindent(editor()->file()->fileName(), range); } } @@ -162,9 +132,18 @@ QString QuickFixOperation::textOf(int start, int end) const return tc.selectedText(); } +TextEditor::RefactoringChanges::Range QuickFixOperation::range(int start, int end) +{ + return TextEditor::RefactoringChanges::Range(start, end); +} + void QuickFixOperation::perform() { createChangeSet(); + + if (!_changeSet.isEmpty()) + refactoringChanges()->changeFile(editor()->file()->fileName(), _changeSet); + apply(); } diff --git a/src/plugins/texteditor/quickfix.h b/src/plugins/texteditor/quickfix.h index d5b9d73895a..413fb1a08fa 100644 --- a/src/plugins/texteditor/quickfix.h +++ b/src/plugins/texteditor/quickfix.h @@ -32,6 +32,8 @@ #include "texteditor_global.h" #include "icompletioncollector.h" + +#include #include #include @@ -58,41 +60,28 @@ class TEXTEDITOR_EXPORT QuickFixOperation public: typedef QSharedPointer Ptr; - struct Range { - Range() {} - Range(const QTextCursor &tc): begin(tc), end(tc) {} - - bool isNull() const { return begin.isNull() || end.isNull(); } - - QTextCursor begin; - QTextCursor end; - }; - public: QuickFixOperation(TextEditor::BaseTextEditor *editor); virtual ~QuickFixOperation(); virtual QString description() const = 0; virtual void createChangeSet() = 0; - virtual Range topLevelRange() const = 0; virtual int match(QuickFixState *state) = 0; void perform(); - void apply(); TextEditor::BaseTextEditor *editor() const; QTextCursor textCursor() const; void setTextCursor(const QTextCursor &cursor); - void reindent(const Range &range); + void reindent(const TextEditor::RefactoringChanges::Range &range); int selectionStart() const; int selectionEnd() const; int position(int line, int column) const; - Range range(int from, int to) const; void move(int start, int end, int to); void replace(int start, int end, const QString &replacement); @@ -104,7 +93,11 @@ public: QChar charAt(int offset) const; QString textOf(int start, int end) const; - const Utils::ChangeSet &changeSet() const; + static TextEditor::RefactoringChanges::Range range(int start, int end); + +protected: + virtual void apply() = 0; + virtual TextEditor::RefactoringChanges *refactoringChanges() const = 0; private: TextEditor::BaseTextEditor *_editor; diff --git a/src/plugins/texteditor/refactoringchanges.cpp b/src/plugins/texteditor/refactoringchanges.cpp new file mode 100644 index 00000000000..456a5291d1f --- /dev/null +++ b/src/plugins/texteditor/refactoringchanges.cpp @@ -0,0 +1,191 @@ +/************************************************************************** +** +** 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 "refactoringchanges.h" + +#include +#include + +#include +#include +#include + +using namespace TextEditor; + +RefactoringChanges::~RefactoringChanges() +{} + +void RefactoringChanges::createFile(const QString &fileName, const QString &contents) +{ + m_contentsByCreatedFile.insert(fileName, contents); +} + +void RefactoringChanges::changeFile(const QString &fileName, const Utils::ChangeSet &changeSet) +{ + m_changesByFile.insert(fileName, changeSet); +} + +void RefactoringChanges::reindent(const QString &fileName, const Range &range) +{ + m_indentRangesByFile[fileName].append(range); +} + +QStringList RefactoringChanges::apply() +{ + QSet changed; + + { // create files + foreach (const QString &fileName, m_contentsByCreatedFile.keys()) { + BaseTextEditor *editor = editorForNewFile(fileName); + if (editor == 0) + continue; + + QTextCursor tc = editor->textCursor(); + tc.beginEditBlock(); + tc.setPosition(0); + tc.insertText(m_contentsByCreatedFile.value(fileName)); + + foreach (const Range &range, m_indentRangesByFile.value(fileName, QList())) { + QTextCursor indentCursor = editor->textCursor(); + indentCursor.setPosition(range.begin); + indentCursor.setPosition(range.end, QTextCursor::KeepAnchor); + editor->indentInsertedText(indentCursor); + } + + tc.endEditBlock(); + changed.insert(fileName); + } + } + + { // change and indent files + foreach (const QString &fileName, m_changesByFile.keys()) { + BaseTextEditor *editor = editorForFile(fileName, true); + if (editor == 0) + continue; + + QTextCursor tc = editor->textCursor(); + tc.beginEditBlock(); + + typedef QPair CursorPair; + QList cursorPairs; + foreach (const Range &range, m_indentRangesByFile.value(fileName, QList())) { + QTextCursor start = editor->textCursor(); + QTextCursor end = editor->textCursor(); + start.setPosition(range.begin); + end.setPosition(range.end); + cursorPairs.append(qMakePair(start, end)); + } + + QTextCursor changeSetCursor = editor->textCursor(); + Utils::ChangeSet changeSet = m_changesByFile[fileName]; + changeSet.apply(&changeSetCursor); + + foreach (const CursorPair &cursorPair, cursorPairs) { + QTextCursor indentCursor = cursorPair.first; + indentCursor.setPosition(cursorPair.second.position(), + QTextCursor::KeepAnchor); + editor->indentInsertedText(indentCursor); + } + + tc.endEditBlock(); + changed.insert(fileName); + } + } + + { // Indent files which are not changed + foreach (const QString &fileName, m_indentRangesByFile.keys()) { + BaseTextEditor *editor = editorForFile(fileName); + + if (editor == 0) + continue; + + if (changed.contains(fileName)) + continue; + + QTextCursor tc = editor->textCursor(); + tc.beginEditBlock(); + + foreach (const Range &range, m_indentRangesByFile.value(fileName, QList())) { + QTextCursor indentCursor = editor->textCursor(); + indentCursor.setPosition(range.begin); + indentCursor.setPosition(range.end, QTextCursor::KeepAnchor); + editor->indentInsertedText(indentCursor); + } + + tc.endEditBlock(); + changed.insert(fileName); + } + } + + { // Delete files + // ### + } + + return changed.toList(); +} + +int RefactoringChanges::positionInFile(const QString &fileName, int line, int column) const +{ + if (BaseTextEditor *editor = editorForFile(fileName)) { + return editor->document()->findBlockByNumber(line).position() + column; + } else { + return -1; + } +} + +BaseTextEditor *RefactoringChanges::editorForFile(const QString &fileName, + bool openIfClosed) +{ + Core::EditorManager *editorManager = Core::EditorManager::instance(); + + const QList editors = editorManager->editorsForFileName(fileName); + foreach (Core::IEditor *editor, editors) { + BaseTextEditor *textEditor = qobject_cast(editor->widget()); + if (textEditor != 0) + return textEditor; + } + + if (!openIfClosed) + return 0; + + Core::IEditor *editor = editorManager->openEditor(fileName, QString(), + Core::EditorManager::NoActivate | Core::EditorManager::IgnoreNavigationHistory | Core::EditorManager::NoModeSwitch); + return qobject_cast(editor->widget()); +} + +BaseTextEditor *RefactoringChanges::editorForNewFile(const QString &fileName) +{ + QFile f(fileName); + if (f.exists()) + return 0; + if (!f.open(QIODevice::Append)) + return 0; + f.close(); + return editorForFile(fileName, true); +} diff --git a/src/plugins/texteditor/refactoringchanges.h b/src/plugins/texteditor/refactoringchanges.h new file mode 100644 index 00000000000..bcaa8adad4f --- /dev/null +++ b/src/plugins/texteditor/refactoringchanges.h @@ -0,0 +1,89 @@ +/************************************************************************** +** +** 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 REFACTORINGCHANGES_H +#define REFACTORINGCHANGES_H + +#include +#include +#include + +#include +#include +#include + +namespace TextEditor { + +class TEXTEDITOR_EXPORT RefactoringChanges +{ +public: + struct Range { + Range() + : begin(0) + , end(0) + {} + Range(int beginPosition, int endPosition) + : begin(beginPosition) + , end(endPosition) + {} + + bool isNull() const + { return begin == 0 || end == 0; } + + int begin; + int end; + }; + +public: + virtual ~RefactoringChanges(); + + void createFile(const QString &fileName, const QString &contents); + void changeFile(const QString &fileName, const Utils::ChangeSet &changeSet); +// TODO: +// void deleteFile(const QString &fileName); + + void reindent(const QString &fileName, const Range &range); + + virtual QStringList apply(); + + int positionInFile(const QString &fileName, int line, int column = 0) const; + + static BaseTextEditor *editorForFile(const QString &fileName, + bool openIfClosed = false); + static BaseTextEditor *editorForNewFile(const QString &fileName); + +private: + QMap m_contentsByCreatedFile; + QMap m_changesByFile; + QMap > m_indentRangesByFile; +}; + +} // namespace TextEditor + +#endif // REFACTORINGCHANGES_H diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index 0c404e9ea7c..d9eb3928053 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -58,7 +58,8 @@ SOURCES += texteditorplugin.cpp \ generichighlighter/highlightersettings.cpp \ generichighlighter/managedefinitionsdialog.cpp \ generichighlighter/highlightdefinitionmetadata.cpp \ - generichighlighter/definitiondownloader.cpp + generichighlighter/definitiondownloader.cpp \ + refactoringchanges.cpp HEADERS += texteditorplugin.h \ textfilewizard.h \ @@ -119,8 +120,8 @@ HEADERS += texteditorplugin.h \ generichighlighter/highlightersettings.h \ generichighlighter/managedefinitionsdialog.h \ generichighlighter/highlightdefinitionmetadata.h \ - generichighlighter/definitiondownloader.h - + generichighlighter/definitiondownloader.h \ + refactoringchanges.h FORMS += behaviorsettingspage.ui \ displaysettingspage.ui \