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

History | View | Annotate | Download (32.4 KB)

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

    
3
import java.awt.BorderLayout;
4
import java.awt.Dimension;
5
import java.awt.Toolkit;
6
import java.awt.datatransfer.Clipboard;
7
import java.awt.datatransfer.StringSelection;
8
import java.awt.event.ActionEvent;
9
import java.awt.event.ActionListener;
10
import java.awt.event.KeyAdapter;
11
import java.awt.event.KeyEvent;
12
import java.awt.event.MouseAdapter;
13
import java.awt.event.MouseEvent;
14
import java.net.URL;
15
import java.util.ArrayList;
16
import java.util.Collection;
17
import java.util.HashSet;
18
import java.util.List;
19
import java.util.Objects;
20
import javax.swing.DefaultListCellRenderer;
21
import javax.swing.ImageIcon;
22
import javax.swing.JComponent;
23
import javax.swing.JEditorPane;
24
import javax.swing.JLabel;
25
import javax.swing.JList;
26
import javax.swing.JMenuItem;
27
import javax.swing.JOptionPane;
28
import javax.swing.JPanel;
29
import javax.swing.JPopupMenu;
30
import javax.swing.JScrollPane;
31
import javax.swing.JTabbedPane;
32
import javax.swing.JTree;
33
import javax.swing.SwingUtilities;
34
import javax.swing.event.CaretEvent;
35
import javax.swing.event.CaretListener;
36
import javax.swing.event.ListSelectionEvent;
37
import javax.swing.event.ListSelectionListener;
38
import javax.swing.event.TreeModelEvent;
39
import javax.swing.event.TreeModelListener;
40
import javax.swing.event.TreeSelectionEvent;
41
import javax.swing.event.TreeSelectionListener;
42
import javax.swing.tree.DefaultTreeCellRenderer;
43
import javax.swing.tree.TreeModel;
44
import javax.swing.tree.TreePath;
45
import org.apache.commons.io.FilenameUtils;
46
import org.apache.commons.lang3.StringUtils;
47
import org.gvsig.expressionevaluator.Expression;
48
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
49
import org.gvsig.expressionevaluator.Function;
50
import org.gvsig.expressionevaluator.SymbolTable;
51
import org.gvsig.expressionevaluator.swing.Element;
52
import org.gvsig.expressionevaluator.swing.Element.CalculatedElement;
53
import org.gvsig.expressionevaluator.swing.Element.ConstantElement;
54
import org.gvsig.expressionevaluator.swing.Element.FunctionElement;
55
import org.gvsig.expressionevaluator.swing.Element.GroupElement;
56
import org.gvsig.expressionevaluator.swing.Element.SimpleElement;
57
import org.gvsig.expressionevaluator.swing.ExpressionBuilderConfig;
58
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
59
import org.gvsig.expressionevaluator.swing.JExpressionBuilder;
60
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.i18n.I18nManager;
62
import org.gvsig.tools.script.Script;
63
import org.gvsig.tools.swing.api.Component;
64
import org.gvsig.tools.swing.api.ListElement;
65
import org.gvsig.tools.swing.api.ToolsSwingLocator;
66
import org.gvsig.tools.swing.api.ToolsSwingManager;
67
import org.gvsig.tools.swing.api.pickercontroller.PickerController;
68
import org.gvsig.tools.swing.api.script.ScriptSwingManager;
69
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
70
import org.gvsig.tools.swing.icontheme.IconTheme;
71

    
72
/**
73
 *
74
 * @author jjdelcerro
75
 */
76
@SuppressWarnings("UseSpecificCatch")
77
public class DefaultJExpressionBuilder
78
        extends DefaultJExpressionBuilderView
