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

History | View | Annotate | Download (37.3 KB)

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

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

    
83
/**
84
 *
85
 * @author jjdelcerro
86
 */
87
@SuppressWarnings("UseSpecificCatch")
88
public class DefaultJExpressionBuilder
89
        extends DefaultJExpressionBuilderView
90
        implements JExpressionBuilder {
91

    
92
    private static final Color COLOR_ERROR = new Color(255,225,232);
93

    
94
    private final ExpressionEvaluatorSwingManager manager;
95
    private GroupElement currentGroup;
96
    private PickerController<List<Script>> scriptPicker;
97
    private ScriptSwingManager.ScriptEditor scriptEditor;
98
    
99
    private final ExpressionBuilderConfig config;
100
    private ElementsTreeModel treeModel;
101
    private java.awt.Component infoPanel = null;
102
    private JEditorPane txtDescription;
103
    private Timer timerExpression;
104
    private ImageIcon defaultIconGroup;
105
    private ImageIcon defaultIconElement;
106
    private JScrollPane scrDescription;
107
    private Color color_ok;
108
    private String messageValue;
109

    
110
    private class ElementsTreeModel implements TreeModel {
111

    
112
        private final GroupElement root;
113
        private final HashSet<TreeModelListener> listeners;
114

    
115
        public ElementsTreeModel(GroupElement root) {
116
            this.root = root;
117
            this.listeners = new HashSet<>();
118
        }
119

    
120
        @Override
121
        public Object getRoot() {
122
            return this.root;
123
        }
124

    
125
        public void reload() {
126
            this.reload(this.root);
127
            this.fireTreeChanged();
128
        }
129
        
130
        private void reload(Element element) {
131
            if (element instanceof Element) {
132
                if (element instanceof GroupElement) {
133
                    reload(element);
134
                }
135
                element.reload();
136
            }
137
        }
138
        
139
        private List<Element> getChilds(final GroupElement node) {
140
            List<Element> x = new ArrayList<>();
141
            for (Element element : node.getElements()) {
142
                if (element instanceof GroupElement) {
143
                    x.add(element);
144
                }
145
            }
146
            return x; //node.getElements();
147
        }
148

    
149
        @Override
150
        public Object getChild(Object parent, int index) {
151
            List<Element> childs = getChilds((GroupElement) parent);
152
            Element child = childs.get(index);
153
            return child;
154
        }
155

    
156
        @Override
157
        public int getChildCount(Object parent) {
158
            List<Element> childs = getChilds((GroupElement) parent);
159
            return childs.size();
160
        }
161

    
162
        @Override
163
        public boolean isLeaf(Object node) {
164
            if( node instanceof GroupElement ) {
165
                return !((GroupElement) node).hasSubgroups();
166
            }
167
            return false;
168
        }
169

    
170
        @Override
171
        public void valueForPathChanged(TreePath path, Object newValue) {
172
        }
173

    
174
        @Override
175
        public int getIndexOfChild(Object parent, Object child) {
176
            List<Element> childs = getChilds((GroupElement) parent);
177
            int n = childs.indexOf(child);
178
            return n;
179
        }
180

    
181
        @Override
182
        public void addTreeModelListener(TreeModelListener l) {
183
            this.listeners.add(l);
184
        }
185

    
186
        @Override
187
        public void removeTreeModelListener(TreeModelListener l) {
188
            this.listeners.remove(l);
189
        }
190

    
191
        protected void fireTreeChanged() {
192
            for (TreeModelListener listener : listeners) {
193
                TreeModelEvent e = new TreeModelEvent(this, new Object[] {this.root});
194
                listener.treeNodesChanged(e);
195
            }
196
        }
197
    }
198

    
199
    @SuppressWarnings("OverridableMethodCallInConstructor")
200
    public DefaultJExpressionBuilder(ExpressionEvaluatorSwingManager manager, ExpressionBuilderConfig config) {
201
        this.manager = manager;
202
        if( config == null ) {
203
            this.config = new DefaultExpressionBuilderConfig(manager);
204
        } else {
205
            this.config = config;
206
        }
207
        this.initComponents();
208
    }
209
    
210
    @Override
211
    public ImageIcon loadImage(String imageName) {
212
        String name = FilenameUtils.getBaseName(imageName);
213
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getDefault();
214
        if (theme.exists(name)) {
215
            return theme.get(name);
216
        }
217
        URL url = this.getClass().getResource(name + ".png");
218
        if (url == null) {
219
            return null;
220
        }
221
        return new ImageIcon(url);
222
    }
223

    
224
    private void initComponents() {
225
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
226
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
227
        final I18nManager i18n = ToolsLocator.getI18nManager();
228
        
229
        this.btnTip.setVisible(false);
230
        this.btnTip.addActionListener(new ActionListener() {
231
            @Override
232
            public void actionPerformed(ActionEvent e) {
233
                ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
234
                dialogs.messageDialog(
235
                        btnTip.getToolTipText(), 
236
                        "Tip", 
237
                        JOptionPane.INFORMATION_MESSAGE
238
                );
239
            }
240
        });
241

    
242
        this.defaultIconGroup = theme.get("expressionbuilder-element-group");
243
        this.defaultIconElement = theme.get("expressionbuilder-element");
244
        
245
        this.timerExpression = new Timer(3000, new ActionListener() {
246
            @Override
247
            public void actionPerformed(ActionEvent e) {
248
                doCheckExpression();
249
            }
250
        });
251
        this.timerExpression.setRepeats(false);
252
        this.txtDescription = new JEditorPane();
253
        this.scrDescription = new JScrollPane(this.txtDescription);
254
        
255
        toolsSwingManager.translate(this.tabExpressionBuilder);
256
        toolsSwingManager.setDefaultPopupMenu(this.txtExpression);
257
        toolsSwingManager.setDefaultPopupMenu(this.txtGroupElement);
258
        toolsSwingManager.setDefaultPopupMenu(this.txtSimpleElementFilter);
259
        toolsSwingManager.setDefaultPopupMenu(this.txtDescription);
260
        toolsSwingManager.addClearButton(this.txtExpression);
261
        toolsSwingManager.addClearButton(this.txtSimpleElementFilter, new ActionListener() {
262
            @Override
263
            public void actionPerformed(ActionEvent e) {
264
                txtSimpleElementFilter.setText("");
265
                doFilter();
266
            }
267
        });
268
        JMenuItem msgMenuTextEditor = new JMenuItem(i18n.getTranslation("text_editor"));
269
        msgMenuTextEditor.addActionListener(new ActionListener() {
270
            @Override
271
            public void actionPerformed(ActionEvent e) {
272
                JEditorPane text = new JEditorPane();
273
                JScrollPane scroll = new JScrollPane(text);
274
                scroll.setPreferredSize(new Dimension(500, 300));
275
                toolsSwingManager.setDefaultPopupMenu(text);
276
                text.setContentType("text/html");
277
                text.setText("<html>"+messageValue+"</html>");
278
                text.setCaretPosition(0);
279
                WindowManager_v2 winmgr = (WindowManager_v2) ToolsSwingLocator.getWindowManager();
280
                Dialog dialog = winmgr.createDialog(
281
                        scroll,
282
                        i18n.getTranslation("_Preview_value"), 
283
                        null,
284
                        WindowManager_v2.BUTTONS_OK
285
                );
286
                dialog.show(WindowManager.MODE.DIALOG);
287
            }
288
        });
289
        JMenuItem msgMenuCopy = new JMenuItem(i18n.getTranslation("copy"));
290
        msgMenuTextEditor.addActionListener(new ActionListener() {
291
            @Override
292
            public void actionPerformed(ActionEvent e) {
293
                StringSelection selection = new StringSelection(messageValue);
294
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
295
                clipboard.setContents(selection, selection);                
296
            }
297
        });
298
        
299
        JPopupMenu msgMenu = new JPopupMenu();
300
        msgMenu.add(msgMenuTextEditor);
301
        msgMenu.addSeparator();
302
        msgMenu.add(msgMenuCopy);
303
        this.lblMsg.setComponentPopupMenu(msgMenu);
304

    
305
        this.pnlDescription.setLayout(new BorderLayout());
306
        this.pnlDescription.setBackground(this.txtDescription.getBackground());
307
        this.color_ok = this.txtExpression.getBackground();
308
        this.txtExpression.addCaretListener(new CaretListener() {
309
            @Override
310
            public void caretUpdate(CaretEvent e) {
311
                lblColumn.setText(Integer.toString(e.getDot()));
312
            }
313
        });
314
        this.txtExpression.getDocument().addDocumentListener(new DocumentListener() {
315
            @Override
316
            public void insertUpdate(DocumentEvent e) {
317
                timerExpression.restart();
318
            }
319

    
320
            @Override
321
            public void removeUpdate(DocumentEvent e) {
322
                timerExpression.restart();
323
            }
324

    
325
            @Override
326
            public void changedUpdate(DocumentEvent e) {
327
                timerExpression.restart();
328
            }
329
        });
330
        this.txtExpression.addKeyListener(new KeyAdapter() {
331
            @Override
332
            public void keyPressed(KeyEvent e) {
333
                   if( e.getKeyCode()==KeyEvent.VK_C && e.isControlDown() ) {
334
                       doCheckExpression();
335
                   } 
336
            }
337
        });
338
        this.treeElements.setCellRenderer(new DefaultTreeCellRenderer() {
339
            @Override
340
            public java.awt.Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
341
                JLabel label = (JLabel) super.getTreeCellRendererComponent(tree,value, selected, expanded, leaf, row, hasFocus);
342
                if( value instanceof Element ) {
343
                    Element element = (Element) value;
344
                    if( element.getIconName()==null ) {
345
                        if( element instanceof GroupElement ) {
346
                            label.setIcon(defaultIconGroup);
347
                        } else {
348
                            label.setIcon(defaultIconElement);
349
                        }
350
                    } else {
351
                        label.setIcon(element.getIcon());
352
                    }
353
                    label.setText(element.getName());
354
                } else {
355
                    label.setIcon(null);
356
                    label.setText(Objects.toString(value, ""));
357
                }
358
                return label;
359
            }
360
        });
361
        
362
        this.treeElements.addTreeSelectionListener(new TreeSelectionListener() {
363
            @Override
364
            public void valueChanged(TreeSelectionEvent e) {
365
                TreePath path = e.getPath();
366
                Element element = (Element) path.getLastPathComponent();
367
                if (element instanceof GroupElement) {
368
                    updateSimpleElementsList((GroupElement) element);
369
                }
370
            }
371
        });
372
        this.treeElements.addMouseListener(new MouseAdapter() {
373
            @Override
374
            public void mouseClicked(MouseEvent e) {
375
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
376
                    TreePath path = treeElements.getSelectionPath();
377
                    Element element = (Element) path.getLastPathComponent();
378
                    if( element instanceof SimpleElement ) {
379
                        doInsert((SimpleElement) element);
380
                    }
381
                }
382
            }
383
        });
