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 / DefaultJExpressionBuilder.java @ 44008

History | View | Annotate | Download (28.7 KB)

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

    
3
import java.awt.BorderLayout;
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.awt.event.MouseAdapter;
10
import java.awt.event.MouseEvent;
11
import java.net.URL;
12
import java.util.ArrayList;
13
import java.util.Collection;
14
import java.util.Date;
15
import java.util.HashSet;
16
import java.util.List;
17
import java.util.Objects;
18
import javax.swing.DefaultListCellRenderer;
19
import javax.swing.ImageIcon;
20
import javax.swing.JComponent;
21
import javax.swing.JEditorPane;
22
import javax.swing.JLabel;
23
import javax.swing.JList;
24
import javax.swing.JOptionPane;
25
import javax.swing.JScrollPane;
26
import javax.swing.JTree;
27
import javax.swing.SwingUtilities;
28
import javax.swing.event.ListSelectionEvent;
29
import javax.swing.event.ListSelectionListener;
30
import javax.swing.event.TreeModelEvent;
31
import javax.swing.event.TreeModelListener;
32
import javax.swing.event.TreeSelectionEvent;
33
import javax.swing.event.TreeSelectionListener;
34
import javax.swing.tree.DefaultTreeCellRenderer;
35
import javax.swing.tree.TreeModel;
36
import javax.swing.tree.TreePath;
37
import org.apache.commons.io.FilenameUtils;
38
import org.apache.commons.lang3.StringUtils;
39
import org.apache.commons.lang.StringEscapeUtils;
40
import org.gvsig.expressionevaluator.Expression;
41
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
42
import org.gvsig.expressionevaluator.Function;
43
import org.gvsig.expressionevaluator.SymbolTable;
44
import org.gvsig.expressionevaluator.swing.Element;
45
import org.gvsig.expressionevaluator.swing.Element.CalculatedElement;
46
import org.gvsig.expressionevaluator.swing.Element.ConstantElement;
47
import org.gvsig.expressionevaluator.swing.Element.FunctionElement;
48
import org.gvsig.expressionevaluator.swing.Element.GroupElement;
49
import org.gvsig.expressionevaluator.swing.Element.SimpleElement;
50
import org.gvsig.expressionevaluator.swing.Element.VariableElement;
51
import org.gvsig.expressionevaluator.swing.ExpressionBuilderConfig;
52
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
53
import org.gvsig.expressionevaluator.swing.JExpressionBuilder;
54
import org.gvsig.tools.ToolsLocator;
55
import org.gvsig.tools.script.Script;
56
import org.gvsig.tools.swing.api.Component;
57
import org.gvsig.tools.swing.api.ListElement;
58
import org.gvsig.tools.swing.api.ToolsSwingLocator;
59
import org.gvsig.tools.swing.api.ToolsSwingManager;
60
import org.gvsig.tools.swing.api.pickercontroller.PickerController;
61
import org.gvsig.tools.swing.api.script.ScriptSwingManager;
62
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
63
import org.gvsig.tools.swing.icontheme.IconTheme;
64

    
65
/**
66
 *
67
 * @author jjdelcerro
68
 */
69
public class DefaultJExpressionBuilder
70
        extends DefaultJExpressionBuilderView
