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 <QtCore/QSet>
36 #include "modelnode.h"
37 #include "nodelistproperty.h"
38 #include "nodeproperty.h"
39 #include "qmltextgenerator.h"
40 #include "rewriteactioncompressor.h"
42 using namespace QmlDesigner;
43 using namespace QmlDesigner::Internal;
45 static bool nodeOrParentInSet(const ModelNode &node, const QSet<ModelNode> &nodeSet)
49 if (nodeSet.contains(n))
52 if (!n.hasParentProperty())
55 n = n.parentProperty().parentModelNode();
61 void RewriteActionCompressor::operator()(QList<RewriteAction *> &actions) const
63 compressImports(actions);
64 compressRereparentActions(actions);
65 compressReparentIntoSamePropertyActions(actions);
66 compressPropertyActions(actions);
67 compressAddEditRemoveNodeActions(actions);
68 compressAddEditActions(actions);
69 compressAddReparentActions(actions);
72 void RewriteActionCompressor::compressImports(QList<RewriteAction *> &actions) const
74 QList<RewriteAction *> actionsToRemove;
75 QHash<Import, RewriteAction *> addedImports;
76 QHash<Import, RewriteAction *> removedImports;
78 QMutableListIterator<RewriteAction *> iter(actions);
80 while (iter.hasPrevious()) {
81 RewriteAction *action = iter.previous();
83 if (RemoveImportRewriteAction *removeImportAction = action->asRemoveImportRewriteAction()) {
84 const Import import = removeImportAction->import();
85 if (removedImports.contains(import)) {
86 actionsToRemove.append(action);
87 } else if (RewriteAction *addImportAction = addedImports.value(import, 0)) {
88 actionsToRemove.append(action);
89 actionsToRemove.append(addImportAction);
90 addedImports.remove(import);
91 delete addImportAction;
93 removedImports.insert(import, action);
95 } else if (AddImportRewriteAction *addImportAction = action->asAddImportRewriteAction()) {
96 const Import import = addImportAction->import();
97 if (RewriteAction *duplicateAction = addedImports.value(import, 0)) {
98 actionsToRemove.append(duplicateAction);
99 addedImports.remove(import);
100 delete duplicateAction;
101 addedImports.insert(import, action);
102 } else if (RewriteAction *removeAction = removedImports.value(import, 0)) {
103 actionsToRemove.append(action);
104 actionsToRemove.append(removeAction);
105 removedImports.remove(import);
108 addedImports.insert(import, action);
113 foreach (RewriteAction *action, actionsToRemove) {
114 actions.removeOne(action);
119 void RewriteActionCompressor::compressRereparentActions(QList<RewriteAction *> &actions) const
121 QList<RewriteAction *> actionsToRemove;
122 QHash<ModelNode, ReparentNodeRewriteAction *> reparentedNodes;
124 QMutableListIterator<RewriteAction*> iter(actions);
126 while (iter.hasPrevious()) {
127 RewriteAction *action = iter.previous();
129 if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) {
130 const ModelNode reparentedNode = reparentAction->reparentedNode();
132 if (ReparentNodeRewriteAction *otherAction = reparentedNodes.value(reparentedNode, 0)) {
133 otherAction->setOldParentProperty(reparentAction->oldParentProperty());
134 actionsToRemove.append(action);
136 reparentedNodes.insert(reparentedNode, reparentAction);
141 foreach (RewriteAction *action, actionsToRemove) {
142 actions.removeOne(action);
147 void RewriteActionCompressor::compressReparentIntoSamePropertyActions(QList<RewriteAction *> &actions) const
149 QList<RewriteAction *> actionsToRemove;
150 QMutableListIterator<RewriteAction *> iter(actions);
152 while (iter.hasPrevious()) {
153 RewriteAction *action = iter.previous();
155 if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) {
156 if (reparentAction->targetProperty() == reparentAction->oldParentProperty())
157 actionsToRemove.append(action);
161 foreach (RewriteAction *action, actionsToRemove) {
162 actions.removeOne(action);
167 void RewriteActionCompressor::compressAddEditRemoveNodeActions(QList<RewriteAction *> &actions) const
169 QList<RewriteAction *> actionsToRemove;
170 QHash<ModelNode, RewriteAction *> removedNodes;
172 QMutableListIterator<RewriteAction*> iter(actions);
174 while (iter.hasPrevious()) {
175 RewriteAction *action = iter.previous();
177 if (RemoveNodeRewriteAction *removeNodeAction = action->asRemoveNodeRewriteAction()) {
178 const ModelNode modelNode = removeNodeAction->node();
180 if (removedNodes.contains(modelNode))
181 actionsToRemove.append(action);
183 removedNodes.insert(modelNode, action);
184 } else if (action->asAddPropertyRewriteAction() || action->asChangePropertyRewriteAction()) {
185 AbstractProperty property;
186 ModelNode containedModelNode;
187 if (action->asAddPropertyRewriteAction()) {
188 property = action->asAddPropertyRewriteAction()->property();
189 containedModelNode = action->asAddPropertyRewriteAction()->containedModelNode();
191 property = action->asChangePropertyRewriteAction()->property();
192 containedModelNode = action->asChangePropertyRewriteAction()->containedModelNode();
195 if (removedNodes.contains(property.parentModelNode())) {
196 actionsToRemove.append(action);
197 } else if (RewriteAction *removeAction = removedNodes.value(containedModelNode, 0)) {
198 actionsToRemove.append(action);
199 actionsToRemove.append(removeAction);
201 } else if (RemovePropertyRewriteAction *removePropertyAction = action->asRemovePropertyRewriteAction()) {
202 const AbstractProperty property = removePropertyAction->property();
204 if (removedNodes.contains(property.parentModelNode()))
205 actionsToRemove.append(action);
206 } else if (ChangeIdRewriteAction *changeIdAction = action->asChangeIdRewriteAction()) {
207 if (removedNodes.contains(changeIdAction->node()))
208 actionsToRemove.append(action);
209 } else if (ChangeTypeRewriteAction *changeTypeAction = action->asChangeTypeRewriteAction()) {
210 if (removedNodes.contains(changeTypeAction->node()))
211 actionsToRemove.append(action);
212 } else if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) {
213 if (removedNodes.contains(reparentAction->reparentedNode()))
214 actionsToRemove.append(action);
218 foreach (RewriteAction *action, actionsToRemove) {
219 actions.removeOne(action);
224 void RewriteActionCompressor::compressPropertyActions(QList<RewriteAction *> &actions) const
226 QList<RewriteAction *> actionsToRemove;
227 QHash<AbstractProperty, RewriteAction *> removedProperties;
228 QHash<AbstractProperty, ChangePropertyRewriteAction *> changedProperties;
229 QHash<AbstractProperty, AddPropertyRewriteAction *> addedProperties;
231 QMutableListIterator<RewriteAction*> iter(actions);
233 while (iter.hasPrevious()) {
234 RewriteAction *action = iter.previous();
236 if (RemovePropertyRewriteAction *removeAction = action->asRemovePropertyRewriteAction()) {
237 const AbstractProperty property = removeAction->property();
238 if (AddPropertyRewriteAction *addAction = addedProperties.value(property, 0)) {
240 removedProperties.insert(property, action);
242 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
243 const AbstractProperty property = changeAction->property();
245 if (removedProperties.contains(property)) {
246 actionsToRemove.append(action);
247 } else if (changedProperties.contains(property)) {
248 if (!property.isValid() || !property.isDefaultProperty())
249 actionsToRemove.append(action);
251 changedProperties.insert(property, changeAction);
253 } else if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
254 const AbstractProperty property = addAction->property();
256 if (RewriteAction *removeAction = removedProperties.value(property, 0)) {
257 actionsToRemove.append(action);
258 actionsToRemove.append(removeAction);
259 removedProperties.remove(property);
261 if (changedProperties.contains(property))
262 changedProperties.remove(property);
264 addedProperties.insert(property, addAction);
269 foreach (RewriteAction *action, actionsToRemove){
270 actions.removeOne(action);
275 void RewriteActionCompressor::compressAddEditActions(QList<RewriteAction *> &actions) const
277 QList<RewriteAction *> actionsToRemove;
278 QSet<ModelNode> addedNodes;
279 QSet<RewriteAction *> dirtyActions;
281 QMutableListIterator<RewriteAction*> iter(actions);
282 while (iter.hasNext()) {
283 RewriteAction *action = iter.next();
285 if (action->asAddPropertyRewriteAction() || action->asChangePropertyRewriteAction()) {
286 AbstractProperty property;
287 ModelNode containedNode;
289 if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
290 property = addAction->property();
291 containedNode = addAction->containedModelNode();
292 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
293 property = changeAction->property();
294 containedNode = changeAction->containedModelNode();
297 if (property.isValid() && addedNodes.contains(property.parentModelNode())) {
298 actionsToRemove.append(action);
302 if (!containedNode.isValid())
305 if (nodeOrParentInSet(containedNode, addedNodes)) {
306 actionsToRemove.append(action);
308 addedNodes.insert(containedNode);
309 dirtyActions.insert(action);
311 } else if (ChangeIdRewriteAction *changeIdAction = action->asChangeIdRewriteAction()) {
312 if (nodeOrParentInSet(changeIdAction->node(), addedNodes)) {
313 actionsToRemove.append(action);
315 } else if (ChangeTypeRewriteAction *changeTypeAction = action->asChangeTypeRewriteAction()) {
316 if (nodeOrParentInSet(changeTypeAction->node(), addedNodes)) {
317 actionsToRemove.append(action);
322 foreach (RewriteAction *action, actionsToRemove){
323 actions.removeOne(action);
327 QmlTextGenerator gen(m_propertyOrder);
328 foreach (RewriteAction *action, dirtyActions) {
329 RewriteAction *newAction = 0;
330 if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
331 newAction = new AddPropertyRewriteAction(addAction->property(),
332 gen(addAction->containedModelNode()),
333 addAction->propertyType(),
334 addAction->containedModelNode());
335 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
336 newAction = new ChangePropertyRewriteAction(changeAction->property(),
337 gen(changeAction->containedModelNode()),
338 changeAction->propertyType(),
339 changeAction->containedModelNode());
342 const int idx = actions.indexOf(action);
343 if (newAction && idx >= 0) {
344 actions[idx] = newAction;
349 void RewriteActionCompressor::compressAddReparentActions(QList<RewriteAction *> &actions) const
351 QList<RewriteAction *> actionsToRemove;
352 QMap<ModelNode, RewriteAction*> addedNodes;
354 QMutableListIterator<RewriteAction*> iter(actions);
355 while (iter.hasNext()) {
356 RewriteAction *action = iter.next();
358 if (action->asAddPropertyRewriteAction() || action->asChangePropertyRewriteAction()) {
359 ModelNode containedNode;
361 if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
362 containedNode = addAction->containedModelNode();
363 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
364 containedNode = changeAction->containedModelNode();
367 if (!containedNode.isValid())
370 addedNodes.insert(containedNode, action);
371 } else if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) {
372 if (addedNodes.contains(reparentAction->reparentedNode())) {
373 RewriteAction *previousAction = addedNodes[reparentAction->reparentedNode()];
374 actionsToRemove.append(previousAction);
376 RewriteAction *replacementAction = 0;
377 if (AddPropertyRewriteAction *addAction = previousAction->asAddPropertyRewriteAction()) {
378 replacementAction = new AddPropertyRewriteAction(reparentAction->targetProperty(),
379 addAction->valueText(),
380 reparentAction->propertyType(),
381 addAction->containedModelNode());
382 } else if (ChangePropertyRewriteAction *changeAction = previousAction->asChangePropertyRewriteAction()) {
383 replacementAction = new AddPropertyRewriteAction(reparentAction->targetProperty(),
384 changeAction->valueText(),
385 reparentAction->propertyType(),
386 changeAction->containedModelNode());
389 iter.setValue(replacementAction);
395 foreach (RewriteAction *action, actionsToRemove){
396 actions.removeOne(action);