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 QSet<AbstractProperty> addedProperties;
231 QMutableListIterator<RewriteAction*> iter(actions);
233 while (iter.hasPrevious()) {
234 RewriteAction *action = iter.previous();
236 if (RemovePropertyRewriteAction *removeAction = action->asRemovePropertyRewriteAction()) {
237 removedProperties.insert(removeAction->property(), action);
238 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
239 const AbstractProperty property = changeAction->property();
241 if (removedProperties.contains(property)) {
242 actionsToRemove.append(action);
243 } else if (changedProperties.contains(property)) {
244 if (!property.isValid() || !property.isDefaultProperty())
245 actionsToRemove.append(action);
247 changedProperties.insert(property, changeAction);
249 } else if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
250 const AbstractProperty property = addAction->property();
252 if (RewriteAction *removeAction = removedProperties.value(property, 0)) {
253 actionsToRemove.append(action);
254 actionsToRemove.append(removeAction);
255 removedProperties.remove(property);
257 if (changedProperties.contains(property))
258 changedProperties.remove(property);
260 addedProperties.insert(property);
265 foreach (RewriteAction *action, actionsToRemove){
266 actions.removeOne(action);
271 void RewriteActionCompressor::compressAddEditActions(QList<RewriteAction *> &actions) const
273 QList<RewriteAction *> actionsToRemove;
274 QSet<ModelNode> addedNodes;
275 QSet<RewriteAction *> dirtyActions;
277 QMutableListIterator<RewriteAction*> iter(actions);
278 while (iter.hasNext()) {
279 RewriteAction *action = iter.next();
281 if (action->asAddPropertyRewriteAction() || action->asChangePropertyRewriteAction()) {
282 AbstractProperty property;
283 ModelNode containedNode;
285 if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
286 property = addAction->property();
287 containedNode = addAction->containedModelNode();
288 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
289 property = changeAction->property();
290 containedNode = changeAction->containedModelNode();
293 if (property.isValid() && addedNodes.contains(property.parentModelNode())) {
294 actionsToRemove.append(action);
298 if (!containedNode.isValid())
301 if (nodeOrParentInSet(containedNode, addedNodes)) {
302 actionsToRemove.append(action);
304 addedNodes.insert(containedNode);
305 dirtyActions.insert(action);
307 } else if (ChangeIdRewriteAction *changeIdAction = action->asChangeIdRewriteAction()) {
308 if (nodeOrParentInSet(changeIdAction->node(), addedNodes)) {
309 actionsToRemove.append(action);
311 } else if (ChangeTypeRewriteAction *changeTypeAction = action->asChangeTypeRewriteAction()) {
312 if (nodeOrParentInSet(changeTypeAction->node(), addedNodes)) {
313 actionsToRemove.append(action);
318 foreach (RewriteAction *action, actionsToRemove){
319 actions.removeOne(action);
323 QmlTextGenerator gen(m_propertyOrder);
324 foreach (RewriteAction *action, dirtyActions) {
325 RewriteAction *newAction = 0;
326 if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
327 newAction = new AddPropertyRewriteAction(addAction->property(),
328 gen(addAction->containedModelNode()),
329 addAction->propertyType(),
330 addAction->containedModelNode());
331 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
332 newAction = new ChangePropertyRewriteAction(changeAction->property(),
333 gen(changeAction->containedModelNode()),
334 changeAction->propertyType(),
335 changeAction->containedModelNode());
338 const int idx = actions.indexOf(action);
339 if (newAction && idx >= 0) {
340 actions[idx] = newAction;
345 void RewriteActionCompressor::compressAddReparentActions(QList<RewriteAction *> &actions) const
347 QList<RewriteAction *> actionsToRemove;
348 QMap<ModelNode, RewriteAction*> addedNodes;
350 QMutableListIterator<RewriteAction*> iter(actions);
351 while (iter.hasNext()) {
352 RewriteAction *action = iter.next();
354 if (action->asAddPropertyRewriteAction() || action->asChangePropertyRewriteAction()) {
355 ModelNode containedNode;
357 if (AddPropertyRewriteAction *addAction = action->asAddPropertyRewriteAction()) {
358 containedNode = addAction->containedModelNode();
359 } else if (ChangePropertyRewriteAction *changeAction = action->asChangePropertyRewriteAction()) {
360 containedNode = changeAction->containedModelNode();
363 if (!containedNode.isValid())
366 addedNodes.insert(containedNode, action);
367 } else if (ReparentNodeRewriteAction *reparentAction = action->asReparentNodeRewriteAction()) {
368 if (addedNodes.contains(reparentAction->reparentedNode())) {
369 RewriteAction *previousAction = addedNodes[reparentAction->reparentedNode()];
370 actionsToRemove.append(previousAction);
372 RewriteAction *replacementAction = 0;
373 if (AddPropertyRewriteAction *addAction = previousAction->asAddPropertyRewriteAction()) {
374 replacementAction = new AddPropertyRewriteAction(reparentAction->targetProperty(),
375 addAction->valueText(),
376 reparentAction->propertyType(),
377 addAction->containedModelNode());
378 } else if (ChangePropertyRewriteAction *changeAction = previousAction->asChangePropertyRewriteAction()) {
379 replacementAction = new AddPropertyRewriteAction(reparentAction->targetProperty(),
380 changeAction->valueText(),
381 reparentAction->propertyType(),
382 changeAction->containedModelNode());
385 iter.setValue(replacementAction);
391 foreach (RewriteAction *action, actionsToRemove){
392 actions.removeOne(action);