71
        implements JExpressionBuilder {
72

    
73
    private final ExpressionEvaluatorSwingManager manager;
74
    private GroupElement currentGroup;
75
    private PickerController<List<Script>> scriptPicker;
76
    private ScriptSwingManager.ScriptEditor scriptEditor;
77
    
78
    private final ExpressionBuilderConfig config;
79
    private ElementsTreeModel treeModel;
80
    private java.awt.Component infoPanel = null;
81
    private JEditorPane txtDescription;
82
    private ImageIcon defaultIconGroup;
83
    private ImageIcon defaultIconElement;
84
    private JScrollPane scrDescription;
85
    
86
    private class ElementsTreeModel implements TreeModel {
87

    
88
        private final GroupElement root;
89
        private final HashSet<TreeModelListener> listeners;
90

    
91
        public ElementsTreeModel(GroupElement root) {
92
            this.root = root;
93
            this.listeners = new HashSet<>();
94
        }
95

    
96
        @Override
97
        public Object getRoot() {
98
            return this.root;
99
        }
100

    
101
        public void reload() {
102
            this.reload(this.root);
103
            this.fireTreeChanged();
104
        }
105
        
106
        private void reload(Element element) {
107
            if (element instanceof Element) {
108
                if (element instanceof GroupElement) {
109
                    reload(element);
110
                }
111
                element.reload();
112
            }
113
        }
114
        
115
        private List<Element> getChilds(final GroupElement node) {
116
            List<Element> x = new ArrayList<>();
117
            for (Element element : node.getElements()) {
118
                if (element instanceof GroupElement) {
119
                    x.add(element);
120
                }
121
            }
122
            return x; //node.getElements();
123
        }
124

    
125
        @Override
126
        public Object getChild(Object parent, int index) {
127
            List<Element> childs = getChilds((GroupElement) parent);
128
            Element child = childs.get(index);
129
            return child;
130
        }
131

    
132
        @Override
133
        public int getChildCount(Object parent) {
134
            List<Element> childs = getChilds((GroupElement) parent);
135
            return childs.size();
136
        }
137

    
138
        @Override
139
        public boolean isLeaf(Object node) {
140
            if( node instanceof GroupElement ) {
141
                return !((GroupElement) node).hasSubgroups();
142
            }
143
            return false;
144
        }
145

    
146
        @Override
147
        public void valueForPathChanged(TreePath path, Object newValue) {
148
        }
149

    
150
        @Override
151
        public int getIndexOfChild(Object parent, Object child) {
152
            List<Element> childs = getChilds((GroupElement) parent);
153
            int n = childs.indexOf(child);
154
            return n;
155
        }
156

    
157
        @Override
158
        public void addTreeModelListener(TreeModelListener l) {
159
            this.listeners.add(l);
160
        }
161

    
162
        @Override
163
        public void removeTreeModelListener(TreeModelListener l) {
164
            this.listeners.remove(l);
165
        }
166

    
167
        protected void fireTreeChanged() {
168
            for (TreeModelListener listener : listeners) {
169
                TreeModelEvent e = new TreeModelEvent(this, new Object[] {this.root});
170
                listener.treeNodesChanged(e);
171
            }
172
        }
173
    }
174

    
175
    public DefaultJExpressionBuilder(ExpressionEvaluatorSwingManager manager, ExpressionBuilderConfig config) {
176
        this.manager = manager;
177
        if( config == null ) {
178
            this.config = new DefaultExpressionBuilderConfig(manager);
179
        } else {
180
            this.config = config;
181
        }
182
        this.initComponents();
183
    }
184
    
185
    @Override
186
    public ImageIcon loadImage(String imageName) {
187
        String name = FilenameUtils.getBaseName(imageName);
188
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getDefault();
189
        if (theme.exists(name)) {
190
            return theme.get(name);
191
        }
192
        URL url = this.getClass().getResource(name + ".png");
193
        if (url == null) {
194
            return null;
195
        }
196
        return new ImageIcon(url);
197
    }
198

    
199
    private void initComponents() {
200
        ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
201
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
202
        
203
        this.defaultIconGroup = theme.get("expressionbuilder-element-group");
204
        this.defaultIconElement = theme.get("expressionbuilder-element");
205
        
206
        this.txtDescription = new JEditorPane();
207
        this.scrDescription = new JScrollPane(this.txtDescription);
208
        
209
        toolsSwingManager.setDefaultPopupMenu(this.txtExpression);
210
        toolsSwingManager.setDefaultPopupMenu(this.txtGroupElement);
211
        toolsSwingManager.setDefaultPopupMenu(this.txtSimpleElementFilter);
212
        toolsSwingManager.setDefaultPopupMenu(this.txtDescription);
213
        toolsSwingManager.addClearButton(this.txtExpression);
214
        toolsSwingManager.addClearButton(this.txtSimpleElementFilter, new ActionListener() {
215
            @Override
216
            public void actionPerformed(ActionEvent e) {
217
                txtSimpleElementFilter.setText("");
218
                doFilter();
219
            }
220
        });
221
        this.pnlDescription.setLayout(new BorderLayout());
222
        this.pnlDescription.setBackground(this.txtDescription.getBackground());
223
        
224
        this.treeElements.setCellRenderer(new DefaultTreeCellRenderer() {
225
            @Override
226
            public java.awt.Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
227
                JLabel label = (JLabel) super.getTreeCellRendererComponent(tree,value, selected, expanded, leaf, row, hasFocus);
228
                if( value instanceof Element ) {
229
                    Element element = (Element) value;
230
                    if( element.getIconName()==null ) {
231
                        if( element instanceof GroupElement ) {
232
                            label.setIcon(defaultIconGroup);
233
                        } else {
234
                            label.setIcon(defaultIconElement);
235
                        }
236
                    } else {
237
                        label.setIcon(element.getIcon());
238
                    }
239
                    label.setText(element.getName());
240
                } else {
241
                    label.setIcon(null);
242
                    label.setText(Objects.toString(value, ""));
243
                }
244
                return label;
245
            }
246
        });
247
        
248
        this.treeElements.addTreeSelectionListener(new TreeSelectionListener() {
249
            @Override
250
            public void valueChanged(TreeSelectionEvent e) {
251
                TreePath path = e.getPath();
252
                Element element = (Element) path.getLastPathComponent();
253
                if (element instanceof GroupElement) {
254
                    updateSimpleElementsList((GroupElement) element);
255
                }
256
            }
257
        });
258
        this.btnGroupElementInsert.addActionListener(new ActionListener() {
259
            @Override
260
            public void actionPerformed(ActionEvent e) {
261
                doInsert(txtGroupElement.getText());
262
            }
263
        });
264
        this.btnSimpleElementInsert.addActionListener(new ActionListener() {
265
            @Override
266
            public void actionPerformed(ActionEvent e) {
267
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
268
                if (element != null) {
269
                    doInsert(element.getValue());
270
                }
271
            }
272
        });
273
        this.btnSimpleElementFilter.addActionListener(new ActionListener() {
274
            @Override
275
            public void actionPerformed(ActionEvent e) {
276
                doFilter();
277
            }
278
        });
279
        
280
        this.lstSimpleElement.setModel(new FilteredListModel());
281
        this.lstSimpleElement.setCellRenderer(new DefaultListCellRenderer() {
282
            @Override
283
            public java.awt.Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
284
                JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
285
                Element element = null;
286
                if( value instanceof ListElement ) {
287
                    if( ((ListElement) value).getValue() instanceof Element ) {
288
                        element = (Element) ((ListElement) value).getValue();
289
                    }
290
                }
291
                if( element !=null ) {
292
                    if( element.getIconName()==null ) {
293
                        if( element instanceof GroupElement ) {
294
                            label.setIcon(defaultIconGroup);
295
                        } else {
296
                            label.setIcon(defaultIconElement);
297
                        }
298
                    } else {
299
                        label.setIcon(element.getIcon());
300
                    }
301
                    label.setText(element.getName());
302
                } else {
303
                    label.setIcon(null);
304
                    label.setText(Objects.toString(value, ""));
305
                }
306
                return label;
307
            }
308
        });
