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 MoveCommand 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  	public MoveCommand(List<SVGElementModel> models, SVGElementModel target, DropGesture dropGesture) {
75  		super(CommandFactories.getDndCommandFactory());
76  		this.target = target;
77  		this.dropGesture = dropGesture;
78  		this.models = new ArrayList<SVGElementModel>(models);
79  		// Sort nodes according to their order in the tree.
80  		Collections.<SVGElementModel>sort(models, SVGElementModel.getAscendingCompataror());
81  		this.sortedModels = models;
82  		Set<SVGElementModel> modelSet = new HashSet<SVGElementModel>(models);
83  		parentModels = new ArrayList<SVGElementModel>();
84  		refModels = new ArrayList<SVGElementModel>();
85  		xforms = new ArrayList<String>();
86  		for (SVGElementModel model : sortedModels) {
87  			SVGElementModel parentModel = (SVGElementModel) model.getParent();
88  			parentModels.add(parentModel);
89  			// Retrieve the next sibling not in the set of models to delete
90  			SVGElementModel siblingModel = model;
91  			while (((siblingModel = siblingModel.getNextSibling()) != null) && modelSet.contains(siblingModel)) {
92  			}
93  			refModels.add(siblingModel);
94  			xforms.add(model.<String>get(SVGConstants.SVG_TRANSFORM_ATTRIBUTE));
95  		}
96  	}
97  
98  	@Override
99  	public String getDescription() {
100 		String message = null;
101 		switch(dropGesture) {
102 			case OnNode:
103 				message = ModelConstants.INSTANCE.dndReorderCmdIn();
104 				break;
105 			case BeforeNode:
106 				message = ModelConstants.INSTANCE.dndReorderCmdBefore();
107 				break;
108 			case AfterNode:
109 				message = ModelConstants.INSTANCE.dndReorderCmdAfter();
110 				break;
111 		}
112 		return Format.substitute(message, SVGNamedElementModel.getNames(models), target.toString(), target.getOwner().getRoot().get(SVGConstants.SVG_TITLE_TAG));
113 	}
114 
115 	@Override
116 	public void commit() {
117 		SVGModel owner = target.getOwner();
118 		SVGElementModel parentModel = null;
119 		SVGElementModel refModel = null;
120 		if (dropGesture == DropGesture.OnNode) {
121 			// target is a folder
122 			parentModel = target;
123 		} else {
124 			// target is a leaf in the same document
125 			parentModel = (SVGElementModel) target.getParent();
126 			if (dropGesture == DropGesture.BeforeNode) {
127 				refModel = target;
128 			} else if (dropGesture == DropGesture.AfterNode) {
129 				refModel = target.getNextSibling();
130 			}
131 		}
132 		
133 		for (SVGElementModel model : models) {
134 			
135 			// Update the transform of a model which is going to be
136 			// attached to a parent model so that the model appears 
137 			// unchanged to the end-user. This is done by applying
138 			// a counter transform (the inverse of the transform
139 			// of the parent) to to nullify its effect
140 			OMSVGElement element = model.getElementWrapper();
141 			OMSVGElement parentElement = parentModel.getElementWrapper();
142 			model.updateTransform(((ISVGTransformable)element).getTransformToElement(parentElement));
143 
144 			owner.insertBefore(parentModel, model, refModel);
145 		}		
146 	}
147 
148 	@Override
149 	public void rollback() {
150 		SVGModel owner = target.getOwner();
151 		for (int i = 0, size = sortedModels.size(); i < size; i++) {
152 			SVGElementModel model = sortedModels.get(i);
153 			SVGElementModel parentModel = parentModels.get(i);
154 			SVGElementModel refModel = refModels.get(i);
155 			owner.insertBefore(parentModel, model, refModel);
156 			String matrix = xforms.get(i);
157 			if (matrix == null || matrix.length() == 0) {
158 				model.remove(SVGConstants.SVG_TRANSFORM_ATTRIBUTE);
159 			} else {
160 				model.set(SVGConstants.SVG_TRANSFORM_ATTRIBUTE, matrix);
161 			}
162 		}
163 	}
164 	
165 	@Override
166 	public BeanModel asModel() {
167 		return BeanModelLookup.get().getFactory(MoveCommand.class).createModel(this);
168 	}
169 
170 }