diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index 9f38859a8808a22617b5ae45af028729bb8b508a..95abbbde120e427880a655d1172fc73cf3dd54a7 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -26,7 +26,8 @@ HEADERS += cppplugin.h \ cppqtstyleindenter.h \ cppautocompleter.h \ cppcompleteswitch.h \ - cppsnippetprovider.h + cppsnippetprovider.h \ + cppinsertqtpropertymembers.h SOURCES += cppplugin.cpp \ cppeditor.cpp \ @@ -47,7 +48,8 @@ SOURCES += cppplugin.cpp \ cppqtstyleindenter.cpp \ cppautocompleter.cpp \ cppcompleteswitch.cpp \ - cppsnippetprovider.cpp + cppsnippetprovider.cpp \ + cppinsertqtpropertymembers.cpp RESOURCES += cppeditor.qrc OTHER_FILES += CppEditor.mimetypes.xml diff --git a/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp b/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a43945ff70f0a65b215e22c1a58ebd0cd5c59f7 --- /dev/null +++ b/src/plugins/cppeditor/cppinsertqtpropertymembers.cpp @@ -0,0 +1,194 @@ +/************************************************************************** +** +** 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 "cppinsertqtpropertymembers.h" + +#include <AST.h> +#include <Token.h> +#include <cplusplus/Overview.h> +#include <cpptools/insertionpointlocator.h> +#include <cpptools/cpprefactoringchanges.h> +#include <cppeditor/cppquickfix.h> + +using namespace CPlusPlus; +using namespace CppTools; +using namespace TextEditor; +using namespace Utils; +using namespace CppEditor; +using namespace CppEditor::Internal; + +QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFixState &state) +{ + const QList<AST *> &path = state.path(); + + if (path.isEmpty()) + return noResult(); + + AST * const ast = path.last(); + QtPropertyDeclarationAST *qtPropertyDeclaration = ast->asQtPropertyDeclaration(); + if (!qtPropertyDeclaration) + return noResult(); + + ClassSpecifierAST *klass = 0; + for (int i = path.size() - 2; i >= 0; --i) { + klass = path.at(i)->asClassSpecifier(); + if (klass) + break; + } + if (!klass) + return noResult(); + + CppRefactoringChanges refactoring(state.snapshot()); + const CppRefactoringFile &file = refactoring.file(state.document()->fileName()); + const QString propertyName = file.textOf(qtPropertyDeclaration->property_name); + QString getterName; + QString setterName; + QString signalName; + int generateFlags; + for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list; + it; it = it->next) { + const QString tokenString = file.tokenAt(it->value->item_name_token).spell(); + if (tokenString == QLatin1String("READ")) { + getterName = file.textOf(it->value->expression); + generateFlags |= GenerateGetter; + } else if (tokenString == QLatin1String("WRITE")) { + setterName = file.textOf(it->value->expression); + generateFlags |= GenerateSetter; + } else if (tokenString == QLatin1String("NOTIFY")) { + signalName = file.textOf(it->value->expression); + generateFlags |= GenerateSignal; + } + } + QString storageName = QString("m_%1").arg(propertyName); + generateFlags |= GenerateStorage; + + Class *c = klass->symbol; + + Overview overview; + for (unsigned i = 0; i < c->memberCount(); ++i) { + Symbol *member = c->memberAt(i); + FullySpecifiedType type = member->type(); + if (member->asFunction() || (type.isValid() && type->asFunctionType())) { + const QString name = overview(member->name()); + if (name == getterName) { + generateFlags &= ~GenerateGetter; + } else if (name == setterName) { + generateFlags &= ~GenerateSetter; + } else if (name == signalName) { + generateFlags &= ~GenerateSignal; + } + } else if (member->asDeclaration()) { + const QString name = overview(member->name()); + if (name == storageName) + generateFlags &= ~GenerateStorage; + } + } + + if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty()) + return noResult(); + + return singleResult(new Operation(state, path.size() - 1, qtPropertyDeclaration, c, + generateFlags, + getterName, setterName, signalName, storageName)); +} + +InsertQtPropertyMembers::Operation::Operation( + const CppQuickFixState &state, int priority, QtPropertyDeclarationAST *declaration, Class *klass, + int generateFlags, const QString &getterName, const QString &setterName, const QString &signalName, + const QString &storageName) + : CppQuickFixOperation(state, priority) + , m_declaration(declaration) + , m_class(klass) + , m_generateFlags(generateFlags) + , m_getterName(getterName) + , m_setterName(setterName) + , m_signalName(signalName) + , m_storageName(storageName) +{ + QString desc = InsertQtPropertyMembers::tr("Generate missing Q_PROPERTY members..."); + setDescription(desc); +} + +void InsertQtPropertyMembers::Operation::performChanges(CppRefactoringFile *file, CppRefactoringChanges *refactoring) +{ + InsertionPointLocator locator(refactoring); + Utils::ChangeSet declarations; + + const QString typeName = file->textOf(m_declaration->type_id); + const QString propertyName = file->textOf(m_declaration->property_name); + + // getter declaration + if (m_generateFlags & GenerateGetter) { + // const QString getterDeclaration = QString("%1 %2() const;").arg(typeName, getterName); + const QString getterDeclaration = QString("%1 %2() const\n{\nreturn %3;\n}\n").arg(typeName, m_getterName, m_storageName); + InsertionLocation getterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Public); + Q_ASSERT(getterLoc.isValid()); + insertAndIndent(file, &declarations, getterLoc, getterDeclaration); + } + + // setter declaration + if (m_generateFlags & GenerateSetter) { + // const QString setterDeclaration = QString("void %1(%2 arg);").arg(setterName, typeName); + QString setterDeclaration = QString("void %1(%2 arg)\n{\n").arg(m_setterName, typeName); + if (!m_signalName.isEmpty()) { + setterDeclaration += QString("if (%1 != arg) {\n%1 = arg;\nemit %2(arg);\n}\n}\n").arg(m_storageName, m_signalName); + } else { + setterDeclaration += QString("%1 = arg;\n}\n").arg(m_storageName); + } + InsertionLocation setterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::PublicSlot); + Q_ASSERT(setterLoc.isValid()); + insertAndIndent(file, &declarations, setterLoc, setterDeclaration); + } + + // signal declaration + if (m_generateFlags & GenerateSignal) { + const QString declaration = QString("void %1(%2 arg);\n").arg(m_signalName, typeName); + InsertionLocation loc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Signals); + Q_ASSERT(loc.isValid()); + insertAndIndent(file, &declarations, loc, declaration); + } + + // storage + if (m_generateFlags & GenerateStorage) { + const QString storageDeclaration = QString("%1 m_%2;\n").arg(typeName, propertyName); + InsertionLocation storageLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Private); + Q_ASSERT(storageLoc.isValid()); + insertAndIndent(file, &declarations, storageLoc, storageDeclaration); + } + + file->change(declarations); +} + +void InsertQtPropertyMembers::Operation::insertAndIndent(RefactoringFile *file, ChangeSet *changeSet, const InsertionLocation &loc, const QString &text) +{ + int targetPosition1 = file->position(loc.line(), loc.column()); + int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1); + changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix()); + file->indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1)); +} diff --git a/src/plugins/cppeditor/cppinsertqtpropertymembers.h b/src/plugins/cppeditor/cppinsertqtpropertymembers.h new file mode 100644 index 0000000000000000000000000000000000000000..94863444fcb104ae464e642ce3f6a9617c230238 --- /dev/null +++ b/src/plugins/cppeditor/cppinsertqtpropertymembers.h @@ -0,0 +1,101 @@ +/************************************************************************** +** +** 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 CPPINSERTQTPROPERTYMEMBERS_H +#define CPPINSERTQTPROPERTYMEMBERS_H + +#include <cppeditor/cppquickfix.h> + +#include <QtCore/QString> + +namespace CPlusPlus { +class QtPropertyDeclarationAST; +class Class; +} + +namespace TextEditor { +class RefactoringFile; +} + +namespace Utils { +class ChangeSet; +} + +namespace CppTools { +class InsertionLocation; +} + +namespace CppEditor { +namespace Internal { + +class InsertQtPropertyMembers : public CppQuickFixFactory +{ + Q_OBJECT + +public: + virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state); + +private: + enum GenerateFlag { + GenerateGetter = 1 << 0, + GenerateSetter = 1 << 1, + GenerateSignal = 1 << 2, + GenerateStorage = 1 << 3 + }; + + class Operation: public CppQuickFixOperation + { + public: + Operation(const CppQuickFixState &state, int priority, + CPlusPlus::QtPropertyDeclarationAST *declaration, CPlusPlus::Class *klass, + int generateFlags, + const QString &getterName, const QString &setterName, const QString &signalName, + const QString &storageName); + + virtual void performChanges(CppTools::CppRefactoringFile *file, + CppTools::CppRefactoringChanges *refactoring); + + private: + void insertAndIndent(TextEditor::RefactoringFile *file, Utils::ChangeSet *changeSet, + const CppTools::InsertionLocation &loc, const QString &text); + + CPlusPlus::QtPropertyDeclarationAST *m_declaration; + CPlusPlus::Class *m_class; + int m_generateFlags; + QString m_getterName; + QString m_setterName; + QString m_signalName; + QString m_storageName; + }; +}; + +} // namespace Internal +} // namespace CppEditor + +#endif // CPPINSERTQTPROPERTYMEMBERS_H diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 3165c5f36c3221d6a43b3f2b2d833b0283ef1f61..158de4118855f77261466ace42eabd53d4f3eb43 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -31,6 +31,7 @@ #include "cppeditor.h" #include "cppquickfix.h" #include "cppinsertdecldef.h" +#include "cppinsertqtpropertymembers.h" #include "cppquickfixcollector.h" #include <ASTVisitor.h> @@ -53,6 +54,7 @@ #include <cplusplus/CppRewriter.h> #include <cpptools/cpptoolsconstants.h> #include <cpptools/cpprefactoringchanges.h> +#include <cpptools/insertionpointlocator.h> #include <extensionsystem/iplugin.h> #include <QtGui/QApplication> @@ -1588,6 +1590,7 @@ void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn) plugIn->addAutoReleasedObject(new FixForwardDeclarationOp); plugIn->addAutoReleasedObject(new AddLocalDeclarationOp); plugIn->addAutoReleasedObject(new ToCamelCaseConverter); + plugIn->addAutoReleasedObject(new Internal::InsertQtPropertyMembers); plugIn->addAutoReleasedObject(new Internal::DeclFromDef); plugIn->addAutoReleasedObject(new Internal::DefFromDecl); }