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.Component;
43  import java.awt.Container;
44  import java.awt.Dimension;
45  import java.awt.FlowLayout;
46  import java.awt.Font;
47  import java.awt.GridBagConstraints;
48  import java.awt.GridBagLayout;
49  import java.awt.Insets;
50  import java.awt.event.ActionEvent;
51  import java.awt.event.ActionListener;
52  import java.awt.event.FocusEvent;
53  import java.awt.event.FocusListener;
54  import java.lang.reflect.InvocationTargetException;
55  import java.util.logging.Level;
56  import java.util.logging.Logger;
57  
58  import javax.swing.BorderFactory;
59  import javax.swing.Box;
60  import javax.swing.ImageIcon;
61  import javax.swing.JButton;
62  import javax.swing.JLabel;
63  import javax.swing.JPanel;
64  import javax.swing.JScrollPane;
65  import javax.swing.JTextArea;
66  import javax.swing.SwingConstants;
67  import javax.swing.SwingUtilities;
68  import javax.swing.border.TitledBorder;
69  
70  import org.openflexo.connie.DataBinding;
71  import org.openflexo.connie.exception.NullReferenceException;
72  import org.openflexo.connie.exception.TypeMismatchException;
73  import org.openflexo.connie.expr.ArithmeticBinaryOperator;
74  import org.openflexo.connie.expr.ArithmeticUnaryOperator;
75  import org.openflexo.connie.expr.BinaryOperator;
76  import org.openflexo.connie.expr.BinaryOperatorExpression;
77  import org.openflexo.connie.expr.BindingValue;
78  import org.openflexo.connie.expr.BooleanBinaryOperator;
79  import org.openflexo.connie.expr.BooleanUnaryOperator;
80  import org.openflexo.connie.expr.ConditionalExpression;
81  import org.openflexo.connie.expr.Constant;
82  import org.openflexo.connie.expr.DefaultExpressionPrettyPrinter;
83  import org.openflexo.connie.expr.Expression;
84  import org.openflexo.connie.expr.Operator;
85  import org.openflexo.connie.expr.OperatorNotSupportedException;
86  import org.openflexo.connie.expr.SymbolicConstant;
87  import org.openflexo.connie.expr.UnaryOperator;
88  import org.openflexo.connie.expr.UnaryOperatorExpression;
89  import org.openflexo.connie.pp.ExpressionPrettyPrinter;
90  import org.openflexo.gina.model.FIBModelObject.FIBModelObjectImpl;
91  import org.openflexo.gina.utils.FIBIconLibrary;
92  import org.openflexo.swing.MouseOverButton;
93  
94  public class BindingExpressionPanel extends JPanel implements FocusListener {
95  
96  	static final Logger LOGGER = Logger.getLogger(BindingExpressionPanel.class.getPackage().getName());
97  
98  	DataBinding<?> dataBinding;
99  
100 	protected static ImageIcon iconForOperator(Operator op) {
101 		if (op == ArithmeticBinaryOperator.ADDITION) {
102 			return FIBIconLibrary.ADDITION_ICON;
103 		}
104 		else if (op == ArithmeticBinaryOperator.SUBSTRACTION) {
105 			return FIBIconLibrary.SUBSTRACTION_ICON;
106 		}
107 		else if (op == ArithmeticBinaryOperator.MULTIPLICATION) {
108 			return FIBIconLibrary.MULTIPLICATION_ICON;
109 		}
110 		else if (op == ArithmeticBinaryOperator.DIVISION) {
111 			return FIBIconLibrary.DIVISION_ICON;
112 		}
113 		else if (op == ArithmeticBinaryOperator.POWER) {
114 			return FIBIconLibrary.POWER_ICON;
115 		}
116 		else if (op == BooleanBinaryOperator.EQUALS) {
117 			return FIBIconLibrary.EQUALS_ICON;
118 		}
119 		else if (op == BooleanBinaryOperator.NOT_EQUALS) {
120 			return FIBIconLibrary.NOT_EQUALS_ICON;
121 		}
122 		else if (op == BooleanBinaryOperator.LESS_THAN) {
123 			return FIBIconLibrary.LESS_THAN_ICON;
124 		}
125 		else if (op == BooleanBinaryOperator.LESS_THAN_OR_EQUALS) {
126 			return FIBIconLibrary.LESS_THAN_OR_EQUALS_ICON;
127 		}
128 		else if (op == BooleanBinaryOperator.GREATER_THAN) {
129 			return FIBIconLibrary.GREATER_THAN_ICON;
130 		}
131 		else if (op == BooleanBinaryOperator.GREATER_THAN_OR_EQUALS) {
132 			return FIBIconLibrary.GREATER_THAN_OR_EQUALS_ICON;
133 		}
134 		else if (op == BooleanBinaryOperator.AND) {
135 			return FIBIconLibrary.AND_ICON;
136 		}
137 		else if (op == BooleanBinaryOperator.OR) {
138 			return FIBIconLibrary.OR_ICON;
139 		}
140 		else if (op == BooleanUnaryOperator.NOT) {
141 			return FIBIconLibrary.NOT_ICON;
142 		}
143 		else if (op == ArithmeticUnaryOperator.UNARY_MINUS) {
144 			return FIBIconLibrary.SUBSTRACTION_ICON;
145 		}
146 		else if (op == ArithmeticUnaryOperator.SIN) {
147 			return FIBIconLibrary.SIN_ICON;
148 		}
149 		else if (op == ArithmeticUnaryOperator.ASIN) {
150 			return FIBIconLibrary.ASIN_ICON;
151 		}
152 		else if (op == ArithmeticUnaryOperator.COS) {
153 			return FIBIconLibrary.COS_ICON;
154 		}
155 		else if (op == ArithmeticUnaryOperator.ACOS) {
156 			return FIBIconLibrary.ACOS_ICON;
157 		}
158 		else if (op == ArithmeticUnaryOperator.TAN) {
159 			return FIBIconLibrary.TAN_ICON;
160 		}
161 		else if (op == ArithmeticUnaryOperator.ATAN) {
162 			return FIBIconLibrary.ATAN_ICON;
163 		}
164 		else if (op == ArithmeticUnaryOperator.EXP) {
165 			return FIBIconLibrary.EXP_ICON;
166 		}
167 		else if (op == ArithmeticUnaryOperator.LOG) {
168 			return FIBIconLibrary.LOG_ICON;
169 		}
170 		else if (op == ArithmeticUnaryOperator.SQRT) {
171 			return FIBIconLibrary.SQRT_ICON;
172 		}
173 		return null;
174 	}
175 
176 	public BindingExpressionPanel(DataBinding<?> aDataBinding) {
177 		super();
178 		// logger.info("Instanciate BindingExpressionPanel with " + aDataBinding);
179 		setLayout(new BorderLayout());
180 		dataBinding = aDataBinding;
181 		init();
182 	}
183 
184 	public void delete() {
185 		if (rootExpressionPanel != null) {
186 			rootExpressionPanel.delete();
187 		}
188 		rootExpressionPanel = null;
189 		dataBinding = null;
190 	}
191 
192 	// private JTextArea expressionTA;
193 	private JPanel controls;
194 	private ExpressionInnerPanel rootExpressionPanel;
195 
196 	private enum ExpressionParsingStatus {
197 		UNDEFINED, VALID, SYNTAXICALLY_VALID, INVALID
198 	}
199 
200 	private ExpressionParsingStatus status = ExpressionParsingStatus.UNDEFINED;
201 	private String message = UNDEFINED_EXPRESSION_MESSAGE;
202 
203 	private static final String UNDEFINED_EXPRESSION_MESSAGE = "please_define_expression";
204 	private static final String UNDEFINED_OPERAND_FOR_OPERATOR = "undefined_operand_for_operator";
205 	private static final String VALID_EXPRESSION = "expression_is_valid_and_conform_to_required_type";
206 	private static final String VALID_EXPRESSION_BUT_MISMATCH_TYPE = "expression_is_valid_but_not_conform_to_requested_type_(found:($0)_expected:($1))";
207 
208 	private JLabel statusIcon;
209 	private JLabel messageLabel;
210 	private JTextArea evaluationTA;
211 	protected JPanel evaluationPanel;
212 
213 	protected ExpressionPrettyPrinter pp = new DefaultExpressionPrettyPrinter();
214 
215 	private ExpressionInnerPanel focusReceiver = null;
216 
217 	private boolean avoidLoop = false;
218 
219 	public void setEditedExpression(DataBinding<?> bindingExpression) {
220 		if (avoidLoop) {
221 			return;
222 		}
223 		dataBinding = bindingExpression;
224 		if (bindingExpression != null) {
225 			_setEditedExpression(bindingExpression.getExpression());
226 			if (rootExpressionPanel.getRepresentedExpression() == null
227 					|| !rootExpressionPanel.getRepresentedExpression().equals(bindingExpression.getExpression())) {
228 				avoidLoop = true;
229 				rootExpressionPanel.setRepresentedExpression(bindingExpression.getExpression());
230 				avoidLoop = false;
231 			}
232 		}
233 		update();
234 	}
235 
236 	protected void setEditedExpression(Expression expression) {
237 		_setEditedExpression(expression);
238 		update();
239 		fireEditedExpressionChanged(dataBinding);
240 	}
241 
242 	private void _setEditedExpression(Expression expression) {
243 		if (dataBinding != null) {
244 			dataBinding.setExpression(expression);
245 		}
246 		_checkEditedExpression();
247 	}
248 
249 	protected void _checkEditedExpression() {
250 		Operator undefinedOperator = null;
251 
252 		if (dataBinding == null) {
253 			return;
254 		}
255 
256 		if (evaluationPanel != null && evaluationTA != null && evaluationPanel.isVisible()) {
257 			evaluationTA.setText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("cannot_evaluate"));
258 		}
259 
260 		if (dataBinding.getExpression() != null) {
261 			if (expressionIsUndefined(dataBinding.getExpression())) {
262 				status = ExpressionParsingStatus.UNDEFINED;
263 				message = FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(UNDEFINED_EXPRESSION_MESSAGE);
264 				return;
265 			}
266 			else {
267 				for (BindingValue bv : dataBinding.getExpression().getAllBindingValues()) {
268 					if (!bv.isValid()) {
269 						message = FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("invalid_binding") + " " + bv;
270 						status = ExpressionParsingStatus.INVALID;
271 						return;
272 					}
273 				}
274 			}
275 		}
276 
277 		if (dataBinding.getExpression() == null) {
278 			message = FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("cannot_parse") + " " + dataBinding.getUnparsedBinding();
279 			status = ExpressionParsingStatus.INVALID;
280 		}
281 		else if ((undefinedOperator = firstOperatorWithUndefinedOperand(dataBinding.getExpression())) != null) {
282 			status = ExpressionParsingStatus.INVALID;
283 			try {
284 				message = FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(UNDEFINED_OPERAND_FOR_OPERATOR) + " "
285 						+ undefinedOperator.getLocalizedName() + " [" + pp.getSymbol(undefinedOperator) + "]";
286 			} catch (OperatorNotSupportedException e) {
287 				message = FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(UNDEFINED_OPERAND_FOR_OPERATOR) + " "
288 						+ undefinedOperator.getLocalizedName() + " [?]";
289 			}
290 		}
291 		else {
292 			try {
293 				if (evaluationPanel != null && evaluationTA != null && evaluationPanel.isVisible() && dataBinding != null) {
294 					Expression evaluatedExpression = dataBinding.getExpression().evaluate(null);
295 					if (evaluatedExpression != null) {
296 						evaluationTA.setText(evaluatedExpression.toString());
297 					}
298 				}
299 
300 			} catch (TypeMismatchException e) {
301 				status = ExpressionParsingStatus.INVALID;
302 				message = e.getHTMLLocalizedMessage();
303 			} catch (NullReferenceException e) {
304 				status = ExpressionParsingStatus.INVALID;
305 				message = e.getHTMLLocalizedMessage();
306 			} catch (InvocationTargetException e) {
307 				status = ExpressionParsingStatus.INVALID;
308 				message = e.getLocalizedMessage();
309 			}
310 
311 		}
312 	}
313 
314 	private static boolean expressionIsUndefined(Expression expression) {
315 		return expression instanceof BindingValue && ((BindingValue) expression).getBindingVariable() == null;
316 	}
317 
318 	private Operator firstOperatorWithUndefinedOperand(Expression expression) {
319 		if (expression instanceof BindingValue) {
320 			return null;
321 		}
322 		else if (expression instanceof Constant) {
323 			return null;
324 		}
325 		else if (expression instanceof BinaryOperatorExpression) {
326 			Expression leftOperand = ((BinaryOperatorExpression) expression).getLeftArgument();
327 			if (expressionIsUndefined(leftOperand)) {
328 				return ((BinaryOperatorExpression) expression).getOperator();
329 			}
330 			Operator returned = firstOperatorWithUndefinedOperand(leftOperand);
331 			if (returned == null) {
332 				Expression rightOperand = ((BinaryOperatorExpression) expression).getRightArgument();
333 				if (expressionIsUndefined(rightOperand)) {
334 					return ((BinaryOperatorExpression) expression).getOperator();
335 				}
336 				return firstOperatorWithUndefinedOperand(rightOperand);
337 			}
338 		}
339 		else if (expression instanceof UnaryOperatorExpression) {
340 			Expression operand = ((UnaryOperatorExpression) expression).getArgument();
341 			if (expressionIsUndefined(operand)) {
342 				return ((UnaryOperatorExpression) expression).getOperator();
343 			}
344 			return firstOperatorWithUndefinedOperand(operand);
345 		}
346 		return null;
347 	}
348 
349 	public DataBinding<?> getEditedExpression() {
350 		return dataBinding;
351 	}
352 
353 	protected void expressionMayHaveBeenEdited() {
354 		if (dataBinding == null) {
355 			return;
356 		}
357 
358 		// try {
359 		Expression newExpression = null;
360 		/*if (expressionTA.getText().trim().equals("")) {
361 			newExpression = new BindingValue();
362 			((BindingValue) newExpression).setDataBinding(dataBinding);
363 			// newExpression = new BindingExpression.BindingValueVariable("", _bindingExpression.getOwner());
364 		} else {
365 			newExpression = ExpressionParser.parse(expressionTA.getText());
366 		}*/
367 		if (!newExpression.equals(dataBinding.getExpression()) || status == ExpressionParsingStatus.INVALID) {
368 			_setEditedExpression(newExpression);
369 			rootExpressionPanel.setRepresentedExpression(dataBinding.getExpression());
370 			update();
371 			fireEditedExpressionChanged(dataBinding);
372 		}
373 		/*} catch (org.openflexo.connie.expr.parser.ParseException e) {
374 			message = "ERROR: cannot parse ";// + expressionTA.getText();
375 			status = ExpressionParsingStatus.INVALID;
376 			updateAdditionalInformations();
377 		}*/
378 	}
379 
380 	final private void init() {
381 		/*expressionTA = new JTextArea(3, 50);
382 		expressionTA.setLineWrap(true);
383 		expressionTA.addKeyListener(new KeyAdapter() {
384 			@Override
385 			public void keyTyped(KeyEvent e) {
386 				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
387 					expressionMayHaveBeenEdited();
388 				}
389 				if (e.getKeyChar() == KeyEvent.VK_ENTER) {
390 					expressionMayHaveBeenEdited();
391 				}
392 			}
393 		});
394 		expressionTA.addFocusListener(new FocusAdapter() {
395 			@Override
396 			public void focusLost(FocusEvent e) {
397 				expressionMayHaveBeenEdited();
398 			}
399 		});*/
400 		/*expressionTA.addMouseListener(new MouseAdapter(){
401 			@Override
402 			public void mouseClicked(MouseEvent e) {
403 				expressionMayHaveBeenEdited();
404 			}
405 		});*/
406 
407 		statusIcon = new JLabel();
408 		messageLabel = new JLabel("", SwingConstants.LEFT);
409 		messageLabel.setFont(new Font("SansSerif", Font.ITALIC, 9));
410 
411 		evaluationPanel = new JPanel(new BorderLayout());
412 		evaluationTA = new JTextArea(1, 20);
413 		evaluationTA.setEditable(false);
414 		evaluationTA.setLineWrap(true);
415 
416 		evaluationPanel.add(new JLabel(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("evaluation") + "  "), BorderLayout.WEST);
417 		evaluationPanel.add(evaluationTA, BorderLayout.CENTER);
418 
419 		final MouseOverButton showEvaluationButton = new MouseOverButton();
420 		showEvaluationButton.setBorder(BorderFactory.createEmptyBorder());
421 		showEvaluationButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_ICON);
422 		showEvaluationButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_SELECTED_ICON);
423 		showEvaluationButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("show_evaluation"));
424 		showEvaluationButton.addActionListener(new ActionListener() {
425 			@Override
426 			public void actionPerformed(ActionEvent e) {
427 				if (!evaluationPanel.isVisible()) {
428 					showEvaluationButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_TOP_ICON);
429 					showEvaluationButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_TOP_SELECTED_ICON);
430 					showEvaluationButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("hide_evaluation"));
431 					evaluationPanel.setVisible(true);
432 					_checkEditedExpression();
433 				}
434 				else {
435 					showEvaluationButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_ICON);
436 					showEvaluationButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_SELECTED_ICON);
437 					showEvaluationButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("show_evaluation"));
438 					evaluationPanel.setVisible(false);
439 				}
440 			}
441 		});
442 
443 		JPanel statusAndMessageLabel = new JPanel(new BorderLayout());
444 		statusAndMessageLabel.add(statusIcon, BorderLayout.WEST);
445 		statusAndMessageLabel.add(messageLabel, BorderLayout.CENTER);
446 		statusAndMessageLabel.add(showEvaluationButton, BorderLayout.EAST);
447 
448 		JPanel topPanel = new JPanel(new BorderLayout());
449 		// topPanel.add(expressionTA, BorderLayout.NORTH);
450 		topPanel.add(statusAndMessageLabel, BorderLayout.CENTER);
451 		topPanel.add(evaluationPanel, BorderLayout.SOUTH);
452 
453 		evaluationPanel.setVisible(false);
454 
455 		add(topPanel, BorderLayout.NORTH);
456 		rootExpressionPanel = new ExpressionInnerPanel(dataBinding.getExpression()) {
457 			@Override
458 			public void representedExpressionChanged(Expression newExpression) {
459 				setEditedExpression(newExpression);
460 			}
461 		};
462 		focusReceiver = rootExpressionPanel;
463 		add(new JScrollPane(rootExpressionPanel), BorderLayout.CENTER);
464 		controls = new JPanel(new BorderLayout());
465 
466 		final JPanel commonControls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
467 		final JPanel mathControls = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
468 
469 		commonControls
470 				.add(createOperatorGroupPanel("logical", BooleanBinaryOperator.AND, BooleanBinaryOperator.OR, BooleanUnaryOperator.NOT));
471 
472 		commonControls.add(createOperatorGroupPanel("comparison", BooleanBinaryOperator.EQUALS, BooleanBinaryOperator.NOT_EQUALS,
473 				BooleanBinaryOperator.LESS_THAN, BooleanBinaryOperator.LESS_THAN_OR_EQUALS, BooleanBinaryOperator.GREATER_THAN,
474 				BooleanBinaryOperator.GREATER_THAN_OR_EQUALS));
475 
476 		commonControls.add(createOperatorGroupPanel("arithmetic", ArithmeticBinaryOperator.ADDITION, ArithmeticBinaryOperator.SUBSTRACTION,
477 				ArithmeticBinaryOperator.MULTIPLICATION, ArithmeticBinaryOperator.DIVISION, ArithmeticUnaryOperator.UNARY_MINUS));
478 
479 		final MouseOverButton moreButton = new MouseOverButton();
480 		moreButton.setBorder(BorderFactory.createEmptyBorder());
481 		moreButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_ICON);
482 		moreButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_SELECTED_ICON);
483 		moreButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("show_more_operators"));
484 		moreButton.addActionListener(new ActionListener() {
485 			@Override
486 			public void actionPerformed(ActionEvent e) {
487 				if (!mathControls.isVisible()) {
488 					moreButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_TOP_ICON);
489 					moreButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_TOP_SELECTED_ICON);
490 					moreButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("hide_extra_operators"));
491 					commonControls.remove(moreButton);
492 					mathControls.add(moreButton);
493 					mathControls.setVisible(true);
494 				}
495 				else {
496 					moreButton.setNormalIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_ICON);
497 					moreButton.setMouseOverIcon(FIBIconLibrary.TOGGLE_ARROW_BOTTOM_SELECTED_ICON);
498 					moreButton.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("show_more_operators"));
499 					mathControls.remove(moreButton);
500 					commonControls.add(moreButton);
501 					mathControls.setVisible(false);
502 				}
503 			}
504 		});
505 
506 		commonControls.add(moreButton);
507 
508 		mathControls.add(createOperatorGroupPanel("scientific", ArithmeticBinaryOperator.POWER, ArithmeticUnaryOperator.SQRT,
509 				ArithmeticUnaryOperator.EXP, ArithmeticUnaryOperator.LOG));
510 
511 		mathControls.add(createOperatorGroupPanel("trigonometric", ArithmeticUnaryOperator.SIN, ArithmeticUnaryOperator.ASIN,
512 				ArithmeticUnaryOperator.COS, ArithmeticUnaryOperator.ACOS, ArithmeticUnaryOperator.TAN, ArithmeticUnaryOperator.ATAN));
513 
514 		controls.add(commonControls, BorderLayout.CENTER);
515 		controls.add(mathControls, BorderLayout.SOUTH);
516 
517 		mathControls.setVisible(false);
518 
519 		add(controls, BorderLayout.SOUTH);
520 		update();
521 	}
522 
523 	private JPanel createOperatorGroupPanel(String title, Operator... operators) {
524 		JPanel returned = new JPanel();
525 		returned.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 0));
526 
527 		for (final Operator o : operators) {
528 			JButton b = new JButton(iconForOperator(o));
529 			b.setBorder(BorderFactory.createEmptyBorder());
530 			b.setToolTipText(o.getLocalizedName());
531 			returned.add(b);
532 			b.addActionListener(new ActionListener() {
533 				@Override
534 				public void actionPerformed(ActionEvent e) {
535 					if (o instanceof UnaryOperator) {
536 						appendUnaryOperator((UnaryOperator) o);
537 					}
538 					else if (o instanceof BinaryOperator) {
539 						appendBinaryOperator((BinaryOperator) o);
540 					}
541 				}
542 			});
543 		}
544 
545 		if (title.equals("logical")) {
546 			JButton b = new JButton(FIBIconLibrary.IF_ICON);
547 			b.setBorder(BorderFactory.createEmptyBorder());
548 			b.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("conditional"));
549 			returned.add(b);
550 			b.addActionListener(new ActionListener() {
551 				@Override
552 				public void actionPerformed(ActionEvent e) {
553 					appendConditional();
554 				}
555 			});
556 		}
557 
558 		returned.setBorder(BorderFactory.createTitledBorder(null, FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey(title),
559 				TitledBorder.CENTER, TitledBorder.TOP, new Font("SansSerif", Font.ITALIC, 8)));
560 		return returned;
561 	}
562 
563 	protected void update() {
564 		_checkEditedExpression();
565 		updateExpressionTextArea();
566 		updateAdditionalInformations();
567 		revalidate();
568 		repaint();
569 	}
570 
571 	protected void fireEditedExpressionChanged(DataBinding<?> expression) {
572 		// Override if required
573 	}
574 
575 	protected void updateExpressionTextArea() {
576 		if (dataBinding == null) {
577 			return;
578 		}
579 		// expressionTA.setText(pp.getStringRepresentation(dataBinding.getExpression()));
580 		if (status == ExpressionParsingStatus.UNDEFINED) {
581 			statusIcon.setIcon(FIBIconLibrary.WARNING_ICON);
582 		}
583 		else if (status == ExpressionParsingStatus.INVALID) {
584 			statusIcon.setIcon(FIBIconLibrary.ERROR_ICON);
585 		}
586 		else if (status == ExpressionParsingStatus.SYNTAXICALLY_VALID) {
587 			statusIcon.setIcon(FIBIconLibrary.WARNING_ICON);
588 		}
589 		else if (status == ExpressionParsingStatus.VALID) {
590 			statusIcon.setIcon(FIBIconLibrary.OK_ICON);
591 		}
592 		messageLabel.setText(message);
593 	}
594 
595 	protected void updateAdditionalInformations() {
596 		if (status == ExpressionParsingStatus.UNDEFINED) {
597 			statusIcon.setIcon(FIBIconLibrary.WARNING_ICON);
598 		}
599 		else if (status == ExpressionParsingStatus.INVALID) {
600 			statusIcon.setIcon(FIBIconLibrary.ERROR_ICON);
601 		}
602 		else if (status == ExpressionParsingStatus.SYNTAXICALLY_VALID) {
603 			statusIcon.setIcon(FIBIconLibrary.WARNING_ICON);
604 		}
605 		else if (status == ExpressionParsingStatus.VALID) {
606 			statusIcon.setIcon(FIBIconLibrary.OK_ICON);
607 		}
608 		messageLabel.setText(message);
609 	}
610 
611 	protected abstract class ExpressionInnerPanel extends JPanel {
612 
613 		private final DataBinding<?> innerDataBinding;
614 		protected Expression _representedExpression;
615 		private BindingSelector _bindingSelector;
616 
617 		// private JTextField variableOrConstantTextField;
618 
619 		protected ExpressionInnerPanel(Expression expression) {
620 			super();
621 			if (LOGGER.isLoggable(Level.FINE)) {
622 				LOGGER.fine("Build new ExpressionInnerPanel with " + (expression != null ? expression.toString() : "null"));
623 			}
624 			_representedExpression = expression;
625 			innerDataBinding = new DataBinding<>(dataBinding.getOwner(), Object.class, DataBinding.BindingDefinitionType.GET);
626 			innerDataBinding.setExpression(_representedExpression);
627 			update();
628 			// addFocusListeners();
629 		}
630 
631 		public void delete() {
632 			if (_bindingSelector != null) {
633 				_bindingSelector.delete();
634 			}
635 			for (Component c : getComponents()) {
636 				if (c instanceof ExpressionInnerPanel) {
637 					((ExpressionInnerPanel) c).delete();
638 				}
639 			}
640 			removeAll();
641 			_representedExpression = null;
642 			_bindingSelector = null;
643 		}
644 
645 		private void addFocusListeners() {
646 			addFocusListenersToAllComponentsOf(this);
647 		}
648 
649 		private void addFocusListenersToAllComponentsOf(Component c) {
650 			c.addFocusListener(BindingExpressionPanel.this);
651 			if (c instanceof Container) {
652 				Container container = (Container) c;
653 				for (Component c2 : container.getComponents()) {
654 					addFocusListenersToAllComponentsOf(c2);
655 				}
656 			}
657 		}
658 
659 		private void removeFocusListeners() {
660 			removeFocusListenersToAllComponentsOf(this);
661 		}
662 
663 		private void removeFocusListenersToAllComponentsOf(Component c) {
664 			c.removeFocusListener(BindingExpressionPanel.this);
665 			if (c instanceof Container) {
666 				Container container = (Container) c;
667 				for (Component c2 : container.getComponents()) {
668 					removeFocusListenersToAllComponentsOf(c2);
669 				}
670 			}
671 		}
672 
673 		/*protected void textChanged()
674 		{
675 			try {
676 				Expression newExpression;
677 				if (variableOrConstantTextField.getText().trim().equals("")) {
678 					newExpression = new Variable("");
679 				}
680 				else {
681 					newExpression = parser.parse(variableOrConstantTextField.getText());
682 				}
683 				setRepresentedExpression(newExpression);
684 				//System.out.println("Text has changed for "+variableOrConstantTextField.getText()+" parsed as "+newExpression);
685 			} catch (ParseException e) {
686 				System.out.println("ERROR: cannot parse "+variableOrConstantTextField.getText());
687 			}
688 		}*/
689 
690 		protected class OperatorPanel extends JPanel {
691 			private final JButton currentOperatorIcon;
692 
693 			protected OperatorPanel(Operator operator) {
694 				super();
695 				setLayout(new BorderLayout());
696 
697 				currentOperatorIcon = new JButton(iconForOperator(operator));
698 				currentOperatorIcon.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
699 				currentOperatorIcon.setToolTipText(operator.getLocalizedName());
700 
701 				add(currentOperatorIcon, BorderLayout.CENTER);
702 			}
703 		}
704 
705 		protected class IfOperatorPanel extends JPanel {
706 			private final JButton currentOperatorIcon;
707 
708 			protected IfOperatorPanel() {
709 				super();
710 				setLayout(new BorderLayout());
711 
712 				currentOperatorIcon = new JButton(FIBIconLibrary.IF_ICON);
713 				currentOperatorIcon.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
714 				currentOperatorIcon.setToolTipText(FIBModelObjectImpl.GINA_LOCALIZATION.localizedForKey("conditional"));
715 
716 				add(currentOperatorIcon, BorderLayout.CENTER);
717 			}
718 		}
719 
720 		private void addBinaryExpressionVerticalLayout() {
721 			GridBagLayout gridbag2 = new GridBagLayout();
722 			GridBagConstraints c2 = new GridBagConstraints();
723 			setLayout(gridbag2);
724 
725 			final BinaryOperatorExpression exp = (BinaryOperatorExpression) _representedExpression;
726 			final ExpressionInnerPanel me = this;
727 
728 			OperatorPanel operatorPanel = new OperatorPanel(exp.getOperator());
729 
730 			c2.weightx = 0.0;
731 			c2.weighty = 0.0;
732 			c2.anchor = GridBagConstraints.CENTER;
733 			c2.fill = GridBagConstraints.VERTICAL;
734 			gridbag2.setConstraints(operatorPanel, c2);
735 			add(operatorPanel);
736 
737 			operatorPanel.setBorder(BorderFactory.createEtchedBorder());
738 			JPanel argsPanel = new JPanel();
739 
740 			GridBagLayout gridbag = new GridBagLayout();
741 			GridBagConstraints c = new GridBagConstraints();
742 
743 			argsPanel.setLayout(gridbag);
744 
745 			ExpressionInnerPanel leftArg = new ExpressionInnerPanel(exp.getLeftArgument()) {
746 				@Override
747 				public void representedExpressionChanged(Expression newExpression) {
748 					exp.setLeftArgument(newExpression);
749 					// Take care that we have here a recursion with inner classes
750 					// (I known this is not recommanded)
751 					// We should here access embedding instance !
752 					me.representedExpressionChanged(exp);
753 				}
754 			};
755 
756 			c.weightx = 1.0;
757 			c.weighty = 1.0;
758 			c.anchor = GridBagConstraints.NORTH;
759 			c.fill = GridBagConstraints.HORIZONTAL;
760 			c.gridwidth = GridBagConstraints.REMAINDER;
761 			gridbag.setConstraints(leftArg, c);
762 			argsPanel.add(leftArg);
763 
764 			ExpressionInnerPanel rightArg = new ExpressionInnerPanel(exp.getRightArgument()/*,depth+1*/) {
765 				@Override
766 				public void representedExpressionChanged(Expression newExpression) {
767 					exp.setRightArgument(newExpression);
768 					// Take care that we have here a recursion with inner classes
769 					// (I known this is not recommanded)
770 					// We should here access embedding instance !
771 					me.representedExpressionChanged(exp);
772 				}
773 			};
774 
775 			c.weightx = 1.0;
776 			c.weighty = 1.0;
777 			c.anchor = GridBagConstraints.NORTH;
778 			c.fill = GridBagConstraints.HORIZONTAL;
779 			c.gridwidth = GridBagConstraints.REMAINDER;
780 			gridbag.setConstraints(rightArg, c);
781 			argsPanel.add(rightArg);
782 
783 			c2.weightx = 1.0;
784 			c2.weighty = 0.0;
785 			c2.anchor = GridBagConstraints.NORTH;
786 			c2.fill = GridBagConstraints.BOTH;
787 			c2.gridwidth = GridBagConstraints.REMAINDER;
788 			gridbag2.setConstraints(argsPanel, c2);
789 			add(argsPanel);
790 
791 			Box box = Box.createHorizontalBox();
792 			c2.weightx = 1.0;
793 			c2.weighty = 1.0;
794 			c2.anchor = GridBagConstraints.SOUTH;
795 			c2.fill = GridBagConstraints.BOTH;
796 			c2.gridwidth = GridBagConstraints.REMAINDER;
797 			gridbag2.setConstraints(box, c2);
798 			add(box);
799 
800 			isHorizontallyLayouted = false;
801 		}
802 
803 		private void addConditionalExpressionVerticalLayout() {
804 			GridBagLayout gridbag2 = new GridBagLayout();
805 			GridBagConstraints c2 = new GridBagConstraints();
806 			setLayout(gridbag2);
807 
808 			final ConditionalExpression exp = (ConditionalExpression) _representedExpression;
809 			final ExpressionInnerPanel me = this;
810 
811 			IfOperatorPanel operatorPanel = new IfOperatorPanel();
812 
813 			c2.weightx = 0.0;
814 			c2.weighty = 0.0;
815 			c2.anchor = GridBagConstraints.EAST;
816 			c2.fill = GridBagConstraints.NONE;
817 			c2.gridwidth = GridBagConstraints.RELATIVE;
818 			c2.insets = new Insets(0, 0, 0, 0);
819 			gridbag2.setConstraints(operatorPanel, c2);
820 			add(operatorPanel);
821 
822 			operatorPanel.setBorder(BorderFactory.createEmptyBorder());
823 
824 			ExpressionInnerPanel conditionArg = new ExpressionInnerPanel(exp.getCondition()) {
825 				@Override
826 				public void representedExpressionChanged(Expression newExpression) {
827 					exp.setCondition(newExpression);
828 					// Take care that we have here a recursion with inner classes
829 					// (I known this is not recommanded)
830 					// We should here access embedding instance !
831 					me.representedExpressionChanged(exp);
832 				}
833 			};
834 
835 			c2.weightx = 1.0;
836 			c2.weighty = 0.0;
837 			c2.anchor = GridBagConstraints.CENTER;
838 			c2.fill = GridBagConstraints.HORIZONTAL;
839 			c2.gridwidth = GridBagConstraints.REMAINDER;
840 			c2.insets = new Insets(0, 0, 0, 0);
841 			gridbag2.setConstraints(conditionArg, c2);
842 			add(conditionArg);
843 
844 			JLabel thenLabel = new JLabel("then");
845 			thenLabel.setFont(thenLabel.getFont().deriveFont(9.0f));
846 
847 			c2.weightx = 0.0;
848 			c2.weighty = 0.0;
849 			c2.anchor = GridBagConstraints.EAST;
850 			c2.fill = GridBagConstraints.NONE;
851 			c2.gridwidth = GridBagConstraints.RELATIVE;
852 			c2.insets = new Insets(0, 0, 0, 3);
853 			gridbag2.setConstraints(thenLabel, c2);
854 			add(thenLabel);
855 
856 			ExpressionInnerPanel thenExp = new ExpressionInnerPanel(exp.getThenExpression()) {
857 				@Override
858 				public void representedExpressionChanged(Expression newExpression) {
859 					exp.setThenExpression(newExpression);
860 					// Take care that we have here a recursion with inner classes
861 					// (I known this is not recommanded)
862 					// We should here access embedding instance !
863 					me.representedExpressionChanged(exp);
864 				}
865 			};
866 
867 			c2.weightx = 1.0;
868 			c2.weighty = 0.0;
869 			c2.anchor = GridBagConstraints.CENTER;
870 			c2.fill = GridBagConstraints.HORIZONTAL;
871 			c2.gridwidth = GridBagConstraints.REMAINDER;
872 			c2.insets = new Insets(0, 0, 0, 0);
873 			gridbag2.setConstraints(thenExp, c2);
874 			add(thenExp);
875 
876 			JLabel elseLabel = new JLabel("else");
877 			elseLabel.setFont(elseLabel.getFont().deriveFont(9.0f));
878 
879 			c2.weightx = 0.0;
880 			c2.weighty = 0.0;
881 			c2.anchor = GridBagConstraints.EAST;
882 			c2.fill = GridBagConstraints.NONE;
883 			c2.gridwidth = GridBagConstraints.RELATIVE;
884 			c2.insets = new Insets(0, 0, 0, 3);
885 			gridbag2.setConstraints(elseLabel, c2);
886 			add(elseLabel);
887 
888 			ExpressionInnerPanel elseExp = new ExpressionInnerPanel(exp.getElseExpression()/*,depth+1*/) {
889 				@Override
890 				public void representedExpressionChanged(Expression newExpression) {
891 					exp.setElseExpression(newExpression);
892 					// Take care that we have here a recursion with inner classes
893 					// (I known this is not recommanded)
894 					// We should here access embedding instance !
895 					me.representedExpressionChanged(exp);
896 				}
897 			};
898 
899 			c2.weightx = 1.0;
900 			c2.weighty = 0.0;
901 			c2.anchor = GridBagConstraints.CENTER;
902 			c2.fill = GridBagConstraints.HORIZONTAL;
903 			c2.gridwidth = GridBagConstraints.REMAINDER;
904 			c2.insets = new Insets(0, 0, 0, 0);
905 			gridbag2.setConstraints(elseExp, c2);
906 			add(elseExp);
907 
908 			Box box = Box.createHorizontalBox();
909 			c2.weightx = 1.0;
910 			c2.weighty = 1.0;
911 			c2.anchor = GridBagConstraints.SOUTH;
912 			c2.fill = GridBagConstraints.BOTH;
913 			c2.gridwidth = GridBagConstraints.REMAINDER;
914 			gridbag2.setConstraints(box, c2);
915 			add(box);
916 
917 			isHorizontallyLayouted = false;
918 		}
919 
920 		private boolean isHorizontallyLayouted = true;
921 
922 		private void addBinaryExpressionHorizontalLayout() {
923 			GridBagLayout gridbag = new GridBagLayout();
924 			GridBagConstraints c = new GridBagConstraints();
925 
926 			setLayout(gridbag);
927 
928 			final BinaryOperatorExpression exp = (BinaryOperatorExpression) _representedExpression;
929 			final ExpressionInnerPanel me = this;
930 
931 			OperatorPanel operatorPanel = new OperatorPanel(exp.getOperator());
932 
933 			ExpressionInnerPanel leftArg = new ExpressionInnerPanel(exp.getLeftArgument()) {
934 				@Override
935 				public void representedExpressionChanged(Expression newExpression) {
936 					exp.setLeftArgument(newExpression);
937 					// Take care that we have here a recursion with inner classes
938 					// (I known this is not recommanded)
939 					// We should here access embedding instance !
940 					me.representedExpressionChanged(exp);
941 				}
942 			};
943 
944 			c.weightx = 1.0;
945 			c.weighty = 1.0;
946 			c.anchor = GridBagConstraints.NORTH;
947 			c.fill = GridBagConstraints.HORIZONTAL;
948 			gridbag.setConstraints(leftArg, c);
949 			add(leftArg);
950 
951 			c.weightx = 0.0;
952 			c.weighty = 1.0;
953 			c.anchor = GridBagConstraints.NORTH;
954 			c.fill = GridBagConstraints.NONE;
955 			gridbag.setConstraints(operatorPanel, c);
956 			add(operatorPanel);
957 
958 			ExpressionInnerPanel rightArg = new ExpressionInnerPanel(exp.getRightArgument()) {
959 				@Override
960 				public void representedExpressionChanged(Expression newExpression) {
961 					exp.setRightArgument(newExpression);
962 					// Take care that we have here a recursion with inner classes
963 					// (I known this is not recommanded)
964 					// We should here access embedding instance !
965 					me.representedExpressionChanged(exp);
966 				}
967 			};
968 
969 			c.weightx = 1.0;
970 			c.weighty = 1.0;
971 			c.anchor = GridBagConstraints.NORTH;
972 			c.fill = GridBagConstraints.HORIZONTAL;
973 			c.gridwidth = GridBagConstraints.REMAINDER;
974 			gridbag.setConstraints(rightArg, c);
975 			add(rightArg);
976 
977 			isHorizontallyLayouted = true;
978 
979 		}
980 
981 		private void addUnaryExpressionHorizontalLayout() {
982 			GridBagLayout gridbag = new GridBagLayout();
983 			GridBagConstraints c = new GridBagConstraints();
984 
985 			setLayout(gridbag);
986 
987 			final UnaryOperatorExpression exp = (UnaryOperatorExpression) _representedExpression;
988 			final ExpressionInnerPanel me = this;
989 
990 			OperatorPanel operatorPanel = new OperatorPanel(exp.getOperator());
991 
992 			c.weightx = 0.0;
993 			c.weighty = 1.0;
994 			c.anchor = GridBagConstraints.NORTH;
995 			c.fill = GridBagConstraints.NONE;
996 			gridbag.setConstraints(operatorPanel, c);
997 			add(operatorPanel);
998 
999 			ExpressionInnerPanel arg = new ExpressionInnerPanel(exp.getArgument()) {
1000 				@Override
1001 				public void representedExpressionChanged(Expression newExpression) {
1002 					exp.setArgument(newExpression);
1003 					// Take care that we have here a recursion with inner classes
1004 					// (I known this is not recommanded)
1005 					// We should here access embedding instance !
1006 					me.representedExpressionChanged(exp);
1007 				}
1008 			};
1009 
1010 			c.weightx = 1.0;
1011 			c.weighty = 1.0;
1012 			c.anchor = GridBagConstraints.NORTH;
1013 			c.fill = GridBagConstraints.HORIZONTAL;
1014 			c.gridwidth = GridBagConstraints.REMAINDER;
1015 			gridbag.setConstraints(arg, c);
1016 			add(arg);
1017 
1018 			isHorizontallyLayouted = true;
1019 		}
1020 
1021 		private void update() {
1022 			ExpressionInnerPanel parent = (ExpressionInnerPanel) SwingUtilities.getAncestorOfClass(ExpressionInnerPanel.class, this);
1023 			if (parent != null && parent.isHorizontallyLayouted && parent._representedExpression.getDepth() > 1) {
1024 				parent.update();
1025 				return;
1026 			}
1027 			removeFocusListeners();
1028 			removeAll();
1029 
1030 			// System.out.println("Update in ExpressionInnerPanel with " + _representedExpression + " of " +
1031 			// _representedExpression.getClass());
1032 
1033 			if (_representedExpression instanceof SymbolicConstant) {
1034 				GridBagLayout gridbag = new GridBagLayout();
1035 				GridBagConstraints c = new GridBagConstraints();
1036 				setLayout(gridbag);
1037 				JLabel symbolicConstantLabel = new JLabel(((SymbolicConstant) _representedExpression).getSymbol());
1038 				c.weightx = 0.0;
1039 				c.weighty = 1.0;
1040 				c.anchor = GridBagConstraints.NORTH;
1041 				c.fill = GridBagConstraints.NONE;
1042 				c.gridwidth = GridBagConstraints.REMAINDER;
1043 				gridbag.setConstraints(symbolicConstantLabel, c);
1044 				add(symbolicConstantLabel);
1045 			}
1046 
1047 			else if (_representedExpression instanceof BindingValue || _representedExpression instanceof Constant) {
1048 				GridBagLayout gridbag = new GridBagLayout();
1049 				GridBagConstraints c = new GridBagConstraints();
1050 				setLayout(gridbag);
1051 
1052 				if (LOGGER.isLoggable(Level.FINE)) {
1053 					LOGGER.fine("Building BindingSelector with " + _representedExpression);
1054 				}
1055 				_bindingSelector = new BindingSelector(innerDataBinding) {
1056 					@Override
1057 					public void apply() {
1058 
1059 						// This method is called whenever the inner DataBinding has been applied
1060 
1061 						super.apply();
1062 
1063 						innerDataBinding.setExpression(_bindingSelector.getEditedObject().getExpression());
1064 						setRepresentedExpression(_bindingSelector.getEditedObject().getExpression());
1065 
1066 						fireEditedExpressionChanged(dataBinding);
1067 					}
1068 
1069 					@Override
1070 					public void cancel() {
1071 						super.cancel();
1072 					}
1073 
1074 					@Override
1075 					public Dimension getPreferredSize() {
1076 						Dimension parentDim = super.getPreferredSize();
1077 						return new Dimension(100, parentDim.height);
1078 					}
1079 				};
1080 
1081 				if (innerDataBinding != null) {
1082 					_bindingSelector.setRevertValue(innerDataBinding.clone());
1083 				}
1084 
1085 				c.weightx = 1.0;
1086 				c.weighty = 1.0;
1087 				c.anchor = GridBagConstraints.NORTH;
1088 				c.fill = GridBagConstraints.HORIZONTAL;
1089 				c.gridwidth = GridBagConstraints.REMAINDER;
1090 				gridbag.setConstraints(_bindingSelector, c);
1091 				add(_bindingSelector);
1092 
1093 			}
1094 
1095 			else if (_representedExpression instanceof BinaryOperatorExpression) {
1096 				if (_representedExpression.getDepth() > 1) {
1097 					addBinaryExpressionVerticalLayout();
1098 				}
1099 				else {
1100 					addBinaryExpressionHorizontalLayout();
1101 				}
1102 			}
1103 
1104 			else if (_representedExpression instanceof UnaryOperatorExpression) {
1105 				addUnaryExpressionHorizontalLayout();
1106 			}
1107 
1108 			else if (_representedExpression instanceof ConditionalExpression) {
1109 				addConditionalExpressionVerticalLayout();
1110 			}
1111 
1112 			addFocusListeners();
1113 			revalidate();
1114 			repaint();
1115 		}
1116 
1117 		public Expression getRepresentedExpression() {
1118 			return _representedExpression;
1119 		}
1120 
1121 		public void setRepresentedExpression(Expression representedExpression) {
1122 			_representedExpression = representedExpression;
1123 			representedExpressionChanged(representedExpression);
1124 			update();
1125 			updateInfos();
1126 		}
1127 
1128 		private void updateInfos() {
1129 			_checkEditedExpression();
1130 			updateExpressionTextArea();
1131 			updateAdditionalInformations();
1132 		}
1133 
1134 		public abstract void representedExpressionChanged(Expression newExpression);
1135 	}
1136 
1137 	protected void appendBinaryOperator(BinaryOperator operator) {
1138 		// System.out.println("appendBinaryOperator " + operator);
1139 		if (focusReceiver != null) {
1140 			BindingValue variable = new BindingValue();
1141 			variable.setDataBinding(dataBinding);
1142 			Expression newExpression = new BinaryOperatorExpression(operator, focusReceiver.getRepresentedExpression(), variable);
1143 			/*logger.info("variable="+variable.getBindingValue());
1144 			logger.info("owner="+variable.getBindingValue().getOwner());
1145 			logger.info("bd="+variable.getBindingValue().getBindingDefinition());*/
1146 			focusReceiver.setRepresentedExpression(newExpression);
1147 		}
1148 	}
1149 
1150 	protected void appendUnaryOperator(UnaryOperator operator) {
1151 		// System.out.println("appendUnaryOperator " + operator);
1152 		if (focusReceiver != null) {
1153 			Expression newExpression = new UnaryOperatorExpression(operator, focusReceiver.getRepresentedExpression());
1154 			focusReceiver.setRepresentedExpression(newExpression);
1155 		}
1156 	}
1157 
1158 	protected void appendConditional() {
1159 		// System.out.println("appendConditional");
1160 		if (focusReceiver != null) {
1161 			BindingValue condition = new BindingValue();
1162 			condition.setDataBinding(dataBinding);
1163 			BindingValue elseExpression = new BindingValue();
1164 			elseExpression.setDataBinding(dataBinding);
1165 			Expression newExpression = new ConditionalExpression(condition, focusReceiver.getRepresentedExpression(), elseExpression);
1166 			focusReceiver.setRepresentedExpression(newExpression);
1167 		}
1168 	}
1169 
1170 	@Override
1171 	public void focusGained(FocusEvent e) {
1172 		focusReceiver = (ExpressionInnerPanel) SwingUtilities.getAncestorOfClass(ExpressionInnerPanel.class, (Component) e.getSource());
1173 		if (focusReceiver != null) {
1174 			if (LOGGER.isLoggable(Level.FINE)) {
1175 				LOGGER.fine("Focus gained by expression " + focusReceiver.getRepresentedExpression() + " receiver=" + focusReceiver);
1176 			}
1177 		}
1178 	}
1179 
1180 	@Override
1181 	public void focusLost(FocusEvent e) {
1182 		// Dont care
1183 		ExpressionInnerPanel whoLoseFocus = (ExpressionInnerPanel) SwingUtilities.getAncestorOfClass(ExpressionInnerPanel.class,
1184 				(Component) e.getSource());
1185 		if (whoLoseFocus != null) {
1186 			if (LOGGER.isLoggable(Level.FINE)) {
1187 				LOGGER.fine("Focus lost by expression " + whoLoseFocus.getRepresentedExpression() + " looser=" + whoLoseFocus);
1188 			}
1189 		}
1190 	}
1191 
1192 }