79
        implements JExpressionBuilder {
80

    
81
    private final ExpressionEvaluatorSwingManager manager;
82
    private GroupElement currentGroup;
83
    private PickerController<List<Script>> scriptPicker;
84
    private ScriptSwingManager.ScriptEditor scriptEditor;
85
    
86
    private final ExpressionBuilderConfig config;
87
    private ElementsTreeModel treeModel;
88
    private ImageIcon defaultIconGroup;
89
    private ImageIcon defaultIconElement;
90
    private InfoPanel infoPanel;
91
    private AbstractAutomaticExpressionChecker automaticExpressionChecker;
92
    
93
    private static class InfoPanel implements Component {
94

    
95
        private final JEditorPane txtDescription;
96
        private final JScrollPane scrDescription;
97
        private final JTabbedPane tab;
98

    
99
        private final String labelDescription;
100
        private final String labelAdditionalPanel;
101
        private final JPanel pnlContainer;
102

    
103
        private String description; 
104
        private Component additionalPanel;
105
        
106
        public InfoPanel(JPanel pnlContainer) {
107
            ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
108
            I18nManager i18n = ToolsLocator.getI18nManager();
109
            
110
            this.pnlContainer = pnlContainer;
111
            this.labelDescription = i18n.getTranslation("_Description");
112
            this.labelAdditionalPanel = i18n.getTranslation("_Assistant");
113
            
114
            this.txtDescription = new JEditorPane();
115
            this.scrDescription = new JScrollPane(this.txtDescription);
116
            this.tab = new JTabbedPane();
117
            
118
            toolsSwingManager.setDefaultPopupMenu(this.txtDescription);
119
            this.txtDescription.setPreferredSize(new Dimension(200,200));
120
        }
121
        
122
        public void clean() {
123
            this.description = null;
124
            this.additionalPanel = null;
125
        }
126
        
127
        public void setDescription(String description) {
128
            this.description = description;
129
        }
130
        
131
        public void setAdditionalPanel(Component panel) {
132
            this.additionalPanel = panel;
133
        }
134

    
135
        @Override
136
        public JComponent asJComponent() {
137
            this.txtDescription.setContentType("text/html");
138
            this.txtDescription.setText(this.description);
139
            this.txtDescription.setCaretPosition(0);
140

    
141
            if( StringUtils.isBlank(this.description) ) {
142
                if( this.additionalPanel==null ) {
143
                    // Sin descripcion ni panel adicional, mostramos
144
                    // la descripcion vacia.
145
                    return this.scrDescription;
146
                }
147
                // Sin descripcion pero con panel adicional, mostramos el 
148
                // panel adicional.
149
                return this.additionalPanel.asJComponent();
150
            }
151
            if( this.additionalPanel==null ) {
152
                // Con descripcion y sin panel adicional, mostramos
153
                // la descripcion.
154
                return this.scrDescription;                
155
            } 
156
            // Con descripcion y panel adicional, mostramos un tab con los dos.
157
            this.tab.removeAll();
158
            this.tab.add(
159
                    this.labelDescription, 
160
                    this.scrDescription
161
            );
162
            this.tab.add(
163
                    this.labelAdditionalPanel, 
164
                    this.additionalPanel.asJComponent()
165
            );
166
            this.tab.setSelectedIndex(1);
167
            return this.tab;
168
        }
169

    
170
        public void repaint() {
171
            this.pnlContainer.removeAll();
172
            this.pnlContainer.add(this.asJComponent(), BorderLayout.CENTER);
173
            this.pnlContainer.revalidate();
174
            this.pnlContainer.repaint();
175
        }
176
    }
177

    
178
    private class ElementsTreeModel implements TreeModel {
179

    
180
        private final GroupElement root;
181
        private final HashSet<TreeModelListener> listeners;
182

    
183
        public ElementsTreeModel(GroupElement root) {
184
            this.root = root;
185
            this.listeners = new HashSet<>();
186
        }
187

    
188
        @Override
189
        public Object getRoot() {
190
            return this.root;
191
        }
192

    
193
        public void reload() {
194
            this.reload(this.root);
195
            this.fireTreeChanged();
196
        }
197
        
198
        private void reload(Element element) {
199
            if (element instanceof Element) {
200
                if (element instanceof GroupElement) {
201
                    reload(element);
202
                }
203
                element.reload();
204
            }
205
        }
206
        
207
        private List<Element> getChilds(final GroupElement node) {
208
            List<Element> x = new ArrayList<>();
209
            for (Element element : node.getElements()) {
210
                if (element instanceof GroupElement) {
211
                    x.add(element);
212
                }
213
            }
214
            return x; //node.getElements();
215
        }
216

    
217
        @Override
218
        public Object getChild(Object parent, int index) {
219
            List<Element> childs = getChilds((GroupElement) parent);
220
            Element child = childs.get(index);
221
            return child;
222
        }
223

    
224
        @Override
225
        public int getChildCount(Object parent) {
226
            List<Element> childs = getChilds((GroupElement) parent);
227
            return childs.size();
228
        }
229

    
230
        @Override
231
        public boolean isLeaf(Object node) {
232
            if( node instanceof GroupElement ) {
233
                return !((GroupElement) node).hasSubgroups();
234
            }
235
            return false;
236
        }
237

    
238
        @Override
239
        public void valueForPathChanged(TreePath path, Object newValue) {
240
        }
241

    
242
        @Override
243
        public int getIndexOfChild(Object parent, Object child) {
244
            List<Element> childs = getChilds((GroupElement) parent);
245
            int n = childs.indexOf(child);
246
            return n;
247
        }
248

    
249
        @Override
250
        public void addTreeModelListener(TreeModelListener l) {
251
            this.listeners.add(l);
252
        }
253

    
254
        @Override
255
        public void removeTreeModelListener(TreeModelListener l) {
256
            this.listeners.remove(l);
257
        }
258

    
259
        protected void fireTreeChanged() {
260
            for (TreeModelListener listener : listeners) {
261
                TreeModelEvent e = new TreeModelEvent(this, new Object[] {this.root});
262
                listener.treeNodesChanged(e);
263
            }
264
        }
265
    }
266
  
267
    @SuppressWarnings("OverridableMethodCallInConstructor")
268
    public DefaultJExpressionBuilder(ExpressionEvaluatorSwingManager manager, ExpressionBuilderConfig config) {
269
        this.manager = manager;
270
        if( config == null ) {
271
            this.config = new DefaultExpressionBuilderConfig(manager);
272
        } else {
273
            this.config = config;
274
        }
275
        this.initComponents();
276
    }
277
    
278
    @Override
279
    public ImageIcon loadImage(String imageName) {
280
        String name = FilenameUtils.getBaseName(imageName);
281
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getDefault();
282
        if (theme.exists(name)) {
283
            return theme.get(name);
284
        }
285
        URL url = this.getClass().getResource(name + ".png");
286
        if (url == null) {
287
            return null;
288
        }
289
        return new ImageIcon(url);
290
    }
291

    
292
    private void initComponents() {
293
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
294
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
295
        final I18nManager i18n = ToolsLocator.getI18nManager();
296
        
297
        this.automaticExpressionChecker = new AbstractAutomaticExpressionChecker(
298
                config, txtExpression
299
            ) {
300
            @Override
301
            protected Expression getExpression() {
302
                return DefaultJExpressionBuilder.this.getExpression();
303
            }
304

    
305
            @Override
306
            protected void setMessage(int mode, String text) {
307
                super.setMessage(mode, text); 
308
                lblMsg.setText("<html>"+StringUtils.abbreviate(text,100)+"</html>");
309
            }
310

    
311
            @Override
312
            protected void setPreview(Object value) {
313
                super.setPreview(value);
314
                lblMsg.setText("<html>"+StringUtils.abbreviate(this.getPreview(),100)+"</html>");
315
            }
316

    
317
            @Override
318
            protected void setTip(String theTip) {
319
                super.setTip(theTip); 
320
                btnTip.setToolTipText(this.getTip());
321
                btnTip.setVisible(this.isTipEnabled());
322
            }
323
            
324
        };
325
        this.infoPanel = new InfoPanel(this.pnlDescription);
326
        
327
        this.btnTip.setVisible(false);
328
        this.btnTip.addActionListener(new ActionListener() {
329
            @Override
330
            public void actionPerformed(ActionEvent e) {
331
                ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
332
                dialogs.messageDialog(
333
                        btnTip.getToolTipText(), 
334
                        "Tip", 
335
                        JOptionPane.INFORMATION_MESSAGE
336
                );
337
            }
338
        });
339

    
340
        this.defaultIconGroup = theme.get("expressionbuilder-element-group");
341
        this.defaultIconElement = theme.get("expressionbuilder-element");
342
        
343
        toolsSwingManager.translate(this.tabExpressionBuilder);
344
        toolsSwingManager.setDefaultPopupMenu(this.txtGroupElement);
345
        toolsSwingManager.setDefaultPopupMenu(this.txtSimpleElementFilter);
346
        toolsSwingManager.addClearButton(this.txtSimpleElementFilter, new ActionListener() {
347
            @Override
348
            public void actionPerformed(ActionEvent e) {
349
                txtSimpleElementFilter.setText("");
350
                doFilter();
351
            }
352
        });
353
        JMenuItem msgMenuTextEditor = new JMenuItem(i18n.getTranslation("text_editor"));
354
        msgMenuTextEditor.addActionListener(new ActionListener() {
355
            @Override
356
            public void actionPerformed(ActionEvent e) {
357
                automaticExpressionChecker.showMessageDialog();
358
            }
359
        });
360
        JMenuItem msgMenuCopy = new JMenuItem(i18n.getTranslation("copy"));
361
        msgMenuTextEditor.addActionListener(new ActionListener() {
362
            @Override
363
            public void actionPerformed(ActionEvent e) {
364
                StringSelection selection = new StringSelection(automaticExpressionChecker.getMessage());
365
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
366
                clipboard.setContents(selection, selection);                
367
            }
368
        });
369
        
370
        JPopupMenu msgMenu = new JPopupMenu();
371
        msgMenu.add(msgMenuTextEditor);
372
        msgMenu.addSeparator();
373
        msgMenu.add(msgMenuCopy);
374
        this.lblMsg.setComponentPopupMenu(msgMenu);
375

    
376
        this.pnlDescription.setLayout(new BorderLayout());
377
//        this.pnlDescription.setBackground(this.txtDescription.getBackground());
378
        this.txtExpression.addCaretListener(new CaretListener() {
379
            @Override
380
            public void caretUpdate(CaretEvent e) {
381
                lblColumn.setText(Integer.toString(e.getDot()));
382
            }
383
        });
384
        this.treeElements.setCellRenderer(new DefaultTreeCellRenderer() {
385
            @Override
386
            public java.awt.Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
387
                JLabel label = (JLabel) super.getTreeCellRendererComponent(tree,value, selected, expanded, leaf, row, hasFocus);
388
                if( value instanceof Element ) {
389
                    Element element = (Element) value;
390
                    if( element.getIconName()==null ) {
391
                        if( element instanceof GroupElement ) {
392
                            label.setIcon(defaultIconGroup);
393
                        } else {
394
                            label.setIcon(defaultIconElement);
395
                        }
396
                    } else {
397
                        label.setIcon(element.getIcon());
398
                    }
399
                    label.setText(element.getName());
400
                    label.setEnabled(element.isEnabled());
401
                } else {
402
                    label.setIcon(null);
403
                    label.setText(Objects.toString(value, ""));
404
                }
405
                return label;
406
            }
407
        });
408
        
409
        this.treeElements.addTreeSelectionListener(new TreeSelectionListener() {
410
            @Override
411
            public void valueChanged(TreeSelectionEvent e) {
412
                TreePath path = e.getPath();
413
                Element element = (Element) path.getLastPathComponent();
414
                if (element instanceof GroupElement) {
415
                    updateSimpleElementsList((GroupElement) element);
416
                }
417
            }
418
        });
419
        this.treeElements.addMouseListener(new MouseAdapter() {
420
            @Override
421
            public void mouseClicked(MouseEvent e) {
422
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
423
                    TreePath path = treeElements.getSelectionPath();
424
                    Element element = (Element) path.getLastPathComponent();
425
                    if( element instanceof SimpleElement ) {
426
                        doInsert((SimpleElement) element);
427
                    }
428
                }
429
            }
430
        });
