View Javadoc
1   /**
2    * 
3    * Copyright (c) 2013-2014, Openflexo
4    * Copyright (c) 2011-2012, AgileBirds
5    * 
6    * This file is part of Gina-swing-editor, a component of the software infrastructure 
7    * developed at Openflexo.
8    * 
9    * 
10   * Openflexo is dual-licensed under the European Union Public License (EUPL, either 
11   * version 1.1 of the License, or any later version ), which is available at 
12   * https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
13   * and the GNU General Public License (GPL, either version 3 of the License, or any 
14   * later version), which is available at http://www.gnu.org/licenses/gpl.html .
15   * 
16   * You can redistribute it and/or modify under the terms of either of these licenses
17   * 
18   * If you choose to redistribute it and/or modify under the terms of the GNU GPL, you
19   * must include the following additional permission.
20   *
21   *          Additional permission under GNU GPL version 3 section 7
22   *
23   *          If you modify this Program, or any covered work, by linking or 
24   *          combining it with software containing parts covered by the terms 
25   *          of EPL 1.0, the licensors of this Program grant you additional permission
26   *          to convey the resulting work. * 
27   * 
28   * This software is distributed in the hope that it will be useful, but WITHOUT ANY 
29   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
30   * PARTICULAR PURPOSE. 
31   *
32   * See http://www.openflexo.org/license.html for details.
33   * 
34   * 
35   * Please contact Openflexo (openflexo-contacts@openflexo.org)
36   * or visit www.openflexo.org if you need additional information.
37   * 
38   */
39  
40  package org.openflexo.gina.swing.editor.view;
41  
42  import java.awt.Component;
43  import java.awt.Container;
44  import java.awt.Point;
45  import java.awt.Window;
46  import java.awt.dnd.DnDConstants;
47  import java.awt.dnd.DragGestureEvent;
48  import java.awt.dnd.DragGestureListener;
49  import java.awt.dnd.DragSource;
50  import java.awt.dnd.DragSourceContext;
51  import java.awt.dnd.DragSourceDragEvent;
52  import java.awt.dnd.DragSourceDropEvent;
53  import java.awt.dnd.DragSourceEvent;
54  import java.awt.dnd.DragSourceListener;
55  import java.awt.dnd.DropTarget;
56  import java.awt.event.FocusEvent;
57  import java.awt.event.FocusListener;
58  import java.awt.event.MouseEvent;
59  import java.awt.event.MouseListener;
60  import java.util.logging.Level;
61  import java.util.logging.Logger;
62  
63  import javax.swing.JComponent;
64  import javax.swing.JFrame;
65  import javax.swing.SwingUtilities;
66  
67  import org.openflexo.gina.controller.FIBController;
68  import org.openflexo.gina.model.FIBComponent;
69  import org.openflexo.gina.model.FIBModelObject;
70  import org.openflexo.gina.swing.editor.controller.FIBEditorController;
71  import org.openflexo.gina.swing.editor.palette.DraggedFIBComponent;
72  import org.openflexo.gina.swing.editor.palette.DropListener;
73  import org.openflexo.gina.swing.editor.palette.ExistingElementDrag;
74  import org.openflexo.gina.swing.editor.palette.FIBEditorPalette;
75  import org.openflexo.gina.swing.editor.view.container.JFIBEditableSplitPanelView;
76  import org.openflexo.gina.swing.view.JFIBView;
77  import org.openflexo.gina.view.FIBView;
78  import org.openflexo.logging.FlexoLogger;
79  import org.openflexo.swing.Focusable;
80  
81  public class FIBSwingEditableViewDelegate<M extends FIBComponent, J extends JComponent> implements MouseListener, FocusListener, Focusable {
82  
83  	static final Logger logger = FlexoLogger.getLogger(FIBSwingEditableViewDelegate.class.getPackage().getName());
84  
85  	private FIBSwingEditableView<M, J> view;
86  
87  	private final DragSource dragSource;
88  	private final MoveDGListener dgListener;
89  	private final MoveDSListener dsListener;
90  	private final int dragAction = DnDConstants.ACTION_MOVE;
91  
92  	public FIBSwingEditableViewDelegate(FIBSwingEditableView<M, J> view) {
93  		this.view = view;
94  
95  		JComponent jComponent = view.getJComponent();
96  
97  		if (jComponent != null) {
98  			jComponent.setFocusable(true);
99  			jComponent.setRequestFocusEnabled(true);
100 			recursivelyAddListenersTo(jComponent);
101 		}
102 
103 		view.getEditorController().registerViewDelegate(this);
104 
105 		dragSource = DragSource.getDefaultDragSource();
106 		dsListener = new MoveDSListener();
107 		dgListener = new MoveDGListener();
108 
109 		if (!(view instanceof JFIBEditableSplitPanelView)) {
110 			// Unused DragGestureRecognizer newDGR =
111 			dragSource.createDefaultDragGestureRecognizer(view.getDraggableComponent(), dragAction, dgListener);
112 		}
113 
114 	}
115 
116 	public FIBSwingEditableView<M, J> getView() {
117 		return view;
118 	}
119 
120 	public void delete() {
121 		logger.fine("Delete delegate view=" + view);
122 		JComponent jComponent = view.getJComponent();
123 		recursivelyDeleteListenersFrom(jComponent);
124 		view.getEditorController().unregisterViewDelegate(this);
125 		view = null;
126 	}
127 
128 	private void recursivelyAddListenersTo(Component c) {
129 		/*
130 		 * for (MouseListener ml : c.getMouseListeners()) {
131 		 * c.removeMouseListener(ml); }
132 		 */
133 		c.addMouseListener(this);
134 		c.addFocusListener(this);
135 		// Listen to drag'n'drop events
136 		new FIBDropTarget(view);
137 
138 		if (c instanceof Container) {
139 			for (Component c2 : ((Container) c).getComponents()) {
140 				if (!isComponentRootComponentForAnyFIBView(c2)) {
141 					recursivelyAddListenersTo(c2);
142 				}
143 			}
144 		}
145 	}
146 
147 	private void recursivelyDeleteListenersFrom(Component c) {
148 		c.removeMouseListener(this);
149 		c.removeFocusListener(this);
150 
151 		if (c instanceof Container) {
152 			for (Component c2 : ((Container) c).getComponents()) {
153 				if (!isComponentRootComponentForAnyFIBView(c2)) {
154 					recursivelyDeleteListenersFrom(c2);
155 				}
156 			}
157 		}
158 	}
159 
160 	private boolean isComponentRootComponentForAnyFIBView(Component c) {
161 		for (FIBView<?, ?> v : getController().getViews()) {
162 			JComponent resultingJComponent = ((JFIBView<?, ?>) v).getResultingJComponent();
163 			if (resultingJComponent == c) {
164 				return true;
165 			}
166 		}
167 		return false;
168 	}
169 
170 	public FIBEditorController getEditorController() {
171 		return view.getEditorController();
172 	}
173 
174 	public FIBController getController() {
175 		return view.getEditorController().getController();
176 	}
177 
178 	final public M getFIBComponent() {
179 		return view.getComponent();
180 	}
181 
182 	public JComponent getJComponent() {
183 		return view.getJComponent();
184 	}
185 
186 	public JComponent getResultingJComponent() {
187 		return view.getResultingJComponent();
188 	}
189 
190 	@Override
191 	public boolean isFocused() {
192 		return getEditorController().getFocusedObject() == getFIBComponent();
193 	}
194 
195 	@Override
196 	public void setFocused(boolean focused) {
197 		getEditorController().setFocusedObject(focused ? getFIBComponent() : null);
198 	}
199 
200 	@Override
201 	public void mouseClicked(MouseEvent e) {
202 		if (getView().isOperatorContentsStart()) {
203 			Point p = SwingUtilities.convertPoint((Component) e.getSource(), e.getPoint(), view.getResultingJComponent());
204 			if (p.x >= 0 && p.x < FIBSwingEditableView.OPERATOR_ICON_SPACE) {
205 				getEditorController().setSelectedObject(getFIBComponent().getParent());
206 				return;
207 			}
208 		}
209 
210 		getEditorController().setSelectedObject(getFIBComponent());
211 		getJComponent().requestFocusInWindow();
212 	}
213 
214 	@Override
215 	public void mousePressed(MouseEvent e) {
216 
217 	}
218 
219 	@Override
220 	public void mouseReleased(MouseEvent e) {
221 		if (e.isPopupTrigger() || e.getButton() == MouseEvent.BUTTON3) {
222 			getEditorController().getContextualMenu().displayPopupMenu(getFIBComponent(), /*getJComponent()*/(Component) e.getSource(),
223 					e.getPoint());
224 		}
225 	}
226 
227 	@Override
228 	public void focusLost(FocusEvent e) {
229 		// getController().setSelectedObject(null);
230 	}
231 
232 	public FIBModelObject getLastSelectedObject() {
233 		return getFIBComponent();
234 	}
235 
236 	@Override
237 	public void focusGained(FocusEvent e) {
238 		// System.out.println(
239 		// "focus gained in " + getFIBComponent() + " last selected=" + getLastSelectedObject() + " component=" + getFIBComponent());
240 		getEditorController().setSelectedObject(getLastSelectedObject());
241 	}
242 
243 	@Override
244 	public void mouseEntered(MouseEvent e) {
245 		if (!getEditorController().isDragging()) {
246 			getEditorController().setFocusedObject(getLastSelectedObject());
247 		}
248 	}
249 
250 	@Override
251 	public void mouseExited(MouseEvent e) {
252 		getEditorController().setFocusedObject(null);
253 	}
254 
255 	public static class FIBDropTarget extends DropTarget {
256 		private final FIBSwingEditableView<?, ?> editableView;
257 
258 		// private final PlaceHolder placeHolder = null;
259 
260 		public FIBDropTarget(FIBSwingEditableView<?, ?> editableView) {
261 			super(editableView.getJComponent(), DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE,
262 					editableView.getEditorController().buildPaletteDropListener(editableView), true);
263 			this.editableView = editableView;
264 			logger.fine("Made FIBDropTarget for " + getFIBComponent());
265 		}
266 
267 		public FIBSwingEditableView<?, ?> getEditableView() {
268 			return editableView;
269 		}
270 
271 		public Window getWindow() {
272 			return SwingUtilities.getWindowAncestor(editableView.getJComponent());
273 		}
274 
275 		public JFrame getFrame() {
276 			if (getWindow() instanceof JFrame) {
277 				return (JFrame) getWindow();
278 			}
279 			return null;
280 		}
281 
282 		/*
283 		 * public FIBDropTarget(PlaceHolder placeHolder) { super(placeHolder,
284 		 * DnDConstants.ACTION_COPY | DnDConstants.ACTION_MOVE,
285 		 * placeHolder.getView()
286 		 * .getEditorController().buildPaletteDropListener(
287 		 * placeHolder.getView(), placeHolder), true); this.placeHolder =
288 		 * placeHolder; this.editableView = placeHolder.getView();
289 		 * logger.fine("Made FIBDropTarget for " + getFIBComponent()); }
290 		 */
291 
292 		public PlaceHolder getPlaceHolder(DropListener dropListener, Point p) {
293 
294 			PlaceHolder returned = null;
295 
296 			if (dropListener.getParentDropListener() != null) {
297 				returned = getPlaceHolder(dropListener.getParentDropListener(),
298 						SwingUtilities.convertPoint(editableView.getResultingJComponent(), p,
299 								((JFIBView<?, ?>) editableView.getParentView()).getResultingJComponent()));
300 				if (returned != null) {
301 					return returned;
302 				}
303 			}
304 
305 			if (dropListener.getEditableView() instanceof FIBSwingEditableContainerView) {
306 				if (((FIBSwingEditableContainerView<?, ?>) dropListener.getEditableView()).getDelegate().getPlaceholders() != null) {
307 					for (PlaceHolder ph : ((FIBSwingEditableContainerView<?, ?>) dropListener.getEditableView()).getDelegate()
308 							.getPlaceholders()) {
309 						if (ph.getBounds().contains(p)) {
310 							return ph;
311 						}
312 					}
313 				}
314 			}
315 
316 			return null;
317 		}
318 
319 		/*
320 		 * public boolean isPlaceHolder() { return placeHolder != null; }
321 		 */
322 
323 		final public FIBComponent getFIBComponent() {
324 			return editableView.getComponent();
325 		}
326 
327 		public FIBEditorController getFIBEditorController() {
328 			return editableView.getEditorController();
329 		}
330 
331 	}
332 
333 	/**
334 	 * DGListener a listener that will start the drag. has access to top level's dsListener and dragSource
335 	 * 
336 	 * @see java.awt.dnd.DragGestureListener
337 	 * @see java.awt.dnd.DragSource
338 	 * @see java.awt.datatransfer.StringSelection
339 	 */
340 	class MoveDGListener implements DragGestureListener {
341 		/**
342 		 * Start the drag if the operation is ok. uses java.awt.datatransfer.StringSelection to transfer the label's data
343 		 * 
344 		 * @param e
345 		 *            the event object
346 		 */
347 		@Override
348 		public void dragGestureRecognized(DragGestureEvent e) {
349 			logger.fine("dragGestureRecognized");
350 
351 			// if the action is ok we go ahead
352 			// otherwise we punt
353 			if ((e.getDragAction() & dragAction) == 0) {
354 				return;
355 				// get the label's text and put it inside a Transferable
356 				// Transferable transferable = new StringSelection(
357 				// DragLabel.this.getText() );
358 			}
359 
360 			ExistingElementDrag transferable = new ExistingElementDrag(new DraggedFIBComponent(view.getComponent()), e.getDragOrigin());
361 
362 			try {
363 				// initial cursor, transferrable, dsource listener
364 				e.startDrag(FIBEditorPalette.dropKO, transferable, dsListener);
365 				logger.info("Starting existing element drag for " + view.getComponent());
366 				// getDrawingView().captureDraggedNode(PaletteElementView.this,
367 				// e);
368 			} catch (Exception idoe) {
369 				idoe.printStackTrace();
370 				logger.warning("Unexpected exception " + idoe);
371 			}
372 		}
373 
374 	}
375 
376 	/**
377 	 * DSListener a listener that will track the state of the DnD operation
378 	 * 
379 	 * @see java.awt.dnd.DragSourceListener
380 	 * @see java.awt.dnd.DragSource
381 	 * @see java.awt.datatransfer.StringSelection
382 	 */
383 	public class MoveDSListener implements DragSourceListener {
384 
385 		/**
386 		 * @param e
387 		 *            the event
388 		 */
389 		@Override
390 		public void dragDropEnd(DragSourceDropEvent e) {
391 
392 			// getDrawingView().resetCapturedNode();
393 			if (!e.getDropSuccess()) {
394 				if (logger.isLoggable(Level.INFO)) {
395 					logger.info("Dropping was not successful");
396 				}
397 				return;
398 			}
399 			/*
400 			 * the dropAction should be what the drop target specified in
401 			 * acceptDrop
402 			 */
403 			// this is the action selected by the drop target
404 			if (e.getDropAction() == DnDConstants.ACTION_MOVE) {
405 				// System.out.println("Tiens, que se passe-t-il donc ?");
406 			}
407 
408 		}
409 
410 		/**
411 		 * @param e
412 		 *            the event
413 		 */
414 		@Override
415 		public void dragEnter(DragSourceDragEvent e) {
416 			DragSourceContext context = e.getDragSourceContext();
417 			// System.out.println("dragEnter() with "+context+" component="+e.getSource());
418 			// intersection of the users selected action, and the source and
419 			// target actions
420 			int myaction = e.getDropAction();
421 			if ((myaction & dragAction) != 0) {
422 				context.setCursor(DragSource.DefaultCopyDrop);
423 			}
424 			else {
425 				context.setCursor(DragSource.DefaultCopyNoDrop);
426 			}
427 		}
428 
429 		/**
430 		 * @param e
431 		 *            the event
432 		 */
433 		@Override
434 		public void dragOver(DragSourceDragEvent e) {
435 
436 		}
437 
438 		/**
439 		 * @param e
440 		 *            the event
441 		 */
442 		@Override
443 		public void dragExit(DragSourceEvent e) {
444 
445 		}
446 
447 		/**
448 		 * for example, press shift during drag to change to a link action
449 		 * 
450 		 * @param e
451 		 *            the event
452 		 */
453 		@Override
454 		public void dropActionChanged(DragSourceDragEvent e) {
455 			DragSourceContext context = e.getDragSourceContext();
456 			context.setCursor(DragSource.DefaultCopyNoDrop);
457 		}
458 	}
459 
460 }