View Javadoc
1   /**
2    * 
3    * Copyright (c) 2014, Openflexo
4    * 
5    * This file is part of Gina-swing, a component of the software infrastructure 
6    * developed at Openflexo.
7    * 
8    * 
9    * Openflexo is dual-licensed under the European Union Public License (EUPL, either 
10   * version 1.1 of the License, or any later version ), which is available at 
11   * https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
12   * and the GNU General Public License (GPL, either version 3 of the License, or any 
13   * later version), which is available at http://www.gnu.org/licenses/gpl.html .
14   * 
15   * You can redistribute it and/or modify under the terms of either of these licenses
16   * 
17   * If you choose to redistribute it and/or modify under the terms of the GNU GPL, you
18   * must include the following additional permission.
19   *
20   *          Additional permission under GNU GPL version 3 section 7
21   *
22   *          If you modify this Program, or any covered work, by linking or 
23   *          combining it with software containing parts covered by the terms 
24   *          of EPL 1.0, the licensors of this Program grant you additional permission
25   *          to convey the resulting work. * 
26   * 
27   * This software is distributed in the hope that it will be useful, but WITHOUT ANY 
28   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
29   * PARTICULAR PURPOSE. 
30   *
31   * See http://www.openflexo.org/license.html for details.
32   * 
33   * 
34   * Please contact Openflexo (openflexo-contacts@openflexo.org)
35   * or visit www.openflexo.org if you need additional information.
36   * 
37   */
38  
39  package org.openflexo.gina.swing.utils;
40  
41  import java.awt.Color;
42  import java.awt.Component;
43  import java.awt.Dimension;
44  import java.awt.Frame;
45  import java.awt.KeyEventDispatcher;
46  import java.awt.KeyboardFocusManager;
47  import java.awt.event.ActionEvent;
48  import java.awt.event.ActionListener;
49  import java.awt.event.FocusEvent;
50  import java.awt.event.FocusListener;
51  import java.awt.event.KeyAdapter;
52  import java.awt.event.KeyEvent;
53  import java.beans.PropertyChangeEvent;
54  import java.beans.PropertyChangeListener;
55  import java.io.IOException;
56  import java.util.Observable;
57  import java.util.Observer;
58  import java.util.StringTokenizer;
59  import java.util.logging.Level;
60  import java.util.logging.Logger;
61  
62  import javax.swing.JButton;
63  import javax.swing.JDialog;
64  import javax.swing.JList;
65  import javax.swing.JPanel;
66  import javax.swing.SwingUtilities;
67  import javax.swing.event.DocumentEvent;
68  import javax.swing.event.DocumentListener;
69  
70  import org.openflexo.connie.Bindable;
71  import org.openflexo.connie.BindingFactory;
72  import org.openflexo.connie.BindingModel;
73  import org.openflexo.connie.BindingVariable;
74  import org.openflexo.connie.DataBinding;
75  import org.openflexo.connie.DefaultBindable;
76  import org.openflexo.connie.binding.BindingModelChanged;
77  import org.openflexo.connie.expr.BindingValue;
78  import org.openflexo.connie.expr.Constant;
79  import org.openflexo.connie.expr.Constant.BooleanConstant;
80  import org.openflexo.connie.expr.Constant.FloatConstant;
81  import org.openflexo.connie.expr.Constant.IntegerConstant;
82  import org.openflexo.connie.expr.Constant.StringConstant;
83  import org.openflexo.connie.expr.Expression;
84  import org.openflexo.connie.expr.parser.ExpressionParser;
85  import org.openflexo.connie.expr.parser.ParseException;
86  import org.openflexo.connie.java.JavaBindingFactory;
87  import org.openflexo.connie.type.TypeUtils;
88  import org.openflexo.gina.ApplicationFIBLibrary.ApplicationFIBLibraryImpl;
89  import org.openflexo.gina.controller.FIBController;
90  import org.openflexo.gina.event.GinaEvent.KIND;
91  import org.openflexo.gina.event.GinaEventNotifier;
92  import org.openflexo.gina.event.description.EventDescription;
93  import org.openflexo.gina.manager.GinaStackEvent;
94  import org.openflexo.gina.model.widget.FIBCustom;
95  import org.openflexo.gina.model.widget.FIBCustom.FIBCustomComponent;
96  import org.openflexo.gina.swing.utils.logging.FlexoLoggingViewer;
97  import org.openflexo.icon.UtilsIconLibrary;
98  import org.openflexo.kvc.InvalidKeyValuePropertyException;
99  import org.openflexo.logging.FlexoLoggingManager;
100 import org.openflexo.rm.Resource;
101 import org.openflexo.rm.ResourceLocator;
102 import org.openflexo.swing.ButtonsControlPanel;
103 import org.openflexo.swing.SwingUtils;
104 import org.openflexo.swing.TextFieldCustomPopup;
105 import org.openflexo.swing.VerticalLayout;
106 import org.openflexo.toolbox.HasPropertyChangeSupport;
107 import org.openflexo.toolbox.StringUtils;
108 
109 /**
110  * Widget allowing to edit a {@link DataBinding}
111  * 
112  * @author sguerin
113  * 
114  */
115 public class BindingSelector extends TextFieldCustomPopup<DataBinding>
116 		implements FIBCustomComponent<DataBinding>, Observer, PropertyChangeListener {
117 	static final Logger LOGGER = Logger.getLogger(BindingSelector.class.getPackage().getName());
118 
119 	private DataBinding<?> _revertBindingValue;
120 
121 	protected boolean _allowsBindingExpressions = true;
122 	protected boolean _allowsCompoundBindings = true;
123 	protected boolean _allowsStaticValues = true;
124 	protected boolean _hideFilteredObjects = false;
125 
126 	protected AbstractBindingSelectorPanel _selectorPanel;
127 	boolean isUpdatingModel = false;
128 
129 	private boolean textIsEditing = false;
130 
131 	private boolean isConnected = false;
132 
133 	protected KeyEventDispatcher tabDispatcher = new KeyEventDispatcher() {
134 		@Override
135 		public boolean dispatchKeyEvent(KeyEvent e) {
136 
137 			if (e.getID() == KeyEvent.KEY_TYPED && (e.getKeyChar() == KeyEvent.VK_TAB)) {
138 				if (LOGGER.isLoggable(Level.FINE)) {
139 					LOGGER.fine("Calling tab pressed " + e);
140 				}
141 				getCustomPanel().processTabPressed();
142 				e.consume();
143 			}
144 			return false;
145 		}
146 	};
147 
148 	static enum EditionMode {
149 		NORMAL_BINDING, COMPOUND_BINDING, STATIC_BINDING, BINDING_EXPRESSION;/*
150 																				* ,
151 																				* NEW_ENTRY
152 																				* ;
153 																				*/
154 
155 		boolean useCommonPanel() {
156 			return this != BINDING_EXPRESSION;
157 		}
158 	}
159 
160 	EditionMode editionMode = EditionMode.NORMAL_BINDING;
161 
162 	public KeyAdapter shortcutsKeyAdapter;
163 	private DocumentListener documentListener;
164 
165 	private Color defaultForeground;
166 
167 	private Color defaultSelectedColor;
168 
169 	protected GinaEventNotifier<EventDescription> GENotifier;
170 
171 	public BindingSelector(DataBinding<?> editedObject) {
172 		this(editedObject, -1);
173 	}
174 
175 	public BindingSelector(DataBinding<?> editedObject, int cols) {
176 		super(null, cols);
177 
178 		GENotifier = new GinaEventNotifier<EventDescription>(null, null) {
179 
180 			@Override
181 			public KIND computeClass(EventDescription e) {
182 				return KIND.UNKNOWN;
183 			}
184 
185 			@Override
186 			public void setIdentity(EventDescription e, Object o) {
187 				if (e instanceof EventDescription) {
188 					// ((FIBEvent) e).setIdentity(getWidget().getBaseName(),
189 					// getWidget().getName(),
190 					// getWidget().getRootComponent().getUniqueID());
191 				}
192 			}
193 
194 		};
195 
196 		setFocusable(true);
197 		getTextField().setFocusable(true);
198 		getTextField().setEditable(true);
199 		getTextField().addFocusListener(new FocusListener() {
200 			@Override
201 			public void focusGained(FocusEvent focusEvent) {
202 				GinaStackEvent stackElement = GENotifier.notifyMethod();
203 
204 				KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(tabDispatcher);
205 
206 				stackElement.end();
207 			}
208 
209 			@Override
210 			public void focusLost(FocusEvent focusEvent) {
211 				GinaStackEvent stackElement = GENotifier.notifyMethod();
212 
213 				KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(tabDispatcher);
214 				Component opposite = focusEvent.getOppositeComponent();
215 				if (LOGGER.isLoggable(Level.FINER)) {
216 					LOGGER.finer("focus lost for " + (opposite != null ? SwingUtils.getComponentPath(opposite) : "null"));
217 				}
218 				if (opposite == null || !SwingUtilities.isDescendingFrom(opposite, BindingSelector.this)
219 						&& !SwingUtilities.isDescendingFrom(opposite, _selectorPanel)) {
220 					// Little hook used to automatically apply a valid value
221 					// which has generally been edited
222 					// By typing text in text field
223 					if (getEditedObject() != null && getEditedObject().forceRevalidate()) {
224 						try {
225 							apply();
226 						} catch (InvalidKeyValuePropertyException e) {
227 							// Abort, widget is on an other object
228 						}
229 					}
230 				}
231 
232 				stackElement.end();
233 			}
234 		});
235 		shortcutsKeyAdapter = new KeyAdapter() {
236 			@Override
237 			public void keyPressed(KeyEvent e) {
238 				GinaStackEvent stackElement = GENotifier.notifyMethod();
239 
240 				// if command-key is pressed, do not open popup
241 				if (e.isAltDown() || e.isAltGraphDown() || e.isControlDown() || e.isMetaDown()) {
242 					stackElement.end();
243 					return;
244 				}
245 
246 				boolean isSignificativeKey = e.getKeyCode() >= KeyEvent.VK_A && e.getKeyCode() <= KeyEvent.VK_Z
247 						|| e.getKeyCode() >= KeyEvent.VK_0 && e.getKeyCode() <= KeyEvent.VK_9;
248 
249 				if (!popupIsShown() && getTextField().getText() != null
250 						&& !isAcceptableAsBeginningOfStaticBindingValue(getTextField().getText()) && isSignificativeKey) {
251 
252 					// Open the popup
253 					openPopup();
254 
255 				}
256 
257 				// This code was added to allow direct typing without opening
258 				// selector panel (sic !)
259 				// TODO:provide better implementation !!!
260 				if (_selectorPanel == null) {
261 					createCustomPanel(getEditedObject());
262 				}
263 
264 				if (_selectorPanel != null) {
265 
266 					if (e.getKeyCode() == KeyEvent.VK_ENTER) {
267 						if (StringUtils.isEmpty(getTextField().getText().trim())) {
268 							getEditedObject().reset();
269 							fireEditedObjectChanged();
270 							apply();
271 						}
272 						else if (StringUtils.isNotEmpty(getTextField().getText()) && textFieldNotSynchWithEditedObject()) {
273 							if (_selectorPanel instanceof BindingValueSelectorPanel) {
274 								BindingValueSelectorPanel selectorPanel = (BindingValueSelectorPanel) _selectorPanel;
275 								if (selectorPanel.isKeyPathFromTextASubKeyPath(getTextField().getText())
276 										&& selectorPanel.isKeyPathFromPanelValid()) {
277 									getEditedObject().setExpression(selectorPanel.makeBindingValueFromPanel());
278 									fireEditedObjectChanged();
279 									if (getEditedObject().forceRevalidate()) {
280 										apply();
281 									}
282 								}
283 								else {
284 									String input = getTextField().getText();
285 									if (input.indexOf(".") > -1) {
286 										String pathIgnoringLastPart = input.substring(0, input.lastIndexOf("."));
287 										if (isKeyPathValid(pathIgnoringLastPart)) {
288 											// Unused String inexitingPart =
289 											input.substring(input.lastIndexOf(".") + 1);
290 											// Unused Type hostType =
291 											selectorPanel.getEndingTypeForSubPath(pathIgnoringLastPart);
292 										}
293 									}
294 								}
295 							}
296 						}
297 						_selectorPanel.processEnterPressed();
298 						e.consume();
299 					}
300 
301 					else if (e.getKeyCode() == KeyEvent.VK_UP) {
302 						_selectorPanel.processUpPressed();
303 						e.consume();
304 					}
305 					else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
306 						_selectorPanel.processDownPressed();
307 						e.consume();
308 					} /*
309 						* else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
310 						* System.out.println("a gauche");
311 						* _selectorPanel.processLeftPressed(); e.consume(); } else
312 						* if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
313 						* System.out.println("a droite");
314 						* _selectorPanel.processRightPressed(); e.consume(); }
315 						*/
316 				}
317 
318 				stackElement.end();
319 			}
320 		};
321 
322 		documentListener = new DocumentListener() {
323 			@Override
324 			public void changedUpdate(DocumentEvent e) {
325 				GinaStackEvent stackElement = GENotifier.notifyMethod();
326 				textEdited(e);
327 				stackElement.end();
328 			}
329 
330 			@Override
331 			public void insertUpdate(DocumentEvent e) {
332 				GinaStackEvent stackElement = GENotifier.notifyMethod();
333 				textEdited(e);
334 				stackElement.end();
335 			}
336 
337 			@Override
338 			public void removeUpdate(DocumentEvent e) {
339 				GinaStackEvent stackElement = GENotifier.notifyMethod();
340 				textEdited(e);
341 				stackElement.end();
342 			}
343 
344 			public void textEdited(DocumentEvent e) {
345 				GinaStackEvent stackElement = GENotifier.notifyMethod();
346 				if (isProgrammaticalySet()) {
347 					stackElement.end();
348 					return;
349 				}
350 				String textValue = getTextField().getText();
351 				textIsEditing = true;
352 				try {
353 					synchronizeWithTextFieldValue(textValue);
354 				} finally {
355 					textIsEditing = false;
356 				}
357 				stackElement.end();
358 			}
359 		};
360 
361 		getTextField().addKeyListener(shortcutsKeyAdapter);
362 		getTextField().getDocument().addDocumentListener(documentListener);
363 		updateUI(); // Just to initiate the default color values
364 		// setEditedObjectAndUpdateBDAndOwner(editedObject);
365 		setEditedObject(editedObject);
366 
367 		/*
368 		 * (new Thread() {
369 		 * 
370 		 * @Override public void run() { while(true) { Component c =
371 		 * (KeyboardFocusManager
372 		 * .getCurrentKeyboardFocusManager().getFocusOwner()); if (c != null)
373 		 * System
374 		 * .out.println("focus owner = "+c.hashCode()+" "+c.getClass().getSimpleName
375 		 * ()+" is "+c); try { sleep(3000); } catch (InterruptedException e1) {
376 		 * // TODO Auto-generated catch block e1.printStackTrace(); } } }
377 		 * }).start();
378 		 */
379 
380 	}
381 
382 	@Override
383 	final public void updateUI() {
384 		super.updateUI();
385 		if (getTextField() != null) {
386 			defaultForeground = getTextField().getForeground();
387 			defaultSelectedColor = getTextField().getSelectedTextColor();
388 		}
389 	}
390 
391 	@Override
392 	public void init(FIBCustom component, FIBController controller) {
393 	}
394 
395 	@Override
396 	public Class<DataBinding> getRepresentedType() {
397 		return DataBinding.class;
398 	}
399 
400 	protected void synchronizeWithTextFieldValue(String textValue) {
401 		try {
402 			isUpdatingModel = true;
403 
404 			DataBinding<?> newEditedBinding = makeBindingFromString(textValue);
405 
406 			// System.out.println("Decoding binding as " + newEditedBinding + " valid=" + newEditedBinding.isValid());
407 
408 			if (newEditedBinding != null) {
409 				if (newEditedBinding.forceRevalidate()) {
410 					if (LOGGER.isLoggable(Level.FINE)) {
411 						LOGGER.fine("Decoded as VALID binding: " + newEditedBinding);
412 					}
413 					getTextField().setForeground(defaultForeground);
414 					getTextField().setSelectedTextColor(defaultSelectedColor);
415 
416 					getLabel().setVisible(true);
417 					getLabel().setIcon(UtilsIconLibrary.OK_ICON);
418 
419 					if (!newEditedBinding.equals(getEditedObject())) {
420 						if (LOGGER.isLoggable(Level.FINE)) {
421 							LOGGER.fine("This is a new one, i take this");
422 						}
423 						setEditedObject(newEditedBinding);
424 						fireEditedObjectChanged();
425 						return;
426 					}
427 					else {
428 						// Anyway, in case of it is the same object, but with
429 						// changes, we always fire fireEditedObjectChanged()
430 						checkIfDisplayModeShouldChange(newEditedBinding, true);
431 						fireEditedObjectChanged();
432 						if (LOGGER.isLoggable(Level.FINE)) {
433 							LOGGER.fine("Skipping as it represents the same binding");
434 						}
435 						return;
436 					}
437 				}
438 				else {
439 					if (LOGGER.isLoggable(Level.FINE)) {
440 						LOGGER.fine("Decoded as INVALID binding: " + newEditedBinding + " trying to synchronize panel");
441 					}
442 					getTextField().setForeground(Color.RED);
443 					getTextField().setSelectedTextColor(Color.RED);
444 					if (_selectorPanel != null) {
445 						_selectorPanel.synchronizePanelWithTextFieldValue(textValue);
446 						_selectorPanel.updateStatus(newEditedBinding);
447 					}
448 
449 					getLabel().setVisible(true);
450 					getLabel().setIcon(UtilsIconLibrary.ERROR_ICON);
451 
452 					return;
453 				}
454 			}
455 
456 			else {
457 				if (LOGGER.isLoggable(Level.FINE)) {
458 					LOGGER.fine("Couldn't decode as binding, trying to synchronize panel anyway");
459 				}
460 				LOGGER.info("Couldn't decode as binding, trying to synchronize panel anyway");
461 				getTextField().setForeground(Color.RED);
462 				getTextField().setSelectedTextColor(Color.RED);
463 				if (_selectorPanel != null) {
464 					_selectorPanel.synchronizePanelWithTextFieldValue(textValue);
465 				}
466 				return;
467 			}
468 
469 		} finally {
470 			isUpdatingModel = false;
471 		}
472 
473 	}
474 
475 	/*
476 	 * public void setEditedObjectAndUpdateBDAndOwner(AbstractBinding object) {
477 	 * setEditedObject(object); if (object != null) { if
478 	 * (object.getBindingDefinition() != null)
479 	 * setBindingDefinition(object.getBindingDefinition()); if
480 	 * (object.getOwner() != null) setBindable((Bindable)object.getOwner()); } }
481 	 */
482 
483 	@Override
484 	public void setEditedObject(DataBinding dataBinding) {
485 
486 		// logger.info("setEditedObject in BindingSelector with " +
487 		// dataBinding);
488 
489 		if (dataBinding == null) {
490 			// Mais des fois, c'est autorise quand meme, il faut donc tracer
491 			// tous les appels pour voir ceux qui sont legaux (sylvain)
492 			// logger.warning("forbidden setEditedObject(null) !!!");
493 			// Thread.dumpStack();
494 			return;
495 		}
496 
497 		setEditedObject(dataBinding, true);
498 		if (dataBinding != null && dataBinding.forceRevalidate()) {
499 			isConnected = true;
500 		}
501 
502 		if (dataBinding != null) {
503 			/*
504 			 * if (dataBinding.getBindingDefinition() != null) {
505 			 * setBindingDefinition(dataBinding.getBindingDefinition()); }
506 			 */
507 			if (dataBinding.getOwner() != null) {
508 				setBindable(dataBinding.getOwner());
509 			}
510 		}
511 		// SGU: I suppress this code that was the cause for huge problems
512 		// in BindingSelector, making it quite unusable
513 		// I don't think this code was usefull, was it ?
514 		/*
515 		 * else { setBindingDefinition(null); setBindable(null); }
516 		 */
517 	}
518 
519 	public void setEditedObject(DataBinding<?> dataBinding, boolean updateBindingSelectionMode) {
520 		// logger.info(">>>>>>>>>>>>>> setEditedObject() with "+object);
521 		if (updateBindingSelectionMode) {
522 			if (dataBinding != null) {
523 				dataBinding = checkIfDisplayModeShouldChange(dataBinding, false);
524 			}
525 			else {
526 				activateNormalBindingMode();
527 			}
528 		}
529 		super.setEditedObject(dataBinding);
530 
531 		if (getEditedObject() != null && getEditedObject().forceRevalidate()) {
532 			getTextField().setForeground(defaultForeground);
533 			getTextField().setSelectedTextColor(defaultSelectedColor);
534 		}
535 		else {
536 			getTextField().setForeground(Color.RED);
537 			getTextField().setSelectedTextColor(Color.RED);
538 		}
539 	}
540 
541 	/**
542 	 * This method is called as a hook allowing to change display mode
543 	 * 
544 	 * @param newDataBinding
545 	 * @param setValueAsNewEditedValue
546 	 * @return
547 	 */
548 	protected DataBinding<?> checkIfDisplayModeShouldChange(DataBinding<?> newDataBinding, boolean setValueAsNewEditedValue) {
549 		EditionMode oldEditionMode = editionMode;
550 		EditionMode newEditionMode = editionMode;
551 
552 		if (newDataBinding != null && newDataBinding.isSet()) {
553 			if (newDataBinding.isConstant()) {
554 				newEditionMode = EditionMode.STATIC_BINDING;
555 			}
556 			else if (newDataBinding.isBindingValue()) {
557 				if (((BindingValue) newDataBinding.getExpression()).isCompoundBinding() || newDataBinding.isExecutable()) {
558 					newEditionMode = EditionMode.COMPOUND_BINDING;
559 				}
560 				else if (oldEditionMode != EditionMode.NORMAL_BINDING && oldEditionMode != EditionMode.COMPOUND_BINDING) {
561 					newEditionMode = EditionMode.NORMAL_BINDING;
562 				}
563 			}
564 			else {
565 				newEditionMode = EditionMode.BINDING_EXPRESSION;
566 			}
567 		}
568 		else {
569 			newEditionMode = EditionMode.NORMAL_BINDING;
570 		}
571 
572 		if (LOGGER.isLoggable(Level.FINE)) {
573 			LOGGER.fine("DISPLAY_MODE was: " + oldEditionMode + " is now " + newEditionMode);
574 		}
575 
576 		boolean editedObjectChanged = false;
577 
578 		// Should i change edited object ???
579 		if (getEditedObject() != newDataBinding && setValueAsNewEditedValue) {
580 			if (LOGGER.isLoggable(Level.FINE)) {
581 				LOGGER.fine("Switching edited object from " + _editedObject + " to " + newDataBinding);
582 			}
583 			_editedObject = newDataBinding;
584 			editedObjectChanged = true;
585 		}
586 
587 		if (oldEditionMode.useCommonPanel() != newEditionMode.useCommonPanel()) {
588 			if (newEditionMode.useCommonPanel()) {
589 				if (newEditionMode == EditionMode.COMPOUND_BINDING) {
590 					activateCompoundBindingMode();
591 				}
592 				else {
593 					activateNormalBindingMode();
594 				}
595 			}
596 			else if (newDataBinding.isExpression()) {
597 				activateBindingExpressionMode();
598 			}
599 		}
600 		if (oldEditionMode != EditionMode.COMPOUND_BINDING && newEditionMode == EditionMode.COMPOUND_BINDING) {
601 			activateCompoundBindingMode();
602 		}
603 
604 		editionMode = newEditionMode;
605 
606 		// Should i change edited object ???
607 		/*
608 		 * if (returned != dataBinding && setValueAsNewEditedValue) { if
609 		 * (logger.isLoggable(Level.FINE)) {
610 		 * logger.fine("Switching edited object from " + dataBinding + " to " +
611 		 * returned); } _editedObject = returned;
612 		 * updateCustomPanel(getEditedObject()); }
613 		 */
614 		if (editedObjectChanged) {
615 			updateCustomPanel(getEditedObject());
616 		}
617 
618 		return newDataBinding;
619 	}
620 
621 	public boolean isConnected() {
622 		return isConnected;
623 	}
624 
625 	public void connect() {
626 		if (getEditedObject().forceRevalidate()) {
627 			// logger.info("Is connected = TRUE");
628 			isConnected = true;
629 		}
630 	}
631 
632 	public void disconnect() {
633 		// logger.info("Is connected = FALSE");
634 		isConnected = false;
635 	}
636 
637 	boolean isKeyPathValid(String pathIgnoringLastPart) {
638 		if (!(_selectorPanel instanceof BindingValueSelectorPanel)) {
639 			return false;
640 		}
641 		StringTokenizer token = new StringTokenizer(pathIgnoringLastPart, ".", false);
642 		Object obj = null;
643 		int i = 0;
644 		while (token.hasMoreTokens()) {
645 			obj = ((BindingValueSelectorPanel) _selectorPanel)
646 					.findElementEquals(((BindingValueSelectorPanel) _selectorPanel).listAtIndex(i).getModel(), token.nextToken());
647 			if (obj == null) {
648 				return false;
649 			}
650 			i++;
651 		}
652 		return true;
653 	}
654 
655 	@Override
656 	public void fireEditedObjectChanged() {
657 		if (getEditedObject() == null || !getEditedObject().forceRevalidate()) {
658 			disconnect();
659 		}
660 		updateCustomPanel(getEditedObject());
661 		if (!getIsUpdatingModel()) {
662 			_isProgrammaticalySet = true;
663 			if (!textIsEditing) {
664 				getTextField().setText(renderedString(getEditedObject()));
665 			}
666 			if (getEditedObject() != null) {
667 				getTextField().setForeground(getEditedObject().isValid() ? defaultForeground : Color.RED);
668 				getTextField().setSelectedTextColor(getEditedObject().isValid() ? defaultSelectedColor : Color.RED);
669 			}
670 			else {
671 				getTextField().setForeground(Color.RED);
672 				getTextField().setSelectedTextColor(Color.RED);
673 			}
674 			_isProgrammaticalySet = false;
675 		}
676 		if (getEditedObject() != null && getEditedObject().getOwner() != null) {
677 			getEditedObject().notifyBindingChanged(null, getEditedObject().getExpression());
678 		}
679 	}
680 
681 	public boolean areCompoundBindingAllowed() {
682 		// if (getBindingDefinition() != null &&
683 		// getBindingDefinition().getIsSettable()) return false;
684 		return _allowsCompoundBindings;
685 	}
686 
687 	public void allowsCompoundBindings() {
688 		_allowsCompoundBindings = true;
689 		rebuildPopup();
690 	}
691 
692 	public void denyCompoundBindings() {
693 		_allowsCompoundBindings = false;
694 		rebuildPopup();
695 	}
696 
697 	public boolean areBindingExpressionsAllowed() {
698 		DataBinding<?> db = getEditedObject();
699 		if (db != null && (db.isSettable() || db.isExecutable())) {
700 			return false;
701 		}
702 		return _allowsBindingExpressions;
703 	}
704 
705 	public void allowsBindingExpressions() {
706 		_allowsBindingExpressions = true;
707 		rebuildPopup();
708 	}
709 
710 	public void denyBindingExpressions() {
711 		_allowsBindingExpressions = false;
712 		rebuildPopup();
713 	}
714 
715 	public boolean areStaticValuesAllowed() {
716 		if (getEditedObject() != null && getEditedObject().isSettable()) {
717 			return false;
718 		}
719 		return _allowsStaticValues;
720 	}
721 
722 	public void allowsStaticValues() {
723 		_allowsStaticValues = true;
724 		rebuildPopup();
725 	}
726 
727 	public void denyStaticValues() {
728 		_allowsStaticValues = false;
729 		rebuildPopup();
730 	}
731 
732 	private void rebuildPopup() {
733 		boolean showAgain = false;
734 		if (popupIsShown()) {
735 			showAgain = true;
736 			closePopup(false);
737 		}
738 		deletePopup();
739 		if (showAgain) {
740 			openPopup();
741 			updateCustomPanel(getEditedObject());
742 		}
743 	}
744 
745 	public void activateCompoundBindingMode() {
746 		GinaStackEvent stackElement = GENotifier.notifyMethod();
747 
748 		if (LOGGER.isLoggable(Level.FINE)) {
749 			LOGGER.fine("ActivateCompoundBindingMode() getEditedObject()=" + getEditedObject() + " editionMode=" + editionMode
750 					+ " popupIsShown()=" + popupIsShown() + " _selectorPanel=" + _selectorPanel);
751 		}
752 		if (_selectorPanel != null && editionMode != EditionMode.COMPOUND_BINDING) {
753 			editionMode = EditionMode.COMPOUND_BINDING;
754 			boolean showAgain = false;
755 			if (popupIsShown()) {
756 				showAgain = true;
757 				closePopup(false);
758 			}
759 			if (getEditedObject() != null && !getEditedObject().isBindingValue()) {
760 				_editedObject.setExpression(makeBinding()); // I dont want to
761 															// notify it !!!
762 				fireEditedObjectChanged();
763 			}
764 			deleteCustomPanel();
765 			if (showAgain) {
766 				openPopup();
767 				updateCustomPanel(getEditedObject());
768 			}
769 		}
770 		editionMode = EditionMode.COMPOUND_BINDING;
771 
772 		stackElement.end();
773 	}
774 
775 	public void activateNormalBindingMode() {
776 		GinaStackEvent stackElement = GENotifier.notifyMethod();
777 
778 		if (LOGGER.isLoggable(Level.FINE)) {
779 			LOGGER.fine("activateNormalBindingMode()");
780 		}
781 		if (_selectorPanel != null && editionMode != EditionMode.NORMAL_BINDING) {
782 			editionMode = EditionMode.NORMAL_BINDING;
783 			boolean showAgain = false;
784 			if (popupIsShown()) {
785 				showAgain = true;
786 				closePopup(false);
787 			}
788 			// sylvain: i don't understand this code, i suppressed it
789 			/*
790 			 * if (getEditedObject() != null &&
791 			 * !(getEditedObject().isBindingValue())) {
792 			 * getEditedObject().setExpression(makeBinding()); // I dont want to
793 			 * notify it !!! fireEditedObjectChanged(); }
794 			 */
795 			deleteCustomPanel();
796 			if (showAgain) {
797 				openPopup();
798 				updateCustomPanel(getEditedObject());
799 			}
800 		}
801 		editionMode = EditionMode.NORMAL_BINDING;
802 
803 		stackElement.end();
804 	}
805 
806 	public void activateBindingExpressionMode(/* Expression bindingExpression */) {
807 		GinaStackEvent stackElement = GENotifier.notifyMethod();
808 
809 		if (LOGGER.isLoggable(Level.FINE)) {
810 			LOGGER.fine("activateBindingExpressionMode()");
811 		}
812 		if (_selectorPanel != null) {
813 			editionMode = EditionMode.BINDING_EXPRESSION;
814 			boolean showAgain = false;
815 			if (popupIsShown()) {
816 				showAgain = true;
817 				closePopup(false);
818 			}
819 			/*
820 			 * if (bindingExpression != null) { _editedObject =
821 			 * bindingExpression; } else { _editedObject = new
822 			 * BindingExpression(getBindingDefinition(), getBindable()); // I
823 			 * dont want to notify it !!! }
824 			 */
825 			deleteCustomPanel();
826 			if (showAgain) {
827 				openPopup();
828 				updateCustomPanel(getEditedObject());
829 			}
830 		}
831 
832 		stackElement.end();
833 	}
834 
835 	@Override
836 	public void delete() {
837 		// System.out.println("Deleting BindingSelector for " +
838 		// getEditedObject());
839 		super.delete();
840 		unregisterListenerForBindable();
841 		// unregisterListenerForBindingDefinition();
842 		if (_selectorPanel != null) {
843 			_selectorPanel.delete();
844 		}
845 		_selectorPanel = null;
846 		_bindable = null;
847 	}
848 
849 	@Override
850 	protected void deleteCustomPanel() {
851 		super.deleteCustomPanel();
852 		if (_selectorPanel != null) {
853 			_selectorPanel.delete();
854 		}
855 		_selectorPanel = null;
856 	}
857 
858 	@Override
859 	public void setRevertValue(DataBinding oldValue) {
860 		if (oldValue != null) {
861 			_revertBindingValue = oldValue.clone();
862 		}
863 		else {
864 			_revertBindingValue = null;
865 		}
866 	}
867 
868 	@Override
869 	public DataBinding getRevertValue() {
870 		return _revertBindingValue;
871 	}
872 
873 	@Override
874 	protected ResizablePanel createCustomPanel(DataBinding editedObject) {
875 		if (editionMode == EditionMode.BINDING_EXPRESSION) {
876 			_selectorPanel = new BindingExpressionSelectorPanel(this);
877 			_selectorPanel.init();
878 		}
879 		/*
880 		 * else if (editionMode == EditionMode.NEW_ENTRY) { _selectorPanel = new
881 		 * BindingExpressionSelectorPanel(this); _selectorPanel.init();sqddqs }
882 		 */
883 		else {
884 			// When creating use normal mode
885 			if (editedObject == null || editedObject.isConstant()) {
886 				editionMode = EditionMode.NORMAL_BINDING;
887 			}
888 			_selectorPanel = new BindingValueSelectorPanel(this);
889 			_selectorPanel.init();
890 		}
891 		refreshBindingModel();
892 		return _selectorPanel;
893 	}
894 
895 	public void refreshBindingModel() {
896 		if (_bindable != null && _selectorPanel != null) {
897 			_selectorPanel.update();
898 		}
899 	}
900 
901 	@Override
902 	public void updateCustomPanel(DataBinding editedObject) {
903 		if (LOGGER.isLoggable(Level.FINE)) {
904 			LOGGER.fine("updateCustomPanel() with " + editedObject);
905 		}
906 		if (_selectorPanel != null) {
907 			// logger.info("Updating custom panel with " +
908 			// editedObject.getExpression());
909 			_selectorPanel.update();
910 		}
911 		if (editedObject != null) {
912 			if (editedObject.isSet()) {
913 				if (editedObject.forceRevalidate()) {
914 					getLabel().setVisible(true);
915 					getLabel().setIcon(UtilsIconLibrary.OK_ICON);
916 				}
917 				else {
918 					// Unused Bindable owner =
919 					editedObject.getOwner();
920 					LOGGER.info("Binding not valid: " + editedObject + " reason=" + editedObject.invalidBindingReason());
921 					/*
922 					 * if (editedObject.isBindingValue()) { BindingValue bv =
923 					 * (BindingValue) (editedObject.getExpression());
924 					 * System.out.println("BV=" + bv);
925 					 * System.out.println("valid=" + bv.isValid());
926 					 * System.out.println("reason=" +
927 					 * bv.invalidBindingReason()); for (BindingPathElement bpe :
928 					 * bv.getBindingPath()) { System.out.println("> " + bpe); if
929 					 * (
930 					 * bpe.getSerializationRepresentation().equals("substring(2)"
931 					 * )) { System.out.println("Valid=" +
932 					 * editedObject.isValid());
933 					 * System.out.println("On s'arrete");
934 					 * editedObject.isValid(); } } }
935 					 */
936 					getLabel().setVisible(true);
937 					getLabel().setIcon(UtilsIconLibrary.ERROR_ICON);
938 				}
939 			}
940 			else {
941 				if (editedObject.isMandatory()) {
942 					getLabel().setVisible(true);
943 					getLabel().setIcon(UtilsIconLibrary.WARNING_ICON);
944 				}
945 				else {
946 					getLabel().setVisible(false);
947 				}
948 			}
949 		}
950 		else {
951 			getLabel().setVisible(true);
952 			getLabel().setIcon(UtilsIconLibrary.ERROR_ICON);
953 		}
954 	}
955 
956 	public void resetMethodCallPanel() {
957 		if (_selectorPanel != null && _selectorPanel instanceof BindingValueSelectorPanel) {
958 			((BindingValueSelectorPanel) _selectorPanel).resetMethodCallPanel();
959 		}
960 	}
961 
962 	@Override
963 	public String renderedString(DataBinding editedObject) {
964 		if (editedObject != null) {
965 			// System.out.println("Try to render " + editedObject);
966 			return editedObject.toString();
967 		}
968 		return "";
969 	}
970 
971 	public Bindable getBindable() {
972 		if (_bindable == null && getEditedObject() != null) {
973 			return getEditedObject().getOwner();
974 		}
975 		return _bindable;
976 	}
977 
978 	@CustomComponentParameter(name = "bindable", type = CustomComponentParameter.Type.MANDATORY)
979 	public void setBindable(Bindable bindable) {
980 		if (LOGGER.isLoggable(Level.FINE)) {
981 			LOGGER.fine("setBindable with " + bindable);
982 		}
983 		unregisterListenerForBindable();
984 		_bindable = bindable;
985 		if (bindable != null && _selectorPanel != null) {
986 			_selectorPanel.fireBindableChanged();
987 		}
988 		registerListenerForBindable();
989 		// getCustomPanel().setBindingModel(bindable.getBindingModel());
990 		updateTextFieldProgrammaticaly();
991 	}
992 
993 	public void registerListenerForBindable() {
994 		if (_bindable instanceof Observable) {
995 			((Observable) _bindable).addObserver(this);
996 		}
997 		if (_bindable instanceof HasPropertyChangeSupport) {
998 			// System.out.println("registering " + bindable + " for " + this);
999 			if (((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport() != null) {
1000 				((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport()
1001 						.addPropertyChangeListener(BindingModelChanged.BINDING_MODEL_CHANGED, this);
1002 			}
1003 		}
1004 	}
1005 
1006 	public void unregisterListenerForBindable() {
1007 		if (_bindable instanceof Observable) {
1008 			((Observable) _bindable).deleteObserver(this);
1009 		}
1010 		if (_bindable instanceof HasPropertyChangeSupport) {
1011 			if (((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport() != null) {
1012 				((HasPropertyChangeSupport) _bindable).getPropertyChangeSupport().removePropertyChangeListener(this);
1013 			}
1014 		}
1015 	}
1016 
1017 	@Override
1018 	public void updateTextFieldProgrammaticaly() {
1019 		// Don't update textfield if original event was triggered by a textfield
1020 		// edition
1021 		if (!textIsEditing) {
1022 			super.updateTextFieldProgrammaticaly();
1023 		}
1024 	}
1025 
1026 	@Override
1027 	public void update(Observable observable, Object notification) {
1028 		if (observable == _bindable) {
1029 			if (notification instanceof BindingModelChanged) {
1030 				LOGGER.fine("Refreshing Binding Model");
1031 				refreshBindingModel();
1032 			}
1033 		}
1034 		/*
1035 		 * if (observable == _bindingDefinition) { if (notification instanceof
1036 		 * BindingDefinitionTypeChanged) {
1037 		 * logger.fine("Updating BindingDefinition type");
1038 		 * refreshBindingDefinitionType(); } }
1039 		 */
1040 	}
1041 
1042 	@Override
1043 	public void propertyChange(PropertyChangeEvent evt) {
1044 		GinaStackEvent stackElement = GENotifier.notifyMethod();
1045 
1046 		if (evt.getPropertyName().equals(BindingModelChanged.BINDING_MODEL_CHANGED)) {
1047 			// System.out.println("!!!!!!!!!!!!!! propertyChange() " +
1048 			// evt.getPropertyName() + " evt=" + evt + " called in " + this);
1049 
1050 			if (_selectorPanel != null && _selectorPanel instanceof BindingValueSelectorPanel) {
1051 				((BindingValueSelectorPanel) _selectorPanel).updateListModels();
1052 			}
1053 
1054 			LOGGER.fine("Refreshing Binding Model");
1055 			refreshBindingModel();
1056 		} /*
1057 			* else if (evt.getPropertyName().equals(BindingDefinitionTypeChanged.
1058 			* BINDING_DEFINITION_TYPE_CHANGED)) {
1059 			* logger.fine("Updating BindingDefinition type");
1060 			* refreshBindingDefinitionType(); }
1061 			*/
1062 
1063 		stackElement.end();
1064 	}
1065 
1066 	/*
1067 	 * public void setCustomBindingModel(BindingModel aBindingModel) {
1068 	 * setBindingModel(aBindingModel); }
1069 	 */
1070 
1071 	/*
1072 	 * private BindingDefinition _bindingDefinitionForSelector = null;
1073 	 * 
1074 	 * public BindingDefinition getBindingDefinition() { if (getCustomPanel() !=
1075 	 * null) return getCustomPanel().getBindingDefinition(); return
1076 	 * _bindingDefinitionForSelector;dqsdsq }
1077 	 * 
1078 	 * public void setBindingDefinition(BindingDefinition bindingDefinition) {
1079 	 * if (logger.isLoggable(Level.FINE))
1080 	 * logger.fine("setBindingDefinition with " + bindingDefinition);
1081 	 * getCustomPanel().setBindingDefinition(bindingDefinition); }
1082 	 */
1083 
1084 	// BindingDefinition _bindingDefinition;
1085 
1086 	// BindingModel _bindingModel;
1087 
1088 	/*
1089 	 * public BindingDefinition getBindingDefinition() { return
1090 	 * _bindingDefinition; }
1091 	 * 
1092 	 * @CustomComponentParameter(name = "bindingDefinition", type =
1093 	 * CustomComponentParameter.Type.MANDATORY) public void
1094 	 * setBindingDefinition(BindingDefinition bindingDefinition) { if
1095 	 * (logger.isLoggable(Level.FINE)) { logger.fine(toString() +
1096 	 * "Setting new binding definition: " + bindingDefinition + " old: " +
1097 	 * _bindingDefinition); } if (bindingDefinition != _bindingDefinition) {
1098 	 * unregisterListenerForBindingDefinition(); _bindingDefinition =
1099 	 * bindingDefinition; DataBinding bindingValue = getEditedObject(); if
1100 	 * (bindingValue != null) {
1101 	 * bindingValue.setBindingDefinition(bindingDefinition); if
1102 	 * (logger.isLoggable(Level.FINE)) { logger.fine("set BD " +
1103 	 * bindingDefinition + " for BV " + bindingValue); } } if (_selectorPanel !=
1104 	 * null) { _selectorPanel.fireBindingDefinitionChanged(); }
1105 	 * registerListenerForBindingDefinition();
1106 	 * updateCustomPanel(getEditedObject()); } }
1107 	 */
1108 
1109 	/*
1110 	 * public void registerListenerForBindingDefinition() { if
1111 	 * (_bindingDefinition instanceof Observable) { ((Observable)
1112 	 * _bindingDefinition).addObserver(this); } if (_bindingDefinition
1113 	 * instanceof HasPropertyChangeSupport) { ((HasPropertyChangeSupport)
1114 	 * _bindingDefinition).getPropertyChangeSupport().addPropertyChangeListener(
1115 	 * BindingDefinitionTypeChanged.BINDING_DEFINITION_TYPE_CHANGED, this);
1116 	 * ((HasPropertyChangeSupport)
1117 	 * _bindingDefinition).getPropertyChangeSupport()
1118 	 * .addPropertyChangeListener(this); } }
1119 	 */
1120 
1121 	/*
1122 	 * public void unregisterListenerForBindingDefinition() { if
1123 	 * (_bindingDefinition instanceof Observable) { ((Observable)
1124 	 * _bindingDefinition).deleteObserver(this); } if (_bindingDefinition
1125 	 * instanceof HasPropertyChangeSupport) { ((HasPropertyChangeSupport)
1126 	 * _bindingDefinition
1127 	 * ).getPropertyChangeSupport().removePropertyChangeListener(
1128 	 * BindingDefinitionTypeChanged.BINDING_DEFINITION_TYPE_CHANGED, this);
1129 	 * ((HasPropertyChangeSupport)
1130 	 * _bindingDefinition).getPropertyChangeSupport()
1131 	 * .removePropertyChangeListener(this); } }
1132 	 */
1133 
1134 	public BindingModel getBindingModel() {
1135 		if (getBindable() != null) {
1136 			return getBindable().getBindingModel();
1137 		}
1138 		return null;
1139 	}
1140 
1141 	@Override
1142 	public AbstractBindingSelectorPanel getCustomPanel() {
1143 		return (AbstractBindingSelectorPanel) super.getCustomPanel();
1144 	}
1145 
1146 	/*
1147 	 * protected Expression makeBindingExpression() { (new
1148 	 * Exception("Qui m'appelle la ?")).printStackTrace(); return new
1149 	 * Variable(""); }
1150 	 */
1151 
1152 	protected Expression makeBinding() {
1153 
1154 		BindingValue newBindingValue = new BindingValue();
1155 		newBindingValue.setDataBinding(getEditedObject());
1156 		return newBindingValue;
1157 
1158 		/*
1159 		 * Expression returned = null; if (editionMode ==
1160 		 * EditionMode.BINDING_EXPRESSION) { if (getBindingDefinition() != null
1161 		 * && getBindable() != null) { returned = makeBindingExpression(); } }
1162 		 * else if (editionMode == EditionMode.STATIC_BINDING) { if
1163 		 * (getBindingDefinition() != null && getBindable() != null) { if
1164 		 * (getBindingDefinition().getType() != null) { if
1165 		 * (TypeUtils.isBoolean(getBindingDefinition().getType())) { return
1166 		 * BooleanConstant.FALSE; } else if
1167 		 * (TypeUtils.isInteger(getBindingDefinition().getType()) ||
1168 		 * TypeUtils.isLong(getBindingDefinition().getType()) ||
1169 		 * TypeUtils.isShort(getBindingDefinition().getType()) ||
1170 		 * TypeUtils.isChar(getBindingDefinition().getType()) ||
1171 		 * TypeUtils.isByte(getBindingDefinition().getType())) { returned = new
1172 		 * Constant.IntegerConstant(0); } else if
1173 		 * (TypeUtils.isFloat(getBindingDefinition().getType()) ||
1174 		 * TypeUtils.isDouble(getBindingDefinition().getType())) { returned =
1175 		 * new Constant.FloatConstant(0); } } else if
1176 		 * (TypeUtils.isString(getBindingDefinition().getType())) { returned =
1177 		 * new Constant.StringConstant(""); } } } else if (editionMode ==
1178 		 * EditionMode.NORMAL_BINDING || editionMode ==
1179 		 * EditionMode.COMPOUND_BINDING) { // Normal or compound binding if
1180 		 * (getBindingDefinition() != null && getBindable() != null) { returned
1181 		 * = new BindingValue(); } } return returned;
1182 		 */
1183 	}
1184 
1185 	void recreateBindingValue() {
1186 		getEditedObject().setExpression(makeBinding());
1187 		fireEditedObjectChanged();
1188 		LOGGER.info("Recreating Binding with mode " + editionMode + " as " + getEditedObject());
1189 	}
1190 
1191 	Bindable _bindable;
1192 
1193 	@Override
1194 	protected CustomJPopupMenu makePopup() {
1195 		CustomJPopupMenu returned = super.makePopup();
1196 
1197 		// This call is very important, because during popup creation (opening),
1198 		// we don't want
1199 		// the popup retrieve the focus
1200 		// FocusableWindowState will be set to true again later during textfield
1201 		// focus retrieving
1202 		returned.setFocusableWindowState(false);
1203 		return returned;
1204 	}
1205 
1206 	@Override
1207 	protected void openPopup() {
1208 
1209 		boolean requestFocus = getTextField().hasFocus();
1210 
1211 		if (_selectorPanel != null) {
1212 			if (_selectorPanel instanceof BindingValueSelectorPanel) {
1213 				JList<?> list = ((BindingValueSelectorPanel) _selectorPanel).listAtIndex(0);
1214 				if (list.getModel().getSize() == 1) {
1215 					list.setSelectedIndex(0);
1216 				}
1217 			}
1218 		}
1219 		super.openPopup();
1220 
1221 		if (_selectorPanel != null) {
1222 			ButtonsControlPanel controlPanel = null;
1223 			if (_selectorPanel instanceof BindingValueSelectorPanel) {
1224 				controlPanel = ((BindingValueSelectorPanel) _selectorPanel)._controlPanel;
1225 			}
1226 			else if (_selectorPanel instanceof BindingExpressionSelectorPanel) {
1227 				controlPanel = ((BindingExpressionSelectorPanel) _selectorPanel)._controlPanel;
1228 			}
1229 			if (controlPanel != null) {
1230 				controlPanel.applyFocusTraversablePolicyTo(controlPanel, false);
1231 			}
1232 		}
1233 
1234 		if (requestFocus) {
1235 
1236 			// Tricky area
1237 			// The goal here is to retrieve the same state of textfield before
1238 			// opening the panel
1239 			// Basically we request the focus, but just before to do it, we save
1240 			// textfield selection parameters
1241 
1242 			LOGGER.info("Request focus in " + getTextField());
1243 
1244 			// We should embedd all this code in an InvokeLater block, because
1245 			// we should do all this stuff after the
1246 			// EventDispatchThread has processed the popup windiw opening
1247 			SwingUtilities.invokeLater(new Runnable() {
1248 				@Override
1249 				public void run() {
1250 
1251 					// We first store the required values
1252 					final int selectionStart = getTextField().getSelectionStart();
1253 					final int selectionEnd = getTextField().getSelectionEnd();
1254 					final int caretPosition = getTextField().getCaretPosition();
1255 
1256 					// Then we create a register a temporary FocusListener which
1257 					// is in charge
1258 					// of detecting the actual focus retrieving (because the
1259 					// focus requesting is also delayed for further
1260 					// processing by the EventDispatchThread
1261 					getTextField().addFocusListener(new FocusListener() {
1262 						@Override
1263 						public void focusLost(FocusEvent arg0) {
1264 							// Don't care
1265 						}
1266 
1267 						@Override
1268 						public void focusGained(FocusEvent arg0) {
1269 							// Now, the could set the values
1270 							getTextField().setSelectionStart(selectionStart);
1271 							getTextField().setSelectionEnd(selectionEnd);
1272 							getTextField().setCaretPosition(caretPosition);
1273 							// And remove this FocusListener
1274 							getTextField().removeFocusListener(this);
1275 
1276 							// Back to focusable window state
1277 							// (which has been set to false during popup
1278 							// creation)
1279 							_popup.setFocusableWindowState(true);
1280 
1281 						}
1282 					});
1283 
1284 					// And we request the focus
1285 					getTextField().requestFocus(false);
1286 				}
1287 			});
1288 		}
1289 
1290 		else {
1291 			// Back to focusable window state
1292 			// (which has been set to false during popup creation)
1293 			_popup.setFocusableWindowState(true);
1294 
1295 		}
1296 
1297 	}
1298 
1299 	@Override
1300 	public void closePopup() {
1301 		super.closePopup();
1302 		// logger.info("closePopup()");
1303 		SwingUtilities.invokeLater(new Runnable() {
1304 			@Override
1305 			public void run() {
1306 				getTextField().requestFocusInWindow();
1307 			}
1308 		});
1309 	}
1310 
1311 	@Override
1312 	public void apply() {
1313 		GinaStackEvent stackElement = GENotifier.notifyMethod();
1314 
1315 		if (_selectorPanel != null) {
1316 			_selectorPanel.willApply();
1317 		}
1318 		DataBinding<?> dataBinding = getEditedObject();
1319 		if (dataBinding != null) {
1320 			if (dataBinding.forceRevalidate()) {
1321 				/*
1322 				 * if (bindingValue instanceof BindingValue) { ((BindingValue)
1323 				 * bindingValue).connect(); }
1324 				 */
1325 				connect();
1326 				getTextField().setForeground(defaultForeground);
1327 				getTextField().setSelectedTextColor(defaultSelectedColor);
1328 			}
1329 			else {
1330 				getTextField().setForeground(Color.RED);
1331 				getTextField().setSelectedTextColor(Color.RED);
1332 			}
1333 			_revertBindingValue = dataBinding.clone();
1334 		}
1335 		updateTextFieldProgrammaticaly();
1336 		if (popupIsShown()) {
1337 			closePopup();
1338 		}
1339 		super.apply();
1340 
1341 		stackElement.end();
1342 	}
1343 
1344 	@Override
1345 	public void cancel() {
1346 		GinaStackEvent stackElement = GENotifier.notifyMethod();
1347 
1348 		if (_revertBindingValue != null) {
1349 			if (_revertBindingValue.getOwner() != null && _revertBindingValue.forceRevalidate()) {
1350 				setEditedObject(_revertBindingValue);
1351 			}
1352 		}
1353 		closePopup();
1354 		super.cancel();
1355 
1356 		stackElement.end();
1357 	}
1358 
1359 	@Override
1360 	protected void pointerLeavesPopup() {
1361 		cancel();
1362 	}
1363 
1364 	public boolean getIsUpdatingModel() {
1365 		return isUpdatingModel;
1366 	}
1367 
1368 	public void setUpdatingModel(boolean isUpdatingModelFlag) {
1369 		this.isUpdatingModel = isUpdatingModelFlag;
1370 	}
1371 
1372 	boolean isAcceptableStaticBindingValue(String stringValue) {
1373 		if (getEditedObject() == null) {
1374 			return false;
1375 		}
1376 		if (getEditedObject().getDeclaredType() == null) {
1377 			return false;
1378 		}
1379 		Constant<?> b = makeStaticBindingFromString(stringValue);
1380 		if (b == null) {
1381 			return false;
1382 		}
1383 		if (TypeUtils.isObject(getEditedObject().getDeclaredType()) && !stringValue.endsWith(".")) {
1384 			return true;
1385 		}
1386 		if (TypeUtils.isBoolean(getEditedObject().getDeclaredType())) {
1387 			return b instanceof BooleanConstant;
1388 		}
1389 		else if (TypeUtils.isInteger(getEditedObject().getDeclaredType()) || TypeUtils.isLong(getEditedObject().getDeclaredType())
1390 				|| TypeUtils.isShort(getEditedObject().getDeclaredType()) || TypeUtils.isChar(getEditedObject().getDeclaredType())
1391 				|| TypeUtils.isByte(getEditedObject().getDeclaredType())) {
1392 			return b instanceof IntegerConstant;
1393 		}
1394 		else if (TypeUtils.isFloat(getEditedObject().getDeclaredType()) || TypeUtils.isDouble(getEditedObject().getDeclaredType())) {
1395 			if (stringValue.endsWith(".")) {
1396 				return false;
1397 			}
1398 			return b instanceof IntegerConstant || b instanceof FloatConstant;
1399 		}
1400 		else if (TypeUtils.isString(getEditedObject().getDeclaredType())) {
1401 			return b instanceof StringConstant;
1402 		}
1403 		return false;
1404 	}
1405 
1406 	private static boolean isAcceptableAsBeginningOfBooleanStaticBindingValue(String stringValue) {
1407 		if (stringValue.length() > 0) {
1408 			if (stringValue.length() <= 4 && "true".substring(0, stringValue.length()).equalsIgnoreCase(stringValue)) {
1409 				return true;
1410 			}
1411 			if (stringValue.length() <= 5 && "false".substring(0, stringValue.length()).equalsIgnoreCase(stringValue)) {
1412 				return true;
1413 			}
1414 			return false;
1415 		}
1416 		else {
1417 			return true;
1418 		}
1419 	}
1420 
1421 	boolean isAcceptableAsBeginningOfStringStaticBindingValue(String stringValue) {
1422 		if (stringValue.length() > 0) {
1423 			if (stringValue.indexOf("\"") == 0 || stringValue.indexOf("'") == 0) {
1424 				return true;
1425 			}
1426 			return false;
1427 		}
1428 		else {
1429 			return true;
1430 		}
1431 	}
1432 
1433 	boolean isAcceptableAsBeginningOfStaticBindingValue(String stringValue) {
1434 		// logger.info("isAcceptableAsBeginningOfStaticBindingValue for ? "+stringValue+" project="+getProject()+"
1435 		// bd="+getBindingDefinition());
1436 		if (getEditedObject() == null) {
1437 			return false;
1438 		}
1439 
1440 		if (stringValue.length() == 0) {
1441 			return true;
1442 		}
1443 
1444 		if (TypeUtils.isObject(getEditedObject().getDeclaredType())) {
1445 			// In this case, any of matching is enough
1446 			return isAcceptableStaticBindingValue(stringValue) && !stringValue.endsWith(".") // Special case to handle
1447 																								// float on-the-fly
1448 					// typing
1449 					|| isAcceptableAsBeginningOfBooleanStaticBindingValue(stringValue)
1450 					|| isAcceptableAsBeginningOfStringStaticBindingValue(stringValue);
1451 		}
1452 
1453 		if (TypeUtils.isBoolean(getEditedObject().getDeclaredType())) {
1454 			return isAcceptableAsBeginningOfBooleanStaticBindingValue(stringValue);
1455 		}
1456 		else if (TypeUtils.isInteger(getEditedObject().getDeclaredType()) || TypeUtils.isLong(getEditedObject().getDeclaredType())
1457 				|| TypeUtils.isShort(getEditedObject().getDeclaredType()) || TypeUtils.isChar(getEditedObject().getDeclaredType())
1458 				|| TypeUtils.isByte(getEditedObject().getDeclaredType())) {
1459 			return isAcceptableStaticBindingValue(stringValue);
1460 		}
1461 		else if (TypeUtils.isFloat(getEditedObject().getDeclaredType()) || TypeUtils.isDouble(getEditedObject().getDeclaredType())) {
1462 			if (stringValue.endsWith(".") && stringValue.length() > 1) {
1463 				return isAcceptableStaticBindingValue(stringValue.substring(0, stringValue.length() - 1));
1464 			}
1465 			return isAcceptableStaticBindingValue(stringValue);
1466 		}
1467 		else if (TypeUtils.isString(getEditedObject().getDeclaredType())) {
1468 			return isAcceptableAsBeginningOfStringStaticBindingValue(stringValue);
1469 		}
1470 		return false;
1471 	}
1472 
1473 	Constant<?> makeStaticBindingFromString(String stringValue) {
1474 		Expression e;
1475 		try {
1476 			e = ExpressionParser.parse(stringValue);
1477 			if (e instanceof Constant) {
1478 				return (Constant<?>) e;
1479 			}
1480 		} catch (ParseException e1) {
1481 			// e1.printStackTrace();
1482 		}
1483 		return null;
1484 	}
1485 
1486 	DataBinding<?> makeBindingFromString(String stringValue) {
1487 
1488 		DataBinding<?> returned = new DataBinding<>(stringValue, getBindable(), getEditedObject());
1489 		returned.decode();
1490 		return returned;
1491 
1492 		/*
1493 		 * if (getEditedObject() != null) {
1494 		 * getEditedObject().setUnparsedBinding(stringValue);
1495 		 * getEditedObject().decode(); return getEditedObject(); }
1496 		 */
1497 		/*
1498 		 * if (getBindable() != null) { DataBinding<?> returned = new
1499 		 * DataBinding<Object>(stringValue, getBindable(),
1500 		 * getBindingDefinition().getType(),
1501 		 * getBindingDefinition().getBindingDefinitionType());
1502 		 * returned.decode(); return returned; }
1503 		 */
1504 		// logger.warning("Cannot build binding: null DataBinding !");
1505 		// return null;
1506 	}
1507 
1508 	boolean textFieldSynchWithEditedObject() {
1509 		if (StringUtils.isEmpty(getTextField().getText())) {
1510 			return getEditedObject() == null || StringUtils.isEmpty(renderedString(getEditedObject()));
1511 		}
1512 		return getTextField().getText() != null && getTextField().getText().equals(renderedString(getEditedObject()));
1513 	}
1514 
1515 	boolean textFieldNotSynchWithEditedObject() {
1516 		return !textFieldSynchWithEditedObject();
1517 	}
1518 
1519 	public static class TestBindable extends DefaultBindable {
1520 		private final BindingFactory bindingFactory = new JavaBindingFactory();
1521 		private final BindingModel bindingModel = new BindingModel();
1522 
1523 		public TestBindable() {
1524 			bindingModel.addToBindingVariables(new BindingVariable("aString", String.class));
1525 			bindingModel.addToBindingVariables(new BindingVariable("anInteger", Integer.class));
1526 			bindingModel.addToBindingVariables(new BindingVariable("aFloat", Float.TYPE));
1527 		}
1528 
1529 		@Override
1530 		public BindingModel getBindingModel() {
1531 			return bindingModel;
1532 		}
1533 
1534 		@Override
1535 		public BindingFactory getBindingFactory() {
1536 			return bindingFactory;
1537 		}
1538 
1539 		@Override
1540 		public void notifiedBindingChanged(DataBinding<?> dataBinding) {
1541 		}
1542 
1543 		@Override
1544 		public void notifiedBindingDecoded(DataBinding<?> dataBinding) {
1545 		}
1546 	}
1547 
1548 	/**
1549 	 * This main allows to launch an application testing the BindingSelector
1550 	 * 
1551 	 * @param args
1552 	 * @throws SecurityException
1553 	 * @throws IOException
1554 	 */
1555 	public static void main(String[] args) throws SecurityException, IOException {
1556 
1557 		Resource loggingFile = ResourceLocator.locateResource("Config/logging_INFO.properties");
1558 		FlexoLoggingManager.initialize(-1, true, loggingFile, Level.INFO, null);
1559 		final JDialog dialog = new JDialog((Frame) null, false);
1560 
1561 		// TODO GinaManager.getInstance().setup();
1562 
1563 		Bindable testBindable = new TestBindable();
1564 
1565 		// Unused BindingFactory factory =
1566 		new JavaBindingFactory();
1567 		DataBinding<String> binding = new DataBinding<>("aString.toString", testBindable, String.class,
1568 				DataBinding.BindingDefinitionType.GET);
1569 		// DataBinding binding = new DataBinding<String>(testBindable,
1570 		// Object.class, DataBinding.BindingDefinitionType.EXECUTE);
1571 
1572 		final BindingSelector _selector = new BindingSelector(null) {
1573 			@Override
1574 			public void apply() {
1575 				super.apply();
1576 				// System.out.println("Apply, getEditedObject()=" +
1577 				// getEditedObject());
1578 			}
1579 
1580 			@Override
1581 			public void cancel() {
1582 				super.cancel();
1583 				// System.out.println("Cancel, getEditedObject()=" +
1584 				// getEditedObject());
1585 			}
1586 		};
1587 		_selector.setBindable(testBindable);
1588 		_selector.setEditedObject(binding);
1589 		_selector.setRevertValue(binding.clone());
1590 
1591 		JButton closeButton = new JButton("Close");
1592 		closeButton.addActionListener(new ActionListener() {
1593 			@Override
1594 			public void actionPerformed(ActionEvent e) {
1595 				_selector.delete();
1596 				dialog.dispose();
1597 				System.exit(0);
1598 			}
1599 		});
1600 
1601 		JButton logButton = new JButton("Logs");
1602 		logButton.addActionListener(new ActionListener() {
1603 			@Override
1604 			public void actionPerformed(ActionEvent e) {
1605 				FlexoLoggingViewer.showLoggingViewer(FlexoLoggingManager.instance(), ApplicationFIBLibraryImpl.instance(), dialog);
1606 			}
1607 		});
1608 
1609 		JPanel panel = new JPanel(new VerticalLayout());
1610 		panel.add(_selector);
1611 
1612 		panel.add(closeButton);
1613 		panel.add(logButton);
1614 
1615 		dialog.setPreferredSize(new Dimension(550, 600));
1616 		dialog.getContentPane().add(panel);
1617 		dialog.pack();
1618 
1619 		dialog.setVisible(true);
1620 	}
1621 }