431
        this.btnGroupElementInsert.addActionListener(new ActionListener() {
432
            @Override
433
            public void actionPerformed(ActionEvent e) {
434
                doInsert(txtGroupElement.getText());
435
            }
436
        });
437
        this.btnSimpleElementInsert.addActionListener(new ActionListener() {
438
            @Override
439
            public void actionPerformed(ActionEvent e) {
440
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
441
                if (element != null) {
442
                    doInsert(element.getValue());
443
                }
444
            }
445
        });
446
        this.btnSimpleElementFilter.addActionListener(new ActionListener() {
447
            @Override
448
            public void actionPerformed(ActionEvent e) {
449
                doFilter();
450
            }
451
        });
452
        
453
        this.lstSimpleElement.setModel(new FilteredListModel());
454
        this.lstSimpleElement.setCellRenderer(new DefaultListCellRenderer() {
455
            @Override
456
            public java.awt.Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
457
                JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
458
                Element element = null;
459
                if( value instanceof ListElement ) {
460
                    if( ((ListElement) value).getValue() instanceof Element ) {
461
                        element = (Element) ((ListElement) value).getValue();
462
                    }
463
                }
464
                if( element !=null ) {
465
                    if( element.getIconName()==null ) {
466
                        if( element instanceof GroupElement ) {
467
                            label.setIcon(defaultIconGroup);
468
                        } else {
469
                            label.setIcon(defaultIconElement);
470
                        }
471
                    } else {
472
                        label.setIcon(element.getIcon());
473
                    }
474
                    label.setText(element.getName());
475
                    label.setEnabled(element.isEnabled());
476
                } else {
477
                    label.setIcon(null);
478
                    label.setText(Objects.toString(value, ""));
479
                }
480
                return label;
481
            }
482
        });
