OSDN Git Service

a6c2b96247dcbca7a445d3239d44dfe1f8551af4
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qmldesigner / designercore / filemanager / moveobjectbeforeobjectvisitor.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 "moveobjectbeforeobjectvisitor.h"
35 #include "textmodifier.h"
36
37 #include <qmljs/parser/qmljsast_p.h>
38 #include <qmljs/parser/qmljsengine_p.h>
39
40 #include <QtCore/QDebug>
41
42 using namespace QmlJS;
43 using namespace QmlJS::AST;
44 using namespace QmlDesigner::Internal;
45 using namespace QmlDesigner;
46
47 MoveObjectBeforeObjectVisitor::MoveObjectBeforeObjectVisitor(TextModifier &modifier,
48                                                              quint32 movingObjectLocation,
49                                                              bool inDefaultProperty):
50     QMLRewriter(modifier),
51     movingObjectLocation(movingObjectLocation),
52     inDefaultProperty(inDefaultProperty),
53     toEnd(true),
54     beforeObjectLocation(0)
55 {}
56
57 MoveObjectBeforeObjectVisitor::MoveObjectBeforeObjectVisitor(TextModifier &modifier,
58                                                              quint32 movingObjectLocation,
59                                                              quint32 beforeObjectLocation,
60                                                              bool inDefaultProperty):
61     QMLRewriter(modifier),
62     movingObjectLocation(movingObjectLocation),
63     inDefaultProperty(inDefaultProperty),
64     toEnd(false),
65     beforeObjectLocation(beforeObjectLocation)
66 {}
67
68 bool MoveObjectBeforeObjectVisitor::operator ()(QmlJS::AST::UiProgram *ast)
69 {
70     movingObject = 0;
71     beforeObject = 0;
72     movingObjectParents.clear();
73
74     QMLRewriter::operator ()(ast);
75
76     if (foundEverything()) {
77         doMove();
78     }
79
80     return didRewriting();
81 }
82
83 bool MoveObjectBeforeObjectVisitor::preVisit(Node *ast)
84 { if (ast) parents.push(ast); return true; }
85
86 void MoveObjectBeforeObjectVisitor::postVisit(Node *ast)
87 { if (ast) parents.pop(); }
88
89 bool MoveObjectBeforeObjectVisitor::visit(UiObjectDefinition *ast)
90 {
91     if (foundEverything())
92         return false;
93
94     const quint32 start = ast->firstSourceLocation().offset;
95     if (start == movingObjectLocation) {
96         movingObject = ast;
97         movingObjectParents = parents;
98         movingObjectParents.pop();
99     } else if (!toEnd && start == beforeObjectLocation) {
100         beforeObject = ast;
101     }
102
103     if (movingObjectLocation < start)
104         return false;
105     else if (!toEnd && beforeObjectLocation < start)
106         return false;
107     else if (foundEverything())
108         return false;
109     else
110         return true;
111 }
112
113 void MoveObjectBeforeObjectVisitor::doMove()
114 {
115     Q_ASSERT(movingObject);
116     Q_ASSERT(!movingObjectParents.isEmpty());
117
118     TextModifier::MoveInfo moveInfo;
119     Node *parent = movingObjectParent();
120     UiArrayMemberList *arrayMember = 0, *otherArrayMember = 0;
121     QString separator;
122
123     if (!inDefaultProperty) {
124         UiArrayBinding *initializer = cast<UiArrayBinding*>(parent);
125         Q_ASSERT(initializer);
126
127         otherArrayMember = 0;
128         for (UiArrayMemberList *cur = initializer->members; cur; cur = cur->next) {
129             if (cur->member == movingObject) {
130                 arrayMember = cur;
131                 if (cur->next)
132                     otherArrayMember = cur->next;
133                 break;
134             }
135             otherArrayMember = cur;
136         }
137         Q_ASSERT(arrayMember && otherArrayMember);
138         separator = QLatin1String(",");
139     }
140
141     moveInfo.objectStart = movingObject->firstSourceLocation().offset;
142     moveInfo.objectEnd = movingObject->lastSourceLocation().end();
143
144     int start = moveInfo.objectStart;
145     int end = moveInfo.objectEnd;
146     if (!inDefaultProperty) {
147         if (arrayMember->commaToken.isValid()) {
148             start = arrayMember->commaToken.begin();
149         }
150         else {
151             end = otherArrayMember->commaToken.end();
152         }
153     }
154
155     includeSurroundingWhitespace(start, end);
156     moveInfo.leadingCharsToRemove = moveInfo.objectStart - start;
157     moveInfo.trailingCharsToRemove = end - moveInfo.objectEnd;
158
159     if (beforeObject) {
160         moveInfo.destination = beforeObject->firstSourceLocation().offset;
161         int dummy = -1;
162         includeSurroundingWhitespace(moveInfo.destination, dummy);
163
164         moveInfo.prefixToInsert = QString(moveInfo.leadingCharsToRemove, QLatin1Char(' '));
165         moveInfo.suffixToInsert = separator + QLatin1String("\n\n");
166     } else {
167         const SourceLocation insertionPoint = lastParentLocation();
168         Q_ASSERT(insertionPoint.isValid());
169         moveInfo.destination = insertionPoint.offset;
170         int dummy = -1;
171         includeSurroundingWhitespace(moveInfo.destination, dummy);
172
173         moveInfo.prefixToInsert = separator + QString(moveInfo.leadingCharsToRemove, QLatin1Char(' '));
174         moveInfo.suffixToInsert = QLatin1String("\n");
175     }
176
177     move(moveInfo);
178     setDidRewriting(true);
179 }
180
181 Node *MoveObjectBeforeObjectVisitor::movingObjectParent() const
182 {
183     if (movingObjectParents.size() > 1)
184         return movingObjectParents.at(movingObjectParents.size() - 2);
185     else
186         return 0;
187 }
188
189 SourceLocation MoveObjectBeforeObjectVisitor::lastParentLocation() const
190 {
191     dump(movingObjectParents);
192
193     Node *parent = movingObjectParent();
194     if (UiObjectInitializer *initializer = cast<UiObjectInitializer*>(parent))
195         return initializer->rbraceToken;
196     else if (UiArrayBinding *initializer = cast<UiArrayBinding*>(parent))
197         return initializer->rbracketToken;
198     else
199         return SourceLocation();
200 }