Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.expressionevaluator / org.gvsig.expressionevaluator.swing / org.gvsig.expressionevaluator.swing.impl / src / main / java / org / gvsig / expressionevaluator / swing / impl / AbstractAutomaticExpressionChecker.java @ 47298

History | View | Annotate | Download (14.3 KB)

1
package org.gvsig.expressionevaluator.swing.impl;
2

    
3
import java.awt.Color;
4
import java.awt.Dimension;
5
import java.awt.event.ActionEvent;
6
import java.awt.event.ActionListener;
7
import java.awt.event.KeyAdapter;
8
import java.awt.event.KeyEvent;
9
import java.util.Collection;
10
import java.util.Objects;
11
import javax.swing.Action;
12
import javax.swing.JComponent;
13
import javax.swing.JEditorPane;
14
import javax.swing.JMenuItem;
15
import javax.swing.JOptionPane;
16
import javax.swing.JPopupMenu;
17
import javax.swing.JScrollPane;
18
import javax.swing.Timer;
19
import javax.swing.event.DocumentEvent;
20
import javax.swing.event.DocumentListener;
21
import javax.swing.text.JTextComponent;
22
import org.apache.commons.lang3.StringUtils;
23
import org.apache.commons.lang3.mutable.Mutable;
24
import org.apache.commons.lang3.mutable.MutableObject;
25
import org.gvsig.configurableactions.ConfigurableActionsMamager;
26
import org.gvsig.expressionevaluator.Code;
27
import org.gvsig.expressionevaluator.Code.Identifier;
28
import org.gvsig.expressionevaluator.Expression;
29
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
30
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
31
import org.gvsig.expressionevaluator.ExpressionRuntimeException;
32
import org.gvsig.expressionevaluator.ExpressionSyntaxException;
33
import org.gvsig.expressionevaluator.Function;
34
import org.gvsig.expressionevaluator.MutableSymbolTable;
35
import org.gvsig.expressionevaluator.swing.ExpressionBuilderConfig;
36
import org.gvsig.tools.ToolsLocator;
37
import org.gvsig.tools.exception.BaseException;
38
import org.gvsig.tools.i18n.I18nManager;
39
import org.gvsig.tools.swing.api.ToolsSwingLocator;
40
import org.gvsig.tools.swing.api.ToolsSwingManager;
41
import org.gvsig.tools.swing.api.windowmanager.Dialog;
42
import org.gvsig.tools.swing.api.windowmanager.WindowManager;
43
import org.gvsig.tools.swing.api.windowmanager.WindowManager_v2;
44
import org.gvsig.tools.visitor.VisitCanceledException;
45
import org.gvsig.tools.visitor.Visitor;
46
import org.gvsig.expressionevaluator.Code.Callable;
47
import org.gvsig.expressionevaluator.ReprMethod;
48
import static org.gvsig.expressionevaluator.swing.JExpressionBuilder.CONFIGURABLE_PANEL_ID;
49
import org.gvsig.tools.util.ToolsUtilLocator;
50

    
51
/**
52
 *
53
 * @author jjdelcerro
54
 */