483
        this.lstSimpleElement.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
484
            @Override
485
            public void valueChanged(ListSelectionEvent e) {
486
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
487
                if (element != null) {
488
                    doSelectElement(element.getValue());
489
                }
490
            }
491
        });
492
        this.lstSimpleElement.addMouseListener(new MouseAdapter() {
493
            @Override
494
            public void mouseClicked(MouseEvent e) {
495
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
496
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
497
                    if (element != null) {
498
                        doSelectElement(element.getValue());
499
                        doInsert(element.getValue());
500
                    }
501
                }
502
            }
503
        });
504
        this.lstSimpleElement.addKeyListener(new KeyAdapter() {
505
            @Override
506
            public void keyReleased(KeyEvent e) {
507
                if( e.getKeyCode()==KeyEvent.VK_ENTER ) {
508
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
509
                    if (element != null) {
510
                        doSelectElement(element.getValue());
511
                        doInsert(element.getValue());
512
                    }
513
                }
514
            }
515
        });
516

    
517
        this.btnSimpleElementTimeLimit.addActionListener(new ActionListener() {
518
            @Override
519
            public void actionPerformed(ActionEvent e) {
520
                doSetTimeLimit();
521
            }
522
        });
523
        this.btnSimpleElementSortDown.addActionListener(new ActionListener() {
524
            @Override
525
            public void actionPerformed(ActionEvent e) {
526
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
527
                model.sort(false);
528
            }
529
        });