384
        this.btnGroupElementInsert.addActionListener(new ActionListener() {
385
            @Override
386
            public void actionPerformed(ActionEvent e) {
387
                doInsert(txtGroupElement.getText());
388
            }
389
        });
390
        this.btnSimpleElementInsert.addActionListener(new ActionListener() {
391
            @Override
392
            public void actionPerformed(ActionEvent e) {
393
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
394
                if (element != null) {
395
                    doInsert(element.getValue());
396
                }
397
            }
398
        });
399
        this.btnSimpleElementFilter.addActionListener(new ActionListener() {
400
            @Override
401
            public void actionPerformed(ActionEvent e) {
402
                doFilter();
403
            }
404
        });
405
        
406
        this.lstSimpleElement.setModel(new FilteredListModel());
407
        this.lstSimpleElement.setCellRenderer(new DefaultListCellRenderer() {
408
            @Override
409
            public java.awt.Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
410
                JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
411
                Element element = null;
412
                if( value instanceof ListElement ) {
413
                    if( ((ListElement) value).getValue() instanceof Element ) {
414
                        element = (Element) ((ListElement) value).getValue();
415
                    }
416
                }
417
                if( element !=null ) {
418
                    if( element.getIconName()==null ) {
419
                        if( element instanceof GroupElement ) {
420
                            label.setIcon(defaultIconGroup);
421
                        } else {
422
                            label.setIcon(defaultIconElement);
423
                        }
424
                    } else {
425
                        label.setIcon(element.getIcon());
426
                    }
427
                    label.setText(element.getName());
428
                    label.setEnabled(element.isEnabled());
429
                } else {
430
                    label.setIcon(null);
431
                    label.setText(Objects.toString(value, ""));
432
                }
433
                return label;
434
            }
435
        });
