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.controller;
41  
42  import java.awt.AlphaComposite;
43  import java.awt.BasicStroke;
44  import java.awt.BorderLayout;
45  import java.awt.Color;
46  import java.awt.Graphics;
47  import java.awt.Graphics2D;
48  import java.awt.Point;
49  import java.awt.Rectangle;
50  import java.awt.RenderingHints;
51  import java.beans.PropertyChangeSupport;
52  import java.lang.reflect.Modifier;
53  import java.util.HashMap;
54  import java.util.Map;
55  import java.util.Observable;
56  import java.util.logging.Logger;
57  
58  import javax.swing.JFrame;
59  import javax.swing.JPanel;
60  import javax.swing.SwingUtilities;
61  
62  import org.openflexo.gina.controller.FIBController;
63  import org.openflexo.gina.model.FIBComponent;
64  import org.openflexo.gina.model.FIBContainer;
65  import org.openflexo.gina.model.FIBModelFactory;
66  import org.openflexo.gina.model.FIBModelObject;
67  import org.openflexo.gina.model.FIBModelObject.FIBModelObjectImpl;
68  import org.openflexo.gina.model.FIBValidationModel;
69  import org.openflexo.gina.model.FIBValidationReport;
70  import org.openflexo.gina.swing.editor.EditedFIBComponent;
71  import org.openflexo.gina.swing.editor.FIBEditor;
72  import org.openflexo.gina.swing.editor.palette.DropListener;
73  import org.openflexo.gina.swing.editor.palette.FIBEditorPalettes;
74  import org.openflexo.gina.swing.editor.view.FIBSwingEditableView;
75  import org.openflexo.gina.swing.editor.view.FIBSwingEditableViewDelegate;
76  import org.openflexo.gina.swing.editor.widget.FIBEditorBrowser;
77  import org.openflexo.gina.swing.utils.FocusedObjectChange;
78  import org.openflexo.gina.swing.utils.SelectedObjectChange;
79  import org.openflexo.gina.swing.view.JFIBView;
80  import org.openflexo.gina.view.FIBView;
81  import org.openflexo.localization.Language;
82  import org.openflexo.logging.FlexoLogger;
83  import org.openflexo.pamela.undo.UndoManager;
84  import org.openflexo.toolbox.HasPropertyChangeSupport;
85  
86  /**
87   * This is a controller managing the edition of a {@link EditedFIBComponent}<br>
88   * 
89   * Swing view to be used is given by {@link #getEditorPanel()} method.
90   * 
91   * Such controller manages:
92   * <ul>
93   * <li>an single instance of {@link EditedFIBComponent}</li>
94   * <li>a</li>
95   * </ul>
96   * 
97   * @author sylvain
98   *
99   */
100 public class FIBEditorController extends Observable implements HasPropertyChangeSupport {
101 
102 	private static final Logger logger = FlexoLogger.getLogger(FIBEditorController.class.getPackage().getName());
103 
104 	private final FIBController controller;
105 
106 	private final EditedFIBComponent editedComponent;
107 
108 	private final FIBEditor editor;
109 
110 	private FIBEditorPanel editorPanel;
111 	private FIBEditorBrowser editorBrowser;
112 
113 	private FIBModelObject selectedObject = null;
114 	private FIBModelObject focusedObject = null;
115 
116 	private final ContextualMenu contextualMenu;
117 
118 	private final Map<FIBComponent, FIBSwingEditableViewDelegate<?, ?>> viewDelegates;
119 
120 	private final PropertyChangeSupport pcSupport;
121 
122 	private FIBValidationReport validationReport;
123 
124 	public FIBEditorController(EditedFIBComponent editedComponent, FIBEditor editor, JFrame frame) {
125 		this(editedComponent, null, editor, frame);
126 		// Class testClass = null;
127 
128 		if (editedComponent.getDataObject() != null) {
129 			editorPanel.updateWithDataObject(editedComponent.getDataObject());
130 		}
131 		else {
132 
133 			if (editedComponent.getFIBComponent() instanceof FIBContainer) {
134 				FIBContainer fibContainer = (FIBContainer) editedComponent.getFIBComponent();
135 				boolean instantiable = fibContainer.getDataClass() != null
136 						&& !Modifier.isAbstract(fibContainer.getDataClass().getModifiers());
137 				if (instantiable) {
138 					try {
139 						instantiable = fibContainer.getDataClass().getConstructor(new Class[0]) != null;
140 					} catch (SecurityException e) {
141 						instantiable = false;
142 					} catch (NoSuchMethodException e) {
143 						instantiable = false;
144 					}
145 				}
146 				if (instantiable) {
147 					try {
148 						// testClass =
149 						// Class.forName(fibComponent.getDataClassName());
150 						Object testData = fibContainer.getDataClass().newInstance();
151 						editorPanel.updateWithDataObject(testData);
152 					} catch (InstantiationException e) {
153 						e.printStackTrace();
154 					} catch (IllegalAccessException e) {
155 						e.printStackTrace();
156 					}
157 				}
158 				else {
159 					editorPanel.updateWithoutDataObject();
160 				}
161 			}
162 			else {
163 				editorPanel.updateWithoutDataObject();
164 			}
165 		}
166 	}
167 
168 	public FIBEditorController(EditedFIBComponent editedComponent, Object dataObject, FIBEditor editor, JFrame frame) {
169 		this(editedComponent, dataObject, editor, FIBController.instanciateController(editedComponent.getFIBComponent(),
170 				SwingEditorViewFactory.INSTANCE, FIBModelObjectImpl.READ_ONLY_GINA_LOCALIZATION), frame);
171 	}
172 
173 	public FIBEditorController(EditedFIBComponent editedComponent, Object dataObject, FIBEditor editor, FIBController controller,
174 			JFrame frame) {
175 
176 		pcSupport = new PropertyChangeSupport(this);
177 		this.editedComponent = editedComponent;
178 
179 		this.controller = controller;
180 		viewDelegates = new HashMap<>();
181 		controller.setViewFactory(new SwingEditorViewFactory(this));
182 
183 		this.editor = editor;
184 
185 		contextualMenu = new ContextualMenu(this, frame);
186 
187 		if (editor.getInspector() != null) {
188 			addObserver(editor.getInspector());
189 		}
190 
191 		if (editor.getInspectors() != null) {
192 			addObserver(editor.getInspectors());
193 		}
194 
195 		editorPanel = new FIBEditorPanel(controller);
196 
197 		editorBrowser = new FIBEditorBrowser(editedComponent.getFIBComponent(), this);
198 
199 		if (dataObject != null) {
200 			editorPanel.updateWithDataObject(dataObject);
201 		}
202 		else {
203 			editorPanel.updateWithoutDataObject();
204 		}
205 
206 	}
207 
208 	@Override
209 	public PropertyChangeSupport getPropertyChangeSupport() {
210 		return pcSupport;
211 	}
212 
213 	@Override
214 	public String getDeletedProperty() {
215 		return null;
216 	}
217 
218 	public EditedFIBComponent getEditedComponent() {
219 		return editedComponent;
220 	}
221 
222 	public FIBComponent getFIBComponent() {
223 		return editedComponent.getFIBComponent();
224 	}
225 
226 	public Object getDataObject() {
227 		return controller.getDataObject();
228 	}
229 
230 	public void setDataObject(Object anObject) {
231 		controller.setDataObject(anObject);
232 	}
233 
234 	public FIBController getController() {
235 		return controller;
236 	}
237 
238 	public FIBEditor getEditor() {
239 		return editor;
240 	}
241 
242 	public FIBModelFactory getFactory() {
243 		return editedComponent.getFactory();
244 	}
245 
246 	public FIBEditorPanel getEditorPanel() {
247 		return editorPanel;
248 	}
249 
250 	public ContextualMenu getContextualMenu() {
251 		return contextualMenu;
252 	}
253 
254 	public FIBEditorPalettes getPalette() {
255 		return editor.getPalettes();
256 	}
257 
258 	public FIBEditorBrowser getEditorBrowser() {
259 		return editorBrowser;
260 	}
261 
262 	public FIBModelObject getFocusedObject() {
263 		return focusedObject;
264 	}
265 
266 	public void setFocusedObject(FIBModelObject aComponent) {
267 
268 		if (aComponent != focusedObject) {
269 			// System.out.println("setFocusedObject with "+aComponent);
270 			FocusedObjectChange change = new FocusedObjectChange(focusedObject, aComponent);
271 			focusedObject = aComponent;
272 			setChanged();
273 			notifyObservers(change);
274 			editorPanel.repaint();
275 		}
276 	}
277 
278 	public FIBModelObject getSelectedObject() {
279 		return selectedObject;
280 	}
281 
282 	public void setSelectedObject(FIBModelObject aComponent) {
283 		if (aComponent != selectedObject) {
284 			// System.out.println("setSelectedObject from " + selectedObject + " to " + aComponent);
285 			FIBModelObject oldValue = selectedObject;
286 			SelectedObjectChange change = new SelectedObjectChange(oldValue, aComponent);
287 			selectedObject = aComponent;
288 			setChanged();
289 			notifyObservers(change);
290 			editorPanel.repaint();
291 			getPropertyChangeSupport().firePropertyChange("selectedObject", oldValue, selectedObject);
292 		}
293 
294 	}
295 
296 	public void notifyFocusedAndSelectedObject() {
297 		FocusedObjectChange change1 = new FocusedObjectChange(focusedObject, focusedObject);
298 		setChanged();
299 		notifyObservers(change1);
300 		SelectedObjectChange change2 = new SelectedObjectChange(selectedObject, selectedObject);
301 		setChanged();
302 		notifyObservers(change2);
303 	}
304 
305 	public FIBView<?, ?> viewForComponent(FIBComponent component) {
306 		return controller.viewForComponent(component);
307 	}
308 
309 	/*
310 	 * public void keyTyped(KeyEvent e) { logger.fine("keyTyped() "+e); if
311 	 * (e.getKeyChar() == KeyEvent.VK_DELETE || e.getKeyChar() ==
312 	 * KeyEvent.VK_BACK_SPACE) { if (getSelectedObject() != null) { boolean
313 	 * deleteIt = JOptionPane.showConfirmDialog(editor.getFrame(),
314 	 * getSelectedObject
315 	 * ()+": really delete this component (undoable operation) ?",
316 	 * "information", JOptionPane.YES_NO_CANCEL_OPTION,
317 	 * JOptionPane.INFORMATION_MESSAGE) == JOptionPane.YES_OPTION; if (deleteIt)
318 	 * { logger.info("Removing object "+getSelectedObject());
319 	 * getSelectedObject().delete(); } } } }
320 	 */
321 
322 	public void switchToLanguage(Language language) {
323 		controller.switchToLanguage(language);
324 	}
325 
326 	public void registerViewDelegate(FIBSwingEditableViewDelegate<?, ?> delegate) {
327 		viewDelegates.put(delegate.getFIBComponent(), delegate);
328 	}
329 
330 	public void unregisterViewDelegate(FIBSwingEditableViewDelegate<?, ?> delegate) {
331 		if (viewDelegates.get(delegate.getFIBComponent()) == delegate) {
332 			viewDelegates.remove(delegate.getFIBComponent());
333 		}
334 	}
335 
336 	public DropListener buildPaletteDropListener(FIBSwingEditableView<?, ?> editableView) {
337 		DropListener returned = new DropListener(editableView);
338 		dropListeners.put(editableView, returned);
339 		return returned;
340 	}
341 
342 	private final Map<FIBSwingEditableView<?, ?>, DropListener> dropListeners = new HashMap<>();
343 
344 	private boolean isDragging = false;
345 
346 	public boolean isDragging() {
347 		return isDragging;
348 	}
349 
350 	public void dragEnter(DropListener dl) {
351 
352 		isDragging = true;
353 
354 		if (getSelectedObject() != null) {
355 			setSelectedObject(null);
356 		}
357 		// System.out.println("Drag ENTER in " + dl.getEditableView());
358 		dropListeners.put(dl.getEditableView(), dl);
359 		if (dl.getEditableView().getParentView() != null) {
360 			DropListener parentDL = dropListeners.get(dl.getEditableView().getParentView());
361 			dl.setParentDropListener(parentDL);
362 		}
363 	}
364 
365 	public void dragExit(DropListener dl) {
366 		// System.out.println("Drag EXIT in " + dl.getEditableView());
367 		isDragging = false;
368 	}
369 
370 	public void dragEnd(DropListener dl) {
371 
372 		isDragging = false;
373 
374 		// System.out.println("Drag END in " + dl.getEditableView());
375 		// dropListeners.clear();
376 	}
377 
378 	public UndoManager getUndoManager() {
379 		return null;
380 	}
381 
382 	public FIBValidationReport getValidationReport() {
383 		if (validationReport == null) {
384 			try {
385 				validationReport = getValidationModel().validate(getFIBComponent());
386 			} catch (InterruptedException e) {
387 				e.printStackTrace();
388 			}
389 		}
390 		return validationReport;
391 	}
392 
393 	public FIBValidationModel getValidationModel() {
394 		return getFIBComponent().getModelFactory().getValidationModel();
395 	}
396 
397 	@SuppressWarnings("serial")
398 	public class FIBEditorPanel extends JPanel {
399 
400 		private JFIBView<?, ?> fibPanel;
401 
402 		public FIBEditorPanel(FIBController controller) {
403 			super(new BorderLayout());
404 
405 			fibPanel = (JFIBView<?, ?>) controller.buildView();
406 			add(fibPanel.getJComponent(), BorderLayout.CENTER);
407 		}
408 
409 		public FIBEditorController getEditorController() {
410 			return FIBEditorController.this;
411 		}
412 
413 		public void updateWithDataObject(Object data) {
414 			fibPanel.getController().setDataObject(data, true);
415 		}
416 
417 		public void updateWithoutDataObject() {
418 			fibPanel.getController().setDataObject(null, true);
419 		}
420 
421 		@Override
422 		public void paint(Graphics g) {
423 			super.paint(g);
424 			paintFocusedAndSelected(g);
425 		}
426 
427 		private void paintFocusedAndSelected(Graphics g) {
428 			FIBSwingEditableViewDelegate<?, ?> focused = viewDelegates.get(getFocusedObject());
429 			FIBSwingEditableViewDelegate<?, ?> selected = viewDelegates.get(getSelectedObject());
430 			if (focused != null && focused != selected && focused.getResultingJComponent() != null) {
431 				Point origin = SwingUtilities.convertPoint(focused.getResultingJComponent(), new Point(), this);
432 				// Graphics componentGraphics = g.create(origin.x, origin.y,
433 				// focused.getJComponent().getWidth(), focused
434 				// .getJComponent().getHeight());
435 				Rectangle bounds = null;
436 				if (focused.getView().isOperatorContentsStart()) {
437 					bounds = new Rectangle(origin.x + FIBSwingEditableView.OPERATOR_ICON_SPACE, origin.y,
438 							focused.getResultingJComponent().getWidth() - FIBSwingEditableView.OPERATOR_ICON_SPACE - 1,
439 							focused.getJComponent().getHeight() - 1);
440 				}
441 				else {
442 					bounds = new Rectangle(origin.x, origin.y, focused.getResultingJComponent().getWidth() - 1,
443 							focused.getJComponent().getHeight() - 1);
444 				}
445 
446 				Graphics2D g2 = (Graphics2D) g;
447 
448 				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
449 
450 				g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
451 				g2.setColor(Color.WHITE);
452 				g2.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 10, 10);
453 				g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
454 				g2.setStroke(new BasicStroke(0.5f));
455 				g2.setColor(Color.LIGHT_GRAY);
456 				g2.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 10, 10);
457 
458 				// FOCUSED_BORDER.paintBorder(focused.getJComponent(),
459 				// componentGraphics, 0, 0, focused.getJComponent()
460 				// .getWidth(), focused.getJComponent().getHeight());
461 				// componentGraphics.dispose();
462 			}
463 			if (selected != null && selected.getResultingJComponent() != null) {
464 				Point origin = SwingUtilities.convertPoint(selected.getResultingJComponent(), new Point(), this);
465 				// Graphics componentGraphics = g.create(origin.x, origin.y,
466 				// selected.getJComponent().getWidth(), selected
467 				// .getJComponent().getHeight());
468 
469 				Rectangle bounds;
470 				if (selected.getView().isOperatorContentsStart()) {
471 					bounds = new Rectangle(origin.x + FIBSwingEditableView.OPERATOR_ICON_SPACE, origin.y,
472 							selected.getResultingJComponent().getWidth() - FIBSwingEditableView.OPERATOR_ICON_SPACE - 1,
473 							selected.getJComponent().getHeight() - 1);
474 				}
475 				else {
476 					bounds = new Rectangle(origin.x, origin.y, selected.getResultingJComponent().getWidth() - 1,
477 							selected.getJComponent().getHeight() - 1);
478 				}
479 				Graphics2D g2 = (Graphics2D) g;
480 
481 				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
482 
483 				g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.05f));
484 				g2.setColor(Color.BLUE);
485 				g2.fillRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 10, 10);
486 				g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
487 				g2.setStroke(new BasicStroke(0.5f));
488 				g2.setColor(Color.BLUE.brighter());
489 				g2.drawRoundRect(bounds.x, bounds.y, bounds.width, bounds.height, 10, 10);
490 
491 				// SELECTED_BORDER.paintBorder(selected.getJComponent(),
492 				// componentGraphics, 0, 0, selected.getJComponent()
493 				// .getWidth(), selected.getJComponent().getHeight());
494 				// componentGraphics.dispose();
495 			}
496 		}
497 	}
498 
499 }