530
        this.btnSimpleElementSortUp.addActionListener(new ActionListener() {
531
            @Override
532
            public void actionPerformed(ActionEvent e) {
533
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
534
                model.sort(true);
535
            }
536
        });
537
        this.txtSimpleElementFilter.addKeyListener(new KeyAdapter() {
538
            @Override
539
            public void keyTyped(KeyEvent e) {
540
                if (e.getKeyChar() == '\n') {
541
                    doFilter();
542
                }
543
            }
544
        });
545
        this.btnAdd.addActionListener(new ActionListener() {
546
            @Override
547
            public void actionPerformed(ActionEvent e) {
548
                doInsert(" + ");
549
            }
550
        });
551
        this.btnDiv.addActionListener(new ActionListener() {
552
            @Override
553
            public void actionPerformed(ActionEvent e) {
554
                doInsert(" / ");
555
            }
556
        });
557
        this.btnEq.addActionListener(new ActionListener() {
558
            @Override
559
            public void actionPerformed(ActionEvent e) {
560
                doInsert(" = ");
561
            }
562
        });
563
        this.btnMult.addActionListener(new ActionListener() {
564
            @Override
565
            public void actionPerformed(ActionEvent e) {
566
                doInsert(" * ");
567
            }
568
        });
569
        this.btnNeq.addActionListener(new ActionListener() {
570
            @Override
571
            public void actionPerformed(ActionEvent e) {
572
                doInsert(" <> ");
573
            }
574
        });