436
        this.lstSimpleElement.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
437
            @Override
438
            public void valueChanged(ListSelectionEvent e) {
439
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
440
                if (element != null) {
441
                    doSelectElement(element.getValue());
442
                }
443
            }
444
        });
445
        this.lstSimpleElement.addMouseListener(new MouseAdapter() {
446
            @Override
447
            public void mouseClicked(MouseEvent e) {
448
                if( e.getButton()==MouseEvent.BUTTON1 && e.getClickCount()==2 ) {
449
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
450
                    if (element != null) {
451
                        doSelectElement(element.getValue());
452
                        doInsert(element.getValue());
453
                    }
454
                }
455
            }
456
        });
457
        this.lstSimpleElement.addKeyListener(new KeyAdapter() {
458
            @Override
459
            public void keyReleased(KeyEvent e) {
460
                if( e.getKeyCode()==KeyEvent.VK_ENTER ) {
461
                    ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
462
                    if (element != null) {
463
                        doSelectElement(element.getValue());
464
                        doInsert(element.getValue());
465
                    }
466
                }
467
            }
468
        });
469

    
470
        this.btnSimpleElementTimeLimit.addActionListener(new ActionListener() {
471
            @Override
472
            public void actionPerformed(ActionEvent e) {
473
                doSetTimeLimit();
474
            }
475
        });