309
        this.lstSimpleElement.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
310
            @Override
311
            public void valueChanged(ListSelectionEvent e) {
312
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
313
                if (element != null) {
314
                    doSelectElement(element.getValue());
315
                }
316
            }
317
        });
318
        this.lstSimpleElement.addMouseListener(new MouseAdapter() {
319
            @Override
320
            public void mouseClicked(MouseEvent e) {
321
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
322
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
323
                    if (element != null) {
324
                        doSelectElement(element.getValue());
325
                        doInsert(element.getValue());
326
                    }
327
                }
328
            }
329
        });
330
        this.lstSimpleElement.addKeyListener(new KeyAdapter() {
331
            @Override
332
            public void keyReleased(KeyEvent e) {
333
                if( e.getKeyCode()==KeyEvent.VK_ENTER ) {
334
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
335
                    if (element != null) {
336
                        doSelectElement(element.getValue());
337
                        doInsert(element.getValue());
338
                    }
339
                }
340
            }
341
        });
342

    
343
        this.btnSimpleElementTimeLimit.addActionListener(new ActionListener() {
344
            @Override
345
            public void actionPerformed(ActionEvent e) {
346
                doSetTimeLimit();
347
            }
348
        });
349
        this.btnSimpleElementSortDown.addActionListener(new ActionListener() {
350
            @Override
351
            public void actionPerformed(ActionEvent e) {
352
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
353
                model.sort(false);
354
            }
355
        });