575
        this.btnParentClose.addActionListener(new ActionListener() {
576
            @Override
577
            public void actionPerformed(ActionEvent e) {
578
                doInsert(" ) ");
579
            }
580
        });
581
        this.btnParentOpen.addActionListener(new ActionListener() {
582
            @Override
583
            public void actionPerformed(ActionEvent e) {
584
                doInsert(" ( ");
585
            }
586
        });
587
        this.btnSubst.addActionListener(new ActionListener() {
588
            @Override
589
            public void actionPerformed(ActionEvent e) {
590
                doInsert(" - ");
591
            }
592
        });
593
        ScriptSwingManager scriptSwingManager = ToolsSwingLocator.getScriptSwingManager();
594
        this.scriptPicker = scriptSwingManager.createListScriptPickerController(
595
                cboPickerScripts,
596
                btnPickerRemove,
597
                btnPickerSelectScript
598
        );
599
        this.scriptEditor = scriptSwingManager.createScriptEditor();
600
        this.pnlScriptEditorContainer.setLayout(new BorderLayout());
601
        this.pnlScriptEditorContainer.add(this.scriptEditor.asJComponent(), BorderLayout.CENTER);
602
    
603
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
604
        this.setPreferredSize(new Dimension(650, 350));
605
    }
606

    
607
    private String removeCursorMark(String s) {
608
        if( s == null ) {
609
            return null;
610
        }
611
        s = s.replace("{{", "");
612
        s = s.replace("}}", "");
613
        return s;
614
    }
615

    
616
    public void insertText(String text) {
617
        doInsert(text);
618
    }
619

    
620
    public String getText() {
621
        return this.txtExpression.getText();
622
    }
623
    
624
    public void setText(String text) {
625
        this.txtExpression.setText(text);
626
    }
627
    
628
    private void doInsert(String s) {
629
        this.txtExpression.replaceSelection(s);
630
        String ss = this.txtExpression.getText();
631
        int start = ss.indexOf("{{");
632
        int end = ss.indexOf("}}");
633
        if (start > 0 && end > 0) {
634
            this.txtExpression.replaceRange("", end, end + 2);
635
            this.txtExpression.replaceRange("", start, start + 2);
636
            this.txtExpression.setSelectionStart(start);
637
            this.txtExpression.setSelectionEnd(end - 2);
638
        }
639
        this.txtExpression.requestFocusInWindow();
640
    }
641

    
642
    private void doInsert(SimpleElement element) {
643
        if( element instanceof FunctionElement ) {
644
            Function function = ((FunctionElement)element).getFunction();
645
            if (function == null) {
646
                doInsert(element.getName());
647
            } else {
648
                doInsert(function.template() == null ? function.name() + "({{}})" : function.template());
649
            }
650
        } else if( element instanceof CalculatedElement) {
651
            Object value = ((CalculatedElement) element).getValue();
652
            if( value != null ) {
653
                doInsert(" "+value.toString()+" ");
654
            }
655
        } else if( element instanceof ConstantElement) {
656
            Object value = ((ConstantElement) element).getValue();
657
            doInsert(" "+Utils.repr(value)+" ");
658
        } else {
659
            doInsert(" "+element.getName()+" ");
660
        }
661
    }
