OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / cppeditor / cppinsertqtpropertymembers.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
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
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
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.
24 **
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.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "cppinsertqtpropertymembers.h"
35
36 #include <AST.h>
37 #include <Token.h>
38 #include <cplusplus/Overview.h>
39 #include <cpptools/insertionpointlocator.h>
40 #include <cpptools/cpprefactoringchanges.h>
41 #include <cppeditor/cppquickfix.h>
42
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;
49
50 QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFixState &state)
51 {
52     const QList<AST *> &path = state.path();
53
54     if (path.isEmpty())
55         return noResult();
56
57     AST * const ast = path.last();
58     QtPropertyDeclarationAST *qtPropertyDeclaration = ast->asQtPropertyDeclaration();
59     if (!qtPropertyDeclaration)
60         return noResult();
61
62     ClassSpecifierAST *klass = 0;
63     for (int i = path.size() - 2; i >= 0; --i) {
64         klass = path.at(i)->asClassSpecifier();
65         if (klass)
66             break;
67     }
68     if (!klass)
69         return noResult();
70
71     CppRefactoringChanges refactoring(state.snapshot());
72     const CppRefactoringFile &file = refactoring.file(state.document()->fileName());
73     const QString propertyName = file.textOf(qtPropertyDeclaration->property_name);
74     QString getterName;
75     QString setterName;
76     QString signalName;
77     int generateFlags = 0;
78     for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
79          it; it = it->next) {
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;
90         }
91     }
92     QString storageName = QString("m_%1").arg(propertyName);
93     generateFlags |= GenerateStorage;
94
95     Class *c = klass->symbol;
96
97     Overview overview;
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;
109             }
110         } else if (member->asDeclaration()) {
111             const QString name = overview(member->name());
112             if (name == storageName)
113                 generateFlags &= ~GenerateStorage;
114         }
115     }
116
117     if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty())
118         return noResult();
119
120     return singleResult(new Operation(state, path.size() - 1, qtPropertyDeclaration, c,
121                                       generateFlags,
122                                       getterName, setterName, signalName, storageName));
123 }
124
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)
131     , m_class(klass)
132     , m_generateFlags(generateFlags)
133     , m_getterName(getterName)
134     , m_setterName(setterName)
135     , m_signalName(signalName)
136     , m_storageName(storageName)
137 {
138     QString desc = InsertQtPropertyMembers::tr("Generate missing Q_PROPERTY members...");
139     setDescription(desc);
140 }
141
142 void InsertQtPropertyMembers::Operation::performChanges(CppRefactoringFile *file, CppRefactoringChanges *refactoring)
143 {
144     InsertionPointLocator locator(refactoring);
145     Utils::ChangeSet declarations;
146
147     const QString typeName = file->textOf(m_declaration->type_id);
148     const QString propertyName = file->textOf(m_declaration->property_name);
149
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);
157     }
158
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);
165         } else {
166             setterDeclaration += QString("%1 = arg;\n}\n").arg(m_storageName);
167         }
168         InsertionLocation setterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::PublicSlot);
169         Q_ASSERT(setterLoc.isValid());
170         insertAndIndent(file, &declarations, setterLoc, setterDeclaration);
171     }
172
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);
179     }
180
181     // storage
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);
187     }
188
189     file->change(declarations);
190 }
191
192 void InsertQtPropertyMembers::Operation::insertAndIndent(RefactoringFile *file, ChangeSet *changeSet, const InsertionLocation &loc, const QString &text)
193 {
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));
198 }