476
        this.btnSimpleElementSortDown.addActionListener(new ActionListener() {
477
            @Override
478
            public void actionPerformed(ActionEvent e) {
479
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
480
                model.sort(false);
481
            }
482
        });
483
        this.btnSimpleElementSortUp.addActionListener(new ActionListener() {
484
            @Override
485
            public void actionPerformed(ActionEvent e) {
486
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
487
                model.sort(true);
488
            }
489
        });
490
        this.txtSimpleElementFilter.addKeyListener(new KeyAdapter() {
491
            @Override
492
            public void keyTyped(KeyEvent e) {
493
                if (e.getKeyChar() == '\n') {
494
                    doFilter();
495
                }
496
            }
497
        });
498
        this.btnAdd.addActionListener(new ActionListener() {
499
            @Override
500
            public void actionPerformed(ActionEvent e) {
501
                doInsert(" + ");
502
            }
503
        });
504
        this.btnDiv.addActionListener(new ActionListener() {
505
            @Override
506
            public void actionPerformed(ActionEvent e) {
507
                doInsert(" / ");
508
            }
509
        });
510
        this.btnEq.addActionListener(new ActionListener() {
511
            @Override
512
            public void actionPerformed(ActionEvent e) {
513
                doInsert(" = ");
514
            }
515
        });
516
        this.btnMult.addActionListener(new ActionListener() {
517
            @Override
518
            public void actionPerformed(ActionEvent e) {
519
                doInsert(" * ");
520
            }
521
        });
522
        this.btnNeq.addActionListener(new ActionListener() {
523
            @Override
524
            public void actionPerformed(ActionEvent e) {
525
                doInsert(" <> ");
526
            }
527
        });
