Index: DefaultCalculatorController.java
===================================================================
--- DefaultCalculatorController.java	(revision 44097)
+++ DefaultCalculatorController.java	(revision 44098)
@@ -5,16 +5,24 @@
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
 import org.gvsig.expressionevaluator.swing.CalculatorController;
 import java.util.Objects;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.JPopupMenu;
+import javax.swing.Timer;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
 import javax.swing.text.JTextComponent;
 import org.apache.commons.lang3.StringUtils;
 import org.gvsig.expressionevaluator.Expression;
 import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
 import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
+import org.gvsig.expressionevaluator.ExpressionSyntaxException;
 import org.gvsig.expressionevaluator.MutableSymbolTable;
 import org.gvsig.expressionevaluator.SymbolTable;
 import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
@@ -23,59 +31,98 @@
 import org.gvsig.tools.dataTypes.CoercionException;
 import org.gvsig.tools.dataTypes.DataTypesManager;
 import org.gvsig.tools.i18n.I18nManager;
+import org.gvsig.tools.swing.api.ChangeListenerHelper;
 import org.gvsig.tools.swing.api.ToolsSwingLocator;
 import org.gvsig.tools.swing.api.ToolsSwingManager;
 import org.gvsig.tools.swing.api.windowmanager.Dialog;
 import org.gvsig.tools.swing.api.windowmanager.WindowManager;
 import org.gvsig.tools.swing.api.windowmanager.WindowManager_v2;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  *
  * @author jjdelcerro
  */
 @SuppressWarnings("UseSpecificCatch")
