View Javadoc

1   /**********************************************
2    * Copyright (C) 2011 Lukas Laag
3    * This file is part of svgreal.
4    * 
5    * svgreal is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    * 
10   * svgreal is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   * 
15   * You should have received a copy of the GNU General Public License
16   * along with svgreal.  If not, see http://www.gnu.org/licenses/
17   **********************************************/
18  package org.vectomatic.svg.edit.client.command.dnd;
19  
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  
26  import org.vectomatic.dom.svg.OMSVGElement;
27  import org.vectomatic.dom.svg.itf.ISVGTransformable;
28  import org.vectomatic.dom.svg.utils.SVGConstants;
29  import org.vectomatic.svg.edit.client.command.CommandFactories;
30  import org.vectomatic.svg.edit.client.command.DndCommandFactory.DropGesture;
31  import org.vectomatic.svg.edit.client.engine.SVGModel;
32  import org.vectomatic.svg.edit.client.model.ModelConstants;
33  import org.vectomatic.svg.edit.client.model.svg.SVGElementModel;
34  import org.vectomatic.svg.edit.client.model.svg.SVGNamedElementModel;
35  
36  import com.extjs.gxt.ui.client.data.BeanModel;
37  import com.extjs.gxt.ui.client.data.BeanModelLookup;
38  import com.extjs.gxt.ui.client.util.Format;
39  
40  /**
41   * Class to represent a tree reordering command
42   * @author laaglu
43   */
44  public class ReorderCommand extends DndCommandBase {
45  	/**
46  	 * The models to move, unsorted
47  	 */
48  	protected List<SVGElementModel> models;
49  	/**
50  	 * The models to move, sorted
51  	 */
52  	protected List<SVGElementModel> sortedModels;
53  	/**
54  	 * The parent models of the models to move, sorted
55  	 */
56  	protected List<SVGElementModel> parentModels;
57  	/**
58  	 * The next non-null siblings of the models to move, sorted, or null if no such siblings exist
59  	 */
60  	protected List<SVGElementModel> refModels;
61  	/**
62  	 * The transform attributes of the models to move, sorted
63  	 */
64  	protected List<String> xforms;
65  	/**
66  	 * The target model
67  	 */
68  	protected SVGElementModel target;
69  	/**
70  	 * The drop gesture
71  	 */
72  	protected DropGesture dropGesture;
73  	/**
74  	 * The owner of the models to move
75  	 */
76  	protected SVGModel owner;
77  
78  	public ReorderCommand(List<SVGElementModel> models, SVGElementModel target, DropGesture dropGesture) {
79  		super(CommandFactories.getDndCommandFactory());
80  		this.target = target;
81  		this.dropGesture = dropGesture;
82  		this.models = new ArrayList<SVGElementModel>(models);
83  		// Sort nodes according to their order in the tree.
84  		Collections.<SVGElementModel>sort(models, SVGElementModel.getAscendingCompataror());
85  		this.sortedModels = models;
86  		Set<SVGElementModel> modelSet = new HashSet<SVGElementModel>(models);
87  		parentModels = new ArrayList<SVGElementModel>();
88  		refModels = new ArrayList<SVGElementModel>();
89  		xforms = new ArrayList<String>();
90  		for (SVGElementModel model : sortedModels) {
91  			SVGModel owner = model.getOwner();
92  			if (this.owner == null) {
93  				this.owner = owner;
94  			} else {
95  				assert this.owner == owner : "Attempt to move models from heterogeneous owners: " + this.owner + ", " + owner;
96  			}
97  			SVGElementModel parentModel = (SVGElementModel) model.getParent();
98  			parentModels.add(parentModel);
99  			// Retrieve the next sibling not in the set of models to delete
100 			SVGElementModel siblingModel = model;
101 			while (((siblingModel = siblingModel.getNextSibling()) != null) && modelSet.contains(siblingModel)) {
102 			}
103 			refModels.add(siblingModel);
104 			xforms.add(model.<String>get(SVGConstants.SVG_TRANSFORM_ATTRIBUTE));
105 		}
106 	}
107 
108 	@Override
109 	public String getDescription() {
110 		String message = null;
111 		switch(dropGesture) {
112 			case OnNode:
113 				message = ModelConstants.INSTANCE.dndReorderCmdIn();
114 				break;
115 			case BeforeNode:
116 				message = ModelConstants.INSTANCE.dndReorderCmdBefore();
117 				break;
118 			case AfterNode:
119 				message = ModelConstants.INSTANCE.dndReorderCmdAfter();
120 				break;
121 		}
122 		return Format.substitute(message, SVGNamedElementModel.getNames(models), target.toString());
123 	}
124 
125 	@Override
126 	public void commit() {
127 		SVGElementModel parentModel = null;
128 		SVGElementModel refModel = null;
129 		if (dropGesture == DropGesture.OnNode) {
130 			// target is a folder
131 			parentModel = target;
132 		} else {
133 			// target is a leaf in the same document
134 			parentModel = (SVGElementModel) target.getParent();
135 			if (dropGesture == DropGesture.BeforeNode) {
136 				refModel = target;
137 			} else if (dropGesture == DropGesture.AfterNode) {
138 				refModel = target.getNextSibling();
139 			}
140 		}
141 		
142 		for (SVGElementModel model : models) {
143 			
144 			// Update the transform of a model which is going to be
145 			// attached to a parent model so that the model appears 
146 			// unchanged to the end-user. This is done by applying
147 			// a counter transform (the inverse of the transform
148 			// of the parent) to to nullify its effect
149 			OMSVGElement element = model.getElementWrapper();
150 			OMSVGElement parentElement = parentModel.getElementWrapper();
151 			model.updateTransform(((ISVGTransformable)element).getTransformToElement(parentElement));
152 
153 			owner.insertBefore(parentModel, model, refModel);
154 		}		
155 	}
156 
157 	@Override
158 	public void rollback() {
159 		for (int i = 0, size = sortedModels.size(); i < size; i++) {
160 			SVGElementModel model = sortedModels.get(i);
161 			SVGElementModel parentModel = parentModels.get(i);
162 			SVGElementModel refModel = refModels.get(i);
163 			owner.insertBefore(parentModel, model, refModel);
164 			String matrix = xforms.get(i);
165 			if (matrix == null || matrix.length() == 0) {
166 				model.remove(SVGConstants.SVG_TRANSFORM_ATTRIBUTE);
167 			} else {
168 				model.set(SVGConstants.SVG_TRANSFORM_ATTRIBUTE, matrix);
169 			}
170 		}
171 	}
172 	
173 	@Override
174 	public BeanModel asModel() {
175 		return BeanModelLookup.get().getFactory(ReorderCommand.class).createModel(this);
176 	}
177 
178 }