528
        this.btnParentClose.addActionListener(new ActionListener() {
529
            @Override
530
            public void actionPerformed(ActionEvent e) {
531
                doInsert(" ) ");
532
            }
533
        });
534
        this.btnParentOpen.addActionListener(new ActionListener() {
535
            @Override
536
            public void actionPerformed(ActionEvent e) {
537
                doInsert(" ( ");
538
            }
539
        });
540
        this.btnSubst.addActionListener(new ActionListener() {
541
            @Override
542
            public void actionPerformed(ActionEvent e) {
543
                doInsert(" - ");
544
            }
545
        });
546
        ScriptSwingManager scriptSwingManager = ToolsSwingLocator.getScriptSwingManager();
547
        this.scriptPicker = scriptSwingManager.createListScriptPickerController(
548
                cboPickerScripts,
549
                btnPickerRemove,
550
                btnPickerSelectScript
551
        );
552
        this.scriptEditor = scriptSwingManager.createScriptEditor();
553
        this.pnlScriptEditorContainer.setLayout(new BorderLayout());
554
        this.pnlScriptEditorContainer.add(this.scriptEditor.asJComponent(), BorderLayout.CENTER);
555
    
556
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
557
        this.setPreferredSize(new Dimension(650, 350));
558
        this.txtDescription.setPreferredSize(new Dimension(200,200));
559
    }
560

    
561
    private void doCheckExpression() {
562
        Expression expression = this.getExpression();
563
        this.btnTip.setVisible(false);
564
        if( expression == null ) {
565
            this.setMessage("");
566
            this.txtExpression.setBackground(this.color_ok);
567
            return;
568
        }
569
        try {
570
            expression.getCode();
571
            this.setMessage("");
572
            this.txtExpression.setBackground(this.color_ok);
573
        } catch(ExpressionSyntaxException ex) {
574
            this.setMessage(ex.getDescription());
575
            this.txtExpression.setBackground(COLOR_ERROR);
576
            return;
577
        } catch(Exception ex) {
578
            this.setMessage("Syntax error in expression");
579
            this.txtExpression.setBackground(COLOR_ERROR);
580
            return;
581
        }
582
        if( this.config.getPreviewSymbolTable()==null ) {
583
            try {
584
                ExpressionEvaluatorManager theManager = ExpressionEvaluatorLocator.getManager();
585
                MutableSymbolTable symbolTable = theManager.createSymbolTable();
586
                Object value = expression.execute(symbolTable);
587
                this.setMessage(Utils.toString(value));
588
                this.txtExpression.setBackground(this.color_ok);
589
            } catch(Exception ex) {
590
                this.setMessage("");
591
            }
592
        } else {
593
            try {
594
                Object value = expression.execute(this.config.getPreviewSymbolTable());
595
                this.setMessage(Utils.toString(value));
596
                this.txtExpression.setBackground(this.color_ok);
597
            } catch(ExpressionRuntimeException ex) {
598
                if( !StringUtils.isBlank(ex.getTip()) ) {
599
                    this.btnTip.setToolTipText(ex.getTip());
600
                    this.btnTip.setVisible(true);
601
                }
602
                this.setMessage("Runtime error. "+ex.getMessage());
603
                this.txtExpression.setBackground(COLOR_ERROR);
604
            } catch(Exception ex) {
605
                this.setMessage("Runtime error. "+ex.getMessage());
606
                this.txtExpression.setBackground(COLOR_ERROR);
607
            }
608
        }
609
    }
610

    
611
    private void setMessage(String msg) {
612
        this.messageValue = msg;
613
        this.lblMsg.setText("<html>"+StringUtils.abbreviate(msg,100)+"</html>");
614
    }
615
    
616
    private String removeCursorMark(String s) {
617
        s = s.replace("{{", "");
618
        s = s.replace("}}", "");
619
        return s;
620
    }