662

    
663
    private void doFilter() {
664
        FilteredListModel model = (FilteredListModel) this.lstSimpleElement.getModel();
665
        model.setFilter(this.txtSimpleElementFilter.getText());
666
    }
667

    
668
    private void doSelectElement(SimpleElement element) {
669
//        if( !element.isEnabled() ) {
670
//            this.infoPanel.clean();
671
//        } else {
672
            this.infoPanel.setDescription(removeCursorMark(element.getDescription()));
673
            this.infoPanel.setAdditionalPanel(element.getAditionalPanel(this));
674
            this.infoPanel.repaint();
675
//        }        
676
    }
677

    
678
    private void updateSimpleElementsList(GroupElement group) {
679
        FilteredListModel model = new FilteredListModel();
680
        model.addElement("Loading...");
681
        this.currentGroup = group;
682
        this.txtGroupElement.setText(group.getName());
683
        this.txtSimpleElementFilter.setText("");
684
        this.infoPanel.clean();
685
        this.infoPanel.repaint();
686
        if (group instanceof SimpleElement) {
687
            this.btnGroupElementInsert.setEnabled(true);
688
        } else {
689
            this.btnGroupElementInsert.setEnabled(false);
690
        }
691
        this.lstSimpleElement.setEnabled(false);
692
        this.lstSimpleElement.setModel(model);
693

    
694
        Thread th = new Thread(new Runnable() {
695
            @Override
696
            public void run() {
697
                simpleElementsUpdater();
698
            }
699
        }, "ExpressionBuilderSimpleElementsUpdater");
700
        th.start();
701
    }
702

    
703
    private void simpleElementsUpdater() {
704
        final GroupElement group = this.currentGroup;
705
        final FilteredListModel model = new FilteredListModel();
706
        for (Element child : group) {
707
            if (group != this.currentGroup) {
708
                return;
709
            }
710
            if (child instanceof SimpleElement) {
711
                String label = child.getName();
712
                Function function = child instanceof FunctionElement?  ((FunctionElement)child).getFunction(): null;
713
                if (function != null && !StringUtils.isEmpty(function.returnType())) {
714
                    label = "<html><b>" + label + "</b> return " + function.returnType() + "</html>";
715
//                    label = label + " return " + function.returnType();
716
                }
717
                model.addElement(new ListElement<>(label, child));
718
            }
719
        }
720
        model.sort(true);
721
        SwingUtilities.invokeLater(new Runnable() {
722
            @Override
723
            public void run() {
724
                if (group != currentGroup) {
725
                    return;
726
                }
727
                if( group.hasMoreElements() ) {
728
                    lblSimpleElementsMsg.setText("More elements...");
729
                } else {
730
                    lblSimpleElementsMsg.setText("");
731
                }
732
                lstSimpleElement.setEnabled(true);
733
                lstSimpleElement.setModel(model);
734
            }
735
        });
736

    
737
    }
738

    
739
    @Override
740
    public Expression getExpression() {
741
        String phrase = this.txtExpression.getText();
742
        if (StringUtils.isEmpty(phrase)) {
743
            return null;
744
        }
745
        Expression expression = ExpressionEvaluatorLocator.getManager().createExpression();
746
        expression.setPhrase(phrase);
747
        Script script = ToolsLocator.getScriptManager().createScript("UserScript", "", "python");
748
        this.scriptEditor.fetch(script);
749
        if( !StringUtils.isEmpty(script.getCode()) ) {
750
            expression.setUserScript(script);
751
        }
752
        return expression;
753
    }
754

    
755
    @Override
