View Javadoc
1   /**
2    * 
3    * Copyright (c) 2013-2014, Openflexo
4    * Copyright (c) 2011-2012, AgileBirds
5    * 
6    * This file is part of Gina-core, 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.controller;
41  
42  import java.awt.Component;
43  import java.awt.Dimension;
44  import java.awt.HeadlessException;
45  import java.awt.Toolkit;
46  import java.awt.Window;
47  import java.awt.event.MouseEvent;
48  import java.beans.PropertyChangeSupport;
49  import java.lang.reflect.Constructor;
50  import java.lang.reflect.InvocationTargetException;
51  import java.util.ArrayList;
52  import java.util.Collection;
53  import java.util.HashMap;
54  import java.util.Hashtable;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.Vector;
58  import java.util.logging.Logger;
59  
60  import javax.swing.Icon;
61  import javax.swing.JDialog;
62  import javax.swing.JOptionPane;
63  
64  import org.openflexo.connie.type.TypeUtils;
65  import org.openflexo.gina.manager.EventManager;
66  import org.openflexo.gina.manager.Registrable;
67  import org.openflexo.gina.manager.URID;
68  import org.openflexo.gina.model.FIBComponent;
69  import org.openflexo.gina.model.FIBContainer;
70  import org.openflexo.gina.model.FIBLocalizedDictionary;
71  import org.openflexo.gina.model.FIBVariable;
72  import org.openflexo.gina.model.FIBWidget;
73  import org.openflexo.gina.model.bindings.RuntimeContext;
74  import org.openflexo.gina.model.listener.FIBMouseClickListener;
75  import org.openflexo.gina.model.listener.FIBSelectionListener;
76  import org.openflexo.gina.view.FIBContainerView;
77  import org.openflexo.gina.view.FIBView;
78  import org.openflexo.gina.view.FIBWidgetView;
79  import org.openflexo.gina.view.GinaViewFactory;
80  import org.openflexo.gina.view.operator.FIBIterationView.IteratedContents;
81  import org.openflexo.gina.view.widget.FIBReferencedComponentWidget;
82  import org.openflexo.localization.FlexoLocalization;
83  import org.openflexo.localization.Language;
84  import org.openflexo.localization.LocalizedDelegate;
85  import org.openflexo.rm.Resource;
86  import org.openflexo.rm.ResourceLocator;
87  import org.openflexo.toolbox.HasPropertyChangeSupport;
88  import org.openflexo.toolbox.PropertyChangedSupportDefaultImplementation;
89  import org.openflexo.toolbox.StringUtils;
90  
91  /**
92   * Represent the controller of an instantiation of a FIBComponent in a particular Window Toolkit context (eg Swing)
93   * 
94   * @author sylvain
95   * 
96   */
97  public class FIBController implements HasPropertyChangeSupport, Registrable {
98  
99  	static final Logger LOGGER = Logger.getLogger(FIBController.class.getPackage().getName());
100 
101 	public static FIBController instanciateController(FIBComponent fibComponent, GinaViewFactory<?> viewFactory,
102 			LocalizedDelegate parentLocalizer) {
103 		return instanciateController(fibComponent, viewFactory, parentLocalizer, null);
104 	}
105 
106 	public static FIBController instanciateController(FIBComponent fibComponent, GinaViewFactory<?> viewFactory,
107 			LocalizedDelegate parentLocalizer, EventManager recorderManager) {
108 		FIBController returned = null;
109 		// System.out.println("Instanciate controller for component: " +
110 		// fibComponent);
111 		/*
112 		 * if (fibComponent != null) {
113 		 * fibComponent.getFactory().stringRepresentation(fibComponent); }
114 		 */
115 		if (fibComponent.getControllerClass() == null) {
116 			LOGGER.warning("No FIBController class declared for " + fibComponent);
117 		}
118 
119 		if (fibComponent.getControllerClass() != null) {
120 
121 			try {
122 				try {
123 					Constructor<? extends FIBController> c = fibComponent.getControllerClass().getConstructor(FIBComponent.class,
124 							GinaViewFactory.class);
125 					returned = c.newInstance(fibComponent, viewFactory);
126 				} catch (NoSuchMethodException e) {
127 					Constructor<? extends FIBController> c = fibComponent.getControllerClass().getConstructor(FIBComponent.class);
128 					// System.out.println("Constructor=" + c);
129 					returned = c.newInstance(fibComponent);
130 				}
131 			} catch (SecurityException e) {
132 				LOGGER.warning("SecurityException: Could not instanciate " + fibComponent.getControllerClass());
133 			} catch (NoSuchMethodException e) {
134 				LOGGER.warning("NoSuchMethodException: Could not instanciate " + fibComponent.getControllerClass());
135 			} catch (IllegalArgumentException e) {
136 				LOGGER.warning("IllegalArgumentException: Could not instanciate " + fibComponent.getControllerClass());
137 			} catch (InstantiationException e) {
138 				LOGGER.warning("InstantiationException: Could not instanciate " + fibComponent.getControllerClass());
139 			} catch (IllegalAccessException e) {
140 				LOGGER.warning("IllegalAccessException: Could not instanciate " + fibComponent.getControllerClass());
141 			} catch (InvocationTargetException e) {
142 				LOGGER.warning("InvocationTargetException: Could not instanciate " + fibComponent.getControllerClass());
143 			}
144 		}
145 		if (returned == null) {
146 			returned = new FIBController(fibComponent, viewFactory);
147 		}
148 		returned.setParentLocalizer(parentLocalizer);
149 
150 		if (recorderManager != null) {
151 			returned.setEventManager(recorderManager);
152 		}
153 
154 		return returned;
155 	}
156 
157 	public static <F extends FIBComponent, C> FIBView<F, ? extends C> makeView(F fibComponent, GinaViewFactory<C> viewFactory,
158 			LocalizedDelegate parentLocalizer, IteratedContents<?> context, boolean updateNow) {
159 		return makeView(fibComponent, viewFactory, instanciateController(fibComponent, viewFactory, parentLocalizer), context, updateNow);
160 	}
161 
162 	public static <F extends FIBComponent, C> FIBView<F, ? extends C> makeView(F fibComponent, GinaViewFactory<C> viewFactory,
163 			FIBController controller, IteratedContents<?> context, boolean updateNow) {
164 		return (FIBView<F, ? extends C>) controller.buildView(fibComponent, context, updateNow);
165 	}
166 
167 	private final FIBComponent rootComponent;
168 	private final Hashtable<FIBComponent, FIBView<?, ?>> views;
169 	private FIBSelectable<?> selectionLeader;
170 	private FIBSelectable<?> lastFocusedSelectable;
171 
172 	private FIBWidgetView<?, ?, ?> focusedWidget;
173 
174 	private LocalizedDelegate parentLocalizer = null;
175 
176 	private EventManager eventManager = null;
177 	private URID urid = null;
178 
179 	private GinaViewFactory<?> viewFactory;
180 
181 	public enum Status {
182 		RUNNING, VALIDATED, CANCELED, ABORTED, NEXT, BACK, RESET, YES, NO, QUIT, OTHER
183 	}
184 
185 	private Status status = Status.RUNNING;
186 
187 	private final Vector<FIBSelectionListener> selectionListeners;
188 	private final Vector<FIBMouseClickListener> mouseClickListeners;
189 
190 	// TODO: check this: Is it this still usefull ?
191 	@Deprecated
192 	private MouseEvent mouseEvent;
193 
194 	private boolean deleted = false;
195 
196 	private final PropertyChangeSupport pcSupport;
197 	public static final String DELETED = "deleted";
198 
199 	public FIBController(FIBComponent rootComponent, GinaViewFactory<?> viewFactory) {
200 		this.rootComponent = rootComponent;
201 		pcSupport = new PropertyChangeSupport(this);
202 		views = new Hashtable<>();
203 		selectionListeners = new Vector<>();
204 		mouseClickListeners = new Vector<>();
205 		this.viewFactory = viewFactory;
206 	}
207 
208 	public void delete() {
209 		if (!deleted) {
210 			if (getRootView() != null) {
211 				getRootView().delete();
212 			}
213 			// Next for-block should not be necessary because deletion is
214 			// recursive, but just to be sure
215 			for (FIBView<?, ?> view : new ArrayList<>(views.values())) {
216 				view.delete();
217 			}
218 			deleted = true;
219 			getPropertyChangeSupport().firePropertyChange(DELETED, false, true);
220 		}
221 	}
222 
223 	@Override
224 	public EventManager getEventManager() {
225 		return eventManager;
226 	}
227 
228 	@Override
229 	public void setEventManager(EventManager eventManager) {
230 		if (this.eventManager != null) {
231 			this.eventManager.unregister(this);
232 		}
233 		this.eventManager = eventManager;
234 		if (this.eventManager != null) {
235 			this.eventManager.register(this);
236 		}
237 	}
238 
239 	@Override
240 	public void setURID(URID urid) {
241 		this.urid = urid;
242 	}
243 
244 	@Override
245 	public URID getURID() {
246 		return this.urid;
247 	}
248 
249 	@Override
250 	public String getBaseIdentifier() {
251 		if (rootComponent == null)
252 			return this.getClass().getName();
253 		return rootComponent.getBaseIdentifier();
254 	}
255 
256 	public boolean isDeleted() {
257 		return deleted;
258 	}
259 
260 	@Override
261 	public PropertyChangeSupport getPropertyChangeSupport() {
262 		return pcSupport;
263 	}
264 
265 	@Override
266 	public String getDeletedProperty() {
267 		return DELETED;
268 	}
269 
270 	public FIBView<FIBComponent, ?> buildView() {
271 		FIBView<FIBComponent, ?> returned = buildView(rootComponent, null, true);
272 		// If data object was previously set, set the value to the root view
273 		if (dataObject != null) {
274 			setDataObject(dataObject);
275 			dataObject = null;
276 		}
277 		returned.update();
278 		return returned;
279 	}
280 
281 	public GinaViewFactory<?> getViewFactory() {
282 		return viewFactory;
283 	}
284 
285 	public void setViewFactory(GinaViewFactory<?> viewFactory) {
286 		this.viewFactory = viewFactory;
287 	}
288 
289 	public void registerView(FIBView<?, ?> view) {
290 		views.put(view.getComponent(), view);
291 		getPropertyChangeSupport().firePropertyChange(((FIBComponent) view.getComponent()).getName(), null, view.getComponent());
292 	}
293 
294 	public void unregisterView(FIBView<?, ?> view) {
295 		views.remove(view.getComponent());
296 	}
297 
298 	public final <M extends FIBComponent> FIBView<M, ?> viewForComponent(M component) {
299 		if (component == null) {
300 			return null;
301 		}
302 		return (FIBView<M, ?>) views.get(component);
303 	}
304 
305 	public FIBView<?, ?> viewForComponent(String componentName) {
306 
307 		// Includes views from embedded components
308 		for (FIBView<?, ?> v : getAllViews()) {
309 			if (StringUtils.isNotEmpty(v.getComponent().getName()) && v.getComponent().getName().equals(componentName)) {
310 				return v;
311 			}
312 		}
313 		return null;
314 
315 	}
316 
317 	public <W extends FIBWidget> FIBWidgetView<W, ?, ?> viewForWidget(W widget) {
318 		return (FIBWidgetView<W, ?, ?>) views.get(widget);
319 	}
320 
321 	public <M extends FIBContainer> FIBContainerView<M, ?, ?> viewForContainer(M container) {
322 		return (FIBContainerView<M, ?, ?>) views.get(container);
323 	}
324 
325 	public Collection<FIBView<?, ?>> getViews() {
326 		return views.values();
327 	}
328 
329 	// Includes views from embedded components
330 	public List<FIBView<?, ?>> getAllViews() {
331 		List<FIBView<?, ?>> l = new ArrayList<>();
332 		l.addAll(views.values());
333 		for (FIBView<?, ?> v : new ArrayList<>(views.values())) {
334 			if (v instanceof FIBReferencedComponentWidget) {
335 				FIBReferencedComponentWidget<?> w = (FIBReferencedComponentWidget<?>) v;
336 				if (w.getReferencedComponentView() != null) {
337 					if (w.getReferencedComponentView().getController() == this) {
338 						System.out.println("Zut alors le controller de " + w.getReferencedComponentView() + " c'est " + this);
339 					}
340 					else {
341 						l.addAll(w.getReferencedComponentView().getController().getAllViews());
342 					}
343 				}
344 			}
345 		}
346 		return l;
347 	}
348 
349 	public FIBComponent getRootComponent() {
350 		return rootComponent;
351 	}
352 
353 	public FIBView<?, ?> getRootView() {
354 		return viewForComponent(getRootComponent());
355 	}
356 
357 	public Object getVariableValue(String variableName) {
358 		FIBView<?, ?> rootView = getRootView();
359 		if (rootView != null) {
360 			FIBVariable<?> v = getRootComponent().getVariable(variableName);
361 			if (v != null)
362 				return rootView.getVariableValue(v);
363 		}
364 		return null;
365 	}
366 
367 	public void setVariableValue(String variableName, Object aValue) {
368 		FIBView<?, ?> rootView = getRootView();
369 		if (rootView != null) {
370 			FIBVariable<Object> v = getRootComponent().getVariable(variableName);
371 			if (v != null)
372 				rootView.setVariableValue(v, aValue);
373 		}
374 	}
375 
376 	// If the root view was not yet instantiated, stores the data object
377 	private Object dataObject = null;
378 
379 	@Deprecated
380 	public Object getDataObject() {
381 		Object returned = getVariableValue(FIBComponent.DEFAULT_DATA_VARIABLE);
382 		if (returned != null) {
383 			return returned;
384 		}
385 		return dataObject;
386 	}
387 
388 	@Deprecated
389 	public void setDataObject(Object anObject) {
390 		if (getRootView() != null && getRootComponent().getVariables().size() > 0) {
391 			getRootView().setVariableValue((FIBVariable) getRootComponent().getVariables().get(0), anObject);
392 		}
393 		else {
394 			dataObject = anObject;
395 		}
396 	}
397 
398 	@Deprecated
399 	public void updateWithoutDataObject() {
400 		setDataObject(null, true);
401 	}
402 
403 	@Deprecated
404 	public void setDataObject(Object anObject, boolean forceUpdate) {
405 		setDataObject(anObject);
406 	}
407 
408 	public final <M extends FIBComponent> FIBView<M, ?> buildView(M fibComponent, RuntimeContext context, boolean updateNow) {
409 		if (fibComponent instanceof FIBContainer) {
410 			return (FIBView<M, ?>) getViewFactory().makeContainer((FIBContainer) fibComponent, this, context, updateNow);
411 		}
412 		else if (fibComponent instanceof FIBWidget) {
413 			return (FIBView<M, ?>) getViewFactory().makeWidget((FIBWidget) fibComponent, this, context, updateNow);
414 		}
415 		return null;
416 	}
417 
418 	public void show() {
419 		getViewFactory().show(this);
420 	}
421 
422 	public void hide() {
423 		getViewFactory().hide(this);
424 	}
425 
426 	public void validateAndDispose() {
427 		status = Status.VALIDATED;
428 		getViewFactory().disposeWindow(this);
429 	}
430 
431 	public void nextAndDispose() {
432 		status = Status.NEXT;
433 		getViewFactory().disposeWindow(this);
434 	}
435 
436 	public void backAndDispose() {
437 		status = Status.BACK;
438 		getViewFactory().disposeWindow(this);
439 	}
440 
441 	public void cancelAndDispose() {
442 		status = Status.CANCELED;
443 		getViewFactory().disposeWindow(this);
444 	}
445 
446 	public void abortAndDispose() {
447 		status = Status.ABORTED;
448 		getViewFactory().disposeWindow(this);
449 	}
450 
451 	public void resetAndDispose() {
452 		status = Status.RESET;
453 		getViewFactory().disposeWindow(this);
454 	}
455 
456 	public void chooseYesAndDispose() {
457 		status = Status.YES;
458 		getViewFactory().disposeWindow(this);
459 	}
460 
461 	public void chooseNoAndDispose() {
462 		status = Status.NO;
463 		getViewFactory().disposeWindow(this);
464 	}
465 
466 	public void chooseQuitAndDispose() {
467 		status = Status.QUIT;
468 		getViewFactory().disposeWindow(this);
469 	}
470 
471 	public Status getStatus() {
472 		return status;
473 	}
474 
475 	public void setStatus(Status status) {
476 		this.status = status;
477 	}
478 
479 	public FIBLocalizedDictionary getLocalizer() {
480 		return getLocalizerForComponent(null);
481 	}
482 
483 	public FIBLocalizedDictionary getLocalizerForComponent(FIBComponent component) {
484 		if (getRootComponent() != null) {
485 			FIBLocalizedDictionary returned = getRootComponent().retrieveFIBLocalizedDictionary();
486 			if (getParentLocalizer() != null) {
487 				returned.setParent(getParentLocalizer());
488 			}
489 			return returned;
490 		}
491 		else {
492 			LOGGER.warning("Could not find localizer");
493 			return null;
494 		}
495 	}
496 
497 	public String getLocalizedForKey(String key) {
498 		// TODO: we always are creating a new entry
499 		// Make this configurable because only relevant in dev mode
500 		String returned = getLocalizer().localizedForKeyAndLanguage(key, FlexoLocalization.getCurrentLanguage(), true);
501 		if (returned == null) {
502 			return key;
503 		}
504 		return returned;
505 	}
506 
507 	/**
508 	 * Return parent localizer for component localizer
509 	 * 
510 	 * @return
511 	 */
512 	public final LocalizedDelegate getParentLocalizer() {
513 		return parentLocalizer;
514 	}
515 
516 	/**
517 	 * Sets parent localizer for component localizer
518 	 * 
519 	 * @param parentLocalizer
520 	 */
521 	public void setParentLocalizer(LocalizedDelegate parentLocalizer) {
522 		this.parentLocalizer = parentLocalizer;
523 	}
524 
525 	public void switchToLanguage(Language language) {
526 		FlexoLocalization.setCurrentLanguage(language);
527 		getRootView().updateLanguage();
528 	}
529 
530 	public void refreshLocalized() {
531 		getRootComponent().retrieveFIBLocalizedDictionary().refresh();
532 	}
533 
534 	public FIBSelectable getSelectionLeader() {
535 		if (isEmbedded()) {
536 			return getEmbeddingController().getSelectionLeader();
537 		}
538 		return selectionLeader;
539 	}
540 
541 	public void setSelectionLeader(FIBSelectable<?> selectionLeader) {
542 		LOGGER.fine("Selection LEADER is now " + selectionLeader);
543 		if (isEmbedded()) {
544 			getEmbeddingController().setSelectionLeader(selectionLeader);
545 			return;
546 		}
547 		this.selectionLeader = selectionLeader;
548 	}
549 
550 	public FIBSelectable getLastFocusedSelectable() {
551 		if (isEmbedded()) {
552 			return getEmbeddingController().getLastFocusedSelectable();
553 		}
554 		return lastFocusedSelectable;
555 	}
556 
557 	public void setLastFocusedSelectable(FIBSelectable<?> lastFocusedSelectable) {
558 		if (isEmbedded()) {
559 			getEmbeddingController().setLastFocusedSelectable(lastFocusedSelectable);
560 			return;
561 		}
562 		this.lastFocusedSelectable = lastFocusedSelectable;
563 	}
564 
565 	public FIBWidgetView getFocusedWidget() {
566 		if (isEmbedded()) {
567 			return getEmbeddingController().getFocusedWidget();
568 		}
569 		return focusedWidget;
570 	}
571 
572 	public void setFocusedWidget(FIBWidgetView newFocusedWidget) {
573 		if (isEmbedded()) {
574 			getEmbeddingController().setFocusedWidget(newFocusedWidget);
575 			return;
576 		}
577 
578 		LOGGER.fine("Focused widget is now " + newFocusedWidget.getComponent() + " was="
579 				+ (focusedWidget != null ? focusedWidget.getComponent() : null));
580 		if (newFocusedWidget != focusedWidget) {
581 			FIBWidgetView oldFocusedWidget = focusedWidget;
582 			focusedWidget = newFocusedWidget;
583 			if (oldFocusedWidget != null) {
584 				oldFocusedWidget.getRenderingAdapter().repaint(oldFocusedWidget.getTechnologyComponent());
585 			}
586 			if (newFocusedWidget != null) {
587 				newFocusedWidget.getRenderingAdapter().repaint(newFocusedWidget.getTechnologyComponent());
588 				if (newFocusedWidget instanceof FIBSelectable) {
589 					FIBSelectable<?> newFocusedWidgetS = (FIBSelectable) newFocusedWidget;
590 					setLastFocusedSelectable(newFocusedWidgetS);
591 					if (getLastFocusedSelectable().synchronizedWithSelection()) {
592 						setSelectionLeader(newFocusedWidgetS);
593 						fireSelectionChanged(newFocusedWidgetS);
594 					}
595 				}
596 			}
597 		}
598 	}
599 
600 	public boolean isFocused(FIBWidgetView<?, ?, ?> widget) {
601 		return focusedWidget == widget;
602 	}
603 
604 	public boolean isEmbedded() {
605 		return (getRootView().getEmbeddingComponent() != null);
606 	}
607 
608 	public FIBController getEmbeddingController() {
609 		if (isEmbedded()) {
610 			return getRootView().getEmbeddingComponent().getController();
611 		}
612 		return null;
613 	}
614 
615 	/**
616 	 * Called from the passed widget.<br>
617 	 * This means that the widget has a new selection and notifies the FIBController of that.<br>
618 	 * If the caller (the widget) is the selection leader, then the new selection is reflected all over the whole component.<br>
619 	 * 
620 	 * @param widget
621 	 * @param oldSelection
622 	 * @param newSelection
623 	 */
624 	public <T> void updateSelection(FIBSelectable<T> widget, List<T> oldSelection, List<T> newSelection) {
625 
626 		// LOGGER.info("updateSelection() dans FIBController with " +
627 		// newSelection);
628 		// LOGGER.info("widget=" + widget);
629 		// LOGGER.info("selectionLeader=" + getSelectionLeader());
630 
631 		if (isEmbedded() && getEmbeddingController() != null) {
632 			// When component is embedded, forward this to the parent
633 			getEmbeddingController().updateSelection(widget, oldSelection, newSelection);
634 			return;
635 		}
636 
637 		// System.out.println("widget=" + widget);
638 		// System.out.println("getSelectionLeader()=" + getSelectionLeader());
639 
640 		// Fixed issue with selection not taken under account when component has
641 		// just been initialized
642 		if (getSelectionLeader() == null) {
643 			setSelectionLeader(widget);
644 		}
645 
646 		if (widget == getSelectionLeader()) {
647 
648 			// LOGGER.info("*************** I'm the SELECTION LEADER: " +
649 			// getSelectionLeader());
650 
651 			// The caller widget is the selection leader, and should fire
652 			// selection change event all over the world !
653 			fireSelectionChanged(widget);
654 			List<Object> objectsToRemoveFromSelection = new Vector<>();
655 			List<Object> objectsToAddToSelection = new Vector<>();
656 			if (oldSelection != null) {
657 				objectsToRemoveFromSelection.addAll(oldSelection);
658 			}
659 			if (newSelection != null) {
660 				for (Object o : newSelection) {
661 					if (oldSelection != null && oldSelection.contains(o)) {
662 						objectsToRemoveFromSelection.remove(o);
663 					}
664 					else {
665 						objectsToAddToSelection.add(o);
666 					}
667 				}
668 			}
669 
670 			for (FIBView<?, ?> v : getAllViews()) {
671 				if (v instanceof FIBWidgetView && v instanceof FIBSelectable && v != getSelectionLeader()
672 						&& ((FIBSelectable<?>) v).synchronizedWithSelection()) {
673 					FIBSelectable<Object> selectableComponent = (FIBSelectable) v;
674 					for (Object o : objectsToAddToSelection) {
675 						if (selectableComponent.mayRepresent(o)) {
676 							selectableComponent.objectAddedToSelection(o);
677 						}
678 					}
679 					for (Object o : objectsToRemoveFromSelection) {
680 						// Don't do this for FIBSelectable which are not
681 						// SelectionLeader !!!
682 						// Otherwise, if this selectable'selection is the cause
683 						// of displaying of selection leader
684 						// the selection leader might disappear
685 						if (selectableComponent.mayRepresent(o) && selectableComponent == getSelectionLeader()) {
686 							selectableComponent.objectRemovedFromSelection(o);
687 						}
688 					}
689 				}
690 			}
691 		}
692 	}
693 
694 	public void objectAddedToSelection(Object o) {
695 
696 		// LOGGER.info("************** objectAddedToSelection() dans FIBController with "
697 		// + o);
698 
699 		LOGGER.fine("FIBController: objectAddedToSelection(): " + o);
700 
701 		for (FIBView<?, ?> v : getViews()) {
702 			if (v instanceof FIBWidgetView && v instanceof FIBSelectable && ((FIBSelectable<?>) v).synchronizedWithSelection()) {
703 				FIBSelectable<Object> selectableComponent = (FIBSelectable) v;
704 				if (selectableComponent.mayRepresent(o)) {
705 					selectableComponent.objectAddedToSelection(o);
706 					if (getSelectionLeader() == null) {
707 						setSelectionLeader(selectableComponent);
708 					}
709 					if (getLastFocusedSelectable() == null) {
710 						setLastFocusedSelectable(getSelectionLeader());
711 					}
712 				}
713 			}
714 		}
715 
716 	}
717 
718 	public void objectRemovedFromSelection(Object o) {
719 
720 		// LOGGER.info("************** objectRemovedFromSelection() dans FIBController with "
721 		// + o);
722 
723 		LOGGER.fine("FIBController: objectRemovedFromSelection(): " + o);
724 		for (FIBView<?, ?> v : getViews()) {
725 			if (v instanceof FIBWidgetView && v instanceof FIBSelectable && ((FIBSelectable<?>) v).synchronizedWithSelection()) {
726 				FIBSelectable<Object> selectableComponent = (FIBSelectable) v;
727 				if (selectableComponent.mayRepresent(o)) {
728 					selectableComponent.objectRemovedFromSelection(o);
729 				}
730 			}
731 		}
732 	}
733 
734 	public void selectionCleared() {
735 		LOGGER.fine("FIBController: selectionCleared()");
736 		for (FIBView<?, ?> v : getViews()) {
737 			if (v instanceof FIBWidgetView && v instanceof FIBSelectable && ((FIBSelectable<?>) v).synchronizedWithSelection()) {
738 				FIBSelectable<Object> selectableComponent = (FIBSelectable) v;
739 				selectableComponent.selectionResetted();
740 			}
741 		}
742 	}
743 
744 	/**
745 	 * Called when a selection leader (a widget managing a selection and declared as the selection leader) has a new selection.<br>
746 	 * Notify the while world of this new selection (well, use the FIBSelectionListener scheme ;-) ).
747 	 * 
748 	 * @param leader
749 	 */
750 	private void fireSelectionChanged(FIBSelectable<?> leader) {
751 		// External synchronization
752 		for (FIBSelectionListener l : selectionListeners) {
753 			if (getSelectionLeader() != null) {
754 				l.selectionChanged(getSelectionLeader().getSelection());
755 			}
756 		}
757 	}
758 
759 	public void fireMouseClicked(FIBView<?, ?> view, int clickCount) {
760 		for (FIBMouseClickListener l : mouseClickListeners) {
761 			l.mouseClicked(view, clickCount);
762 		}
763 	}
764 
765 	public void addSelectionListener(FIBSelectionListener l) {
766 		selectionListeners.add(l);
767 	}
768 
769 	public void removeSelectionListener(FIBSelectionListener l) {
770 		selectionListeners.remove(l);
771 	}
772 
773 	public void addMouseClickListener(FIBMouseClickListener l) {
774 		mouseClickListeners.add(l);
775 	}
776 
777 	public void removeMouseClickListener(FIBMouseClickListener l) {
778 		mouseClickListeners.remove(l);
779 	}
780 
781 	public MouseEvent getMouseEvent() {
782 		return mouseEvent;
783 	}
784 
785 	public void setMouseEvent(MouseEvent mouseEvent) {
786 		this.mouseEvent = mouseEvent;
787 	}
788 
789 	/**
790 	 * Called when a throwable has been raised during model code invocation. Requires to be overriden, this base implementation just log
791 	 * exception
792 	 * 
793 	 * @param t
794 	 * @return true is exception was correctely handled
795 	 */
796 	public boolean handleException(Throwable t) {
797 		LOGGER.warning("Unexpected exception raised: " + t.getMessage());
798 		t.printStackTrace();
799 		return false;
800 	}
801 
802 	public void performCopyAction(Object focused, List<?> selection) {
803 		LOGGER.warning("COPY action not implemented. Please override this method");
804 	}
805 
806 	public void performCutAction(Object focused, List<?> selection) {
807 		LOGGER.warning("CUT action not implemented. Please override this method");
808 	}
809 
810 	public void performPasteAction(Object focused, List<?> selection) {
811 		LOGGER.warning("PASTE action not implemented. Please override this method");
812 	}
813 
814 	public Resource getFIBPanelForObject(Object anObject) {
815 		if (anObject != null) {
816 			return getFIBPanelForClass(anObject.getClass());
817 		}
818 		return null;
819 	}
820 
821 	private final Map<Class<?>, Resource> fibPanelsForClasses = new HashMap<Class<?>, Resource>() {
822 		@Override
823 		public Resource get(Object key) {
824 			if (containsKey(key)) {
825 				return super.get(key);
826 			}
827 			if (key instanceof Class) {
828 				Class<?> aClass = (Class<?>) key;
829 				if (aClass.getAnnotation(org.openflexo.gina.annotation.FIBPanel.class) != null) {
830 					String fibPanelName = aClass.getAnnotation(org.openflexo.gina.annotation.FIBPanel.class).value();
831 					Resource fibPanelResource = ResourceLocator.locateResource(fibPanelName);
832 					if (fibPanelResource != null) {
833 						put(aClass, fibPanelResource);
834 						return fibPanelResource;
835 					}
836 				}
837 				put(aClass, null);
838 				return null;
839 			}
840 			return null;
841 		}
842 	};
843 
844 	public Resource getFIBPanelForClass(Class<?> aClass) {
845 		return TypeUtils.objectForClass(aClass, fibPanelsForClasses);
846 	}
847 
848 	private SampleData sampleData;
849 
850 	public SampleData getSampleData() {
851 		if (sampleData == null) {
852 			sampleData = new SampleData();
853 		}
854 		return sampleData;
855 	}
856 
857 	public static class SampleData extends PropertyChangedSupportDefaultImplementation {
858 		public List<Family> families;
859 		public List<Person> persons;
860 		public Person martin, mary, john, martinJr1, martinJr2, martinJr3, martinJr4;
861 
862 		public SampleData() {
863 			families = new ArrayList<>();
864 			persons = new ArrayList<>();
865 			families.add(makeFamily1());
866 			families.add(makeFamily2());
867 			families.add(makeFamily3());
868 			families.add(makeFamily4());
869 			families.add(makeFamily5());
870 		}
871 
872 		public void logString(String s) {
873 			System.out.println(s);
874 		}
875 
876 		public Family addNewFamily() {
877 			Person father, mother, child;
878 			List<Person> children = new ArrayList<>();
879 			persons.add(father = new Person("Father", 173, 73.7));
880 			persons.add(mother = new Person("Mother", 165, 57.0));
881 			persons.add(child = new Person("Child", 107, 26.3));
882 			children.add(child);
883 			Family returned = new Family(father, mother, children);
884 			families.add(returned);
885 			System.out.println("New family created: " + returned);
886 			getPropertyChangeSupport().firePropertyChange("families", null, returned);
887 			return returned;
888 		}
889 
890 		private Family makeFamily1() {
891 			List<Person> children = new ArrayList<>();
892 			persons.add(martin = new Person("Martin", 173, 73.7));
893 			persons.add(mary = new Person("Mary", 165, 57.0));
894 			persons.add(john = new Person("John", 107, 26.3));
895 			persons.add(martinJr1 = new Person("Martin Jr 1", 97, 19.2));
896 			persons.add(martinJr2 = new Person("Martin Jr 2", 95, 18.7));
897 			persons.add(martinJr3 = new Person("Martin Jr 3", 74, 10.2));
898 			persons.add(martinJr4 = new Person("Martin Jr 4", 57, 5.2));
899 			children.add(john);
900 			children.add(martinJr1);
901 			children.add(martinJr2);
902 			children.add(martinJr3);
903 			children.add(martinJr4);
904 			return new Family(martin, mary, children);
905 		}
906 
907 		private static Family makeFamily2() {
908 			Person tarzan, jane, cheeta;
909 			List<Person> children = new ArrayList<>();
910 			tarzan = new Person("Tarzan", 187, 92.7);
911 			jane = new Person("Jane", 175, 62.0);
912 			cheeta = new Person("Cheeta", 88, 26.3);
913 			children.add(cheeta);
914 			return new Family(tarzan, jane, children);
915 		}
916 
917 		private static Family makeFamily3() {
918 			Person romeo, juliette, romeoJr1, romeoJr2, romeoJr3;
919 			List<Person> children = new ArrayList<>();
920 			romeo = new Person("Romeo", 173, 82.7);
921 			juliette = new Person("Juliette", 165, 52.0);
922 			romeoJr1 = new Person("Romeo Jr 1", 97, 19.2);
923 			romeoJr2 = new Person("Romeo Jr 2", 95, 18.7);
924 			romeoJr3 = new Person("Romeo Jr 3", 74, 10.2);
925 			children.add(romeoJr1);
926 			children.add(romeoJr2);
927 			children.add(romeoJr3);
928 			return new Family(romeo, juliette, children);
929 		}
930 
931 		private static Family makeFamily4() {
932 			Person donald, daisy, riri, fifi, loulou;
933 			List<Person> children = new ArrayList<>();
934 			donald = new Person("Donald", 135, 53.5);
935 			daisy = new Person("Daisy", 123, 48.6);
936 			riri = new Person("Riri", 74, 10.3);
937 			fifi = new Person("Fifi", 74, 10.1);
938 			loulou = new Person("Loulou", 74, 10.2);
939 			children.add(riri);
940 			children.add(fifi);
941 			children.add(loulou);
942 			return new Family(donald, daisy, children);
943 		}
944 
945 		private static Family makeFamily5() {
946 			Person adam, eve, cain, abel, seth;
947 			List<Person> children = new ArrayList<>();
948 			adam = new Person("Adam", 178, 84.7);
949 			eve = new Person("Eve", 168, 54.0);
950 			cain = new Person("Cain", 130, 37.2);
951 			abel = new Person("Abel", 127, 28.1);
952 			seth = new Person("Seth", 107, 10.2);
953 			children.add(cain);
954 			children.add(abel);
955 			children.add(seth);
956 			return new Family(adam, eve, children);
957 		}
958 
959 		private int personId = 2;
960 
961 		public Person addPerson() {
962 			Person newPerson = new Person("Person" + personId, 170, 60);
963 			personId++;
964 			persons.add(newPerson);
965 			getPropertyChangeSupport().firePropertyChange("persons", null, newPerson);
966 			return newPerson;
967 		}
968 
969 		public Person deletePerson(Person person) {
970 			persons.remove(person);
971 			getPropertyChangeSupport().firePropertyChange("persons", person, null);
972 			return person;
973 		}
974 
975 		public static class Person extends PropertyChangedSupportDefaultImplementation {
976 			private String name;
977 			private int size;
978 			private double weight;
979 
980 			public Person(String name, int size, double weight) {
981 				super();
982 				this.name = name;
983 				this.size = size;
984 				this.weight = weight;
985 			}
986 
987 			public void maryTo(Person otherPerson) {
988 				System.out.println("Mary " + this + " with " + otherPerson);
989 			}
990 
991 			public boolean canMaryWith(Person otherPerson) {
992 				System.out.println("Can i mary with " + otherPerson + " ?");
993 				/*if ((this == mary && otherPerson == john) || (this == mary && otherPerson == john)) {
994 					return true;
995 				}*/
996 				return true;
997 			}
998 
999 			@Override
1000 			public String toString() {
1001 				return name;
1002 			}
1003 
1004 			public String getName() {
1005 				return name;
1006 			}
1007 
1008 			public void setName(String name) {
1009 				if ((name == null && this.name != null) || (name != null && !name.equals(this.name))) {
1010 					String oldValue = this.name;
1011 					this.name = name;
1012 					getPropertyChangeSupport().firePropertyChange("name", oldValue, name);
1013 				}
1014 			}
1015 
1016 			public int getSize() {
1017 				return size;
1018 			}
1019 
1020 			public void setSize(int size) {
1021 				if (this.size != size) {
1022 					int oldValue = this.size;
1023 					this.size = size;
1024 					getPropertyChangeSupport().firePropertyChange("size", oldValue, size);
1025 				}
1026 			}
1027 
1028 			public double getWeight() {
1029 				return weight;
1030 			}
1031 
1032 			public void setWeight(double weight) {
1033 				if (this.weight != weight) {
1034 					double oldValue = this.weight;
1035 					this.weight = weight;
1036 					getPropertyChangeSupport().firePropertyChange("weight", oldValue, weight);
1037 				}
1038 			}
1039 		}
1040 
1041 		public static class Family extends PropertyChangedSupportDefaultImplementation {
1042 			public Person father;
1043 			public Person mother;
1044 			public List<Person> children;
1045 			public List<Person> persons;
1046 
1047 			public Family(Person father, Person mother, List<Person> children) {
1048 				super();
1049 				this.father = father;
1050 				this.mother = mother;
1051 				this.children = children;
1052 				persons = new ArrayList<>();
1053 				persons.add(father);
1054 				persons.add(mother);
1055 				persons.addAll(children);
1056 			}
1057 
1058 			private int personId = 2;
1059 
1060 			public Person addPerson() {
1061 				System.out.println("New person created in " + this);
1062 				Person newPerson = new Person("Person" + personId, 170, 60);
1063 				personId++;
1064 				persons.add(newPerson);
1065 				getPropertyChangeSupport().firePropertyChange("persons", null, newPerson);
1066 				return newPerson;
1067 			}
1068 
1069 			public Person deletePerson(Person person) {
1070 				persons.remove(person);
1071 				getPropertyChangeSupport().firePropertyChange("persons", person, null);
1072 				return person;
1073 			}
1074 
1075 			@Override
1076 			public String toString() {
1077 				return "Family:" + father;
1078 			}
1079 		}
1080 
1081 	}
1082 
1083 	public static String askForString(String msg) throws HeadlessException {
1084 		return showInputDialog(msg, FlexoLocalization.getMainLocalizer().localizedForKey("information"), JOptionPane.QUESTION_MESSAGE);
1085 	}
1086 
1087 	private static String showInputDialog(Object message, String title, int messageType) throws HeadlessException {
1088 		Window activeWindow = javax.swing.FocusManager.getCurrentManager().getActiveWindow();
1089 		return (String) showInputDialog(activeWindow, message, title, messageType, null, null, null);
1090 	}
1091 
1092 	private static Object showInputDialog(Component parentComponent, Object message, String title, int messageType, Icon icon,
1093 			Object[] selectionValues, Object initialSelectionValue) throws HeadlessException {
1094 		Object[] availableOptions = new Object[] { FlexoLocalization.getMainLocalizer().localizedForKey("OK"),
1095 				FlexoLocalization.getMainLocalizer().localizedForKey("cancel") };
1096 		JOptionPane pane = new JOptionPane(message, messageType, JOptionPane.OK_CANCEL_OPTION, icon, availableOptions, availableOptions[0]);
1097 		pane.setWantsInput(true);
1098 		pane.setSelectionValues(selectionValues);
1099 		pane.setInitialSelectionValue(initialSelectionValue);
1100 		// pane.setComponentOrientation((parentComponent == null ? FlexoFrame.getActiveFrame() :
1101 		// parentComponent).getComponentOrientation());
1102 		pane.setMessageType(messageType);
1103 		JDialog dialog = pane.createDialog(parentComponent, title);
1104 		pane.selectInitialValue();
1105 
1106 		dialog.validate();
1107 		dialog.pack();
1108 		if (parentComponent == null) {
1109 			Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
1110 			dialog.setLocation((dim.width - dialog.getSize().width) / 2, (dim.height - dialog.getSize().height) / 2);
1111 		}
1112 
1113 		dialog.setVisible(true);
1114 		dialog.dispose();
1115 
1116 		Object val = pane.getValue();
1117 
1118 		for (int counter = 0, maxCounter = availableOptions.length; counter < maxCounter; counter++) {
1119 			if (availableOptions[counter].equals(val)) {
1120 				if (counter == 1) {
1121 					return null;
1122 				}
1123 			}
1124 
1125 		}
1126 
1127 		Object value = pane.getInputValue();
1128 		if (value == JOptionPane.UNINITIALIZED_VALUE) {
1129 			return null;
1130 		}
1131 		return value;
1132 	}
1133 
1134 }