621

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

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

    
657
    private void doFilter() {
658
        FilteredListModel model = (FilteredListModel) this.lstSimpleElement.getModel();
659
        model.setFilter(this.txtSimpleElementFilter.getText());
660
    }
661

    
662
    private void doSelectElement(SimpleElement element) {
663
        if( !element.isEnabled() ) {
664
            this.cleanDescription();
665
            return;
666
        }
667
        I18nManager i18n = ToolsLocator.getI18nManager();
668
        
669
        Component aditionalPanel = element.getAditionalPanel();
670
        java.awt.Component newInfoPanel;
671
        if( aditionalPanel == null ) {
672
            StringBuilder html = new StringBuilder();
673
            html.append("<html>\n");
674
            if( element instanceof ConstantElement ) {
675
                Object value = ((ConstantElement)element).getValue();
676
                if( value == null ) {
677
                    html.append("<b>").append(i18n.getTranslation("_Constant")).append("</b><br>\n<br>\n");
678
                    html.append("<b>").append(i18n.getTranslation("_Value")).append("</b> NULL<br>\n");
679
                } else {
680
                    html.append("<b>").append(i18n.getTranslation("_Constant")).append("</b><br>\n<br>\n");
681
                    html.append("<b>").append(i18n.getTranslation("_Value")).append("</b> ").append(Utils.repr(value)).append("<br>\n");
682
                    html.append("<b>").append(i18n.getTranslation("_Type")).append("</b> ").append(value.getClass().getSimpleName()).append("<br>\n");
683
                }
684

    
685
            } else if( element instanceof VariableElement ) {
686
                    VariableElement var = (VariableElement)element;
687
                    html.append("<b>").append(var.getLabel()).append("</b><br>\n<br>\n");
688
                    html.append("<b>").append(i18n.getTranslation("_Source")).append("</b> ").append(var.getSource()).append("<br>\n");
689
                    html.append("<b>").append(i18n.getTranslation("_Name")).append("</b> ").append(var.getName()).append("<br>\n");
690
                    html.append("<b>").append(i18n.getTranslation("_Type")).append("</b> ").append(var.getTypeName()).append("<br>\n");
691

    
692
            } else if( element instanceof FunctionElement ) {
693
                Function function = ((FunctionElement)element).getFunction();
694
                if (function == null) {
695
                    html.append("<b>").append(i18n.getTranslation("_Function")).append("</b> ").append(element.getName()).append("<br>\n<br>\n");
696
                    html.append("<b>").append(i18n.getTranslation("_Return")).append("</b> Object<br>\n<br>\n");
697
                    html.append("<b>").append(i18n.getTranslation("_Template")).append(":</b> ").append(element.getName()).append("()<br>\n");
698
                } else {
699
                    html.append("<b>").append(i18n.getTranslation("_Function")).append("</b> ").append(element.getName()).append("<br>\n<br>\n");
700
                    html.append("<b>").append(i18n.getTranslation("_Return")).append("</b> ");
701
                    html.append(StringUtils.isEmpty(function.returnType())?"Objec": function.returnType());
702
                    html.append("<br>\n");
703
                    html.append("<b>").append(i18n.getTranslation("_Template")).append("</b> ");
704
                    html.append(StringUtils.isEmpty(function.template())?element.getName()+"()": removeCursorMark(function.template()));
705
                    html.append("<br>\n");
706

    
707
                    String[] args = function.descriptionArgs();
708
                    if (args != null) {
709
                        html.append("<b>").append(i18n.getTranslation("_Arguments")).append(":</b> ").append("<ul>\n");
710
                        for (String arg : args) {
711
                            html.append("<li>").append(arg).append("</li>\n");
712
                        }
713
                        html.append("</ul>\n");
714
                        html.append("<br>\n");
715
                    }
716
                }
717
            } else {
718
                html.append("<b>").append(i18n.getTranslation("_Generic_element")).append("<br>\n<br>\n");
719
                html.append("<b>").append(i18n.getTranslation("_Name")).append("</b> ").append(element.getName()).append("</br>\n");
720

    
721
            }
722

    
723
            if( element.getDescription()!=null ) {
724
                html.append("<b>").append(i18n.getTranslation("_Description")).append("</b><br>\n");
725
                html.append(element.getDescription().replace("\n", "<br>")).append("<br>\n");
726
            }
727
            html.append("</html>\n");
728
            this.txtDescription.setContentType("text/html");
729
            this.txtDescription.setText(html.toString());
730
            this.txtDescription.setCaretPosition(0);
731
            newInfoPanel = this.scrDescription;
732
        } else {
733
            newInfoPanel = aditionalPanel.asJComponent();
734
        }
735
        
736
        if( this.infoPanel != newInfoPanel ) {
737
            this.pnlDescription.removeAll();
738
            this.pnlDescription.add(newInfoPanel, BorderLayout.CENTER);
739
            this.pnlDescription.revalidate();
740
            this.pnlDescription.repaint();
741
            this.infoPanel = newInfoPanel;
742
        }
743
        
744
    }
