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 @ 44855

History | View | Annotate | Download (13.9 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 static org.gvsig.expressionevaluator.swing.JExpressionBuilder.CONFIGURABLE_PANEL_ID;
48
import org.gvsig.tools.util.ToolsUtilLocator;
49

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

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

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

    
63
    private Color color_ok;
64
    private Timer timerExpression;
65

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

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

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

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

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

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

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

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

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

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

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

    
256
    protected boolean isTipEnabled() {
257
        return !StringUtils.isBlank(this.tip);
258
    }
259
    
260
    protected boolean isPreviewEnabled() {
261
        return !StringUtils.isBlank(this.preview);
262
    }
263
    
264
    protected boolean isMessageEnabled() {
265
        return !StringUtils.isBlank(this.message);
266
    }
267
    
268
    protected String getTip() {
269
        return this.tip;
270
    }
271

    
272
    protected String getMessage() {
273
        return this.message;
274
    }
275

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

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

    
359
    protected String toHTML(String s) {
360
      s = StringUtils.replace(s, "<html>", "");
361
      s = StringUtils.replace(s, "</html>", "");
362
      s = StringUtils.replace(s, "\n", "<br>");
363
      s = "<html>"+s+"</html>";
364
      return s;
365
    }
366
}