OSDN Git Service

b5cf72bdd762c52b8295bc34f2b8715392249e31
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmljseditor / qmljscomponentfromobjectdef.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 "qmljscomponentfromobjectdef.h"
35 #include "qmljscomponentnamedialog.h"
36
37 #include <coreplugin/ifile.h>
38
39 #include <qmljs/parser/qmljsast_p.h>
40 #include <qmljs/qmljsdocument.h>
41 #include <qmljstools/qmljsrefactoringchanges.h>
42
43 #include <QtCore/QCoreApplication>
44 #include <QtCore/QDir>
45 #include <QtCore/QFileInfo>
46
47 using namespace QmlJS::AST;
48 using namespace QmlJSEditor;
49 using namespace QmlJSEditor::Internal;
50 using namespace QmlJSTools;
51
52 namespace {
53
54 static QString toString(Statement *statement)
55 {
56     ExpressionStatement *expStmt = cast<ExpressionStatement *>(statement);
57     if (!expStmt)
58         return QString();
59     if (IdentifierExpression *idExp = cast<IdentifierExpression *>(expStmt->expression)) {
60         return idExp->name->asString();
61     } else if (StringLiteral *strExp = cast<StringLiteral *>(expStmt->expression)) {
62         return strExp->value->asString();
63     }
64     return QString();
65 }
66
67 static QString getIdProperty(UiObjectDefinition *def)
68 {
69     QString objectName;
70
71     if (def && def->initializer) {
72         for (UiObjectMemberList *iter = def->initializer->members; iter; iter = iter->next) {
73             if (UiScriptBinding *script = cast<UiScriptBinding*>(iter->member)) {
74                 if (!script->qualifiedId)
75                     continue;
76                 if (script->qualifiedId->next)
77                     continue;
78                 if (script->qualifiedId->name) {
79                     if (script->qualifiedId->name->asString() == QLatin1String("id"))
80                         return toString(script->statement);
81                     if (script->qualifiedId->name->asString() == QLatin1String("objectName"))
82                         objectName = toString(script->statement);
83                 }
84             }
85         }
86     }
87
88     return objectName;
89 }
90
91 class Operation: public QmlJSQuickFixOperation
92 {
93     UiObjectDefinition *m_objDef;
94     QString m_idName, m_componentName;
95
96 public:
97     Operation(const QmlJSQuickFixState &state, UiObjectDefinition *objDef)
98         : QmlJSQuickFixOperation(state, 0)
99         , m_objDef(objDef)
100     {
101         Q_ASSERT(m_objDef != 0);
102
103         m_idName = getIdProperty(m_objDef);
104
105         if (m_idName.isEmpty()) {
106             setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
107                                                        "Move Component into separate file"));
108         } else {
109             m_componentName = m_idName;
110             m_componentName[0] = m_componentName.at(0).toUpper();
111             setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
112                                                        "Move Component into '%1.qml'").arg(m_componentName));
113         }
114     }
115
116     virtual void performChanges(QmlJSRefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring)
117     {
118         QString componentName = m_componentName;
119         QString path = QFileInfo(fileName()).path();
120         if (componentName.isEmpty()) {
121             ComponentNameDialog::go(&componentName, &path, state().editor());
122         }
123
124         if (componentName.isEmpty() || path.isEmpty())
125             return;
126
127         const QString newFileName = path + QDir::separator() + componentName
128                 + QLatin1String(".qml");
129
130         QString imports;
131         UiProgram *prog = currentFile->qmljsDocument()->qmlProgram();
132         if (prog && prog->imports) {
133             const int start = currentFile->startOf(prog->imports->firstSourceLocation());
134             const int end = currentFile->startOf(prog->members->member->firstSourceLocation());
135             imports = currentFile->textOf(start, end);
136         }
137
138         const int start = currentFile->startOf(m_objDef->firstSourceLocation());
139         const int end = currentFile->startOf(m_objDef->lastSourceLocation());
140         const QString txt = imports + currentFile->textOf(start, end)
141                 + QLatin1String("}\n");
142
143         // stop if we can't create the new file
144         if (!refactoring->createFile(newFileName, txt))
145             return;
146
147         QString replacement = componentName + QLatin1String(" {\n");
148         if (!m_idName.isEmpty())
149                 replacement += QLatin1String("id: ") + m_idName
150                         + QLatin1Char('\n');
151
152         Utils::ChangeSet changes;
153         changes.replace(start, end, replacement);
154         currentFile->change(changes);
155         currentFile->indent(Range(start, end + 1));
156     }
157 };
158
159 } // end of anonymous namespace
160
161 QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(const QmlJSQuickFixState &state)
162 {
163     const int pos = state.currentFile().cursor().position();
164
165     QList<Node *> path = state.semanticInfo().astPath(pos);
166     for (int i = path.size() - 1; i >= 0; --i) {
167         Node *node = path.at(i);
168         if (UiObjectDefinition *objDef = cast<UiObjectDefinition *>(node)) {
169             if (!state.currentFile().isCursorOn(objDef->qualifiedTypeNameId))
170                 return noResult();
171              // check that the node is not the root node
172             if (i > 0 && !cast<UiProgram*>(path.at(i - 1))) {
173                 return singleResult(new Operation(state, objDef));
174             }
175         }
176     }
177
178     return noResult();
179 }