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;
19  
20  import java.util.List;
21  
22  import org.vectomatic.svg.edit.client.command.dnd.DndCopyHandler;
23  import org.vectomatic.svg.edit.client.command.dnd.DndLinkHandler;
24  import org.vectomatic.svg.edit.client.command.dnd.DndMoveHandler;
25  import org.vectomatic.svg.edit.client.command.dnd.IDndHandler;
26  import org.vectomatic.svg.edit.client.event.KeyPressProcessor;
27  import org.vectomatic.svg.edit.client.event.KeyUpProcessor;
28  import org.vectomatic.svg.edit.client.gxt.widget.DNDGhost;
29  import org.vectomatic.svg.edit.client.model.ModelConstants;
30  import org.vectomatic.svg.edit.client.model.svg.SVGElementModel;
31  
32  import com.extjs.gxt.ui.client.dnd.StatusProxy;
33  import com.extjs.gxt.ui.client.event.ComponentEvent;
34  import com.extjs.gxt.ui.client.event.DNDEvent;
35  import com.google.gwt.core.client.GWT;
36  import com.google.gwt.dom.client.Style;
37  import com.google.gwt.dom.client.Style.Position;
38  import com.google.gwt.dom.client.Style.Unit;
39  
40  /**
41   * Base class for drag and drop command factories
42   * @author laaglu
43   */
44  public class DndCommandFactory extends CommandFactoryBase implements KeyPressProcessor, KeyUpProcessor {
45  	/**
46  	 * Enum to represent the drop gestures
47  	 */
48  	public enum DropGesture {
49  		/**
50  		 * The source is released precisely on the target
51  		 */
52  		OnNode,
53  		/**
54  		 * The source is released slightly before the target
55  		 */
56  		BeforeNode,
57  		/**
58  		 * The source is released slightly after the target
59  		 */
60  		AfterNode
61  	}
62  	/**
63  	 * Default handler for drag and drop events
64  	 */
65  	private static IDndHandler defaultHandler = new DndMoveHandler();
66  	/**
67  	 * Handlers for drag and drop events
68  	 */
69  	private static IDndHandler[] handlers = new IDndHandler[] { new DndCopyHandler(), new DndLinkHandler(), defaultHandler};
70  	/**
71  	 * The handler which currently processes the drag interactions
72  	 */
73  	private IDndHandler currentHandler;
74  	/**
75  	 * The drag and drop proxy
76  	 */
77  	StatusProxy proxy;
78  	/**
79  	 * To graphically represent the drag operation
80  	 */
81  	private DNDGhost dndGhost;
82  	/**
83  	 * The drag source elements
84  	 */
85  	private List<SVGElementModel> sourceElements;
86  	/**
87  	 * The drop target over which the user has last move the mouse
88  	 */
89  	private SVGElementModel targetElement;
90  	/**
91  	 * True if the current drop target is valid
92  	 */
93  	boolean validTarget;
94  
95  
96  	@SuppressWarnings("serial")
97  	public static final IFactoryInstantiator<DndCommandFactory> INSTANTIATOR = new FactoryInstantiatorBase<DndCommandFactory>(ModelConstants.INSTANCE.dndCmdFactory(), ModelConstants.INSTANCE.dndCmdFactoryDesc()) {
98  		@Override
99  		public DndCommandFactory create() {
100 			return new DndCommandFactory();
101 		}
102 	};
103 	@Override
104 	public IFactoryInstantiator<?> getInstantiator() {
105 		return INSTANTIATOR;
106 	}
107 	
108 	@Override
109 	public void start(Object requester) {
110 		GWT.log("DndCommandFactory.start(" + requester + ")");
111 		super.start(requester);
112 		updateStatus(ModelConstants.INSTANCE.dndCmdFactory1());
113 	}
114 
115 	/**
116 	 * Returns true if the drag start event comes from a valid drag source
117 	 * @param event a drag start event
118 	 * @return true if the drag start event comes from a valid drag source
119 	 */
120 	public boolean isValidSource(DNDEvent event, List<SVGElementModel> sourceElements) {
121 		targetElement = null;
122 		validTarget = false;
123 		
124 		this.sourceElements = sourceElements;
125 		for (IDndHandler handler : handlers) {
126 			if (handler.isValidSource(event, sourceElements)) {
127 				dndGhost = new DNDGhost(sourceElements, event);
128 				proxy = event.getStatus();
129 				proxy.update(dndGhost.getElement());
130 				targetElement = null;
131 				setHandler(handler);
132 
133 				/*
134 				 * The drag and drop elements in GXT are positionned as follows:
135 				 * div container (x-dd-drag-proxy)
136 				 *   div icon (x-dd-drop-icon)
137 				 *   div proxy (x-dd-drag-ghost)
138 				 *     div ghost (custom ghost)
139 				 *     
140 				 * x-dd-drag-ghost needs to be altered to be made absolute
141 				 * in order to support custom ghost with absolute positioning
142 				 */
143 				Style proxyStyle = dndGhost.getElement().getParentElement().getStyle();
144 				proxyStyle.setPosition(Position.ABSOLUTE);
145 				proxyStyle.setLeft(0, Unit.PX);
146 				proxyStyle.setRight(0, Unit.PX);
147 				proxyStyle.setTop(0, Unit.PX);
148 				proxyStyle.setBottom(0, Unit.PX);
149 				
150 				return true;
151 			}
152 		}
153 		return false;
154 	}
155 	
156 	public boolean isValidDropTarget(SVGElementModel element) {
157 		if (targetElement != element) {
158 			targetElement = element;
159 			validTarget = currentHandler.isValidTarget(sourceElements, targetElement);
160 			GWT.log("isValidDropTarget(" + targetElement + ") = " + validTarget);
161 		}
162 		return validTarget;
163 	}
164 	
165 	public void processDragAndDrop(DropGesture dropGesture) {
166 		GWT.log("processDragAndDrop(" + sourceElements + ", " + targetElement + "," + dropGesture + ") = " + validTarget);
167 		// TODO
168 		// ignore useless drag and drops:
169 		// drag last item of a folder in its parent
170 		// drag an item before of after itself
171 		currentHandler.createCommands(sourceElements, targetElement, dropGesture);
172 		currentHandler = null;
173 	}
174 	
175 	@Override
176 	public boolean processKeyPress(ComponentEvent event) {
177 		for (IDndHandler handler : handlers) {
178 			if (handler.getKeyCode() == event.getKeyCode()) {
179 				setHandler(handler);
180 				return true;
181 			}
182 		}
183 		return false;
184 	}
185 
186 	@Override
187 	public boolean processKeyUp(ComponentEvent event) {
188 		for (IDndHandler handler : handlers) {
189 			if (handler.getKeyCode() == event.getKeyCode()) {
190 				setHandler(defaultHandler);
191 				return true;
192 			}
193 		}
194 		return false;
195 	}
196 	
197 	private void setHandler(IDndHandler handler) {
198 		if (handler != currentHandler) {
199 			currentHandler = handler;
200 			dndGhost.update(currentHandler);
201 			proxy.setStatus(currentHandler.isValidTarget(sourceElements, targetElement));
202 		}
203 	}
204 	
205 //	/**
206 //	 * Extracts the SVG models from a drag and drop event
207 //	 * @param event the event
208 //	 * @return the SVG models associated to the event
209 //	 */
210 //	public static List<SVGElementModel> getData(DNDEvent event) {
211 //		List<TreeStoreModel> storeModels = event.getData();
212 //		ArrayList<SVGElementModel> svgModels = new ArrayList<SVGElementModel>();
213 //		for (TreeStoreModel storeModel : storeModels) {
214 //			svgModels.add((SVGElementModel) storeModel.getModel());
215 //		}
216 //		return svgModels;
217 //	}
218 //
219 //
220 //	static private List<String> eventLog;
221 //	static public void logDNDEvent(String origin, DNDEvent event) {
222 //		List<String> strList = new ArrayList<String>();
223 //		strList.add("=================== DNDListener =====================");
224 //		strList.add("origin = " +  origin);
225 //		EventType type = event.getType();
226 //		if (type == Events.DragStart) {
227 //			strList.add("type = DragStart");
228 //		} else if (type == Events.DragEnter) {
229 //			strList.add("type = DragEnter");
230 //		} else if (type == Events.DragLeave) {
231 //			strList.add("type = DragLeave");
232 //		} else if (type == Events.DragMove) {
233 //			strList.add("type = DragMove");
234 //		} else if (type == Events.Drop) {
235 //			strList.add("type = Drop");
236 //		}
237 //		strList.add("component = " +  event.getComponent());
238 //		strList.add("data = " +  DndHandlerBase.getSourceElementNames(getData(event)));
239 //		strList.add("operation = " +  event.getOperation());
240 //		strList.add("source = " +  event.getSource());
241 //		DragSource dragSource = event.getDragSource();
242 //		if (dragSource instanceof SVGTreePanelDragSource) {
243 //			SVGTreePanelDragSource source = (SVGTreePanelDragSource)dragSource;
244 //			strList.add("sourceModel = " +  source.getSvgModel());
245 //		}
246 //		DropTarget dropTarget = event.getDropTarget();
247 //		if (dropTarget instanceof SVGTreePanelDropTarget) {
248 //			SVGTreePanelDropTarget target = (SVGTreePanelDropTarget)dropTarget;
249 //			strList.add("targetModel = " +  target.getSvgModel());
250 //			SVGElementModel activeItem = target.getActiveItem();
251 //			if (activeItem != null) {
252 //				strList.add("activeItem = " +  activeItem.get(SVGConstants.SVG_TITLE_TAG));
253 //			}
254 //			SVGElementModel appendItem = target.getActiveItem();
255 //			if (appendItem != null) {
256 //				strList.add("appendItem = " +  appendItem.get(SVGConstants.SVG_TITLE_TAG));
257 //			}
258 //		}
259 //		if (!strList.equals(eventLog)) {
260 //			eventLog = strList;
261 //			for(String str : eventLog) {
262 //				GWT.log(str);
263 //			}
264 //		}
265 //	}
266 }