356
        this.btnSimpleElementSortUp.addActionListener(new ActionListener() {
357
            @Override
358
            public void actionPerformed(ActionEvent e) {
359
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
360
                model.sort(true);
361
            }
362
        });
363
        this.txtSimpleElementFilter.addKeyListener(new KeyAdapter() {
364
            @Override
365
            public void keyTyped(KeyEvent e) {
366
                if (e.getKeyChar() == '\n') {
367
                    doFilter();
368
                }
369
            }
370
        });
371
        this.btnAdd.addActionListener(new ActionListener() {
372
            @Override
373
            public void actionPerformed(ActionEvent e) {
374
                doInsert(" + ");
375
            }
376
        });
377
        this.btnDiv.addActionListener(new ActionListener() {
378
            @Override
379
            public void actionPerformed(ActionEvent e) {
380
                doInsert(" / ");
381
            }
382
        });
383
        this.btnEq.addActionListener(new ActionListener() {
384
            @Override
385
            public void actionPerformed(ActionEvent e) {
386
                doInsert(" = ");
387
            }
388
        });
389
        this.btnMult.addActionListener(new ActionListener() {
390
            @Override
391
            public void actionPerformed(ActionEvent e) {
392
                doInsert(" * ");
393
            }
394
        });
395
        this.btnNeq.addActionListener(new ActionListener() {
396
            @Override
397
            public void actionPerformed(ActionEvent e) {
398
                doInsert(" <> ");
399
            }
400
        });
401
        this.btnParentClose.addActionListener(new ActionListener() {
402
            @Override
403
            public void actionPerformed(ActionEvent e) {
404
                doInsert(" ) ");
405
            }
406
        });
407
        this.btnParentOpen.addActionListener(new ActionListener() {
408
            @Override
409
            public void actionPerformed(ActionEvent e) {
410
                doInsert(" ( ");
411
            }
412
        });
413
        this.btnSubst.addActionListener(new ActionListener() {
414
            @Override
415
            public void actionPerformed(ActionEvent e) {
416
                doInsert(" - ");
417
            }
418
        });
419
        ScriptSwingManager scriptSwingManager = ToolsSwingLocator.getScriptSwingManager();
420
        this.scriptPicker = scriptSwingManager.createListScriptPickerController(
421
                cboPickerScripts,
422
                btnPickerRemove,
423
                btnPickerSelectScript
424
        );
425
        this.scriptEditor = scriptSwingManager.createScriptEditor();
426
        this.pnlScriptEditorContainer.setLayout(new BorderLayout());
427
        this.pnlScriptEditorContainer.add(this.scriptEditor.asJComponent(), BorderLayout.CENTER);
428
    
429
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
430
        this.setPreferredSize(new Dimension(650, 350));
431
        this.txtDescription.setPreferredSize(new Dimension(200,200));
432
    }
433

    
434
    private String removeCursorMark(String s) {
435
        s = s.replace("{{", "");
436
        s = s.replace("}}", "");
437
        return s;
438
    }
