1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "cppinsertqtpropertymembers.h"
38 #include <cplusplus/Overview.h>
39 #include <cpptools/insertionpointlocator.h>
40 #include <cpptools/cpprefactoringchanges.h>
41 #include <cppeditor/cppquickfix.h>
43 using namespace CPlusPlus;
44 using namespace CppTools;
45 using namespace TextEditor;
46 using namespace Utils;
47 using namespace CppEditor;
48 using namespace CppEditor::Internal;
50 QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFixState &state)
52 const QList<AST *> &path = state.path();
57 AST * const ast = path.last();
58 QtPropertyDeclarationAST *qtPropertyDeclaration = ast->asQtPropertyDeclaration();
59 if (!qtPropertyDeclaration)
62 ClassSpecifierAST *klass = 0;
63 for (int i = path.size() - 2; i >= 0; --i) {
64 klass = path.at(i)->asClassSpecifier();
71 CppRefactoringChanges refactoring(state.snapshot());
72 const CppRefactoringFile &file = refactoring.file(state.document()->fileName());
73 const QString propertyName = file.textOf(qtPropertyDeclaration->property_name);
77 int generateFlags = 0;
78 for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
80 const QString tokenString = file.tokenAt(it->value->item_name_token).spell();
81 if (tokenString == QLatin1String("READ")) {
82 getterName = file.textOf(it->value->expression);
83 generateFlags |= GenerateGetter;
84 } else if (tokenString == QLatin1String("WRITE")) {
85 setterName = file.textOf(it->value->expression);
86 generateFlags |= GenerateSetter;
87 } else if (tokenString == QLatin1String("NOTIFY")) {
88 signalName = file.textOf(it->value->expression);
89 generateFlags |= GenerateSignal;
92 QString storageName = QString("m_%1").arg(propertyName);
93 generateFlags |= GenerateStorage;
95 Class *c = klass->symbol;
98 for (unsigned i = 0; i < c->memberCount(); ++i) {
99 Symbol *member = c->memberAt(i);
100 FullySpecifiedType type = member->type();
101 if (member->asFunction() || (type.isValid() && type->asFunctionType())) {
102 const QString name = overview(member->name());
103 if (name == getterName) {
104 generateFlags &= ~GenerateGetter;
105 } else if (name == setterName) {
106 generateFlags &= ~GenerateSetter;
107 } else if (name == signalName) {
108 generateFlags &= ~GenerateSignal;
110 } else if (member->asDeclaration()) {
111 const QString name = overview(member->name());
112 if (name == storageName)
113 generateFlags &= ~GenerateStorage;
117 if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty())
120 return singleResult(new Operation(state, path.size() - 1, qtPropertyDeclaration, c,
122 getterName, setterName, signalName, storageName));
125 InsertQtPropertyMembers::Operation::Operation(
126 const CppQuickFixState &state, int priority, QtPropertyDeclarationAST *declaration, Class *klass,
127 int generateFlags, const QString &getterName, const QString &setterName, const QString &signalName,
128 const QString &storageName)
129 : CppQuickFixOperation(state, priority)
130 , m_declaration(declaration)
132 , m_generateFlags(generateFlags)
133 , m_getterName(getterName)
134 , m_setterName(setterName)
135 , m_signalName(signalName)
136 , m_storageName(storageName)
138 QString desc = InsertQtPropertyMembers::tr("Generate missing Q_PROPERTY members...");
139 setDescription(desc);
142 void InsertQtPropertyMembers::Operation::performChanges(CppRefactoringFile *file, CppRefactoringChanges *refactoring)
144 InsertionPointLocator locator(refactoring);
145 Utils::ChangeSet declarations;
147 const QString typeName = file->textOf(m_declaration->type_id);
148 const QString propertyName = file->textOf(m_declaration->property_name);
150 // getter declaration
151 if (m_generateFlags & GenerateGetter) {
152 // const QString getterDeclaration = QString("%1 %2() const;").arg(typeName, getterName);
153 const QString getterDeclaration = QString("%1 %2() const\n{\nreturn %3;\n}\n").arg(typeName, m_getterName, m_storageName);
154 InsertionLocation getterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Public);
155 Q_ASSERT(getterLoc.isValid());
156 insertAndIndent(file, &declarations, getterLoc, getterDeclaration);
159 // setter declaration
160 if (m_generateFlags & GenerateSetter) {
161 // const QString setterDeclaration = QString("void %1(%2 arg);").arg(setterName, typeName);
162 QString setterDeclaration = QString("void %1(%2 arg)\n{\n").arg(m_setterName, typeName);
163 if (!m_signalName.isEmpty()) {
164 setterDeclaration += QString("if (%1 != arg) {\n%1 = arg;\nemit %2(arg);\n}\n}\n").arg(m_storageName, m_signalName);
166 setterDeclaration += QString("%1 = arg;\n}\n").arg(m_storageName);
168 InsertionLocation setterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::PublicSlot);
169 Q_ASSERT(setterLoc.isValid());
170 insertAndIndent(file, &declarations, setterLoc, setterDeclaration);
173 // signal declaration
174 if (m_generateFlags & GenerateSignal) {
175 const QString declaration = QString("void %1(%2 arg);\n").arg(m_signalName, typeName);
176 InsertionLocation loc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Signals);
177 Q_ASSERT(loc.isValid());
178 insertAndIndent(file, &declarations, loc, declaration);
182 if (m_generateFlags & GenerateStorage) {
183 const QString storageDeclaration = QString("%1 m_%2;\n").arg(typeName, propertyName);
184 InsertionLocation storageLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Private);
185 Q_ASSERT(storageLoc.isValid());
186 insertAndIndent(file, &declarations, storageLoc, storageDeclaration);
189 file->change(declarations);
192 void InsertQtPropertyMembers::Operation::insertAndIndent(RefactoringFile *file, ChangeSet *changeSet, const InsertionLocation &loc, const QString &text)
194 int targetPosition1 = file->position(loc.line(), loc.column());
195 int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
196 changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix());
197 file->indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1));