745

    
746
    private void cleanDescription() {
747
        this.txtDescription.setText("");
748
        if( this.infoPanel != this.scrDescription ) {
749
            this.pnlDescription.removeAll();
750
            this.pnlDescription.add(this.scrDescription, BorderLayout.CENTER);
751
            this.pnlDescription.revalidate();
752
            this.pnlDescription.repaint();
753
            this.infoPanel = this.scrDescription;
754
        }
755
    }
756
    
757
    private void updateSimpleElementsList(GroupElement group) {
758
        FilteredListModel model = new FilteredListModel();
759
        model.addElement("Loading...");
760
        this.currentGroup = group;
761
        this.txtGroupElement.setText(group.getName());
762
        this.txtSimpleElementFilter.setText("");
763
        this.cleanDescription();
764
        if (group instanceof SimpleElement) {
765
            this.btnGroupElementInsert.setEnabled(true);
766
        } else {
767
            this.btnGroupElementInsert.setEnabled(false);
768
        }
769
        this.lstSimpleElement.setEnabled(false);
770
        this.lstSimpleElement.setModel(model);
771

    
772
        Thread th = new Thread(new Runnable() {
773
            @Override
774
            public void run() {
775
                simpleElementsUpdater();
776
            }
777
        }, "ExpressionBuilderSimpleElementsUpdater");
778
        th.start();
779
    }
780

    
781
    private void simpleElementsUpdater() {
782
        final GroupElement group = this.currentGroup;
783
        final FilteredListModel model = new FilteredListModel();
784
        for (Element child : group) {
785
            if (group != this.currentGroup) {
786
                return;
787
            }
788
            if (child instanceof SimpleElement) {
789
                String label = child.getName();
790
                Function function = child instanceof FunctionElement?  ((FunctionElement)child).getFunction(): null;
791
                if (function != null && !StringUtils.isEmpty(function.returnType())) {
792
                    label = "<html><b>" + label + "</b> return " + function.returnType() + "</html>";
793
//                    label = label + " return " + function.returnType();
794
                }
795
                model.addElement(new ListElement<>(label, child));
796
            }
797
        }
798
        model.sort(true);
799
        SwingUtilities.invokeLater(new Runnable() {
800
            @Override
801
            public void run() {
802
                if (group != currentGroup) {
803
                    return;
804
                }
805
                if( group.hasMoreElements() ) {
806
                    lblSimpleElementsMsg.setText("More elements...");
807
                } else {
808
                    lblSimpleElementsMsg.setText("");
809
                }
810
                lstSimpleElement.setEnabled(true);
811
                lstSimpleElement.setModel(model);
812
            }
813
        });
814

    
815
    }
816

    
817
    @Override