55
@SuppressWarnings("UseSpecificCatch")
56
public abstract class AbstractAutomaticExpressionChecker {
57

    
58
    private static final Color COLOR_ERROR = new Color(255,225,232);
59
    private static final Color COLOR_SUGGESTION = new Color(255,255,159);
60

    
61
    private final JTextComponent text;
62
    private final ExpressionBuilderConfig builderConfig;
63

    
64
    private Color color_ok;
65
    private Timer timerExpression;
66

    
67
    private JMenuItem menuItemShowPreview;
68
    private JMenuItem menuItemShowTip;
69
    private JMenuItem menuItemShowMessage;
70

    
71
    private String message;
72
    protected String tip;
73
    private String preview;
74
    private DocumentListener doclistener;
75
    private KeyAdapter keylistener;
76
    private ActionListener timelistener;
77

    
78
    public AbstractAutomaticExpressionChecker(ExpressionBuilderConfig config, JTextComponent theText) {
79
        this.text = theText;
80
        this.builderConfig = config;
81
        this.initComponents();
82
    }
83

    
84
    private void initComponents() {
85
        final I18nManager i18n = ToolsLocator.getI18nManager();
86
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
87

    
88
        this.color_ok = this.text.getBackground();
89

    
90
        toolsSwingManager.setDefaultPopupMenu(this.text);
91
        toolsSwingManager.addClearButton(this.text);
92

    
93
        JPopupMenu popupMenu = this.text.getComponentPopupMenu();
94
        
95
        this.menuItemShowTip = new JMenuItem(i18n.getTranslation("_Show_tip"));
96
        this.menuItemShowTip.addActionListener((ActionEvent e) -> {
97
          if( StringUtils.isBlank(tip) ) {
98
            return;
99
          }
100
          JOptionPane.showMessageDialog(
101
                  text.getParent(),
102
                  toHTML(tip),
103
                  i18n.getTranslation("Tip"),
104
                  JOptionPane.INFORMATION_MESSAGE
105
          );
106
        });
107
        popupMenu.add(this.menuItemShowTip);
108

    
109
        this.menuItemShowPreview = new JMenuItem(i18n.getTranslation("_Show_preview"));
110
        this.menuItemShowPreview.addActionListener((ActionEvent e) -> {
111
          showMessageDialog(i18n.getTranslation("_Preview_value"),preview);
112
        });
113
        popupMenu.add(this.menuItemShowPreview);
114
        
115
        this.menuItemShowMessage = new JMenuItem(i18n.getTranslation("_Show_message"));
116
        this.menuItemShowMessage.addActionListener((ActionEvent e) -> {
117
          showMessageDialog(i18n.getTranslation("_Message"),message+"\n\n"+tip);
118
        });
119
        popupMenu.add(this.menuItemShowMessage);
120
        
121
        ConfigurableActionsMamager cfgActionsManager = ToolsUtilLocator.getConfigurableActionsMamager();
122
        Collection<Action> actions = cfgActionsManager.getConfigurableActions(CONFIGURABLE_PANEL_ID);
123
        if( !actions.isEmpty() ) {
124
          popupMenu.addSeparator();
125
          for( Action action :  actions) {
126
            JMenuItem item = new JMenuItem(action);
127
            item.addActionListener((ActionEvent e) -> {
128
              e.setSource(this);
129
              action.actionPerformed(e);
130
            });
131
            popupMenu.add(item);
132
          }
133
        }        
134

    
135
        this.timelistener = (ActionEvent e) -> {
136
          doCheckExpression();
137
          stateChanged();
138
        };
139
        this.doclistener = new DocumentListener() {
140
            @Override
141
            public void insertUpdate(DocumentEvent e) {
142
                timerExpression.restart();
143
            }
144

    
145
            @Override
146
            public void removeUpdate(DocumentEvent e) {
147
                timerExpression.restart();
148
            }
149

    
150
            @Override
151
            public void changedUpdate(DocumentEvent e) {
152
                timerExpression.restart();
153
            }
154
        };
155
        this.keylistener = new KeyAdapter() {
156
            @Override
157
            public void keyPressed(KeyEvent e) {
158
                if (e.getKeyCode() == KeyEvent.VK_C && e.isControlDown()) {
159
                    doCheckExpression();
160
                }
161
            }
162
        };
163
        this.timerExpression = new Timer(3000, this.timelistener);
164
        this.timerExpression.setRepeats(false);
165
        this.text.getDocument().addDocumentListener(this.doclistener);
166
        this.text.addKeyListener(this.keylistener);
167
    }
168
    
169
    private void doCheckExpression() {
170
        if( this.text == null || this.builderConfig == null ) {
171
            return;
172
        }
173
        if( !this.text.isShowing() || !this.text.isEnabled() ) {
174
            this.timerExpression.restart();
175
            return;
176
        }
177
        Expression expression = this.getExpression();
178
        this.setTip(null);
179
        this.setPreview(null);
180
        this.setMessage(JOptionPane.INFORMATION_MESSAGE, null);
181
        if (expression == null) {
182
            return;
183
        }
184
        try {
185
            expression.getCode();
186
            this.setMessage(JOptionPane.INFORMATION_MESSAGE, "");
187
        } catch (ExpressionSyntaxException ex) {
188
            this.setMessage(JOptionPane.ERROR_MESSAGE, ex.getDescription());
189
            return;
190
        } catch (Exception ex) {
191
            this.setMessage(JOptionPane.ERROR_MESSAGE, "Syntax error in expression");
192
            return;
193
        }
194
        final Mutable<String> theTip = new MutableObject<>(null);
195
        expression.setSQLCompatible(false);
196
        if (this.builderConfig.getPreviewSymbolTable() == null) {
197
            try {
198
                ExpressionEvaluatorManager theManager = ExpressionEvaluatorLocator.getManager();
199
                MutableSymbolTable symbolTable = theManager.createSymbolTable();
200
                Object theValue = expression.execute(symbolTable);
201
                this.setPreview(theValue);
202
            } catch (Exception ex) {
203
                this.setMessage(JOptionPane.INFORMATION_MESSAGE, "");
204
            }
205
        } else {
206
            try {
207
                Object theValue = expression.execute(this.builderConfig.getPreviewSymbolTable());
208
                this.setPreview(theValue);
209
            } catch (ExpressionRuntimeException ex) {
210
                theTip.setValue(ex.getTip());
211
                this.setMessage(JOptionPane.ERROR_MESSAGE, "Runtime error. " + ex.getMessage());
212
            } catch (Exception ex) {
213
                this.setMessage(JOptionPane.ERROR_MESSAGE, "Runtime error. " + ex.getMessage());
214
            }
215
        }
216
        if( this.builderConfig.getPreferences().isSQLCompatible() ) {
217
            Code code = expression.getCode();
218
            try {
219
                code.accept(new Visitor() {
220
                    @Override
221
                    public void visit(Object obj) throws VisitCanceledException, BaseException {
222
                        Code code = (Code) obj;
223
                        switch(code.code()) {
224
                            case Code.CALLABLE:
225
                                Function function = ((Callable)code).function();
226
                                if( function!=null && !function.isSQLCompatible() ) {
227
                                    theTip.setValue(I18N.Avoid_the_use_of_functions_not_compatible_with_SQL_in_this_data_source(function.name()));
228
                                }
229
                                break;
230
                            case Code.IDENTIFIER:
231
                                if( builderConfig.getPreviewSymbolTable()!=null && 
232
                                        !builderConfig.getPreviewSymbolTable().isSQLCompatible(((Identifier)code).name()) ) {
233
                                    theTip.setValue(I18N.Avoid_the_use_of_functions_not_compatible_with_SQL_in_this_data_source(((Identifier)code).name()));
234
                                }
235
                                break;
236
                            case Code.METHOD:
237
                                theTip.setValue(I18N.Avoid_the_use_of_functions_not_compatible_with_SQL_in_this_data_source(((Callable)code).name()));
238
                                break;
239
                        }
240
                    }
241
                });
242
            } catch (BaseException ex) {
243
            }
244
        }
245
        String suggestion = this.getSuggestion();
246
        if( suggestion!=null ) {
247
          if( StringUtils.isBlank(theTip.getValue()) ) {
248
            theTip.setValue(suggestion);
249
          } else {
250
            theTip.setValue(suggestion+"\n\n"+theTip.getValue());
251
          }
252
        }
253
        if( !StringUtils.isBlank(theTip.getValue()) ) {
254
            this.setTip(theTip.getValue());
255
            if( this.text.getBackground()==this.color_ok ) {
256
              this.text.setBackground(COLOR_SUGGESTION);
257
            }
258
//            this.setMessage(JOptionPane.INFORMATION_MESSAGE, theTip.getValue());
259
        }
260
    }
261

    
262
    protected boolean isTipEnabled() {
263
        return !StringUtils.isBlank(this.tip);
264
    }
265
    
266
    protected boolean isPreviewEnabled() {
267
        return !StringUtils.isBlank(this.preview);
268
    }
269
    
270
    protected boolean isMessageEnabled() {
271
        return !StringUtils.isBlank(this.message);
272
    }
273
    
274
    protected String getTip() {
275
        return this.tip;
276
    }
277

    
278
    protected String getMessage() {
279
        return this.message;
280
    }
281

    
282
    protected String getPreview() {
283
        return this.preview; 
284
    }
285
    
286
    protected void showMessageDialog() {
287
        final I18nManager i18n = ToolsLocator.getI18nManager();
288
        if( this.isMessageEnabled() ) {
289
            this.showMessageDialog(
290
                    i18n.getTranslation("_Message"),
291
                    this.getMessage()
292
            );
293
        } else if( this.isPreviewEnabled()) {
294
            this.showMessageDialog(
295
                    i18n.getTranslation("_Preview_value"),
296
                    this.getPreview()
297
            );
298
        }
299
    }
300
    
301
    protected void showMessageDialog(String title, String msg) {
302
        final I18nManager i18n = ToolsLocator.getI18nManager();
303
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
304

    
305
        JEditorPane textMessage = new JEditorPane();
306
        JScrollPane scroll = new JScrollPane(textMessage);
307
        scroll.setPreferredSize(new Dimension(500, 300));
308
        toolsSwingManager.setDefaultPopupMenu(textMessage);
309
        textMessage.setContentType("text/html");
310
        textMessage.setText(toHTML(msg));
311
        textMessage.setCaretPosition(0);
312
        WindowManager_v2 winmgr = (WindowManager_v2) ToolsSwingLocator.getWindowManager();
313
        Dialog dialog = winmgr.createDialog(
314
                scroll,
315
                title, 
316
                null,
317
                WindowManager_v2.BUTTONS_OK
318
        );
319
        dialog.show(WindowManager.MODE.DIALOG);        
320
    }
321
    
322
    protected void setPreview(Object value) {
323
        ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getExpressionEvaluatorManager();
324
        ReprMethod repr = manager.getReprMethod(value);
325
        this.preview = repr.repr(value);
326
        this.text.setToolTipText(
327
                toHTML(StringUtils.abbreviate(Objects.toString(this.preview,""),100))
328
        );
329
        this.menuItemShowPreview.setEnabled(this.isPreviewEnabled());
330
        this.text.setBackground(color_ok);
331
    }
332
    
333
    protected void setMessage(int mode, String text) {
334
        if( StringUtils.isBlank(text) ) {
335
            this.message = "";
336
            this.text.setToolTipText("");
337
            this.menuItemShowMessage.setEnabled(false);
338
            this.text.setBackground(color_ok);
339
            return;
340
        } 
341
        this.message = text;
342
        this.text.setToolTipText(
343
                toHTML(StringUtils.abbreviate(Objects.toString(text,""),100))
344
        );
345
        this.menuItemShowMessage.setEnabled(true);
346
        switch (mode) {
347
            case JOptionPane.INFORMATION_MESSAGE:
348
                this.text.setBackground(COLOR_SUGGESTION);
349
                break;
350
            case JOptionPane.WARNING_MESSAGE:
351
            case JOptionPane.ERROR_MESSAGE:
352
            default:
353
                this.text.setBackground(COLOR_ERROR);
354
                break;
355
        }
356
    }
357
    
358
    protected void setTip(String theTip) {
359
        this.tip = theTip;
360
        this.menuItemShowTip.setEnabled(this.isTipEnabled());
361
    }
362
    
363
    protected abstract Expression getExpression();
364
    
365
    protected abstract String getSuggestion();
366

    
367
    protected String toHTML(String s) {
368
      s = StringUtils.replace(s, "<html>", "");
369
      s = StringUtils.replace(s, "</html>", "");
370
      s = StringUtils.replace(s, "\n", "<br>");
371
      s = "<html>"+s+"</html>";
372
      return s;
373
    }
374
    
375
    protected void stateChanged() {
376
        
377
    }
378
}