756
    public void setExpression(Expression expression) {
757
        if( expression==null ) {
758
            this.txtExpression.setText("");
759
            try { this.scriptEditor.set(null); } catch(Exception ex) {}
760
            this.scriptPicker.set(null);
761
        } else {
762
            this.txtExpression.setText(expression.getPhrase());
763
            if( expression.getUserScript()!=null ) {
764
                this.scriptEditor.set(expression.getUserScript());
765
            }
766
            if( expression.getScripts()!=null ) {
767
                this.scriptPicker.set(expression.getScripts().toList());
768
            }
769
        }
770
    }
771
    
772
    @Override
773
    public int getSimpleElementsLimit() {
774
        return this.config.getSimpleElementsLimit();
775
    }
776

    
777
    @Override
778
    public void setSimpleElementsLimit(int limit) {
779
        this.config.setSimpleElementsLimit(limit);
780
    }
781
    
782
    @Override
783
    public List<Element> getElements() {
784
        return this.config.getElements();
785
    }
786
    
787
    @Override
788
    public void addElement(Element element) {
789
        this.config.addElement(element);
790
    }
791
    
792
    @Override
793
    public Collection<SymbolTable> getSymbolTables() {
794
        return this.config.getSymbolTables();
795
    }
796
    
797
    @Override
798
    public void addSymbolTable(String name) {
799
        this.config.addSymbolTable(name);
800
    }
801
    
802
    @Override
803
    public void addSymbolTable(SymbolTable symbolTable) {
804
        this.config.addSymbolTable(symbolTable);
805
    }
806

    
807
    @Override
808
    public void removeAllSymbolTables() {
809
        this.config.removeAllSymbolTables();
810
    }
811

    
812
    @Override
813
    public void removeSymbolTable(String name) {
814
        this.config.removeSymbolTable(name);
815
    }
816

    
817
    @Override
818
    public SymbolTable getPreviewSymbolTable() {
819
        return this.config.getPreviewSymbolTable();
820
    }
821

    
822
    @Override
823
    public void setPreviewSymbolTable(SymbolTable symbolTable) {
824
        this.config.setPreviewSymbolTable(symbolTable);
825
    }
826

    
827
    @Override
828
    public void setScriptsEnabled(boolean enabled) {
829
        this.config.setScriptsEnabled(enabled);
830
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
831
    }
832

    
833
    @Override
834
    public boolean getScriptsEnabled() {
835
        return this.config.getScriptsEnabled();
836
    }
837

    
838
    @Override
839
    public void setSQLCompatible(boolean sqlCompatible) {
840
        this.config.setSQLCompatible(sqlCompatible);
841
    }
842

    
843
    @Override
844
    public boolean isSQLCompatible() {
845
        return this.config.isSQLCompatible();
846
    }
847
    
848
    @Override
849
    public JComponent asJComponent() {
850
        if( this.treeModel == null ) {
851
            I18nManager i18n = ToolsLocator.getI18nManager();
852
            this.treeModel = new ElementsTreeModel(
853
                    this.manager.createGroupElement(
854
                            this.config,
855
                            i18n.getTranslation("_Elements"),
856
                            this.getElements()
857
                    )
858
            );
859
            this.treeElements.setModel(this.treeModel);
860
        }
861
        return this;
862
    }
863
    
864
    private void doSetTimeLimit() {
865
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
866
        String s = dialogs.inputDialog(
867
                "Indicate the time limit in seconds for calculating the elements", 
868
                "Time limit", 
869
                JOptionPane.QUESTION_MESSAGE, 
870
                String.valueOf(this.config.getSimpleElementsLimit())
871
        );
872
        if( StringUtils.isBlank(s) ) {
873
            return;
874
        }
875
        try {
876
            int n = Integer.parseInt(s);
877
            this.config.setSimpleElementsLimit(n);
878
            this.treeModel.reload();
879
        } catch(Exception ex) {
880
            dialogs.messageDialog(
881
                "Invalid time limit '"+s+"'.", 
882
                "Time limit", 
883
                JOptionPane.WARNING_MESSAGE
884
            );                    
885
        }
886
    }
887
}