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.BorderLayout;
42  import java.awt.Color;
43  import java.awt.Component;
44  import java.awt.Container;
45  import java.awt.Dimension;
46  import java.awt.Font;
47  import java.awt.Rectangle;
48  import java.awt.event.ActionEvent;
49  import java.awt.event.ActionListener;
50  import java.awt.event.KeyAdapter;
51  import java.awt.event.KeyEvent;
52  import java.awt.event.MouseAdapter;
53  import java.awt.event.MouseEvent;
54  import java.beans.PropertyChangeEvent;
55  import java.beans.PropertyChangeListener;
56  import java.lang.reflect.Type;
57  import java.util.ArrayList;
58  import java.util.Hashtable;
59  import java.util.List;
60  import java.util.Map;
61  import java.util.StringTokenizer;
62  import java.util.Vector;
63  import java.util.logging.Level;
64  import java.util.logging.Logger;
65  
66  import javax.swing.AbstractListModel;
67  import javax.swing.BorderFactory;
68  import javax.swing.BoxLayout;
69  import javax.swing.DefaultListCellRenderer;
70  import javax.swing.Icon;
71  import javax.swing.JButton;
72  import javax.swing.JComponent;
73  import javax.swing.JLabel;
74  import javax.swing.JList;
75  import javax.swing.JPanel;
76  import javax.swing.JScrollPane;
77  import javax.swing.JSplitPane;
78  import javax.swing.ListModel;
79  import javax.swing.ListSelectionModel;
80  import javax.swing.ScrollPaneConstants;
81  import javax.swing.SwingConstants;
82  import javax.swing.SwingUtilities;
83  import javax.swing.event.ListSelectionEvent;
84  import javax.swing.event.ListSelectionListener;
85  
86  import org.openflexo.connie.Bindable;
87  import org.openflexo.connie.BindingEvaluationContext;
88  import org.openflexo.connie.BindingFactory;
89  import org.openflexo.connie.BindingModel;
90  import org.openflexo.connie.BindingVariable;
91  import org.openflexo.connie.DataBinding;
92  import org.openflexo.connie.DataBinding.BindingDefinitionType;
93  import org.openflexo.connie.binding.BindingPathElement;
94  import org.openflexo.connie.binding.Function;
95  import org.openflexo.connie.binding.Function.FunctionArgument;
96  import org.openflexo.connie.binding.FunctionPathElement;
97  import org.openflexo.connie.binding.IBindingPathElement;
98  import org.openflexo.connie.binding.SimplePathElement;
99  import org.openflexo.connie.expr.BindingValue;
100 import org.openflexo.connie.type.TypeUtils;
101 import org.openflexo.connie.type.Typed;
102 import org.openflexo.gina.model.FIBModelObject.FIBModelObjectImpl;
103 import org.openflexo.gina.swing.utils.BindingSelector.EditionMode;
104 import org.openflexo.gina.swing.utils.table.AbstractModel;
105 import org.openflexo.gina.swing.utils.table.BindingValueColumn;
106 import org.openflexo.gina.swing.utils.table.IconColumn;
107 import org.openflexo.gina.swing.utils.table.StringColumn;
108 import org.openflexo.gina.swing.utils.table.TabularPanel;
109 import org.openflexo.gina.utils.FIBIconLibrary;
110 import org.openflexo.swing.ButtonsControlPanel;
111 import org.openflexo.swing.MouseOverButton;
112 import org.openflexo.swing.VerticalLayout;
113 import org.openflexo.toolbox.HasPropertyChangeSupport;
114 import org.openflexo.toolbox.StringUtils;
115 import org.openflexo.toolbox.ToolBox;
116 
117 /**
118  * This class encodes the panel representing a {@link BindingValue}<br>
119  * Such a panel is always used in a context of a {@link BindingSelector} and thus always provides access to its {@link BindingSelector}
120  * 
121  * @author sylvain
122  * 
123  */
124 @SuppressWarnings("serial")
125 public class BindingValueSelectorPanel extends AbstractBindingSelectorPanel implements ListSelectionListener {
126 
127 	static final Logger LOGGER = Logger.getLogger(BindingValueSelectorPanel.class.getPackage().getName());
128 
129 	private static final String SPECIFY_BASIC_BINDING = "specify_basic_binding";
130 	private static final String SPECIFY_COMPOUND_BINDING = "specify_complex_binding";
131 
132 	/**
133 	 * References the master {@link BindingSelector}
134 	 */
135 	final BindingSelector bindingSelector;
136 
137 	/**
138 	 * This is the panel where the browser is defined
139 	 */
140 	protected JPanel browserPanel;
141 
142 	/**
143 	 * Panel where buttons are defined
144 	 */
145 	protected ButtonsControlPanel _controlPanel;
146 
147 	protected JButton connectButton;
148 	protected JButton cancelButton;
149 	protected JButton resetButton;
150 	protected JButton expressionButton;
151 
152 	protected JButton createsButton;
153 
154 	private final Map<IBindingPathElement, Hashtable<Type, BindingColumnListModel>> _listModels;
155 
156 	private final Vector<FilteredJList<?>> _lists;
157 
158 	protected int defaultVisibleColCount = 3;
159 
160 	protected final EmptyColumnListModel EMPTY_MODEL = new EmptyColumnListModel();
161 
162 	private BindingColumnListModel _rootBindingColumnListModel = null;
163 
164 	JLabel currentTypeLabel;
165 	private JLabel searchedTypeLabel;
166 	// private JTextArea bindingValueRepresentation;
167 	protected BindingColumnElement currentFocused = null;
168 
169 	protected BindingValueSelectorPanel(BindingSelector bindingSelector) {
170 		super();
171 		this.bindingSelector = bindingSelector;
172 		_listModels = new Hashtable<>();
173 		_rootBindingColumnListModel = null;
174 		_lists = new Vector<>();
175 	}
176 
177 	@Override
178 	public void delete() {
179 		if (_methodCallBindingsModel != null) {
180 			_methodCallBindingsModel.delete();
181 			_methodCallBindingsModel = null;
182 		}
183 		for (JList<?> list : _lists) {
184 			list.removeListSelectionListener(this);
185 			list.setModel(null);
186 		}
187 		_lists.clear();
188 		_listModels.clear();
189 		_rootBindingColumnListModel = null;
190 		currentFocused = null;
191 	}
192 
193 	public int getIndexOfList(BindingColumnListModel model) {
194 		for (int i = 0; i < _lists.size(); i++) {
195 			FilteredJList<?> l = _lists.get(i);
196 			if (l.getModel() == model) {
197 				return i;
198 			}
199 		}
200 		return -1;
201 	}
202 
203 	public Class<?> getAccessedEntity() {
204 		Class<?> reply = null;
205 		int i = 1;
206 		BindingColumnElement last = null;
207 		while (listAtIndex(i) != null && listAtIndex(i).getSelectedValue() != null) {
208 			last = (BindingColumnElement) listAtIndex(i).getSelectedValue();
209 			i++;
210 		}
211 		if (last != null) {
212 			return TypeUtils.getBaseClass(last.getElement().getType());
213 		}
214 		return reply;
215 	}
216 
217 	public BindingVariable getSelectedBindingVariable() {
218 		if (listAtIndex(0) != null && listAtIndex(0).getSelectedValue() != null) {
219 			return (BindingVariable) ((BindingColumnElement) listAtIndex(0).getSelectedValue()).getElement();
220 		}
221 		else if (listAtIndex(0) != null && listAtIndex(0).getModel().getSize() == 1) {
222 			return (BindingVariable) listAtIndex(0).getModel().getElementAt(0).getElement();
223 		}
224 		else {
225 			return null;
226 		}
227 	}
228 
229 	@Deprecated
230 	private static BindingColumnElement findElementMatching(ListModel listModel, String subPartialPath, Vector<Integer> pathElementIndex) {
231 		for (int i = 0; i < listModel.getSize(); i++) {
232 			if (listModel.getElementAt(i) instanceof BindingColumnElement
233 					&& ((BindingColumnElement) listModel.getElementAt(i)).getLabel().startsWith(subPartialPath)) {
234 				if (pathElementIndex.size() == 0) {
235 					pathElementIndex.add(i);
236 				}
237 				else {
238 					pathElementIndex.set(0, i);
239 				}
240 				return (BindingColumnElement) listModel.getElementAt(i);
241 			}
242 		}
243 		return null;
244 	}
245 
246 	Vector<BindingColumnElement> findElementsMatching(BindingColumnListModel listModel, String subPartialPath) {
247 		Vector<BindingColumnElement> returned = new Vector<>();
248 		for (int i = 0; i < listModel.getUnfilteredSize(); i++) {
249 			if (listModel.getUnfilteredElementAt(i).getLabel().startsWith(subPartialPath)) {
250 				returned.add(listModel.getUnfilteredElementAt(i));
251 			}
252 		}
253 		return returned;
254 	}
255 
256 	BindingColumnElement findElementEquals(ListModel<?> listModel, String subPartialPath) {
257 		for (int i = 0; i < listModel.getSize(); i++) {
258 			if (listModel.getElementAt(i) instanceof BindingColumnElement) {
259 				if (((BindingColumnElement) listModel.getElementAt(i)).getLabel() != null
260 						&& ((BindingColumnElement) listModel.getElementAt(i)).getLabel().equals(subPartialPath)) {
261 					return (BindingColumnElement) listModel.getElementAt(i);
262 				}
263 			}
264 		}
265 		return null;
266 	}
267 
268 	public Type getEndingTypeForSubPath(String pathIgnoringLastPart) {
269 		StringTokenizer token = new StringTokenizer(pathIgnoringLastPart, ".", false);
270 		Object obj = null;
271 		int i = 0;
272 		while (token.hasMoreTokens()) {
273 			obj = findElementEquals(listAtIndex(i).getModel(), token.nextToken());
274 			i++;
275 		}
276 		if (obj instanceof BindingColumnElement) {
277 			Typed element = ((BindingColumnElement) obj).getElement();
278 			return element.getType();
279 		}
280 		return null;
281 	}
282 
283 	protected class MethodCallBindingsModel extends AbstractModel<FunctionPathElement, Function.FunctionArgument> {
284 		public MethodCallBindingsModel(FunctionPathElement functionPathElement) {
285 			super(functionPathElement);
286 			addToColumns(new IconColumn<Function.FunctionArgument>("icon", 25) {
287 				@Override
288 				public Icon getIcon(Function.FunctionArgument entity) {
289 					return FIBIconLibrary.METHOD_ICON;
290 				}
291 			});
292 			addToColumns(new StringColumn<Function.FunctionArgument>("name", 100) {
293 				@Override
294 				public String getValue(Function.FunctionArgument arg) {
295 					if (arg != null) {
296 						return arg.getArgumentName();
297 					}
298 					/*
299 					 * if (paramForValue(bindingValue) != null) return
300 					 * paramForValue(bindingValue).getName();
301 					 */
302 					return "null";
303 				}
304 			});
305 			addToColumns(new StringColumn<Function.FunctionArgument>("type", 100) {
306 				@Override
307 				public String getValue(Function.FunctionArgument arg) {
308 					if (arg != null) {
309 						return TypeUtils.simpleRepresentation(arg.getArgumentType());
310 					}
311 					return "null";
312 				}
313 			});
314 			addToColumns(new BindingValueColumn<Function.FunctionArgument>("value", 250, true) {
315 				@Override
316 				public DataBinding getValue(Function.FunctionArgument arg) {
317 					return getFunctionPathElement().getParameter(arg);
318 				}
319 
320 				/**
321 				 * Called when the value of an argument has changed
322 				 */
323 				@Override
324 				public void setValue(Function.FunctionArgument arg, DataBinding aValue) {
325 					if (LOGGER.isLoggable(Level.FINE)) {
326 						LOGGER.fine("Sets value " + arg + " to be " + aValue);
327 					}
328 
329 					if (arg != null && getFunctionPathElement() != null) {
330 
331 						// OK, we first set the parameter value
332 						getFunctionPathElement().setParameter(arg, aValue);
333 
334 						// We need to update parsed binding path according to this new value (important if the binding is still not
335 						// parseable)
336 						BindingValue bv = (BindingValue) bindingSelector.getEditedObject().getExpression();
337 						bv.updateParsedBindingPathFromBindingPath();
338 
339 						// Then, we explicitely force the DataBinding to be reanalyzed (we cannot rely anymore on validity status)
340 						bindingSelector.getEditedObject().markedAsToBeReanalized();
341 
342 					}
343 
344 					// Finally, we notify that DataBinding has changed
345 					bindingSelector.fireEditedObjectChanged();
346 				}
347 
348 				@Override
349 				public Bindable getBindableFor(DataBinding<?> value, Function.FunctionArgument rowObject) {
350 					if (value != null) {
351 						return value.getOwner();
352 					}
353 					return null;
354 				}
355 
356 				@Override
357 				public boolean allowsCompoundBinding(DataBinding<?> value) {
358 					return true;
359 				}
360 
361 				@Override
362 				public boolean allowsNewEntryCreation(DataBinding<?> value) {
363 					return false;
364 				}
365 			});
366 		}
367 
368 		/*
369 		 * DMMethodParameter paramForValue(AbstractBinding bindingValue) { if
370 		 * ((bindingValue.getBindingDefinition() != null) &&
371 		 * (bindingValue.getBindingDefinition() instanceof
372 		 * MethodCall.MethodCallParamBindingDefinition)) { return
373 		 * ((MethodCall.MethodCallParamBindingDefinition
374 		 * )bindingValue.getBindingDefinition()).getParam(); } return null; }
375 		 */
376 
377 		public FunctionPathElement getFunctionPathElement() {
378 			return getModel();
379 		}
380 
381 		@Override
382 		public Function.FunctionArgument elementAt(int row) {
383 			if (row >= 0 && row < getRowCount()) {
384 				return getFunctionPathElement().getFunction().getArguments().get(row);
385 			}
386 			return null;
387 		}
388 
389 		@Override
390 		public int getRowCount() {
391 			if (getFunctionPathElement() != null) {
392 				return getFunctionPathElement().getFunction().getArguments().size();
393 			}
394 			return 0;
395 		}
396 
397 		@Override
398 		public void setModel(FunctionPathElement model) {
399 			// logger.info("Setting MethodCallBindingsModel with " + model);
400 			if (model != null) {
401 				model.instanciateParameters(bindingSelector.getBindable());
402 			}
403 			super.setModel(model);
404 		}
405 
406 		@Override
407 		public BindingEvaluationContext getBindingEvaluationContext() {
408 			return null;
409 		}
410 
411 		public void delete() {
412 			for (int i = 0; i < getColumnCount(); i++) {
413 				columnAt(i).delete();
414 			}
415 		}
416 	}
417 
418 	protected class MethodCallBindingsPanel extends TabularPanel {
419 		public MethodCallBindingsPanel() {
420 			super(getMethodCallBindingsModel(), 3);
421 		}
422 
423 	}
424 
425 	private MethodCallBindingsModel _methodCallBindingsModel;
426 
427 	private MethodCallBindingsPanel _methodCallBindingsPanel;
428 
429 	public MethodCallBindingsPanel getMethodCallBindingsPanel() {
430 		if (_methodCallBindingsPanel == null) {
431 			_methodCallBindingsPanel = new MethodCallBindingsPanel();
432 
433 		}
434 
435 		return _methodCallBindingsPanel;
436 	}
437 
438 	public MethodCallBindingsModel getMethodCallBindingsModel() {
439 		if (_methodCallBindingsModel == null) {
440 			_methodCallBindingsModel = new MethodCallBindingsModel(null);
441 		}
442 		return _methodCallBindingsModel;
443 	}
444 
445 	@Override
446 	public Dimension getDefaultSize() {
447 		int baseHeight;
448 
449 		if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING) {
450 			baseHeight = 300;
451 		}
452 		else {
453 			baseHeight = 180;
454 		}
455 
456 		if (bindingSelector.areStaticValuesAllowed() || bindingSelector.areCompoundBindingAllowed()) {
457 			baseHeight += 30;
458 		}
459 
460 		return new Dimension(500, baseHeight);
461 
462 	}
463 
464 	@Override
465 	protected void willApply() {
466 		if (editStaticValue && staticBindingPanel != null) {
467 			staticBindingPanel.willApply();
468 		}
469 	}
470 
471 	private MouseOverButton showHideCompoundBindingsButton;
472 
473 	private ConstantValuePanel staticBindingPanel;
474 
475 	@Override
476 	protected void init() {
477 		if (LOGGER.isLoggable(Level.FINE)) {
478 			LOGGER.fine("init() with " + bindingSelector.editionMode + " for " + bindingSelector.getEditedObject());
479 		}
480 
481 		setLayout(new BorderLayout());
482 
483 		browserPanel = new JPanel();
484 		browserPanel.setLayout(new BoxLayout(browserPanel, BoxLayout.X_AXIS));
485 		for (int i = 0; i < defaultVisibleColCount; i++) {
486 			makeNewJList();
487 		}
488 
489 		_controlPanel = new ButtonsControlPanel() {
490 			@Override
491 			public String localizedForKeyAndButton(String key, JButton component) {
492 				return FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(key, component);
493 			}
494 		};
495 		connectButton = _controlPanel.addButton("connect", new ActionListener() {
496 			@Override
497 			public void actionPerformed(ActionEvent e) {
498 				bindingSelector.apply();
499 			}
500 		});
501 		cancelButton = _controlPanel.addButton("cancel", new ActionListener() {
502 			@Override
503 			public void actionPerformed(ActionEvent e) {
504 				bindingSelector.cancel();
505 			}
506 		});
507 		resetButton = _controlPanel.addButton("reset", new ActionListener() {
508 			@Override
509 			public void actionPerformed(ActionEvent e) {
510 				bindingSelector.getEditedObject().reset();
511 				bindingSelector.apply();
512 			}
513 		});
514 		if (bindingSelector.areBindingExpressionsAllowed()) {
515 			expressionButton = _controlPanel.addButton("expression", new ActionListener() {
516 				@Override
517 				public void actionPerformed(ActionEvent e) {
518 					bindingSelector.activateBindingExpressionMode();
519 				}
520 			});
521 		}
522 
523 		_controlPanel.applyFocusTraversablePolicyTo(_controlPanel, false);
524 
525 		JPanel optionsPanel = new JPanel();
526 		optionsPanel.setLayout(new BorderLayout());
527 
528 		if (bindingSelector.areCompoundBindingAllowed()) {
529 			showHideCompoundBindingsButton = new MouseOverButton();
530 			showHideCompoundBindingsButton.setBorder(BorderFactory.createEmptyBorder());
531 			showHideCompoundBindingsButton.addActionListener(new ActionListener() {
532 				@Override
533 				public void actionPerformed(ActionEvent e) {
534 					if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING) {
535 						bindingSelector.activateNormalBindingMode();
536 					}
537 					else {
538 						bindingSelector.activateCompoundBindingMode();
539 					}
540 				}
541 			});
542 
543 			JLabel showHideCompoundBindingsButtonLabel = new JLabel("", SwingConstants.RIGHT);
544 			showHideCompoundBindingsButtonLabel.setFont(new Font("SansSerif", Font.PLAIN, 10));
545 			if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING) {
546 				showHideCompoundBindingsButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_TOP_ICON);
547 				showHideCompoundBindingsButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_TOP_SELECTED_ICON);
548 				showHideCompoundBindingsButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(SPECIFY_BASIC_BINDING));
549 				showHideCompoundBindingsButtonLabel
550 						.setText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(SPECIFY_BASIC_BINDING) + "  ");
551 			}
552 			else {
553 				showHideCompoundBindingsButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_ICON);
554 				showHideCompoundBindingsButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_SELECTED_ICON);
555 				showHideCompoundBindingsButton
556 						.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(SPECIFY_COMPOUND_BINDING));
557 				showHideCompoundBindingsButtonLabel
558 						.setText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(SPECIFY_COMPOUND_BINDING) + "  ");
559 			}
560 
561 			JPanel showHideCompoundBindingsButtonPanel = new JPanel();
562 			showHideCompoundBindingsButtonPanel.setLayout(new BorderLayout());
563 			showHideCompoundBindingsButtonPanel.add(showHideCompoundBindingsButtonLabel, BorderLayout.CENTER);
564 			showHideCompoundBindingsButtonPanel.add(showHideCompoundBindingsButton, BorderLayout.EAST);
565 
566 			optionsPanel.add(showHideCompoundBindingsButtonPanel, BorderLayout.EAST);
567 		}
568 
569 		if (bindingSelector.areStaticValuesAllowed()) {
570 			JPanel optionsWestPanel = new JPanel();
571 			optionsWestPanel.setLayout(new VerticalLayout());
572 			staticBindingPanel = new ConstantValuePanel(this);
573 			optionsWestPanel.add(staticBindingPanel);
574 			optionsPanel.add(optionsWestPanel, BorderLayout.WEST);
575 		}
576 
577 		currentTypeLabel = new JLabel(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("no_type"), SwingConstants.LEFT);
578 		currentTypeLabel.setFont(new Font("SansSerif", Font.ITALIC, 10));
579 		currentTypeLabel.setForeground(Color.GRAY);
580 
581 		searchedTypeLabel = new JLabel("[" + FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("no_type") + "]", SwingConstants.LEFT);
582 		searchedTypeLabel.setFont(new Font("SansSerif", Font.PLAIN, 10));
583 		searchedTypeLabel.setForeground(Color.RED);
584 
585 		JPanel labelPanel = new JPanel();
586 		labelPanel.setLayout(new BorderLayout());
587 		labelPanel.add(currentTypeLabel, BorderLayout.CENTER);
588 		labelPanel.add(searchedTypeLabel, BorderLayout.EAST);
589 
590 		JComponent topPane;
591 
592 		if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING) {
593 			topPane = new JPanel();
594 			topPane.setLayout(new BorderLayout());
595 			/*bindingValueRepresentation = new JTextArea(3, 80);
596 			bindingValueRepresentation.setFont(new Font("SansSerif", Font.PLAIN, 10));
597 			bindingValueRepresentation.setEditable(false);
598 			bindingValueRepresentation.setLineWrap(true);*/
599 			// topPane.add(bindingValueRepresentation, BorderLayout.CENTER);
600 			topPane.add(labelPanel, BorderLayout.SOUTH);
601 		}
602 		else {
603 			topPane = labelPanel;
604 		}
605 
606 		add(topPane, BorderLayout.NORTH);
607 
608 		JComponent middlePane;
609 
610 		// logger.info("Rebuild middle pane, with mode="+editionMode);
611 
612 		if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING) {
613 			middlePane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(browserPanel,
614 					ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
615 					getMethodCallBindingsPanel()); // ICI
616 			((JSplitPane) middlePane).setDividerLocation(0.5);
617 			((JSplitPane) middlePane).setResizeWeight(0.5);
618 		}
619 		else { // For NORMAL_BINDING and STATIC_BINDING
620 			middlePane = new JScrollPane(browserPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
621 					ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); // ICI
622 		}
623 
624 		JPanel middlePaneWithOptions = new JPanel();
625 		middlePaneWithOptions.setLayout(new BorderLayout());
626 		middlePaneWithOptions.add(middlePane, BorderLayout.CENTER);
627 		if (bindingSelector.areStaticValuesAllowed() || bindingSelector.areCompoundBindingAllowed()) {
628 			middlePaneWithOptions.add(optionsPanel, BorderLayout.SOUTH);
629 		}
630 
631 		add(middlePaneWithOptions, BorderLayout.CENTER);
632 		add(_controlPanel, BorderLayout.SOUTH);
633 
634 		resetMethodCallPanel();
635 
636 		// Init static panel
637 		editStaticValue = true;
638 		setEditStaticValue(false);
639 
640 		update();
641 		FilteredJList<?> firstList = listAtIndex(0);
642 		if (firstList != null && firstList.getModel().getSize() == 1) {
643 			firstList.setSelectedIndex(0);
644 		}
645 
646 		// disableFocus(this);
647 	}
648 
649 	/*private void disableFocus(Component c) {
650 		c.setFocusable(false);
651 		if (c instanceof Container) {
652 			for (Component c2 : ((Container) c).getComponents()) {
653 				disableFocus(c2);
654 			}
655 		}
656 	}*/
657 
658 	protected void updateSearchedTypeLabel() {
659 		searchedTypeLabel.setText("[" + getTypeStringRepresentation() + "]");
660 	}
661 
662 	private String getTypeStringRepresentation() {
663 		if (bindingSelector.getEditedObject() == null || bindingSelector.getEditedObject().getDeclaredType() == null) {
664 			return FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("no_type");
665 		}
666 		else {
667 			return TypeUtils.simpleRepresentation(bindingSelector.getEditedObject().getDeclaredType());
668 		}
669 	}
670 
671 	protected int getVisibleColsCount() {
672 		return _lists.size();
673 	}
674 
675 	public boolean ensureBindingValueExists() {
676 		if (bindingSelector.getEditedObject() == null) {
677 			return false;
678 		}
679 		if (bindingSelector.getEditedObject().getExpression() == null) {
680 			bindingSelector.getEditedObject().setExpression(bindingSelector.makeBinding());
681 			bindingSelector.fireEditedObjectChanged();
682 		}
683 		return true;
684 	}
685 
686 	protected class FilteredJList<T> extends JList<T> {
687 		public FilteredJList() {
688 			super(new EmptyColumnListModel());
689 		}
690 
691 		public String getFilter() {
692 			return getModel().getFilter();
693 		}
694 
695 		public void setFilter(String aFilter) {
696 			getModel().setFilter(aFilter);
697 		}
698 
699 		public boolean isFiltered() {
700 			return StringUtils.isNotEmpty(getFilter());
701 		}
702 
703 		@Override
704 		public void setModel(ListModel<T> model) {
705 			if (model != null && !(model instanceof BindingColumnListModel)) {
706 				new Exception("Oops, this model is " + model).printStackTrace();
707 			}
708 			setFilter(null);
709 			if (model != null) {
710 				super.setModel(model);
711 			}
712 		}
713 
714 		@Override
715 		public BindingColumnListModel getModel() {
716 			if (super.getModel() instanceof BindingColumnListModel) {
717 				return (BindingColumnListModel) super.getModel();
718 			}
719 			new Exception("Oops, got a " + super.getModel()).printStackTrace();
720 			return null;
721 		}
722 	}
723 
724 	protected JList<String> makeNewJList() {
725 		FilteredJList<String> newList = new FilteredJList<>();
726 
727 		TypeResolver typeResolver = new TypeResolver(newList);
728 
729 		newList.addMouseMotionListener(typeResolver);
730 		newList.addMouseListener(typeResolver);
731 
732 		_lists.add(newList);
733 		if (LOGGER.isLoggable(Level.FINE)) {
734 			LOGGER.fine("makeNewJList() size = " + _lists.size());
735 		}
736 		newList.setPrototypeCellValue("123456789012345"); // ICI
737 		newList.setSize(new Dimension(100, 150));
738 		// newList.setPreferredSize(new Dimension(200,150)); // ICI
739 		// newList.setMinimumSize(new Dimension(200,150)); // ICI
740 		newList.setCellRenderer(new BindingSelectorCellRenderer());
741 		newList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
742 		newList.addListSelectionListener(this);
743 		newList.addMouseListener(new MouseAdapter() {
744 			@Override
745 			public void mouseClicked(MouseEvent e) {
746 				if (e.getClickCount() == 2) {
747 					if (bindingSelector.getEditedObject() != null && bindingSelector.getEditedObject().isValid()) {
748 						bindingSelector.apply();
749 					}
750 				}
751 				else if (e.getClickCount() == 1) {
752 					// Trying to update MethodCall Panel
753 					JList<?> list = (JList<?>) e.getSource();
754 					int index = _lists.indexOf(list);
755 					if (LOGGER.isLoggable(Level.FINE)) {
756 						LOGGER.fine("Click on index " + index);
757 					}
758 					if (index < 0) {
759 						return;
760 					}
761 					_selectedPathElementIndex = index;
762 					updateMethodCallPanel();
763 				}
764 			}
765 		});
766 
767 		newList.addKeyListener(new KeyAdapter() {
768 			@Override
769 			public void keyTyped(KeyEvent e) {
770 				// processAnyKeyTyped(e);
771 			}
772 
773 			@Override
774 			public void keyPressed(KeyEvent e) {
775 				if (e.getKeyChar() == '\n') {
776 					bindingSelector._selectorPanel.processEnterPressed();
777 					e.consume();
778 				}
779 				else if (e.getKeyChar() == KeyEvent.VK_BACK_SPACE) {
780 					bindingSelector._selectorPanel.processBackspace();
781 					e.consume();
782 				}
783 				else if (e.getKeyChar() == KeyEvent.VK_DELETE) {
784 					bindingSelector._selectorPanel.processDelete();
785 					e.consume();
786 				}
787 				else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
788 					if (!ensureBindingValueExists()) {
789 						return;
790 					}
791 					DataBinding<?> dataBinding = bindingSelector.getEditedObject();
792 					if (dataBinding.isBindingValue()) {
793 						int i = _lists.indexOf(e.getSource());
794 						if (i > -1 && i < _lists.size() && listAtIndex(i + 1) != null
795 								&& listAtIndex(i + 1).getModel().getElementAt(0) != null
796 								&& listAtIndex(i + 1).getModel().getElementAt(0).getElement() instanceof BindingPathElement) {
797 							((BindingValue) dataBinding.getExpression()).setBindingPathElementAtIndex(
798 									(BindingPathElement) listAtIndex(i + 1).getModel().getElementAt(0).getElement(), i);
799 							bindingSelector.setEditedObject(dataBinding);
800 							bindingSelector.fireEditedObjectChanged();
801 							listAtIndex(i + 1).requestFocusInWindow();
802 						}
803 						e.consume();
804 					}
805 				}
806 				else if (e.getKeyCode() == KeyEvent.VK_LEFT) {
807 					if (!ensureBindingValueExists()) {
808 						return;
809 					}
810 					DataBinding<?> dataBinding = bindingSelector.getEditedObject();
811 					if (dataBinding.isBindingValue()) {
812 						int i = _lists.indexOf(e.getSource()) - 1;
813 						if (((BindingValue) dataBinding.getExpression()).getBindingPath().size() > i && i > -1 && i < _lists.size()) {
814 							((BindingValue) dataBinding.getExpression()).removeBindingPathAt(i);
815 							// ((BindingValue) dataBinding.getExpression()).disconnect();
816 							// _bindingSelector.disconnect();
817 							bindingSelector.setEditedObject(dataBinding);
818 							bindingSelector.fireEditedObjectChanged();
819 							listAtIndex(i).requestFocusInWindow();
820 						}
821 						e.consume();
822 					}
823 				}
824 			}
825 
826 		});
827 
828 		browserPanel.add(
829 				new JScrollPane(newList, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER)); // ICI
830 		newList.setVisibleRowCount(6);
831 		revalidate();
832 		repaint();
833 		return newList;
834 	}
835 
836 	int _selectedPathElementIndex = -1;
837 
838 	protected void resetMethodCallPanel() {
839 		if (bindingSelector.getEditedObject() == null || bindingSelector.getEditedObject().isConstant()
840 				|| bindingSelector.getEditedObject().isBindingValue()
841 						&& ((BindingValue) bindingSelector.getEditedObject().getExpression()).getBindingPath().size() == 0) {
842 			_selectedPathElementIndex = -1;
843 		}
844 		else if (bindingSelector.getEditedObject().isBindingValue()) {
845 			_selectedPathElementIndex = ((BindingValue) bindingSelector.getEditedObject().getExpression()).getBindingPath().size();
846 		}
847 		updateMethodCallPanel();
848 	}
849 
850 	void updateMethodCallPanel() {
851 		if (LOGGER.isLoggable(Level.FINE)) {
852 			LOGGER.fine("updateMethodCallPanel with " + bindingSelector.editionMode + " binding=" + bindingSelector.getEditedObject()
853 					+ " _selectedPathElementIndex=" + _selectedPathElementIndex);
854 		}
855 		if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING && bindingSelector.getEditedObject().isBindingValue()) {
856 			if (((BindingValue) bindingSelector.getEditedObject().getExpression()).isCompoundBinding() && _selectedPathElementIndex == -1) {
857 				_selectedPathElementIndex = ((BindingValue) bindingSelector.getEditedObject().getExpression()).getBindingPathElementCount();
858 			}
859 			if (_selectedPathElementIndex >= _lists.size()) {
860 				_selectedPathElementIndex = -1;
861 			}
862 			BindingValue bindingValue = (BindingValue) bindingSelector.getEditedObject().getExpression();
863 			if (bindingValue == null) {
864 				_selectedPathElementIndex = -1;
865 			}
866 			else if (_selectedPathElementIndex > bindingValue.getBindingPath().size()) {
867 				_selectedPathElementIndex = -1;
868 			}
869 			if (_selectedPathElementIndex > -1 && bindingValue != null) {
870 				JList<?> list = _lists.get(_selectedPathElementIndex);
871 				int newSelectedIndex = list.getSelectedIndex();
872 				if (newSelectedIndex > 0) {
873 					BindingColumnElement selectedValue = (BindingColumnElement) list.getSelectedValue();
874 					if (selectedValue.getElement() instanceof FunctionPathElement) {
875 						BindingPathElement currentElement = bindingValue.getBindingPathElementAtIndex(_selectedPathElementIndex - 1);
876 						if (currentElement instanceof FunctionPathElement && ((FunctionPathElement) currentElement).getFunction() != null
877 								&& ((FunctionPathElement) currentElement).getFunction()
878 										.equals(((FunctionPathElement) selectedValue.getElement()).getFunction())) {
879 							getMethodCallBindingsModel().setModel((FunctionPathElement) currentElement);
880 							return;
881 						}
882 					}
883 				}
884 			}
885 			getMethodCallBindingsModel().setModel(null);
886 			return;
887 		}
888 	}
889 
890 	protected void deleteJList(JList<?> list) {
891 		_lists.remove(list);
892 		Component[] scrollPanes = browserPanel.getComponents();
893 		for (int i = 0; i < scrollPanes.length; i++) {
894 			if (((Container) scrollPanes[i]).isAncestorOf(list)) {
895 				browserPanel.remove(scrollPanes[i]);
896 			}
897 		}
898 		if (LOGGER.isLoggable(Level.FINE)) {
899 			LOGGER.fine("deleteJList() size = " + _lists.size());
900 		}
901 		revalidate();
902 		repaint();
903 	}
904 
905 	protected FilteredJList<?> listAtIndex(int index) {
906 		if (index >= 0 && index < _lists.size()) {
907 			return _lists.elementAt(index);
908 		}
909 		return null;
910 	}
911 
912 	// TODO ???
913 	/*
914 	 * public void setBindingDefinition(BindingDefinition bindingDefinition) {
915 	 * if (bindingDefinition != getBindingDefinition()) {
916 	 * super.setBindingDefinition(bindingDefinition);
917 	 * staticBindingPanel.updateStaticBindingPanel(); } }
918 	 */
919 
920 	@Override
921 	protected void fireBindableChanged() {
922 		_rootBindingColumnListModel = buildRootColumnListModel();
923 		update();
924 	}
925 
926 	/*@Override
927 	protected void fireBindingDefinitionChanged() {
928 		if (logger.isLoggable(Level.FINE)) {
929 			logger.fine("fireBindingDefinitionChanged / Setting new binding definition: " + bindingSelector.getBindingDefinition());
930 		}
931 	
932 		update();
933 	
934 		if (staticBindingPanel != null) {
935 			staticBindingPanel.updateConstantValuePanel();
936 		}
937 	
938 	}*/
939 
940 	private void clearColumns() {
941 		listAtIndex(0).setModel(getRootColumnListModel());
942 		int lastUpdatedList = 0;
943 		// Remove unused lists
944 		int lastVisibleList = defaultVisibleColCount - 1;
945 		if (lastUpdatedList > lastVisibleList) {
946 			lastVisibleList = lastUpdatedList;
947 		}
948 		int currentSize = getVisibleColsCount();
949 		for (int i = lastVisibleList + 1; i < currentSize; i++) {
950 			JList<?> toRemove = listAtIndex(getVisibleColsCount() - 1);
951 			deleteJList(toRemove);
952 		}
953 		// Sets model to null for visible but unused lists
954 		for (int i = lastUpdatedList + 1; i < getVisibleColsCount(); i++) {
955 			JList<?> list = listAtIndex(i);
956 			list.setModel(EMPTY_MODEL);
957 		}
958 	}
959 
960 	@Override
961 	protected void update() {
962 		DataBinding<?> binding = bindingSelector.getEditedObject();
963 		if (LOGGER.isLoggable(Level.FINE)) {
964 			LOGGER.fine("update with " + binding);
965 		}
966 
967 		// logger.info("Update in BindingValueSelectorPanel with binding " + binding);
968 
969 		if (binding == null || binding.isConstant() || binding.isUnset()) {
970 			clearColumns();
971 			if (binding == null) {
972 				setEditStaticValue(false);
973 			}
974 		}
975 		else if (binding.isBindingValue()) {
976 			BindingValue bindingValue = (BindingValue) binding.getExpression();
977 			listAtIndex(0).setModel(getRootColumnListModel());
978 			int lastUpdatedList = 0;
979 
980 			// logger.info("bindingValue.getBindingVariable()="+bindingValue.getBindingVariable());
981 
982 			if (bindingValue.getBindingVariable() != null) {
983 				if (bindingValue.getBindingVariable().getType() != null) {
984 					listAtIndex(1)
985 							.setModel(getColumnListModel(bindingValue.getBindingVariable(), bindingValue.getBindingVariable().getType()));
986 				}
987 				else {
988 					listAtIndex(1).setModel(EMPTY_MODEL);
989 				}
990 				listAtIndex(0).removeListSelectionListener(this);
991 				BindingColumnElement elementToSelect = listAtIndex(0).getModel().getElementFor(bindingValue.getBindingVariable());
992 
993 				listAtIndex(0).setSelectedValue(elementToSelect, true);
994 				listAtIndex(0).addListSelectionListener(this);
995 				lastUpdatedList = 1;
996 
997 				for (int i = 0; i < bindingValue.getBindingPath().size(); i++) {
998 					BindingPathElement pathElement = bindingValue.getBindingPath().get(i);
999 					if (i + 2 == getVisibleColsCount()) {
1000 						final JList<?> l = makeNewJList();
1001 						SwingUtilities.invokeLater(new Runnable() {
1002 							@Override
1003 							public void run() {
1004 								Rectangle r = SwingUtilities.convertRectangle(l, l.getBounds(), browserPanel);
1005 								// System.out.println("scrollRectToVisible with "+r);
1006 								browserPanel.scrollRectToVisible(r); // ICI
1007 							}
1008 						});
1009 					}
1010 
1011 					// Fixed MODULES-306/MODULES-333
1012 					// I think this conditional is not necessary, but i'm not sure not to have missed something
1013 					// Please report any regression
1014 					// if (!(bindingValue.isValid() && bindingValue.isLastBindingPathElement(pathElement) && bindingSelector.isConnected()))
1015 					// {
1016 					Type resultingType = bindingValue.getBindingPath().get(i).getType();
1017 					listAtIndex(i + 2).setModel(getColumnListModel(bindingValue.getBindingPath().get(i), resultingType));
1018 					lastUpdatedList = i + 2;
1019 					// }
1020 					listAtIndex(i + 1).removeListSelectionListener(this);
1021 
1022 					BindingColumnElement theElementToSelect = listAtIndex(i + 1).getModel().getElementFor(pathElement);
1023 					listAtIndex(i + 1).setSelectedValue(theElementToSelect, true);
1024 
1025 					listAtIndex(i + 1).addListSelectionListener(this);
1026 					if (i < bindingValue.getBindingPath().size() - 1) {
1027 						listAtIndex(i).setFilter(null);
1028 					}
1029 				}
1030 				// logger.info("FIN");
1031 			}
1032 
1033 			// Remove and clean unused lists
1034 			cleanLists(lastUpdatedList);
1035 
1036 			if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING /*&& bindingValueRepresentation != null*/) {
1037 				// bindingValueRepresentation.setText(bindingSelector.renderedString(binding));
1038 				// bindingValueRepresentation.setForeground(bindingValue.isValid() ? Color.BLACK : Color.RED);
1039 				updateMethodCallPanel();
1040 			}
1041 
1042 			// currentTypeLabel.setText(FlexoLocalization.localizedForKey(FIBModelObject.LOCALIZATION, "no_type"));
1043 			// currentTypeLabel.setToolTipText(null);
1044 
1045 		}
1046 
1047 		updateSearchedTypeLabel();
1048 
1049 		if (binding != null) {
1050 			if (LOGGER.isLoggable(Level.FINE)) {
1051 				LOGGER.fine("Binding " + binding + " isValid()=" + binding.isValid());
1052 			}
1053 			else if (LOGGER.isLoggable(Level.FINE)) {
1054 				LOGGER.fine("Binding is null");
1055 			}
1056 		}
1057 
1058 		updateStatus(binding);
1059 	}
1060 
1061 	@Override
1062 	protected void updateStatus(DataBinding<?> binding) {
1063 		// Set connect button state
1064 		connectButton.setEnabled(binding != null && binding.isValid());
1065 		/*if (!binding.isBindingValid()) {
1066 			logger.info("Binding NOT valid: " + binding);
1067 			binding.debugIsBindingValid();
1068 		}*/
1069 		if (binding != null && binding.isValid()) {
1070 			if (ToolBox.isMacOSLaf()) {
1071 				connectButton.setSelected(true);
1072 			}
1073 		}
1074 		if (binding != null) {
1075 			bindingSelector.getTextField().setForeground(binding.isValid() ? Color.BLACK : Color.RED);
1076 			bindingSelector.getTextField().setSelectedTextColor(binding.isValid() ? Color.BLACK : Color.RED);
1077 
1078 			if (bindingSelector.areStaticValuesAllowed() && staticBindingPanel != null) {
1079 				staticBindingPanel.updateConstantValuePanel();
1080 			}
1081 
1082 			if (binding.isBindingValue()) {
1083 				setEditStaticValue(false);
1084 			}
1085 			else if (binding.isConstant()) {
1086 				setEditStaticValue(true);
1087 			}
1088 		}
1089 	}
1090 
1091 	private void cleanLists(int lastUpdatedList) {
1092 		// Remove unused lists
1093 		int lastVisibleList = defaultVisibleColCount - 1;
1094 		if (lastUpdatedList > lastVisibleList) {
1095 			lastVisibleList = lastUpdatedList;
1096 		}
1097 		int currentSize = getVisibleColsCount();
1098 		for (int i = lastVisibleList + 1; i < currentSize; i++) {
1099 			JList<?> toRemove = listAtIndex(getVisibleColsCount() - 1);
1100 			deleteJList(toRemove);
1101 		}
1102 		// Sets model to null for visible but unused lists
1103 		for (int i = lastUpdatedList + 1; i < getVisibleColsCount(); i++) {
1104 			JList<?> list = listAtIndex(i);
1105 			list.setModel(EMPTY_MODEL);
1106 		}
1107 
1108 	}
1109 
1110 	private boolean editStaticValue;
1111 
1112 	boolean getEditStaticValue() {
1113 		return editStaticValue;
1114 	}
1115 
1116 	void setEditStaticValue(boolean aFlag) {
1117 		if (!bindingSelector.areStaticValuesAllowed() || staticBindingPanel == null) {
1118 			return;
1119 		}
1120 		if (editStaticValue != aFlag) {
1121 			editStaticValue = aFlag;
1122 			if (editStaticValue) {
1123 				staticBindingPanel.enableStaticBindingPanel();
1124 				for (int i = 0; i < getVisibleColsCount(); i++) {
1125 					listAtIndex(i).setEnabled(false);
1126 				}
1127 			}
1128 			else {
1129 				staticBindingPanel.disableStaticBindingPanel();
1130 				// _bindingSelector.setEditedObject(null,false);
1131 				for (int i = 0; i < getVisibleColsCount(); i++) {
1132 					listAtIndex(i).setEnabled(true);
1133 				}
1134 				// logger.info("bindable="+getBindable()+" bm="+getBindingModel());
1135 				_rootBindingColumnListModel = buildRootColumnListModel();
1136 				// if (listAtIndex(0).getModel() instanceof
1137 				// EmptyColumnListModel) {
1138 				listAtIndex(0).setModel(getRootColumnListModel());
1139 				// }
1140 			}
1141 			staticBindingPanel.updateConstantValuePanel();
1142 		}
1143 	}
1144 
1145 	private boolean editTranstypedBinding;
1146 
1147 	boolean getEditTranstypedBinding() {
1148 		return editTranstypedBinding;
1149 	}
1150 
1151 	protected void updateListModels() {
1152 		_rootBindingColumnListModel = buildRootColumnListModel();
1153 
1154 		for (Hashtable<Type, BindingColumnListModel> h : _listModels.values()) {
1155 			for (BindingColumnListModel columnListModel : h.values()) {
1156 				columnListModel.updateListModel();
1157 			}
1158 		}
1159 	}
1160 
1161 	protected BindingColumnListModel getRootColumnListModel() {
1162 		if (_rootBindingColumnListModel == null) {
1163 			_rootBindingColumnListModel = buildRootColumnListModel();
1164 		}
1165 		return _rootBindingColumnListModel;
1166 	}
1167 
1168 	protected BindingColumnListModel buildRootColumnListModel() {
1169 		if (bindingSelector.getBindingModel() != null) {
1170 			if (LOGGER.isLoggable(Level.FINE)) {
1171 				LOGGER.fine("buildRootColumnListModel() from " + bindingSelector.getBindingModel());
1172 			}
1173 			return new RootBindingColumnListModel(bindingSelector.getBindingModel());
1174 		}
1175 		if (LOGGER.isLoggable(Level.FINE)) {
1176 			LOGGER.fine("buildRootColumnListModel(): EMPTY_MODEL");
1177 		}
1178 		return EMPTY_MODEL;
1179 	}
1180 
1181 	// public void refreshColumListModel(DMType type){
1182 	// _listModels.remove(type);
1183 	// getColumnListModel(type);
1184 	// }
1185 
1186 	protected BindingColumnListModel getColumnListModel(IBindingPathElement element, Type resultingType) {
1187 		if (element == null) {
1188 			return EMPTY_MODEL;
1189 		}
1190 		if (resultingType == null) {
1191 			return EMPTY_MODEL;
1192 		}
1193 		// if (TypeUtils.isResolved(element.getType())) {
1194 		Hashtable<Type, BindingColumnListModel> h = _listModels.get(element);
1195 		if (h == null) {
1196 			h = new Hashtable<>();
1197 			_listModels.put(element, h);
1198 		}
1199 		BindingColumnListModel returned = h.get(resultingType);
1200 		if (returned == null) {
1201 			returned = makeColumnListModel(element, resultingType);
1202 			h.put(resultingType, returned);
1203 		}
1204 		return returned;
1205 		/*} else {
1206 			return EMPTY_MODEL;
1207 		}*/
1208 	}
1209 
1210 	protected BindingColumnListModel makeColumnListModel(IBindingPathElement element, Type resultingType) {
1211 		return new NormalBindingColumnListModel(element, resultingType);
1212 	}
1213 
1214 	protected class BindingColumnElement {
1215 		private IBindingPathElement _element;
1216 		private Type _resultingType;
1217 
1218 		protected BindingColumnElement(IBindingPathElement element, Type resultingType) {
1219 			_element = element;
1220 			_resultingType = resultingType;
1221 			if (resultingType == null) {
1222 				LOGGER.warning("make BindingColumnElement with null type !");
1223 			}
1224 		}
1225 
1226 		private void delete() {
1227 			_element = null;
1228 			_resultingType = null;
1229 		}
1230 
1231 		public IBindingPathElement getElement() {
1232 			return _element;
1233 		}
1234 
1235 		// TODO: we also need to observe BindingPathElement to track type modifications !!!
1236 		public Type getResultingType() {
1237 			return _resultingType;
1238 		}
1239 
1240 		public String getLabel() {
1241 			return getElement().getLabel();
1242 			/*
1243 			 * if (getElement() != null && getElement() instanceof
1244 			 * BindingVariable) { return
1245 			 * ((BindingVariable)getElement()).getVariableName(); } else if
1246 			 * (getElement() != null && getElement() instanceof
1247 			 * KeyValueProperty) { return ((KeyValueProperty)
1248 			 * getElement()).getName(); } else if (getElement() != null &&
1249 			 * getElement() instanceof MethodDefinition) { MethodDefinition
1250 			 * method = (MethodDefinition) getElement(); return
1251 			 * method.getSimplifiedSignature(); }
1252 			 */
1253 			// return "???";
1254 		}
1255 
1256 		public String getTypeStringRepresentation() {
1257 			if (getResultingType() == null) {
1258 				return FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("no_type");
1259 			}
1260 			return TypeUtils.simpleRepresentation(getResultingType());
1261 		}
1262 
1263 		public String getTooltipText() {
1264 			return getElement().getTooltipText(getResultingType());
1265 
1266 			/*
1267 			 * if (getElement() instanceof BindingVariable) { return
1268 			 * getTooltipText((BindingVariable)getElement()); } else if
1269 			 * (getElement() instanceof KeyValueProperty) { return
1270 			 * getTooltipText
1271 			 * ((KeyValueProperty)getElement(),getResultingType()); } else if
1272 			 * (getElement() instanceof MethodDefinition) { return
1273 			 * getTooltipText
1274 			 * ((MethodDefinition)getElement(),getResultingType()); } else
1275 			 * return "???";
1276 			 */
1277 		}
1278 
1279 		/*
1280 		 * private String getTooltipText(BindingVariable bv) { String returned =
1281 		 * "<html>"; String resultingTypeAsString; if (bv.getType()!=null) {
1282 		 * resultingTypeAsString = TypeUtils.simpleRepresentation(bv.getType());
1283 		 * resultingTypeAsString = ToolBox.replaceStringByStringInString("<",
1284 		 * "&LT;", resultingTypeAsString); resultingTypeAsString =
1285 		 * ToolBox.replaceStringByStringInString(">", "&GT;",
1286 		 * resultingTypeAsString); } else { resultingTypeAsString = "???"; }
1287 		 * returned +=
1288 		 * "<p><b>"+resultingTypeAsString+" "+bv.getVariableName()+"</b></p>";
1289 		 * //returned +=
1290 		 * "<p><i>"+(bv.getDescription()!=null?bv.getDescription():
1291 		 * FlexoLocalization.localizedForKey("no_description"))+"</i></p>";
1292 		 * returned += "</html>"; return returned; }
1293 		 */
1294 
1295 		/*
1296 		 * private String getTooltipText(KeyValueProperty property, Type
1297 		 * resultingType) { String returned = "<html>"; String
1298 		 * resultingTypeAsString; if (resultingType!=null) {
1299 		 * resultingTypeAsString =
1300 		 * TypeUtils.simpleRepresentation(resultingType); resultingTypeAsString
1301 		 * = ToolBox.replaceStringByStringInString("<", "&LT;",
1302 		 * resultingTypeAsString); resultingTypeAsString =
1303 		 * ToolBox.replaceStringByStringInString(">", "&GT;",
1304 		 * resultingTypeAsString); } else { resultingTypeAsString = "???"; }
1305 		 * returned +=
1306 		 * "<p><b>"+resultingTypeAsString+" "+property.getName()+"</b></p>";
1307 		 * //returned +=
1308 		 * "<p><i>"+(property.getDescription()!=null?property.getDescription
1309 		 * ():FlexoLocalization.localizedForKey("no_description"))+"</i></p>";
1310 		 * returned += "</html>"; return returned; }
1311 		 */
1312 
1313 		/*
1314 		 * private String getTooltipText(MethodDefinition method, Type
1315 		 * resultingType) { String returned = "<html>"; String
1316 		 * resultingTypeAsString; if (resultingType!=null) {
1317 		 * resultingTypeAsString =
1318 		 * TypeUtils.simpleRepresentation(resultingType); resultingTypeAsString
1319 		 * = ToolBox.replaceStringByStringInString("<", "&LT;",
1320 		 * resultingTypeAsString); resultingTypeAsString =
1321 		 * ToolBox.replaceStringByStringInString(">", "&GT;",
1322 		 * resultingTypeAsString); } else { resultingTypeAsString = "???"; }
1323 		 * returned +=
1324 		 * "<p><b>"+resultingTypeAsString+" "+method.getSimplifiedSignature
1325 		 * ()+"</b></p>"; //returned +=
1326 		 * "<p><i>"+(method.getDescription()!=null?method
1327 		 * .getDescription():FlexoLocalization
1328 		 * .localizedForKey("no_description"))+"</i></p>"; returned +=
1329 		 * "</html>"; return returned; }
1330 		 */
1331 
1332 		@Override
1333 		public String toString() {
1334 			return "BindingColumnElement/" + getLabel() + "[" + _element.toString() + "]";
1335 		}
1336 
1337 		@Override
1338 		public int hashCode() {
1339 			return (_element == null ? 0 : _element.hashCode()) + (_resultingType == null ? 0 : _resultingType.hashCode());
1340 		}
1341 
1342 		@Override
1343 		public boolean equals(Object obj) {
1344 			if (obj instanceof BindingColumnElement) {
1345 				BindingColumnElement bce = (BindingColumnElement) obj;
1346 				if (_element == null) {
1347 					return false;
1348 				}
1349 				if (_resultingType == null) {
1350 					return false;
1351 				}
1352 				return _element.equals(bce._element) && _resultingType.equals(bce._resultingType);
1353 			}
1354 			return super.equals(obj);
1355 		}
1356 
1357 	}
1358 
1359 	abstract class BindingColumnListModel extends AbstractListModel implements PropertyChangeListener {
1360 		public void fireModelChanged() {
1361 			fireContentsChanged(this, 0, getUnfilteredSize() - 1);
1362 		}
1363 
1364 		public BindingColumnElement getElementFor(IBindingPathElement element) {
1365 			// logger.info("getElementFor() " + element + " of " + element.getClass());
1366 			/*if (element instanceof MethodCall) {
1367 				element = ((MethodCall) element).getMethodDefinition();
1368 			}*/
1369 			for (int i = 0; i < getSize(); i++) {
1370 				// logger.info("getElementAt(i)=" + getElementAt(i).getElement() + " of " + getElementAt(i).getElement().getClass());
1371 				if (getElementAt(i).getElement().equals(element)) {
1372 					return getElementAt(i);
1373 				}
1374 				if (element instanceof FunctionPathElement && getElementAt(i).getElement() instanceof FunctionPathElement) {
1375 					// Special equals, we try to find a FunctionPathElement even if parameters are different
1376 					FunctionPathElement f1 = (FunctionPathElement) element;
1377 					FunctionPathElement f2 = (FunctionPathElement) getElementAt(i).getElement();
1378 					if (f1.getFunction() != null && f1.getFunction().equals(f2.getFunction())) {
1379 						// We decide here that both FunctionPathElement are equivalent
1380 						return getElementAt(i);
1381 					}
1382 
1383 				}
1384 			}
1385 			LOGGER.info("I cannot find " + element + " of " + (element != null ? element.getClass() : null));
1386 			/*for (int i = 0; i < getSize(); i++) {
1387 				logger.info("Looking with " + getElementAt(i).getElement() + " of "
1388 						+ (getElementAt(i).getElement() != null ? getElementAt(i).getElement().getClass() : null));
1389 			}*/
1390 
1391 			return null;
1392 		}
1393 
1394 		@Override
1395 		public void propertyChange(PropertyChangeEvent evt) {
1396 			// System.out.println("*** propertyChange() called in " + this);
1397 		}
1398 
1399 		public void updateListModel() {
1400 			// System.out.println("*** updateListModel() called in " + this);
1401 		}
1402 
1403 		public void delete() {
1404 
1405 		}
1406 
1407 		private String filter = null;
1408 
1409 		public String getFilter() {
1410 			return filter;
1411 		}
1412 
1413 		public void setFilter(String aFilter) {
1414 			filter = aFilter;
1415 			fireModelChanged();
1416 		}
1417 
1418 		@Override
1419 		public int getSize() {
1420 			if (getFilter() == null && !bindingSelector._hideFilteredObjects) {
1421 				return getUnfilteredSize();
1422 			}
1423 			int returned = 0;
1424 			if (!bindingSelector._hideFilteredObjects) {
1425 				for (int i = 0; i < getUnfilteredSize(); i++) {
1426 					if (getUnfilteredElementAt(i).getLabel().startsWith(filter)) {
1427 						returned++;
1428 					}
1429 				}
1430 			}
1431 			else if (getFilter() == null) {
1432 				for (int i = 0; i < getUnfilteredSize(); i++) {
1433 					if (!isFiltered(getUnfilteredElementAt(i))) {
1434 						returned++;
1435 					}
1436 				}
1437 			}
1438 			else {
1439 				for (int i = 0; i < getUnfilteredSize(); i++) {
1440 					if (getUnfilteredElementAt(i).getLabel().startsWith(filter) && !isFiltered(getUnfilteredElementAt(i))) {
1441 						returned++;
1442 					}
1443 				}
1444 			}
1445 			return returned;
1446 		}
1447 
1448 		@Override
1449 		public BindingColumnElement getElementAt(int index) {
1450 			if (getFilter() == null && !bindingSelector._hideFilteredObjects) {
1451 				return getUnfilteredElementAt(index);
1452 			}
1453 			if (!bindingSelector._hideFilteredObjects) {
1454 				int searchedIndex = -1;
1455 				for (int i = 0; i < getUnfilteredSize(); i++) {
1456 					if (getUnfilteredElementAt(i).getLabel().startsWith(filter)) {
1457 						searchedIndex++;
1458 					}
1459 					if (searchedIndex == index) {
1460 						return getUnfilteredElementAt(i);
1461 					}
1462 				}
1463 			}
1464 			else if (getFilter() == null) {
1465 				int searchedIndex = -1;
1466 				for (int i = 0; i < getUnfilteredSize(); i++) {
1467 					if (!isFiltered(getUnfilteredElementAt(i))) {
1468 						searchedIndex++;
1469 					}
1470 					if (searchedIndex == index) {
1471 						return getUnfilteredElementAt(i);
1472 					}
1473 				}
1474 			}
1475 			else {
1476 				int searchedIndex = -1;
1477 				for (int i = 0; i < getUnfilteredSize(); i++) {
1478 					if (getUnfilteredElementAt(i).getLabel().startsWith(filter) && !isFiltered(getUnfilteredElementAt(i))) {
1479 						searchedIndex++;
1480 					}
1481 					if (searchedIndex == index) {
1482 						return getUnfilteredElementAt(i);
1483 					}
1484 				}
1485 			}
1486 			return null;
1487 		}
1488 
1489 		private boolean isFiltered(BindingColumnElement columnElement) {
1490 			// Class resultingTypeBaseClass =
1491 			// TypeUtils.getBaseClass(columnElement.getResultingType());
1492 			// Unused Type resultingType =
1493 			columnElement.getResultingType();
1494 
1495 			if (columnElement.getElement() != null && columnElement.getElement() instanceof BindingVariable) {
1496 				BindingVariable bv = (BindingVariable) columnElement.getElement();
1497 				if (bv.getType() == null) {
1498 					return true;
1499 				}
1500 			}
1501 			else if (columnElement.getElement() != null) {
1502 				DataBinding<?> binding = bindingSelector.getEditedObject();
1503 				if (binding != null && binding.isBindingValue()) {
1504 					BindingValue bindingValue = (BindingValue) binding.getExpression();
1505 					if (bindingValue.isValid()
1506 							&& bindingValue.isLastBindingPathElement(columnElement.getElement()/*, getIndexOfList(this) - 1*/)
1507 							&& bindingSelector.isConnected()) {
1508 						// setIcon(label, CONNECTED_ICON, list);
1509 					}
1510 					else if (columnElement.getResultingType() != null) {
1511 						if (TypeUtils.isResolved(columnElement.getResultingType()) && bindingSelector.getBindable() != null) {
1512 							// if (columnElement.getElement().getAccessibleBindingPathElements().size() > 0) {
1513 							if (bindingSelector.getBindable().getBindingFactory()
1514 									.getAccessibleSimplePathElements(columnElement.getElement()).size() > 0) {}
1515 							else {
1516 								if (!TypeUtils.isTypeAssignableFrom(binding.getDeclaredType(), columnElement.getResultingType(), true)) {
1517 									return true;
1518 								}
1519 								if (binding.isSettable() && !columnElement.getElement().isSettable()) {
1520 									return true;
1521 								}
1522 							}
1523 						}
1524 					}
1525 				}
1526 			} /*
1527 				* else if (columnElement.getElement() != null &&
1528 				* columnElement.getElement() instanceof KeyValueProperty) {
1529 				* KeyValueProperty property = (KeyValueProperty)
1530 				* columnElement.getElement(); AbstractBinding binding =
1531 				* _bindingSelector.getEditedObject(); if
1532 				* ((binding != null) && binding instanceof BindingValue) {
1533 				* BindingValue bindingValue = (BindingValue)binding; if
1534 				* (bindingValue.isConnected() &&
1535 				* (bindingValue.isLastBindingPathElement(property,
1536 				* getIndexOfList(this) - 1))) { //setIcon(label, CONNECTED_ICON,
1537 				* list); } else if (columnElement.getResultingType() != null) { if
1538 				* (TypeUtils.isResolved(columnElement.getResultingType()) &&
1539 				* _bindingSelector.getBindable() != null) { if
1540 				* (_bindingSelector.getBindable
1541 				* ().getBindingFactory().getAccessibleBindingPathElements
1542 				* (columnElement.getElement()).size() > 0) { //if
1543 				* (KeyValueLibrary.getAccessibleProperties(resultingType).size() >
1544 				* 0) { //setIcon(label, ARROW_RIGHT_ICON, list); } else { if
1545 				* ((_bindingSelector.getBindingDefinition() != null) &&
1546 				* (_bindingSelector.getBindingDefinition().getType() != null) &&
1547 				* (!TypeUtils
1548 				* .isTypeAssignableFrom(_bindingSelector
1549 				* .getBindingDefinition
1550 				* ().getType(),columnElement.getResultingType(),true))) { return
1551 				* true; } if ((_bindingSelector.getBindingDefinition() != null) &&
1552 				* (_bindingSelector.getBindingDefinition().getIsSettable()) &&
1553 				* !property.isSettable()) { return true; } } } } } } else if
1554 				* (columnElement.getElement() != null && columnElement.getElement()
1555 				* instanceof MethodDefinition) { MethodDefinition method =
1556 				* (MethodDefinition) columnElement.getElement();
1557 				* 
1558 				* String methodAsString = method.getSimplifiedSignature(); int idx
1559 				* = getIndexOfList(this); if (idx > 0 &&
1560 				* _lists.elementAt(idx-1).getSelectedValue()!=null) { Type context
1561 				* =
1562 				* ((BindingColumnElement)_lists.elementAt(idx-1).getSelectedValue(
1563 				* )).getResultingType(); methodAsString =
1564 				* method.getSimplifiedSignature();
1565 				* //method.getSimplifiedSignatureInContext(context); }
1566 				* 
1567 				* AbstractBinding binding = _bindingSelector.getEditedObject(); if
1568 				* (binding instanceof BindingValue) { BindingValue bindingValue =
1569 				* (BindingValue)binding; BindingPathElement bpe =
1570 				* bindingValue.getBindingPathElementAtIndex(getIndexOfList(this) -
1571 				* 1); if ((bindingValue.isConnected()) &&
1572 				* (bindingValue.isLastBindingPathElement(bpe, getIndexOfList(this)
1573 				* - 1)) && ((bpe instanceof MethodCall) &&
1574 				* (((MethodCall)bpe).getMethod().equals(method.getMethod())))) { }
1575 				* else if (columnElement.getResultingType() != null &&
1576 				* resultingType != null && _bindingSelector.getBindable() != null)
1577 				* { if(_bindingSelector.getBindable().getBindingFactory().
1578 				* getAccessibleBindingPathElements
1579 				* (columnElement.getElement()).size() +
1580 				* _bindingSelector.getBindable
1581 				* ().getBindingFactory().getAccessibleCompoundBindingPathElements
1582 				* (columnElement.getElement()).size() > 0) { //if
1583 				* (KeyValueLibrary.getAccessibleProperties(resultingType).size() //
1584 				* + KeyValueLibrary.getAccessibleMethods(resultingType).size() > 0)
1585 				* { } else { if ((_bindingSelector.getBindingDefinition() != null)
1586 				* && (_bindingSelector.getBindingDefinition().getType() != null &&
1587 				* TypeUtils
1588 				* .getBaseClass(_bindingSelector.getBindingDefinition().getType
1589 				* ())!=null) &&
1590 				* (!TypeUtils.isClassAncestorOf(TypeUtils.getBaseClass
1591 				* (_bindingSelector
1592 				* .getBindingDefinition().getType()),TypeUtils.getBaseClass
1593 				* (resultingType)))) { return true; } } } } }
1594 				*/
1595 			return false;
1596 		}
1597 
1598 		public abstract int getUnfilteredSize();
1599 
1600 		public abstract BindingColumnElement getUnfilteredElementAt(int index);
1601 
1602 	}
1603 
1604 	private class NormalBindingColumnListModel extends BindingColumnListModel {
1605 		private final Type _type;
1606 		private final IBindingPathElement _element;
1607 		private final Vector<BindingPathElement> _accessibleProperties;
1608 		private final Vector<BindingPathElement> _accessibleMethods;
1609 		private final Vector<BindingColumnElement> _elements;
1610 
1611 		NormalBindingColumnListModel(IBindingPathElement element, Type resultingType) {
1612 			super();
1613 			_element = element;
1614 			_type = resultingType;
1615 			if (LOGGER.isLoggable(Level.FINE)) {
1616 				LOGGER.fine("Build NormalBindingColumnListModel for " + element + " base class=" + TypeUtils.getBaseClass(_type));
1617 			}
1618 			_accessibleProperties = new Vector<>();
1619 			_accessibleMethods = new Vector<>();
1620 			_elements = new Vector<>();
1621 			updatePathElements();
1622 			if (element instanceof HasPropertyChangeSupport && ((HasPropertyChangeSupport) element).getPropertyChangeSupport() != null) {
1623 				((HasPropertyChangeSupport) element).getPropertyChangeSupport().addPropertyChangeListener(this);
1624 			}
1625 		}
1626 
1627 		@Override
1628 		public void delete() {
1629 			if (_element instanceof HasPropertyChangeSupport && ((HasPropertyChangeSupport) _element).getPropertyChangeSupport() != null) {
1630 				((HasPropertyChangeSupport) _element).getPropertyChangeSupport().removePropertyChangeListener(this);
1631 			}
1632 			super.delete();
1633 		}
1634 
1635 		@Override
1636 		public void propertyChange(PropertyChangeEvent evt) {
1637 			super.propertyChange(evt);
1638 			if (evt.getPropertyName().equals(BindingPathElement.BINDING_PATH_CHANGED)) {
1639 				updatePathElements();
1640 			}
1641 		}
1642 
1643 		@Override
1644 		public void updateListModel() {
1645 			super.updateListModel();
1646 			updatePathElements();
1647 		}
1648 
1649 		private void updatePathElements() {
1650 			// System.out.println("*** updatePathElements() called in " + this);
1651 			_accessibleProperties.clear();
1652 			_accessibleMethods.clear();
1653 
1654 			if (bindingSelector.getBindable() == null) {
1655 				return;
1656 			}
1657 
1658 			_elements.clear();
1659 
1660 			if (TypeUtils.getBaseClass(_type) == null) {
1661 				return;
1662 			}
1663 
1664 			Bindable bdable = bindingSelector.getBindable();
1665 			if (bdable != null) {
1666 				BindingFactory bf = bdable.getBindingFactory();
1667 				if (bf != null) {
1668 					_accessibleProperties.addAll(bf.getAccessibleSimplePathElements(_element));
1669 
1670 					if (bindingSelector.editionMode == EditionMode.COMPOUND_BINDING) {
1671 						_accessibleProperties
1672 								.addAll(bindingSelector.getBindable().getBindingFactory().getAccessibleFunctionPathElements(_element));
1673 					}
1674 
1675 					for (BindingPathElement p : _accessibleProperties) {
1676 						_elements.add(new BindingColumnElement(p, TypeUtils.makeInstantiatedType(p.getType(), _type)));
1677 					}
1678 					for (BindingPathElement m : _accessibleMethods) {
1679 						_elements.add(new BindingColumnElement(m, TypeUtils.makeInstantiatedType(m.getType(), _type)));
1680 					}
1681 				}
1682 			}
1683 		}
1684 
1685 		@Override
1686 		public int getUnfilteredSize() {
1687 			return _elements.size();
1688 		}
1689 
1690 		@Override
1691 		public BindingColumnElement getUnfilteredElementAt(int index) {
1692 			if (index < _elements.size() && index >= 0) {
1693 				return _elements.elementAt(index);
1694 			}
1695 			return null;
1696 		}
1697 
1698 		/*@Override
1699 		public void update(Observable observable, Object dataModification) {
1700 		}*/
1701 
1702 	}
1703 
1704 	class EmptyColumnListModel extends BindingColumnListModel {
1705 		@Override
1706 		public int getUnfilteredSize() {
1707 			return 0;
1708 		}
1709 
1710 		@Override
1711 		public BindingColumnElement getUnfilteredElementAt(int index) {
1712 			return null;
1713 		}
1714 
1715 	}
1716 
1717 	private class RootBindingColumnListModel extends BindingColumnListModel {
1718 		private final BindingModel _myBindingModel;
1719 		private final Vector<BindingColumnElement> _elements;
1720 
1721 		RootBindingColumnListModel(BindingModel bindingModel) {
1722 			super();
1723 			_myBindingModel = bindingModel;
1724 			_elements = new Vector<>();
1725 			bindingModel.getPropertyChangeSupport().addPropertyChangeListener(this);
1726 			updateBindingVariables();
1727 		}
1728 
1729 		@Override
1730 		public void propertyChange(PropertyChangeEvent evt) {
1731 			super.propertyChange(evt);
1732 			if (evt.getSource() == _myBindingModel) {
1733 				updateBindingVariables();
1734 			}
1735 			else if (evt.getSource() instanceof BindingVariable) {
1736 				// Unused BindingVariable bv = (BindingVariable)
1737 				evt.getSource();
1738 				// System.out.println("-------> YES, j'ai vu que la variable: " + bv + " a ete modifiee: " + evt);
1739 			}
1740 		}
1741 
1742 		@Override
1743 		public void updateListModel() {
1744 			super.updateListModel();
1745 			updateBindingVariables();
1746 		}
1747 
1748 		private final List<BindingVariable> observedBindingVariables = new ArrayList<>();
1749 
1750 		private void updateBindingVariables() {
1751 			// System.out.println("*** updateBindingVariables() called in " + this);
1752 			if (LOGGER.isLoggable(Level.FINE)) {
1753 				LOGGER.fine("BindingModel is: " + _myBindingModel + " with " + _myBindingModel.getBindingVariablesCount());
1754 			}
1755 			for (BindingVariable bv : observedBindingVariables) {
1756 				if (bv.getPropertyChangeSupport() != null) {
1757 					bv.getPropertyChangeSupport().removePropertyChangeListener(this);
1758 				}
1759 			}
1760 			for (BindingColumnElement e : _elements) {
1761 				e.delete();
1762 			}
1763 			_elements.clear();
1764 			for (int i = 0; i < _myBindingModel.getBindingVariablesCount(); i++) {
1765 				BindingVariable bv = _myBindingModel.getBindingVariableAt(i);
1766 				_elements.add(new BindingColumnElement(bv, bv.getType()));
1767 				if (bv.getPropertyChangeSupport() != null) {
1768 					bv.getPropertyChangeSupport().addPropertyChangeListener(this);
1769 				}
1770 			}
1771 		}
1772 
1773 		@Override
1774 		public int getUnfilteredSize() {
1775 			return _elements.size();
1776 		}
1777 
1778 		@Override
1779 		public BindingColumnElement getUnfilteredElementAt(int index) {
1780 			return _elements.elementAt(index);
1781 		}
1782 
1783 		@Override
1784 		public String toString() {
1785 			return "RootBindingColumnListModel with " + getSize() + " elements";
1786 		}
1787 
1788 	}
1789 
1790 	protected class TypeResolver extends MouseAdapter {
1791 
1792 		private final JList<?> list;
1793 
1794 		protected TypeResolver(JList<?> aList) {
1795 			currentFocused = null;
1796 			list = aList;
1797 		}
1798 
1799 		@Override
1800 		public void mouseMoved(MouseEvent e) {
1801 			displayLabel(e);
1802 		}
1803 
1804 		@Override
1805 		public void mouseClicked(MouseEvent e) {
1806 			displayLabel(e);
1807 		}
1808 
1809 		private void displayLabel(MouseEvent e) {
1810 
1811 			// Get item index
1812 			int index = list.locationToIndex(e.getPoint());
1813 
1814 			// Get item
1815 			if (index < 0 || index >= list.getModel().getSize()) {
1816 				return;
1817 			}
1818 			BindingColumnElement item = ((BindingColumnListModel) list.getModel()).getElementAt(index);
1819 
1820 			if (item != currentFocused) {
1821 				currentFocused = item;
1822 				currentTypeLabel.setText(currentFocused.getTypeStringRepresentation());
1823 			}
1824 		}
1825 
1826 	}
1827 
1828 	protected class BindingSelectorCellRenderer extends DefaultListCellRenderer {
1829 
1830 		private final JPanel panel;
1831 		private final JLabel iconLabel;
1832 
1833 		public BindingSelectorCellRenderer() {
1834 			panel = new JPanel(new BorderLayout());
1835 			iconLabel = new JLabel();
1836 			panel.add(iconLabel, BorderLayout.EAST);
1837 			panel.add(this);
1838 		}
1839 
1840 		@Override
1841 		public Component getListCellRendererComponent(JList<?> list, Object bce, int index, boolean isSelected, boolean cellHasFocus) {
1842 			JComponent returned = (JComponent) super.getListCellRendererComponent(list, bce, index, isSelected, cellHasFocus);
1843 			if (returned instanceof JLabel) {
1844 				JLabel label = (JLabel) returned;
1845 				label.setToolTipText(null);
1846 				iconLabel.setVisible(false);
1847 
1848 				if (bce instanceof BindingColumnElement) {
1849 					BindingColumnElement columnElement = (BindingColumnElement) bce;
1850 					// Class resultingTypeBaseClass =
1851 					// TypeUtils.getBaseClass(columnElement.getResultingType());
1852 					// Unused Type resultingType =
1853 					columnElement.getResultingType();
1854 					label.setText(columnElement.getLabel());
1855 					// if (!(columnElement.getElement() instanceof FinalBindingPathElement)) {
1856 					returned = getIconLabelComponent(label, FIBIconLibrary.ARROW_RIGHT_ICON);
1857 					// }
1858 					if (columnElement.getElement().getType() != null) {
1859 						returned.setToolTipText(columnElement.getTooltipText());
1860 					}
1861 					else {
1862 						label.setForeground(Color.GRAY);
1863 					}
1864 
1865 					DataBinding<?> binding = bindingSelector.getEditedObject();
1866 					if (binding != null && binding.isBindingValue()) {
1867 						BindingValue bindingValue = (BindingValue) binding.getExpression();
1868 						// System.out.println("bindingValue=" + bindingValue + " valid=" + isValid());
1869 						if (bindingValue.isValid()
1870 								&& bindingValue.isLastBindingPathElement(columnElement.getElement()/*, _lists.indexOf(list) - 1*/)
1871 								&& bindingSelector.isConnected()) {
1872 							// System.out.println("connecte");
1873 							returned = getIconLabelComponent(label, FIBIconLibrary.CONNECTED_ICON);
1874 						}
1875 						else if (columnElement.getResultingType() != null) {
1876 							if (TypeUtils.isResolved(columnElement.getResultingType()) && bindingSelector.getBindable() != null) {
1877 								// if (columnElement.getElement().getAccessibleBindingPathElements().size() > 0) {
1878 								if (bindingSelector.getBindable().getBindingFactory() != null
1879 										&& bindingSelector.getBindable().getBindingFactory()
1880 												.getAccessibleSimplePathElements(columnElement.getElement()) != null
1881 										&& bindingSelector.getBindable().getBindingFactory()
1882 												.getAccessibleSimplePathElements(columnElement.getElement()).size() > 0) {
1883 									returned = getIconLabelComponent(label, FIBIconLibrary.ARROW_RIGHT_ICON);
1884 								}
1885 								else {
1886 									if (!TypeUtils.isTypeAssignableFrom(binding.getDeclaredType(), columnElement.getResultingType(),
1887 											true)) {
1888 										label.setForeground(Color.GRAY);
1889 									}
1890 									if (binding.isSettable() && !columnElement.getElement().isSettable()) {
1891 										label.setForeground(Color.GRAY);
1892 									}
1893 								}
1894 							}
1895 						}
1896 					}
1897 
1898 				}
1899 				else {
1900 					// Happen because of prototype value !
1901 					// logger.warning("Unexpected type: "+bce+" of "+(bce!=null?bce.getClass():"null"));
1902 				}
1903 
1904 			}
1905 			return returned;
1906 		}
1907 
1908 		private JComponent getIconLabelComponent(JLabel label, Icon icon) {
1909 			iconLabel.setVisible(true);
1910 			iconLabel.setIcon(icon);
1911 			iconLabel.setOpaque(label.isOpaque());
1912 			iconLabel.setBackground(label.getBackground());
1913 			panel.setToolTipText(label.getToolTipText());
1914 			if (label.getParent() != panel) {
1915 				panel.add(label);
1916 			}
1917 			return panel;
1918 		}
1919 	}
1920 
1921 	protected JPanel getControlPanel() {
1922 		return _controlPanel;
1923 	}
1924 
1925 	@Override
1926 	public void valueChanged(ListSelectionEvent e) {
1927 
1928 		if (e.getValueIsAdjusting()) {
1929 			return;
1930 		}
1931 
1932 		DataBinding<?> dataBinding = bindingSelector.getEditedObject();
1933 
1934 		if (dataBinding == null) {
1935 			LOGGER.warning("dataBinding should not be null");
1936 			return;
1937 		}
1938 
1939 		if (dataBinding.getExpression() == null) {
1940 			// if (bindingSelector.getBindingDefinition() != null && bindingSelector.getBindable() != null) {
1941 			BindingValue newBindingValue = new BindingValue();
1942 			newBindingValue.setBindingVariable(getSelectedBindingVariable());
1943 			newBindingValue.setDataBinding(dataBinding);
1944 			// System.out.println("getSelectedBindingVariable()=" + getSelectedBindingVariable());
1945 			dataBinding.setExpression(newBindingValue /*bindingSelector.makeBinding()*/);
1946 			// bindingValue.setBindingVariable(getSelectedBindingVariable());
1947 			// setEditedObject(bindingValue);
1948 			// bindingSelector.fireEditedObjectChanged();
1949 			/*} else {
1950 				return;
1951 			}*/
1952 		}
1953 
1954 		JList<?> list = (JList<?>) e.getSource();
1955 		int index = _lists.indexOf(list);
1956 		_selectedPathElementIndex = index;
1957 		if (index < 0) {
1958 			return;
1959 		}
1960 		int newSelectedIndex = list.getSelectedIndex();
1961 
1962 		if (LOGGER.isLoggable(Level.FINE)) {
1963 			LOGGER.fine("I select something from list at index " + index + " selected=" + newSelectedIndex);
1964 		}
1965 
1966 		if (newSelectedIndex < 0) {
1967 			return;
1968 		}
1969 
1970 		// This call will perform BV edition
1971 		valueSelected(index, list);
1972 
1973 		list.removeListSelectionListener(this);
1974 		list.setSelectedIndex(newSelectedIndex);
1975 		list.addListSelectionListener(this);
1976 
1977 	}
1978 
1979 	private static boolean hasBindingPathForm(String textValue) {
1980 		if (textValue.length() == 0) {
1981 			return false;
1982 		}
1983 
1984 		boolean startingPathItem = true;
1985 		for (int i = 0; i < textValue.length(); i++) {
1986 			char c = textValue.charAt(i);
1987 			if (c == '.') {
1988 				startingPathItem = true;
1989 			}
1990 			else {
1991 				boolean isNormalChar = c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' && !startingPathItem;
1992 				if (!isNormalChar) {
1993 					return false;
1994 				}
1995 				startingPathItem = false;
1996 			}
1997 		}
1998 		return true;
1999 	}
2000 
2001 	@Override
2002 	protected void synchronizePanelWithTextFieldValue(String textValue) {
2003 		if (LOGGER.isLoggable(Level.FINE)) {
2004 			LOGGER.fine("Request synchronizePanelWithTextFieldValue " + textValue);
2005 		}
2006 
2007 		try {
2008 			bindingSelector.isUpdatingModel = true;
2009 
2010 			if (!bindingSelector.popupIsShown() && textValue != null
2011 					&& !bindingSelector.isAcceptableAsBeginningOfStaticBindingValue(textValue)) {
2012 				boolean requestFocus = bindingSelector.getTextField().hasFocus();
2013 				bindingSelector.openPopup();
2014 				if (requestFocus) {
2015 					SwingUtilities.invokeLater(new Runnable() {
2016 						@Override
2017 						public void run() {
2018 							bindingSelector.getTextField().requestFocusInWindow();
2019 						}
2020 					});
2021 				}
2022 			}
2023 
2024 			if (bindingSelector.getTextField().hasFocus()) {
2025 				if (bindingSelector.getEditedObject() != null && bindingSelector.getEditedObject().isBindingValue()) {
2026 					// ((BindingValue) _bindingSelector.getEditedObject()).disconnect();
2027 				}
2028 				if (bindingSelector._selectorPanel != null) {
2029 					filterWithCurrentInput(textValue);
2030 				}
2031 			}
2032 
2033 			if (textValue == null || !textValue.equals(bindingSelector.renderedString(bindingSelector.getEditedObject()))) {
2034 				bindingSelector.getTextField().setForeground(Color.RED);
2035 			}
2036 			else {
2037 				bindingSelector.getTextField().setForeground(Color.BLACK);
2038 			}
2039 
2040 		} finally {
2041 			bindingSelector.isUpdatingModel = false;
2042 		}
2043 
2044 	}
2045 
2046 	private void filterWithCurrentInput(String textValue) {
2047 		if (LOGGER.isLoggable(Level.FINE)) {
2048 			LOGGER.fine("Try to filter for current input " + textValue);
2049 		}
2050 
2051 		if (!hasBindingPathForm(textValue)) {
2052 			return;
2053 		}
2054 
2055 		StringTokenizer tokenizer = new StringTokenizer(textValue, ".", false);
2056 		boolean isCurrentlyValid = true;
2057 		int listIndex = 0;
2058 		String element = null;
2059 		while (isCurrentlyValid && tokenizer.hasMoreTokens()) {
2060 			element = tokenizer.nextToken();
2061 			BindingColumnElement col_element = findElementEquals(_lists.get(listIndex).getModel(), element);
2062 			if (col_element == null) {
2063 				isCurrentlyValid = false;
2064 			}
2065 			else {
2066 				bindingSelector.setUpdatingModel(true);
2067 				if (!ensureBindingValueExists()) {
2068 					bindingSelector.setUpdatingModel(false);
2069 					return;
2070 				}
2071 
2072 				/*
2073 				 * if (listIndex == 0) {
2074 				 * logger.info("Je selectionne "+col_element
2075 				 * +" pour la premiere colonne"); boolean found = false; for
2076 				 * (int i=0; i<_lists.get(listIndex).getModel().getSize(); i++)
2077 				 * { Object o =
2078 				 * _lists.get(listIndex).getModel().getElementAt(i); if
2079 				 * (o.equals(col_element)) { found = true;
2080 				 * logger.info("OK, je l'ai trouve"); } else {
2081 				 * logger.info("Pas pareil: "+o); } } if (!found)
2082 				 * logger.info("Je le trouve pas"); }
2083 				 */
2084 
2085 				_lists.get(listIndex).removeListSelectionListener(this);
2086 				_lists.get(listIndex).setFilter(null);
2087 				_lists.get(listIndex).setSelectedValue(col_element, true);
2088 				_lists.get(listIndex).addListSelectionListener(this);
2089 				valueSelected(listIndex, _lists.get(listIndex));
2090 				bindingSelector.setUpdatingModel(false);
2091 				listIndex++;
2092 			}
2093 		}
2094 
2095 		if (!isCurrentlyValid) {
2096 			_lists.get(listIndex).setFilter(element);
2097 			completionInfo = new CompletionInfo(_lists.get(listIndex), element, textValue);
2098 			if (completionInfo.matchingElements.size() > 0) {
2099 				BindingColumnElement col_element = completionInfo.matchingElements.firstElement();
2100 				_lists.get(listIndex).removeListSelectionListener(this);
2101 				_lists.get(listIndex).setSelectedValue(col_element, true);
2102 				_lists.get(listIndex).addListSelectionListener(this);
2103 			}
2104 
2105 		}
2106 
2107 		cleanLists(listIndex);
2108 	}
2109 
2110 	private CompletionInfo completionInfo;
2111 
2112 	protected class CompletionInfo {
2113 		String validPath = null;
2114 		String completionInitPath = null;
2115 		String commonBeginningPath = null;
2116 		Vector<BindingColumnElement> matchingElements = null;
2117 
2118 		protected CompletionInfo(FilteredJList<?> list, String subPartialPath, String fullPath) {
2119 			validPath = fullPath.substring(0, fullPath.lastIndexOf(".") + 1);
2120 			completionInitPath = subPartialPath;
2121 			matchingElements = findElementsMatching(list.getModel(), subPartialPath);
2122 			if (matchingElements.size() == 1) {
2123 				commonBeginningPath = matchingElements.firstElement().getLabel();
2124 			}
2125 			else if (matchingElements.size() > 1) {
2126 				int endCommonPathIndex = 0;
2127 				boolean foundDiff = false;
2128 				while (!foundDiff) {
2129 					if (endCommonPathIndex < matchingElements.firstElement().getLabel().length()) {
2130 						char c = matchingElements.firstElement().getLabel().charAt(endCommonPathIndex);
2131 						for (int i = 1; i < matchingElements.size(); i++) {
2132 							String label = matchingElements.elementAt(i).getLabel();
2133 							if (endCommonPathIndex < label.length() && label.charAt(endCommonPathIndex) != c) {
2134 								foundDiff = true;
2135 							}
2136 						}
2137 						if (!foundDiff) {
2138 							endCommonPathIndex++;
2139 						}
2140 					}
2141 					else {
2142 						foundDiff = true;
2143 					}
2144 				}
2145 				commonBeginningPath = matchingElements.firstElement().getLabel().substring(0, endCommonPathIndex);
2146 			}
2147 		}
2148 
2149 		@Override
2150 		public String toString() {
2151 			return "CompletionInfo, completionInitPath=" + completionInitPath + " validPath=" + validPath + " commonBeginningPath="
2152 					+ commonBeginningPath + " matchingElements=" + matchingElements;
2153 		}
2154 
2155 		private boolean alreadyAutocompleted = false;
2156 
2157 		protected void autoComplete() {
2158 			if (!alreadyAutocompleted) {
2159 				bindingSelector.getTextField().setText(validPath + commonBeginningPath);
2160 			}
2161 			else {
2162 				bindingSelector.getTextField().setText(validPath + commonBeginningPath + ".");
2163 			}
2164 			alreadyAutocompleted = true;
2165 			SwingUtilities.invokeLater(new Runnable() {
2166 				@Override
2167 				public void run() {
2168 					bindingSelector.getTextField().requestFocusInWindow();
2169 				}
2170 			});
2171 		}
2172 
2173 	}
2174 
2175 	@Override
2176 	protected void processEnterPressed() {
2177 		LOGGER.fine("Pressed on ENTER");
2178 
2179 		int index = 0;
2180 		if (bindingSelector.getEditedObject() != null) {
2181 			index = StringUtils.countMatches(bindingSelector.getTextField().getText(), ".");
2182 		}
2183 
2184 		FilteredJList<?> list = listAtIndex(index);
2185 		if (list != null) {
2186 			int currentSelected = list.getSelectedIndex();
2187 			if (currentSelected > -1) {
2188 				valueChanged(new ListSelectionEvent(list, currentSelected, currentSelected, false));
2189 				// list.setSelectedIndex(currentSelected);
2190 				update();
2191 				completionInfo = null;
2192 			}
2193 		}
2194 
2195 		// System.out.println("bindingSelector.getEditedObject()=" + bindingSelector.getEditedObject());
2196 		// System.out.println("valid=" + bindingSelector.getEditedObject().isValid());
2197 
2198 		if (bindingSelector.getEditedObject() != null && bindingSelector.getEditedObject().isValid()) {
2199 			bindingSelector.apply();
2200 		}
2201 	}
2202 
2203 	@Override
2204 	protected void processDelete() {
2205 		LOGGER.fine("Pressed on DELETE");
2206 		suppressSelection();
2207 	}
2208 
2209 	@Override
2210 	protected void processBackspace() {
2211 		LOGGER.fine("Pressed on BACKSPACE");
2212 		if (!suppressSelection()) {
2213 			if (bindingSelector.getTextField().getText().length() > 0) {
2214 				bindingSelector.getTextField().setText(
2215 						bindingSelector.getTextField().getText().substring(0, bindingSelector.getTextField().getText().length() - 1));
2216 
2217 			}
2218 		}
2219 	}
2220 
2221 	private boolean suppressSelection() {
2222 		if (bindingSelector.getTextField().getText().length() > 0) {
2223 			if (bindingSelector.getTextField().getSelectedText() != null && bindingSelector.getTextField().getSelectedText().length() > 0) {
2224 				int begin = bindingSelector.getTextField().getSelectionStart();
2225 				int end = bindingSelector.getTextField().getSelectionEnd();
2226 				bindingSelector.getTextField().setText(bindingSelector.getTextField().getText().substring(0, begin)
2227 						+ bindingSelector.getTextField().getText().substring(end, bindingSelector.getTextField().getText().length()));
2228 				return true;
2229 			}
2230 		}
2231 		return false;
2232 	}
2233 
2234 	@Override
2235 	protected void processTabPressed() {
2236 		LOGGER.fine("Pressed on TAB, completionInfo=" + completionInfo);
2237 		if (completionInfo != null) {
2238 			// System.out.println("Autocomplete !!!");
2239 			completionInfo.autoComplete();
2240 		}
2241 	}
2242 
2243 	@Override
2244 	protected void processUpPressed() {
2245 		LOGGER.fine("Pressed on UP");
2246 
2247 		int index = 0;
2248 		if (bindingSelector.getEditedObject() != null) {
2249 			index = StringUtils.countMatches(bindingSelector.getTextField().getText(), ".");
2250 		}
2251 
2252 		FilteredJList<?> list = listAtIndex(index);
2253 
2254 		int currentSelected = list.getSelectedIndex();
2255 		if (currentSelected > 0) {
2256 			list.removeListSelectionListener(this);
2257 			list.setSelectedIndex(currentSelected - 1);
2258 			list.addListSelectionListener(this);
2259 		}
2260 	}
2261 
2262 	@Override
2263 	protected void processDownPressed() {
2264 		LOGGER.fine("Pressed on DOWN");
2265 		if (!bindingSelector.popupIsShown()) {
2266 			bindingSelector.openPopup();
2267 		}
2268 
2269 		int index = 0;
2270 		if (bindingSelector.getEditedObject() != null) {
2271 			index = StringUtils.countMatches(bindingSelector.getTextField().getText(), ".");
2272 		}
2273 
2274 		FilteredJList<?> list = listAtIndex(index);
2275 
2276 		int currentSelected = list.getSelectedIndex();
2277 		list.removeListSelectionListener(this);
2278 		list.setSelectedIndex(currentSelected + 1);
2279 		list.addListSelectionListener(this);
2280 
2281 	}
2282 
2283 	/*@Override
2284 	protected void processLeftPressed() {
2285 		logger.fine("Pressed on LEFT");
2286 	}*/
2287 
2288 	/*@Override
2289 	protected void processRightPressed() {
2290 		logger.fine("Pressed on RIGHT");
2291 	
2292 		if (!bindingSelector.popupIsShown()) {
2293 			bindingSelector.openPopup();
2294 		}
2295 	
2296 		int index = 0;
2297 		if (bindingSelector.getEditedObject() != null) {
2298 			index = StringUtils.countMatches(bindingSelector.getTextField().getText(), ".");
2299 		}
2300 	
2301 		FilteredJList list = listAtIndex(index);
2302 	
2303 		int currentSelected = list.getSelectedIndex();
2304 		if (currentSelected > -1 && list.isFiltered()) {
2305 			valueChanged(new ListSelectionEvent(list, currentSelected, currentSelected, false));
2306 			update();
2307 			completionInfo = null;
2308 		} else if (completionInfo != null) {
2309 			completionInfo.autoComplete();
2310 		} else {
2311 			list.requestFocusInWindow();
2312 		}
2313 	}*/
2314 
2315 	boolean isKeyPathFromTextASubKeyPath(String inputText) {
2316 		int dotCount = StringUtils.countMatches(inputText, ".");
2317 		if (listAtIndex(dotCount) == null) {
2318 			return false;
2319 		}
2320 		BindingColumnListModel listModel = listAtIndex(dotCount).getModel();
2321 		String subPartialPath = inputText.substring(inputText.lastIndexOf(".") + 1);
2322 		Vector<Integer> pathElementIndex = new Vector<>();
2323 		;
2324 		BindingColumnElement pathElement = findElementMatching(listModel, subPartialPath, pathElementIndex);
2325 		return pathElement != null;
2326 	}
2327 
2328 	boolean isKeyPathFromPanelValid() {
2329 		if (bindingSelector.getEditedObject() == null) {
2330 			return false;
2331 		}
2332 		int i = 0;
2333 		while (listAtIndex(i) != null && listAtIndex(i).getSelectedValue() != null) {
2334 			i++;
2335 		}
2336 		if (listAtIndex(i - 1).getSelectedValue() instanceof BindingColumnElement) {
2337 			if (TypeUtils.isTypeAssignableFrom(bindingSelector.getEditedObject().getDeclaredType(),
2338 					((BindingColumnElement) listAtIndex(i - 1).getSelectedValue()).getResultingType(), true)) {
2339 				return true;
2340 			}
2341 		}
2342 		return false;
2343 	}
2344 
2345 	BindingValue makeBindingValueFromPanel() {
2346 		if (bindingSelector.getEditedObject() == null || !bindingSelector.getEditedObject().isBindingValue()) {
2347 			return null;
2348 		}
2349 		int i = 1;
2350 		BindingColumnElement last = null;
2351 		while (listAtIndex(i) != null && listAtIndex(i).getSelectedValue() != null) {
2352 			last = (BindingColumnElement) listAtIndex(i).getSelectedValue();
2353 			// System.out.println("Selecting " + last.getElement());
2354 
2355 			if (last.getElement() instanceof FunctionPathElement) {
2356 				for (FunctionArgument arg : ((FunctionPathElement) last.getElement()).getArguments()) {
2357 					DataBinding<?> argValue = ((FunctionPathElement) last.getElement()).getParameter(arg);
2358 					if (argValue == null) {
2359 						if (TypeUtils.isNumber(arg.getArgumentType())) {
2360 							argValue = new DataBinding<>("0", bindingSelector.getBindable(), arg.getArgumentType(),
2361 									BindingDefinitionType.GET);
2362 						}
2363 						else {
2364 							argValue = new DataBinding<>("null", bindingSelector.getBindable(), arg.getArgumentType(),
2365 									BindingDefinitionType.GET);
2366 						}
2367 						((FunctionPathElement) last.getElement()).setParameter(arg, argValue);
2368 					}
2369 					// System.out.println("> ARG " + arg + " = " + ((FunctionPathElement) last.getElement()).getParameter(arg));
2370 				}
2371 			}
2372 
2373 			((BindingValue) bindingSelector.getEditedObject().getExpression())
2374 					.setBindingPathElementAtIndex((BindingPathElement) last.getElement(), i - 1);
2375 			i++;
2376 		}
2377 		if (last != null) {
2378 			((BindingValue) bindingSelector.getEditedObject().getExpression())
2379 					.removeBindingPathElementAfter((BindingPathElement) last.getElement());
2380 		}
2381 		return (BindingValue) bindingSelector.getEditedObject().getExpression();
2382 	}
2383 
2384 	protected void valueSelected(int index, JList<?> list) {
2385 
2386 		DataBinding<?> binding = bindingSelector.getEditedObject();
2387 
2388 		// Unused boolean bindingRecreated = false;
2389 
2390 		if (!binding.isBindingValue()) {
2391 
2392 			bindingSelector.editionMode = EditionMode.NORMAL_BINDING;
2393 			binding.setExpression(bindingSelector.makeBinding()); // Should create a BindingValue instance !!!
2394 			// Unused bindingRecreated = true;
2395 			if (!binding.isBindingValue()) {
2396 				LOGGER.severe("Should never happen: valueSelected() called for a non-BindingValue instance !");
2397 				return;
2398 			}
2399 		}
2400 		BindingValue bindingValue = (BindingValue) binding.getExpression();
2401 		if (LOGGER.isLoggable(Level.FINE)) {
2402 			LOGGER.fine("Value selected: index=" + index + " list=" + list + " bindingValue=" + bindingValue);
2403 		}
2404 		BindingValueSelectorPanel.BindingColumnElement selectedValue = (BindingValueSelectorPanel.BindingColumnElement) list
2405 				.getSelectedValue();
2406 
2407 		// System.out.println("element: " + selectedValue.getElement() + " of " + selectedValue.getElement().getClass());
2408 		// System.out.println("editionMode=" + bindingSelector.editionMode);
2409 
2410 		if (selectedValue == null) {
2411 			return;
2412 		}
2413 		if (index == 0 && selectedValue.getElement() instanceof BindingVariable) { // ICI
2414 			if (list.getSelectedValue() != bindingValue.getBindingVariable()) {
2415 				bindingSelector.disconnect();
2416 				bindingValue.setBindingVariable((BindingVariable) selectedValue.getElement());
2417 				binding.setExpression(bindingValue);
2418 				bindingSelector.fireEditedObjectChanged();
2419 			}
2420 		}
2421 		else {
2422 			if (selectedValue.getElement() instanceof SimplePathElement) {
2423 				// FIXED invalid type object comparison
2424 				if (selectedValue.getElement() != bindingValue.getBindingPathElementAtIndex(index - 1)) {
2425 					bindingSelector.disconnect();
2426 					bindingValue.setBindingPathElementAtIndex((BindingPathElement) selectedValue.getElement(), index - 1);
2427 					binding.setExpression(bindingValue);
2428 					bindingSelector.fireEditedObjectChanged();
2429 				}
2430 			}
2431 			else if (selectedValue.getElement() instanceof FunctionPathElement) {
2432 
2433 				BindingPathElement currentElement = bindingValue.getBindingPathElementAtIndex(index - 1);
2434 
2435 				LOGGER.info("Selecting currentElement " + currentElement + " selectedValue=" + selectedValue);
2436 
2437 				if (currentElement == null || !(currentElement instanceof FunctionPathElement)
2438 						|| ((FunctionPathElement) currentElement).getFunction() == null || !((FunctionPathElement) currentElement)
2439 								.getFunction().equals(((FunctionPathElement) selectedValue.getElement()).getFunction())) {
2440 					bindingSelector.disconnect();
2441 					Function function = ((FunctionPathElement) selectedValue.getElement()).getFunction();
2442 					LOGGER.info("Selecting function " + function);
2443 					List<DataBinding<?>> args = new ArrayList<>();
2444 					for (FunctionArgument arg : function.getArguments()) {
2445 						if (TypeUtils.isNumber(arg.getArgumentType())) {
2446 							args.add(new DataBinding<>("0", bindingSelector.getBindable(), arg.getArgumentType(),
2447 									BindingDefinitionType.GET));
2448 						}
2449 						else {
2450 							args.add(new DataBinding<>("null", bindingSelector.getBindable(), arg.getArgumentType(),
2451 									BindingDefinitionType.GET));
2452 						}
2453 					}
2454 					FunctionPathElement newFunctionPathElement = bindingSelector.getBindable().getBindingFactory().makeFunctionPathElement(
2455 							currentElement != null ? currentElement.getParent() : bindingValue.getLastBindingPathElement(), function, args);
2456 
2457 					if (newFunctionPathElement != null) {
2458 						// TODO: we need to handle here generic FunctionPathElement and not only JavaMethodPathElement
2459 						/*JavaMethodPathElement newMethodCall = new JavaMethodPathElement(bindingValue.getLastBindingPathElement(),
2460 								(MethodDefinition) ((FunctionPathElement) selectedValue.getElement()).getFunction(),
2461 								new ArrayList<DataBinding<?>>());*/
2462 						bindingValue.setBindingPathElementAtIndex(newFunctionPathElement, index - 1);
2463 						binding.setExpression(bindingValue);
2464 						bindingSelector.fireEditedObjectChanged();
2465 
2466 					}
2467 					else {
2468 						LOGGER.warning("Cannot retrieve new FunctionPathElement for " + bindingValue.getLastBindingPathElement()
2469 								+ " function=" + function);
2470 					}
2471 				}
2472 				// }
2473 			}
2474 		}
2475 	}
2476 }