summaryrefslogtreecommitdiff
path: root/src/plugins/qmldesigner/core/filemanager/moveobjectvisitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmldesigner/core/filemanager/moveobjectvisitor.cpp')
-rw-r--r--src/plugins/qmldesigner/core/filemanager/moveobjectvisitor.cpp293
1 files changed, 293 insertions, 0 deletions
diff --git a/src/plugins/qmldesigner/core/filemanager/moveobjectvisitor.cpp b/src/plugins/qmldesigner/core/filemanager/moveobjectvisitor.cpp
new file mode 100644
index 0000000000..ce95b03bad
--- /dev/null
+++ b/src/plugins/qmldesigner/core/filemanager/moveobjectvisitor.cpp
@@ -0,0 +1,293 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 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 <QtCore/QDebug>
+
+#include <qmljsast_p.h>
+#include <qmljsengine_p.h>
+
+#include "moveobjectvisitor.h"
+#include "textmodifier.h"
+
+using namespace QmlJS;
+using namespace QmlJS::AST;
+using namespace QmlEditor::Internal;
+using namespace QmlDesigner;
+
+class Inserter: public QMLRewriter
+{
+public:
+ Inserter(QmlDesigner::TextModifier &modifier,
+ quint32 targetParentObjectLocation,
+ const QString &targetPropertyName,
+ bool targetIsArrayBinding,
+ TextModifier::MoveInfo moveInfo,
+ const QStringList &propertyOrder):
+ QMLRewriter(modifier),
+ targetParentObjectLocation(targetParentObjectLocation),
+ targetPropertyName(targetPropertyName),
+ targetIsArrayBinding(targetIsArrayBinding),
+ moveInfo(moveInfo),
+ propertyOrder(propertyOrder)
+ {}
+
+protected:
+ virtual bool visit(UiObjectBinding *ast)
+ {
+ if (didRewriting())
+ return false;
+
+ if (ast->qualifiedTypeNameId->identifierToken.offset == targetParentObjectLocation) {
+ insertInto(ast->initializer);
+ }
+
+ return !didRewriting();
+ }
+
+ virtual bool visit(UiObjectDefinition *ast)
+ {
+ if (didRewriting())
+ return false;
+
+ if (ast->firstSourceLocation().offset == targetParentObjectLocation) {
+ insertInto(ast->initializer);
+ }
+
+ return !didRewriting();
+ }
+
+private:
+ void insertInto(UiObjectInitializer *ast)
+ {
+ if (targetPropertyName.isEmpty()) {
+ // insert as UiObjectDefinition:
+ UiObjectMemberList *insertAfter = searchMemberToInsertAfter(ast->members, QString::null, propertyOrder);
+
+ if (insertAfter && insertAfter->member) {
+ moveInfo.destination = insertAfter->member->lastSourceLocation().end();
+ moveInfo.prefixToInsert = QLatin1String("\n\n");
+ } else {
+ moveInfo.destination = ast->lbraceToken.end();
+ moveInfo.prefixToInsert = QLatin1String("\n");
+ }
+
+ move(moveInfo);
+
+ setDidRewriting(true);
+ return;
+ }
+
+ // see if we need to insert into an UiArrayBinding:
+ for (UiObjectMemberList *iter = ast->members; iter; iter = iter->next) {
+ UiObjectMember *member = iter->member;
+
+ if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(member)) {
+ if (flatten(arrayBinding->qualifiedId) == targetPropertyName) {
+ appendToArray(arrayBinding);
+
+ setDidRewriting(true);
+ return;
+ }
+ }
+ }
+
+ { // insert (create) a UiObjectBinding:
+ UiObjectMemberList *insertAfter = searchMemberToInsertAfter(ast->members, targetPropertyName, propertyOrder);
+ moveInfo.prefixToInsert = QLatin1String("\n") + targetPropertyName + (targetIsArrayBinding ? QLatin1String(": [") : QLatin1String(": "));
+ moveInfo.suffixToInsert = targetIsArrayBinding ? QLatin1String("\n]") : QLatin1String("");
+
+ if (insertAfter && insertAfter->member) {
+ moveInfo.destination = insertAfter->member->lastSourceLocation().end();
+ } else {
+ moveInfo.destination = ast->lbraceToken.end();
+ }
+
+ setDidRewriting(true);
+ }
+ }
+
+ void appendToArray(UiArrayBinding *ast)
+ {
+ UiObjectMember *lastMember = 0;
+
+ for (UiArrayMemberList *iter = ast->members; iter; iter = iter->next) {
+ if (iter->member)
+ lastMember = iter->member;
+ }
+
+ if (!lastMember)
+ Q_ASSERT(!"Invalid QML: empty array found.");
+
+ moveInfo.destination = lastMember->lastSourceLocation().end();
+ moveInfo.suffixToInsert = QLatin1String(",\n");
+ move(moveInfo);
+ }
+
+private:
+ quint32 targetParentObjectLocation;
+ QString targetPropertyName;
+ bool targetIsArrayBinding;
+ TextModifier::MoveInfo moveInfo;
+ QStringList propertyOrder;
+};
+
+MoveObjectVisitor::MoveObjectVisitor(QmlDesigner::TextModifier &modifier,
+ quint32 objectLocation,
+ const QString &targetPropertyName,
+ bool targetIsArrayBinding,
+ quint32 targetParentObjectLocation,
+ const QStringList &propertyOrder):
+ QMLRewriter(modifier),
+ objectLocation(objectLocation),
+ targetPropertyName(targetPropertyName),
+ targetIsArrayBinding(targetIsArrayBinding),
+ targetParentObjectLocation(targetParentObjectLocation),
+ propertyOrder(propertyOrder)
+{
+}
+
+bool MoveObjectVisitor::operator()(UiProgram *ast)
+{
+ program = ast;
+
+ return QMLRewriter::operator()(ast);
+}
+
+bool MoveObjectVisitor::visit(UiArrayBinding *ast)
+{
+ if (didRewriting())
+ return false;
+
+ UiArrayMemberList *currentMember = 0;
+
+ for (UiArrayMemberList *it = ast->members; it; it = it->next) {
+ if (it->member->firstSourceLocation().offset == objectLocation) {
+ currentMember = it;
+ break;
+ }
+ }
+
+ if (currentMember) {
+ TextModifier::MoveInfo moveInfo;
+ moveInfo.objectEnd = currentMember->member->lastSourceLocation().end();
+
+ if (currentMember == ast->members && !currentMember->next) {
+ // array with 1 element, which is moved away, so also remove the array binding
+ int start = ast->firstSourceLocation().offset;
+ int end = ast->lastSourceLocation().end();
+ includeSurroundingWhitespace(start, end);
+ moveInfo.leadingCharsToRemove = objectLocation - start;
+ moveInfo.trailingCharsToRemove = end - moveInfo.objectEnd;
+ } else if (currentMember->next) {
+ // we're not the last element, so remove the trailing comma too
+ Q_ASSERT(currentMember->next->commaToken.isValid());
+
+ int start = objectLocation;
+ int end = currentMember->next->commaToken.end();
+ includeSurroundingWhitespace(start, end);
+ moveInfo.leadingCharsToRemove = objectLocation - start;
+ moveInfo.trailingCharsToRemove = end - moveInfo.objectEnd;
+ } else {
+ // we're the last member, but not the only member, so remove the preceeding comma too
+ Q_ASSERT(currentMember->commaToken.isValid());
+
+ int start = currentMember->commaToken.offset;
+ int end = moveInfo.objectEnd;
+ includeSurroundingWhitespace(start, end);
+ moveInfo.leadingCharsToRemove = objectLocation - start;
+ moveInfo.trailingCharsToRemove = end - moveInfo.objectEnd;
+ }
+
+ doMove(moveInfo);
+ }
+
+ return !didRewriting();
+}
+
+bool MoveObjectVisitor::visit(UiObjectBinding *ast)
+{
+ if (didRewriting())
+ return false;
+
+ if (ast->qualifiedTypeNameId->identifierToken.offset == objectLocation) {
+ TextModifier::MoveInfo moveInfo;
+ moveInfo.objectEnd = ast->lastSourceLocation().end();
+
+ // remove leading indentation and property name:
+ int start = ast->firstSourceLocation().offset;
+ int end = moveInfo.objectEnd;
+ includeSurroundingWhitespace(start, end);
+ includeLeadingEmptyLine(start);
+ moveInfo.leadingCharsToRemove = objectLocation - start;
+
+ // remove trailing indentation
+ moveInfo.trailingCharsToRemove = end - moveInfo.objectEnd;
+
+ doMove(moveInfo);
+ }
+
+ return !didRewriting();
+}
+
+bool MoveObjectVisitor::visit(UiObjectDefinition *ast)
+{
+ if (didRewriting())
+ return false;
+
+ if (ast->qualifiedTypeNameId->identifierToken.offset == objectLocation) {
+ TextModifier::MoveInfo moveInfo;
+ moveInfo.objectStart = objectLocation;
+ moveInfo.objectEnd = ast->lastSourceLocation().end();
+
+ // remove leading indentation:
+ int start = objectLocation;
+ int end = moveInfo.objectEnd;
+ includeSurroundingWhitespace(start, end);
+ includeLeadingEmptyLine(start);
+ moveInfo.leadingCharsToRemove = objectLocation - start;
+ moveInfo.trailingCharsToRemove = end - moveInfo.objectEnd;
+
+ doMove(moveInfo);
+ }
+
+ return !didRewriting();
+}
+
+void MoveObjectVisitor::doMove(TextModifier::MoveInfo moveInfo)
+{
+ if (moveInfo.objectEnd > moveInfo.objectStart) {
+ Inserter findTargetAndInsert(*textModifier(),
+ targetParentObjectLocation,
+ targetPropertyName,
+ targetIsArrayBinding,
+ moveInfo,
+ propertyOrder);
+ setDidRewriting(findTargetAndInsert(program));
+ }
+}