439

    
440
    private void doInsert(String s) {
441
        this.txtExpression.replaceSelection(s);
442
        String ss = this.txtExpression.getText();
443
        int start = ss.indexOf("{{");
444
        int end = ss.indexOf("}}");
445
        if (start > 0 && end > 0) {
446
            this.txtExpression.replaceRange("", end, end + 2);
447
            this.txtExpression.replaceRange("", start, start + 2);
448
            this.txtExpression.setSelectionStart(start);
449
            this.txtExpression.setSelectionEnd(end - 2);
450
        }
451
        this.txtExpression.requestFocusInWindow();
452
    }
453

    
454
    private void doInsert(SimpleElement element) {
455
        if( element instanceof FunctionElement ) {
456
            Function function = ((FunctionElement)element).getFunction();
457
            if (function == null) {
458
                doInsert(element.getName());
459
            } else {
460
                doInsert(function.template() == null ? function.name() + "({{}})" : function.template());
461
            }
462
        } else if( element instanceof CalculatedElement) {
463
            Object value = ((CalculatedElement) element).getValue();
464
            if( value != null ) {
465
                doInsert(" "+value.toString()+" ");
466
            }
467
        } else if( element instanceof ConstantElement) {
468
            Object value = ((ConstantElement) element).getValue();
469
            doInsert(" "+repr(value)+" ");
470
        } else {
471
            doInsert(" "+element.getName()+" ");
472
        }
473
    }
474

    
475
    private void doFilter() {
476
        FilteredListModel model = (FilteredListModel) this.lstSimpleElement.getModel();
477
        model.setFilter(this.txtSimpleElementFilter.getText());
478
    }
479

    
480
    private void doSelectElement(SimpleElement element) {
481
        Component aditionalPanel = element.getAditionalPanel();
482
        java.awt.Component newInfoPanel = null;
483
        if( aditionalPanel == null ) {
484
            StringBuilder html = new StringBuilder();
485
            html.append("<html>\n");
486
            if( element instanceof ConstantElement ) {
487
                Object value = ((ConstantElement)element).getValue();
488
                if( value == null ) {
489
                    html.append("<b>Constant</b><br>\n<br>\n");
490
                    html.append("<b>Value</b> NULL<br>\n");
491
                } else {
492
                    html.append("<b>Constant</b><br>\n<br>\n");
493
                    html.append("<b>Value</b> ").append(repr(value)).append("<br>\n");
494
                    html.append("<b>Type</b> ").append(value.getClass().getSimpleName()).append("<br>\n");
495
                }
496

    
497
            } else if( element instanceof VariableElement ) {
498
                    VariableElement var = (VariableElement)element;
499
                    html.append("<b>").append(var.getLabel()).append("</b><br>\n<br>\n");
500
                    html.append("<b>Source</b> ").append(var.getSource()).append("<br>\n");
501
                    html.append("<b>Name</b> ").append(var.getName()).append("<br>\n");
502
                    html.append("<b>Type</b> ").append(var.getTypeName()).append("<br>\n");
503

    
504
            } else if( element instanceof FunctionElement ) {
505
                Function function = ((FunctionElement)element).getFunction();
506
                if (function == null) {
507
                    html.append("<b>Function</b> ").append(element.getName()).append("<br>\n<br>\n");
508
                    html.append("<b>Return</b> Object<br>\n<br>\n");
509
                    html.append("<b>Template:</b> ").append(element.getName()).append("()<br>\n");
510
                } else {
511
                    html.append("<b>Function</b> ").append(element.getName()).append("<br>\n<br>\n");
512
                    html.append("<b>Return</b> ");
513
                    html.append(StringUtils.isEmpty(function.returnType())?"Objec": function.returnType());
514
                    html.append("<br>\n");
515
                    html.append("<b>Template</b> ");
516
                    html.append(StringUtils.isEmpty(function.template())?element.getName()+"()": removeCursorMark(function.template()));
517
                    html.append("<br>\n");
518

    
519
                    String[] args = function.descriptionArgs();
520
                    if (args != null) {
521
                        html.append("<b>Arguments:</b> ").append("<ul>\n");
522
                        for (String arg : args) {
523
                            html.append("<li>").append(arg).append("</li>\n");
524
                        }
525
                        html.append("</ul>\n");
526
                        html.append("<br>\n");
527
                    }
528
                }
529
            } else {
530
                html.append("<b>Generic element<br>\n<br>\n");
531
                html.append("<b>Name</b> ").append(element.getName()).append("</br>\n");
532

    
533
            }
534

    
535
            if( element.getDescription()!=null ) {
536
                html.append("<b>Description</b><br>\n");
537
                html.append(element.getDescription().replace("\n", "<br>")).append("<br>\n");
538
            }
539
            html.append("</html>\n");
540
            this.txtDescription.setContentType("text/html");
541
            this.txtDescription.setText(html.toString());
542
            this.txtDescription.setCaretPosition(0);
543
            newInfoPanel = this.scrDescription;
544
        } else {
545
            newInfoPanel = aditionalPanel.asJComponent();
546
        }
547
        
548
        if( this.infoPanel != newInfoPanel ) {
549
            this.pnlDescription.removeAll();
550
            this.pnlDescription.add(newInfoPanel, BorderLayout.CENTER);
551
            this.pnlDescription.revalidate();
552
            this.pnlDescription.repaint();
553
            this.infoPanel = newInfoPanel;
554
        }
555
        
556
    }
