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

History | View | Annotate | Download (32.1 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
                } else {
401
                    label.setIcon(null);
402
                    label.setText(Objects.toString(value, ""));
403
                }
404
                return label;
405
            }
406
        });
407
        
408
        this.treeElements.addTreeSelectionListener(new TreeSelectionListener() {
409
            @Override
410
            public void valueChanged(TreeSelectionEvent e) {
411
                TreePath path = e.getPath();
412
                Element element = (Element) path.getLastPathComponent();
413
                if (element instanceof GroupElement) {
414
                    updateSimpleElementsList((GroupElement) element);
415
                }
416
            }
417
        });
418
        this.treeElements.addMouseListener(new MouseAdapter() {
419
            @Override
420
            public void mouseClicked(MouseEvent e) {
421
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
422
                    TreePath path = treeElements.getSelectionPath();
423
                    Element element = (Element) path.getLastPathComponent();
424
                    if( element instanceof SimpleElement ) {
425
                        doInsert((SimpleElement) element);
426
                    }
427
                }
428
            }
429
        });
430
        this.btnGroupElementInsert.addActionListener(new ActionListener() {
431
            @Override
432
            public void actionPerformed(ActionEvent e) {
433
                doInsert(txtGroupElement.getText());
434
            }
435
        });
436
        this.btnSimpleElementInsert.addActionListener(new ActionListener() {
437
            @Override
438
            public void actionPerformed(ActionEvent e) {
439
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
440
                if (element != null) {
441
                    doInsert(element.getValue());
442
                }
443
            }
444
        });
445
        this.btnSimpleElementFilter.addActionListener(new ActionListener() {
446
            @Override
447
            public void actionPerformed(ActionEvent e) {
448
                doFilter();
449
            }
450
        });
451
        
452
        this.lstSimpleElement.setModel(new FilteredListModel());
453
        this.lstSimpleElement.setCellRenderer(new DefaultListCellRenderer() {
454
            @Override
455
            public java.awt.Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
456
                JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
457
                Element element = null;
458
                if( value instanceof ListElement ) {
459
                    if( ((ListElement) value).getValue() instanceof Element ) {
460
                        element = (Element) ((ListElement) value).getValue();
461
                    }
462
                }
463
                if( element !=null ) {
464
                    if( element.getIconName()==null ) {
465
                        if( element instanceof GroupElement ) {
466
                            label.setIcon(defaultIconGroup);
467
                        } else {
468
                            label.setIcon(defaultIconElement);
469
                        }
470
                    } else {
471
                        label.setIcon(element.getIcon());
472
                    }
473
                    label.setText(element.getName());
474
                    label.setEnabled(element.isEnabled());
475
                } else {
476
                    label.setIcon(null);
477
                    label.setText(Objects.toString(value, ""));
478
                }
479
                return label;
480
            }
481
        });
482
        this.lstSimpleElement.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
483
            @Override
484
            public void valueChanged(ListSelectionEvent e) {
485
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
486
                if (element != null) {
487
                    doSelectElement(element.getValue());
488
                }
489
            }
490
        });
491
        this.lstSimpleElement.addMouseListener(new MouseAdapter() {
492
            @Override
493
            public void mouseClicked(MouseEvent e) {
494
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
495
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
496
                    if (element != null) {
497
                        doSelectElement(element.getValue());
498
                        doInsert(element.getValue());
499
                    }
500
                }
501
            }
502
        });
503
        this.lstSimpleElement.addKeyListener(new KeyAdapter() {
504
            @Override
505
            public void keyReleased(KeyEvent e) {
506
                if( e.getKeyCode()==KeyEvent.VK_ENTER ) {
507
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
508
                    if (element != null) {
509
                        doSelectElement(element.getValue());
510
                        doInsert(element.getValue());
511
                    }
512
                }
513
            }
514
        });
515

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

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

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

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

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

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

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

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

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

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

    
736
    }
737

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

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

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

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

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

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

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

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

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