-class DefaultCalculatorController<T> implements CalculatorController<T> {
+class DefaultCalculatorController<T> 
+        implements CalculatorController<T> , ChangeListenerHelper
+    {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCalculatorController.class);
     
     private static final Color COLOR_ERROR = new Color(255,225,232);
     
     private final JTextComponent text;
     private final int dataType;
     private final MutableSymbolTable defaultSymbolTable;
-    private final Color backgroundColor;
-    private final ExpressionEvaluatorSwingManager manager;
+    private final Color color_ok;
+    private final ExpressionEvaluatorSwingManager swingManager;
     private DefaultExpressionBuilderConfig config;
     private Expression expression;
+    private boolean warning;
+    private final ChangeListenerHelper changeListenerHelper;
+    private final Timer fireChangeTimer;
+    private String lastText;
+    private final ExpressionEvaluatorManager manager;
 
     public DefaultCalculatorController(ExpressionEvaluatorSwingManager manager, final JTextComponent text, int dataType) {
-        ToolsSwingManager swingManager = ToolsSwingLocator.getToolsSwingManager();
+        ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
         I18nManager i18n = ToolsLocator.getI18nManager();
 
-        this.manager = manager;
+        this.swingManager = manager;
+        this.manager = ExpressionEvaluatorLocator.getManager();
         this.config = null;
         this.expression = null;
-
+        this.warning = false;
+        this.changeListenerHelper = toolsSwingManager.createChangeListenerHelper();
+        
         this.text = text;
         this.dataType = dataType;
-        this.backgroundColor = this.text.getBackground();
+        this.color_ok = this.text.getBackground();
         this.defaultSymbolTable = ExpressionEvaluatorLocator.getManager().createSymbolTable();
+        this.text.addKeyListener(new KeyAdapter() {
+            @Override
+            public void keyPressed(KeyEvent e) {
+                   if( e.getKeyCode()==KeyEvent.VK_C && e.isControlDown() ) {
+                       doCalculate(true);
+                   } 
+            }
+        });
+        this.text.getDocument().addDocumentListener(new DocumentListener() {
+            @Override
+            public void insertUpdate(DocumentEvent e) {
+                fireChangeEvent();
+            }
+
+            @Override
+            public void removeUpdate(DocumentEvent e) {
+                fireChangeEvent();
+            }
+
+            @Override
+            public void changedUpdate(DocumentEvent e) {
+                fireChangeEvent();
+            }
+        });
         this.text.addFocusListener(new FocusListener() {
             @Override
             public void focusLost(FocusEvent e) {
-                doCalculate();
+                doCalculate(true);
             }
 
             @Override
             public void focusGained(FocusEvent e) {
-                doCalculate();
+                doCalculate(true);
             }
         });
-        swingManager.addClearButton(this.text, new ActionListener() {
+        toolsSwingManager.addClearButton(this.text, new ActionListener() {
             @Override
             public void actionPerformed(ActionEvent e) {
                 set(null);
             }
         });
-        swingManager.setDefaultPopupMenu(this.text);
+        toolsSwingManager.setDefaultPopupMenu(this.text);
         JPopupMenu popupMenu = this.text.getComponentPopupMenu();
         Action showExpressionBuilderAction = new AbstractAction(i18n.getTranslation("_Show_expression_builder")) {
             @Override
@@ -85,11 +132,22 @@
         };  
         popupMenu.addSeparator();
         popupMenu.add(showExpressionBuilderAction);
+        this.fireChangeTimer = new Timer(100, new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                fireEvent();
+            }
+        });
     }
 
+    private void fireChangeEvent() {
+        this.fireChangeTimer.setRepeats(false);
+        this.fireChangeTimer.restart();
+    }
+    
     private void doShowExpressionBuilder() {
         if( this.config == null ) {
-            this.config = new DefaultExpressionBuilderConfig(this.manager);
+            this.config = new DefaultExpressionBuilderConfig(this.swingManager);
             this.config.addSymbolTable(this.defaultSymbolTable);
         }
         if( this.expression == null ) {
@@ -97,7 +155,7 @@
         }
         expression.setPhrase(this.text.getText());
 
-        DefaultJExpressionBuilder panel = new DefaultJExpressionBuilder(this.manager, this.config);
+        DefaultJExpressionBuilder panel = new DefaultJExpressionBuilder(this.swingManager, this.config);
         panel.setExpression(this.expression);
         
         WindowManager_v2 windowManager = (WindowManager_v2) ToolsSwingLocator.getWindowManager();
@@ -123,27 +181,59 @@
         return this.defaultSymbolTable;
     }
 
-    private void doCalculate() {
+    private Object doCalculate(boolean updateText) {
+        System.out.println("doCalculate("+this.text.getName()+"), warning "+this.warning+", text '"+this.text.getText()+"'");
         if( !this.text.isEditable() ) {
-            return;
+            return null;
         }
         String source = this.text.getText();
         try {
             if( !StringUtils.isBlank(source) ) {
-                ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
-                Object value = manager.evaluate(this.defaultSymbolTable, source);
-                this.text.setText(Objects.toString(value, ""));
+                final Object value = this.manager.evaluate(this.defaultSymbolTable, source);
+                if( updateText ) {
+                    String s = Utils.repr(value);
+                    if( !StringUtils.equals(s, this.lastText) ) {
+                        this.setWarning(false);
+                        this.lastText = s;
+                        this.text.setText(this.lastText);
+                    }
+                }
+                return value;
             }
-            this.text.setBackground(this.backgroundColor);
+            this.setWarning(false);
+        } catch (ExpressionSyntaxException ex) {
+            System.out.println("doCalculate("+this.text.getName()+"), Error, text '"+this.text.getText()+"' "+ex.getDescription());
+            this.setWarning(true, ex.getDescription());
         } catch (Exception ex) {
+            this.setWarning(true);
+        }
+        return null;
+    }
+
+    public void setWarning(boolean warning) {
+        this.setWarning(warning, null);
+    }
+    
+    public void setWarning(boolean warning, String description) {
+        this.warning = warning;
+        if( warning ) {
             this.text.setBackground(COLOR_ERROR);
+            this.text.setToolTipText(description==null?"":description);
+        } else {
+            this.text.setBackground(this.color_ok);
+            this.text.setToolTipText("");
         }
     }
+
+    @Override
+    public boolean getWarning() {
+        return warning;
+    }
     
+    
     @Override
     public T get() {
-        doCalculate();
-        Object value = this.text.getText();
+        Object value = doCalculate(false);
         try {
             DataTypesManager dataManager = ToolsLocator.getDataTypesManager();
             value = dataManager.coerce(this.dataType, value);
@@ -156,7 +246,7 @@
     @Override
     public void set(T value) {
         this.text.setText(Objects.toString(value, ""));
-        this.text.setBackground(this.backgroundColor);
+        this.text.setBackground(this.color_ok);
     }
 
     @Override
@@ -169,7 +259,7 @@
             }
         }
         this.text.setText(Objects.toString(value, ""));
-        this.text.setBackground(this.backgroundColor);
+        this.text.setBackground(this.color_ok);
     }
 
     @Override
@@ -191,5 +281,40 @@
     public boolean isEditable() {
         return this.text.isEditable();
     }
+
+    @Override
+    public void addChangeListener(ChangeListener cl) {
+        this.changeListenerHelper.addChangeListener(cl);
+    }
+
+    @Override
+    public ChangeListener[] getChangeListeners() {
+        return this.changeListenerHelper.getChangeListeners();
+    }
+
+    @Override
+    public void removeChangeListener(ChangeListener cl) {
+        this.changeListenerHelper.removeAllChangeListener();
+    }
+
+    @Override
+    public void removeAllChangeListener() {
+        this.changeListenerHelper.removeAllChangeListener();
+    }
+
+    @Override
+    public boolean hasChangeListeners() {
+        return this.changeListenerHelper.hasChangeListeners();
+    }
+
+    @Override
+    public void fireEvent() {
+        this.changeListenerHelper.fireEvent();
+    }
+
+    @Override
+    public void fireEvent(ChangeEvent ce) {
+        this.changeListenerHelper.fireEvent(ce);
+    }
     
 }