557

    
558
    private void updateSimpleElementsList(GroupElement group) {
559
        FilteredListModel model = new FilteredListModel();
560
        model.addElement("Loading...");
561
        this.currentGroup = group;
562
        this.txtGroupElement.setText(group.getName());
563
        this.txtSimpleElementFilter.setText("");
564
        this.txtDescription.setText("");
565
        if( this.infoPanel != this.scrDescription ) {
566
            this.pnlDescription.removeAll();
567
            this.pnlDescription.add(this.scrDescription, BorderLayout.CENTER);
568
            this.pnlDescription.revalidate();
569
            this.pnlDescription.repaint();
570
            this.infoPanel = this.scrDescription;
571
        }
572
        if (group instanceof SimpleElement) {
573
            this.btnGroupElementInsert.setEnabled(true);
574
        } else {
575
            this.btnGroupElementInsert.setEnabled(false);
576
        }
577
        this.lstSimpleElement.setEnabled(false);
578
        this.lstSimpleElement.setModel(model);
579

    
580
        Thread th = new Thread(new Runnable() {
581
            @Override
582
            public void run() {
583
                simpleElementsUpdater();
584
            }
585
        }, "ExpressionBuilderSimpleElementsUpdater");
586
        th.start();
587
    }
588

    
589
    private void simpleElementsUpdater() {
590
        final GroupElement group = this.currentGroup;
591
        final FilteredListModel model = new FilteredListModel();
592
        for (Element child : group) {
593
            if (group != this.currentGroup) {
594
                return;
595
            }
596
            if (child instanceof SimpleElement) {
597
                String label = child.getName();
598
                Function function = child instanceof FunctionElement?  ((FunctionElement)child).getFunction(): null;
599
                if (function != null && !StringUtils.isEmpty(function.returnType())) {
600
                    label = "<html><b>" + label + "</b> return " + function.returnType() + "</html>";
601
//                    label = label + " return " + function.returnType();
602
                }
603
                model.addElement(new ListElement<>(label, child));
604
            }
605
        }
606
        model.sort(true);
607
        SwingUtilities.invokeLater(new Runnable() {
608
            @Override
609
            public void run() {
610
                if (group != currentGroup) {
611
                    return;
612
                }
613
                if( group.hasMoreElements() ) {
614
                    lblSimpleElementsMsg.setText("More elements...");
615
                } else {
616
                    lblSimpleElementsMsg.setText("");
617
                }
618
                lstSimpleElement.setEnabled(true);
619
                lstSimpleElement.setModel(model);
620
            }
621
        });
622

    
623
    }
624

    
625
    @Override
