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 "qmljscomponentfromobjectdef.h"
35 #include "qmljscomponentnamedialog.h"
37 #include <coreplugin/ifile.h>
39 #include <qmljs/parser/qmljsast_p.h>
40 #include <qmljs/qmljsdocument.h>
41 #include <qmljstools/qmljsrefactoringchanges.h>
43 #include <QtCore/QCoreApplication>
44 #include <QtCore/QDir>
45 #include <QtCore/QFileInfo>
47 using namespace QmlJS::AST;
48 using namespace QmlJSEditor;
49 using namespace QmlJSEditor::Internal;
50 using namespace QmlJSTools;
54 static QString toString(Statement *statement)
56 ExpressionStatement *expStmt = cast<ExpressionStatement *>(statement);
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();
67 static QString getIdProperty(UiObjectDefinition *def)
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)
76 if (script->qualifiedId->next)
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);
91 class Operation: public QmlJSQuickFixOperation
93 UiObjectDefinition *m_objDef;
94 QString m_idName, m_componentName;
97 Operation(const QmlJSQuickFixState &state, UiObjectDefinition *objDef)
98 : QmlJSQuickFixOperation(state, 0)
101 Q_ASSERT(m_objDef != 0);
103 m_idName = getIdProperty(m_objDef);
105 if (m_idName.isEmpty()) {
106 setDescription(QCoreApplication::translate("QmlJSEditor::ComponentFromObjectDef",
107 "Move Component into separate file"));
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));
116 virtual void performChanges(QmlJSRefactoringFile *currentFile, QmlJSRefactoringChanges *refactoring)
118 QString componentName = m_componentName;
119 QString path = QFileInfo(fileName()).path();
120 if (componentName.isEmpty()) {
121 ComponentNameDialog::go(&componentName, &path, state().editor());
124 if (componentName.isEmpty() || path.isEmpty())
127 const QString newFileName = path + QDir::separator() + componentName
128 + QLatin1String(".qml");
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);
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");
143 // stop if we can't create the new file
144 if (!refactoring->createFile(newFileName, txt))
147 QString replacement = componentName + QLatin1String(" {\n");
148 if (!m_idName.isEmpty())
149 replacement += QLatin1String("id: ") + m_idName
152 Utils::ChangeSet changes;
153 changes.replace(start, end, replacement);
154 currentFile->change(changes);
155 currentFile->indent(Range(start, end + 1));
159 } // end of anonymous namespace
161 QList<QmlJSQuickFixOperation::Ptr> ComponentFromObjectDef::match(const QmlJSQuickFixState &state)
163 const int pos = state.currentFile().cursor().position();
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))
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));