818
    public Expression getExpression() {
819
        String phrase = this.txtExpression.getText();
820
        if (StringUtils.isEmpty(phrase)) {
821
            return null;
822
        }
823
        Expression expression = ExpressionEvaluatorLocator.getManager().createExpression();
824
        expression.setPhrase(phrase);
825
        Script script = ToolsLocator.getScriptManager().createScript("UserScript", "", "python");
826
        this.scriptEditor.fetch(script);
827
        if( !StringUtils.isEmpty(script.getCode()) ) {
828
            expression.setUserScript(script);
829
        }
830
        return expression;
831
    }
832

    
833
    @Override
834
    public void setExpression(Expression expression) {
835
        this.txtExpression.setText(expression.getPhrase());
836
        if( expression.getUserScript()!=null ) {
837
            this.scriptEditor.set(expression.getUserScript());
838
        }
839
        if( expression.getScripts()!=null ) {
840
            this.scriptPicker.set(expression.getScripts().toList());
841
        }
842
    }
843
    
844
    @Override
845
    public int getSimpleElementsLimit() {
846
        return this.config.getSimpleElementsLimit();
847
    }
848

    
849
    @Override
850
    public void setSimpleElementsLimit(int limit) {
851
        this.config.setSimpleElementsLimit(limit);
852
    }
853
    
854
    @Override
855
    public List<Element> getElements() {
856
        return this.config.getElements();
857
    }
858
    
859
    @Override
860
    public void addElement(Element element) {
861
        this.config.addElement(element);
862
    }
863
    
864
    @Override
865
    public Collection<SymbolTable> getSymbolTables() {
866
        return this.config.getSymbolTables();
867
    }
868
    
869
    @Override
870
    public void addSymbolTable(String name) {
871
        this.config.addSymbolTable(name);
872
    }
873
    
874
    @Override
875
    public void addSymbolTable(SymbolTable symbolTable) {
876
        this.config.addSymbolTable(symbolTable);
877
    }
878

    
879
    @Override
880
    public void removeAllSymbolTables() {
881
        this.config.removeAllSymbolTables();
882
    }
883

    
884
    @Override
885
    public void removeSymbolTable(String name) {
886
        this.config.removeSymbolTable(name);
887
    }
888

    
889
    @Override
890
    public SymbolTable getPreviewSymbolTable() {
891
        return this.config.getPreviewSymbolTable();
892
    }
893

    
894
    @Override
895
    public void setPreviewSymbolTable(SymbolTable symbolTable) {
896
        this.config.setPreviewSymbolTable(symbolTable);
897
    }
898

    
899
    @Override
900
    public void setScriptsEnabled(boolean enabled) {
901
        this.config.setScriptsEnabled(enabled);
902
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
903
    }
904

    
905
    @Override
906
    public boolean getScriptsEnabled() {
907
        return this.config.getScriptsEnabled();
908
    }
909
    
910
    @Override
911
    public JComponent asJComponent() {
912
        if( this.treeModel == null ) {
913
            I18nManager i18n = ToolsLocator.getI18nManager();
914
            this.treeModel = new ElementsTreeModel(
915
                    this.manager.createGroupElement(
916
                            i18n.getTranslation("_Elements"),
917
                            this.getElements()
918
                    )
919
            );
920
            this.treeElements.setModel(this.treeModel);
921
        }
922
        return this;
923
    }
924
    
925
    private void doSetTimeLimit() {
926
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
927
        String s = dialogs.inputDialog(
928
                "Indicate the time limit in seconds for calculating the elements", 
929
                "Time limit", 
930
                JOptionPane.QUESTION_MESSAGE, 
931
                String.valueOf(this.config.getSimpleElementsLimit())
932
        );
933
        if( StringUtils.isBlank(s) ) {
934
            return;
935
        }
936
        try {
937
            int n = Integer.parseInt(s);
938
            this.config.setSimpleElementsLimit(n);
939
            this.treeModel.reload();
940
        } catch(Exception ex) {
941
            dialogs.messageDialog(
942
                "Invalid time limit '"+s+"'.", 
943
                "Time limit", 
944
                JOptionPane.WARNING_MESSAGE
945
            );                    
946
        }
947
    }
948
}