626
    public Expression getExpression() {
627
        String phrase = this.txtExpression.getText();
628
        if (StringUtils.isEmpty(phrase)) {
629
            return null;
630
        }
631
        Expression expression = ExpressionEvaluatorLocator.getManager().createExpression();
632
        expression.setPhrase(phrase);
633
        Script script = ToolsLocator.getScriptManager().createScript("UserScript", "", "python");
634
        this.scriptEditor.fetch(script);
635
        if( !StringUtils.isEmpty(script.getCode()) ) {
636
            expression.setUserScript(script);
637
        }
638
        return expression;
639
    }
640

    
641
    @Override
642
    public void setExpression(Expression expression) {
643
        this.txtExpression.setText(expression.getPhrase());
644
        if( expression.getUserScript()!=null ) {
645
            this.scriptEditor.set(expression.getUserScript());
646
        }
647
        if( expression.getScripts()!=null ) {
648
            this.scriptPicker.set(expression.getScripts().toList());
649
        }
650
    }
651
    
652
    @Override
653
    public int getSimpleElementsLimit() {
654
        return this.config.getSimpleElementsLimit();
655
    }
656

    
657
    @Override
658
    public void setSimpleElementsLimit(int limit) {
659
        this.config.setSimpleElementsLimit(limit);
660
    }
661
    
662
    @Override
663
    public List<Element> getElements() {
664
        return this.config.getElements();
665
    }
666

    
667
    @Override
668
    public Collection<SymbolTable> getSymbolTables() {
669
        return this.config.getSymbolTables();
670
    }
671
    
672
    @Override
673
    public void addSymbolTable(String name) {
674
        this.config.addSymbolTable(name);
675
    }
676
    
677
    @Override
678
    public void addSymbolTable(SymbolTable symbolTable) {
679
        this.config.addSymbolTable(symbolTable);
680
    }
681

    
682
    @Override
683
    public void removeAllSymbolTables() {
684
        this.config.removeAllSymbolTables();
685
    }
686

    
687
    @Override
688
    public void removeSymbolTable(String name) {
689
        this.config.removeSymbolTable(name);
690
    }
691

    
692
    @Override
693
    public void setScriptsEnabled(boolean enabled) {
694
        this.config.setScriptsEnabled(enabled);
695
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
696
    }
697

    
698
    @Override
699
    public boolean getScriptsEnabled() {
700
        return this.config.getScriptsEnabled();
701
    }
702
    
703
    @Override
704
    public JComponent asJComponent() {
705
        if( this.treeModel == null ) {
706
            this.treeModel = new ElementsTreeModel(
707
                    this.manager.createGroupElement("_Elements", this.getElements())
708
            );
709
            this.treeElements.setModel(this.treeModel);
710
        }
711
        return this;
712
    }
713

    
714
    private String repr(Object value)  {
715
        if (value == null) {
716
            return "NULL";
717
        } else if (value instanceof Date) {
718
            return "DATE('" + value + "')";
719
        } else if (value instanceof Boolean) {
720
            return value.toString();
721
        } else if (value instanceof String) {
722
            return "'" + StringEscapeUtils.escapeSql((String) value) + "'";
723
        } else {
724
            return StringEscapeUtils.escapeSql(value.toString());
725
        }
726
        
727
    }
728
    
729
    private void doSetTimeLimit() {
730
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
731
        String s = dialogs.inputDialog(
732
                "Indicate the time limit in seconds for calculating the elements", 
733
                "Time limit", 
734
                JOptionPane.QUESTION_MESSAGE, 
735
                String.valueOf(this.config.getSimpleElementsLimit())
736
        );
737
        if( StringUtils.isBlank(s) ) {
738
            return;
739
        }
740
        try {
741
            int n = Integer.parseInt(s);
742
            this.config.setSimpleElementsLimit(n);
743
            this.treeModel.reload();
744
        } catch(Exception ex) {
745
            dialogs.messageDialog(
746
                "Invalid time limit '"+s+"'.", 
747
                "Time limit", 
748
                JOptionPane.WARNING_MESSAGE
749
            );                    
750
        }
751
    }
752
}