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

History | View | Annotate | Download (34.2 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.io.InputStream;
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.Locale;
21
import java.util.Objects;
22
import javax.swing.DefaultListCellRenderer;
23
import javax.swing.ImageIcon;
24
import javax.swing.JComponent;
25
import javax.swing.JEditorPane;
26
import javax.swing.JLabel;
27
import javax.swing.JList;
28
import javax.swing.JMenuItem;
29
import javax.swing.JOptionPane;
30
import javax.swing.JPanel;
31
import javax.swing.JPopupMenu;
32
import javax.swing.JScrollPane;
33
import javax.swing.JTabbedPane;
34
import javax.swing.JTree;
35
import javax.swing.SwingUtilities;
36
import javax.swing.event.CaretEvent;
37
import javax.swing.event.CaretListener;
38
import javax.swing.event.ListSelectionEvent;
39
import javax.swing.event.ListSelectionListener;
40
import javax.swing.event.TreeModelEvent;
41
import javax.swing.event.TreeModelListener;
42
import javax.swing.event.TreeSelectionEvent;
43
import javax.swing.event.TreeSelectionListener;
44
import javax.swing.tree.DefaultTreeCellRenderer;
45
import javax.swing.tree.TreeModel;
46
import javax.swing.tree.TreePath;
47
import org.apache.commons.io.FilenameUtils;
48
import org.apache.commons.io.IOUtils;
49
import org.apache.commons.lang3.StringUtils;
50
import org.gvsig.expressionevaluator.Expression;
51
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
52
import org.gvsig.expressionevaluator.Function;
53
import org.gvsig.expressionevaluator.SymbolTable;
54
import org.gvsig.expressionevaluator.swing.Element;
55
import org.gvsig.expressionevaluator.swing.Element.CalculatedElement;
56
import org.gvsig.expressionevaluator.swing.Element.ConstantElement;
57
import org.gvsig.expressionevaluator.swing.Element.FunctionElement;
58
import org.gvsig.expressionevaluator.swing.Element.GroupElement;
59
import org.gvsig.expressionevaluator.swing.Element.SimpleElement;
60
import org.gvsig.expressionevaluator.swing.ExpressionBuilderConfig;
61
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
62
import org.gvsig.expressionevaluator.swing.JExpressionBuilder;
63
import org.gvsig.tools.ToolsLocator;
64
import org.gvsig.tools.i18n.I18nManager;
65
import org.gvsig.tools.script.Script;
66
import org.gvsig.tools.swing.api.Component;
67
import org.gvsig.tools.swing.api.ListElement;
68
import org.gvsig.tools.swing.api.ToolsSwingLocator;
69
import org.gvsig.tools.swing.api.ToolsSwingManager;
70
import org.gvsig.tools.swing.api.pickercontroller.PickerController;
71
import org.gvsig.tools.swing.api.script.ScriptSwingManager;
72
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
73
import org.gvsig.tools.swing.icontheme.IconTheme;
74

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

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

    
98
        private final JEditorPane txtDescription;
99
        private final JScrollPane scrDescription;
100
        private final JTabbedPane tab;
101

    
102
        private final String labelDescription;
103
        private final String labelAdditionalPanel;
104
        private final JPanel pnlContainer;
105
        
106
        private final String defautltDescription;
107

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

    
141
        @Override
142
        public JComponent asJComponent() {
143
            this.txtDescription.setContentType("text/html");
144
            this.txtDescription.setText(this.description);
145
            this.txtDescription.setCaretPosition(0);
146

    
147
            if( StringUtils.isBlank(this.description) ) {
148
                if( this.additionalPanel==null ) {
149
                    // Sin descripcion ni panel adicional, mostramos
150
                    // la descripcion por defecto.
151
                    this.txtDescription.setText(this.defautltDescription);
152
                    this.txtDescription.setCaretPosition(0);
153
                    return this.scrDescription;
154
                }
155
                // Sin descripcion pero con panel adicional, mostramos el 
156
                // panel adicional.
157
                return this.additionalPanel.asJComponent();
158
            }
159
            if( this.additionalPanel==null ) {
160
                // Con descripcion y sin panel adicional, mostramos
161
                // la descripcion.
162
                return this.scrDescription;                
163
            } 
164
            // Con descripcion y panel adicional, mostramos un tab con los dos.
165
            this.tab.removeAll();
166
            this.tab.add(
167
                    this.labelDescription, 
168
                    this.scrDescription
169
            );
170
            this.tab.add(
171
                    this.labelAdditionalPanel, 
172
                    this.additionalPanel.asJComponent()
173
            );
174
            this.tab.setSelectedIndex(1);
175
            return this.tab;
176
        }
177

    
178
        public void repaint() {
179
            this.pnlContainer.removeAll();
180
            this.pnlContainer.add(this.asJComponent(), BorderLayout.CENTER);
181
            this.pnlContainer.revalidate();
182
            this.pnlContainer.repaint();
183
        }
184
    }
185

    
186
    private class ElementsTreeModel implements TreeModel {
187

    
188
        private final GroupElement root;
189
        private final HashSet<TreeModelListener> listeners;
190

    
191
        public ElementsTreeModel(GroupElement root) {
192
            this.root = root;
193
            this.listeners = new HashSet<>();
194
        }
195

    
196
        @Override
197
        public Object getRoot() {
198
            return this.root;
199
        }
200

    
201
        public void reload() {
202
            this.reload(this.root);
203
            this.fireTreeChanged();
204
        }
205
        
206
        private void reload(Element element) {
207
            if (element instanceof Element) {
208
                if (element instanceof GroupElement) {
209
                    reload(element);
210
                }
211
                element.reload();
212
            }
213
        }
214
        
215
        private List<Element> getChilds(final GroupElement node) {
216
            List<Element> x = new ArrayList<>();
217
            for (Element element : node.getElements()) {
218
                if (element instanceof GroupElement) {
219
                    x.add(element);
220
                }
221
            }
222
            return x; //node.getElements();
223
        }
224

    
225
        @Override
226
        public Object getChild(Object parent, int index) {
227
            List<Element> childs = getChilds((GroupElement) parent);
228
            Element child = childs.get(index);
229
            return child;
230
        }
231

    
232
        @Override
233
        public int getChildCount(Object parent) {
234
            List<Element> childs = getChilds((GroupElement) parent);
235
            return childs.size();
236
        }
237

    
238
        @Override
239
        public boolean isLeaf(Object node) {
240
            if( node instanceof GroupElement ) {
241
                return !((GroupElement) node).hasSubgroups();
242
            }
243
            return false;
244
        }
245

    
246
        @Override
247
        public void valueForPathChanged(TreePath path, Object newValue) {
248
        }
249

    
250
        @Override
251
        public int getIndexOfChild(Object parent, Object child) {
252
            List<Element> childs = getChilds((GroupElement) parent);
253
            int n = childs.indexOf(child);
254
            return n;
255
        }
256

    
257
        @Override
258
        public void addTreeModelListener(TreeModelListener l) {
259
            this.listeners.add(l);
260
        }
261

    
262
        @Override
263
        public void removeTreeModelListener(TreeModelListener l) {
264
            this.listeners.remove(l);
265
        }
266

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

    
300
    private void initComponents() {
301
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
302
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
303
        final I18nManager i18n = ToolsLocator.getI18nManager();
304
        
305
        this.automaticExpressionChecker = new AbstractAutomaticExpressionChecker(
306
                config, txtExpression
307
            ) {
308
            @Override
309
            protected Expression getExpression() {
310
                return DefaultJExpressionBuilder.this.getExpression();
311
            }
312

    
313
            @Override
314
            protected void setMessage(int mode, String text) {
315
                super.setMessage(mode, text); 
316
                lblMsg.setText("<html>"+StringUtils.abbreviate(text,100)+"</html>");
317
            }
318

    
319
            @Override
320
            protected void setPreview(Object value) {
321
                super.setPreview(value);
322
                lblMsg.setText("<html>"+StringUtils.abbreviate(this.getPreview(),100)+"</html>");
323
            }
324

    
325
            @Override
326
            protected void setTip(String theTip) {
327
                super.setTip(theTip); 
328
                btnTip.setToolTipText(this.getTip());
329
                btnTip.setVisible(this.isTipEnabled());
330
            }
331
            
332
        };
333
        this.infoPanel = new InfoPanel(this.pnlDescription, load_description_from_resource());
334
        
335
        this.btnTip.setVisible(false);
336
        this.btnTip.addActionListener(new ActionListener() {
337
            @Override
338
            public void actionPerformed(ActionEvent e) {
339
                ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
340
                dialogs.messageDialog(
341
                        btnTip.getToolTipText(), 
342
                        "Tip", 
343
                        JOptionPane.INFORMATION_MESSAGE
344
                );
345
            }
346
        });
347

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

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

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

    
618
    private String removeCursorMark(String s) {
619
        if( s == null ) {
620
            return null;
621
        }
622
        s = s.replace("{{", "");
623
        s = s.replace("}}", "");
624
        return s;
625
    }
626

    
627
    @Override
628
    public void insertText(String text) {
629
        doInsert(text);
630
    }
631

    
632
    @Override
633
    public String getText() {
634
        return this.txtExpression.getText();
635
    }
636
    
637
    public void setText(String text) {
638
        this.txtExpression.setText(text);
639
    }
640
    
641
    private void doInsert(String s) {
642
        this.txtExpression.replaceSelection(s);
643
        String ss = this.txtExpression.getText();
644
        int start = ss.indexOf("{{");
645
        int end = ss.indexOf("}}");
646
        if (start > 0 && end > 0) {
647
            this.txtExpression.replaceRange("", end, end + 2);
648
            this.txtExpression.replaceRange("", start, start + 2);
649
            this.txtExpression.setSelectionStart(start);
650
            this.txtExpression.setSelectionEnd(end - 2);
651
        }
652
        this.txtExpression.requestFocusInWindow();
653
    }
654

    
655
    private void doInsert(SimpleElement element) {
656
        if( element instanceof FunctionElement ) {
657
            Function function = ((FunctionElement)element).getFunction();
658
            if (function == null) {
659
                doInsert(element.getName());
660
            } else {
661
                doInsert(function.template() == null ? function.name() + "({{}})" : function.template());
662
            }
663
        } else if( element instanceof CalculatedElement) {
664
            Object value = ((CalculatedElement) element).getValue();
665
            if( value != null ) {
666
                doInsert(" "+value.toString()+" ");
667
            }
668
        } else if( element instanceof ConstantElement) {
669
            Object value = ((ConstantElement) element).getValue();
670
            doInsert(" "+Utils.repr(value)+" ");
671
        } else {
672
            doInsert(" "+element.getName()+" ");
673
        }
674
    }
675

    
676
    private void doFilter() {
677
        FilteredListModel model = (FilteredListModel) this.lstSimpleElement.getModel();
678
        model.setFilter(this.txtSimpleElementFilter.getText());
679
    }
680

    
681
    private void doSelectElement(SimpleElement element) {
682
//        if( !element.isEnabled() ) {
683
//            this.infoPanel.clean();
684
//        } else {
685
            this.infoPanel.setDescription(removeCursorMark(element.getDescription()));
686
            this.infoPanel.setAdditionalPanel(element.getAditionalPanel(this));
687
            this.infoPanel.repaint();
688
//        }        
689
    }
690

    
691
    private void updateSimpleElementsList(GroupElement group) {
692
        FilteredListModel model = new FilteredListModel();
693
        model.addElement("Loading...");
694
        this.currentGroup = group;
695
        this.txtGroupElement.setText(group.getName());
696
        this.txtSimpleElementFilter.setText("");
697
        this.infoPanel.clean();
698
        this.infoPanel.repaint();
699
        if (group instanceof SimpleElement) {
700
            this.btnGroupElementInsert.setEnabled(true);
701
        } else {
702
            this.btnGroupElementInsert.setEnabled(false);
703
        }
704
        this.lstSimpleElement.setEnabled(false);
705
        this.lstSimpleElement.setModel(model);
706

    
707
        Thread th = new Thread(new Runnable() {
708
            @Override
709
            public void run() {
710
                simpleElementsUpdater();
711
            }
712
        }, "ExpressionBuilderSimpleElementsUpdater");
713
        th.start();
714
    }
715

    
716
    private void simpleElementsUpdater() {
717
        final GroupElement group = this.currentGroup;
718
        final FilteredListModel model = new FilteredListModel();
719
        for (Element child : group) {
720
            if (group != this.currentGroup) {
721
                return;
722
            }
723
            if (child instanceof SimpleElement) {
724
                String label = child.getName();
725
                Function function = child instanceof FunctionElement?  ((FunctionElement)child).getFunction(): null;
726
                if (function != null && !StringUtils.isEmpty(function.returnType())) {
727
                    label = "<html><b>" + label + "</b> return " + function.returnType() + "</html>";
728
//                    label = label + " return " + function.returnType();
729
                }
730
                model.addElement(new ListElement<>(label, child));
731
            }
732
        }
733
        model.sort(true);
734
        SwingUtilities.invokeLater(new Runnable() {
735
            @Override
736
            public void run() {
737
                if (group != currentGroup) {
738
                    return;
739
                }
740
                if( group.hasMoreElements() ) {
741
                    lblSimpleElementsMsg.setText("More elements...");
742
                } else {
743
                    lblSimpleElementsMsg.setText("");
744
                }
745
                lstSimpleElement.setEnabled(true);
746
                lstSimpleElement.setModel(model);
747
            }
748
        });
749

    
750
    }
751

    
752
    @Override
753
    public Expression getExpression() {
754
        String phrase = this.txtExpression.getText();
755
        if (StringUtils.isEmpty(phrase)) {
756
            return null;
757
        }
758
        Expression expression = ExpressionEvaluatorLocator.getManager().createExpression();
759
        expression.setPhrase(phrase);
760
        Script script = ToolsLocator.getScriptManager().createScript("UserScript", "", "python");
761
        this.scriptEditor.fetch(script);
762
        if( !StringUtils.isEmpty(script.getCode()) ) {
763
            expression.setUserScript(script);
764
        }
765
        return expression;
766
    }
767

    
768
    @Override
769
    public void setExpression(Expression expression) {
770
        if( expression==null ) {
771
            this.txtExpression.setText("");
772
            try { this.scriptEditor.set(null); } catch(Exception ex) {}
773
            this.scriptPicker.set(null);
774
        } else {
775
            this.txtExpression.setText(expression.getPhrase());
776
            if( expression.getUserScript()!=null ) {
777
                this.scriptEditor.set(expression.getUserScript());
778
            }
779
            if( expression.getScripts()!=null ) {
780
                this.scriptPicker.set(expression.getScripts().toList());
781
            }
782
        }
783
    }
784
    
785
    @Override
786
    public int getSimpleElementsLimit() {
787
        return this.config.getSimpleElementsLimit();
788
    }
789

    
790
    @Override
791
    public void setSimpleElementsLimit(int limit) {
792
        this.config.setSimpleElementsLimit(limit);
793
    }
794
    
795
    @Override
796
    public List<Element> getElements() {
797
        return this.config.getElements();
798
    }
799
    
800
    @Override
801
    public void addElement(Element element) {
802
        this.config.addElement(element);
803
    }
804
    
805
    @Override
806
    public Collection<SymbolTable> getSymbolTables() {
807
        return this.config.getSymbolTables();
808
    }
809
    
810
    @Override
811
    public void addSymbolTable(String name) {
812
        this.config.addSymbolTable(name);
813
    }
814
    
815
    @Override
816
    public void addSymbolTable(SymbolTable symbolTable) {
817
        this.config.addSymbolTable(symbolTable);
818
    }
819

    
820
    @Override
821
    public void removeAllSymbolTables() {
822
        this.config.removeAllSymbolTables();
823
    }
824

    
825
    @Override
826
    public void removeSymbolTable(String name) {
827
        this.config.removeSymbolTable(name);
828
    }
829

    
830
    @Override
831
    public SymbolTable getPreviewSymbolTable() {
832
        return this.config.getPreviewSymbolTable();
833
    }
834

    
835
    @Override
836
    public void setPreviewSymbolTable(SymbolTable symbolTable) {
837
        this.config.setPreviewSymbolTable(symbolTable);
838
    }
839

    
840
    @Override
841
    public void setScriptsEnabled(boolean enabled) {
842
        this.config.setScriptsEnabled(enabled);
843
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
844
    }
845

    
846
    @Override
847
    public boolean getScriptsEnabled() {
848
        return this.config.getScriptsEnabled();
849
    }
850

    
851
    @Override
852
    public void setSQLCompatible(boolean sqlCompatible) {
853
        this.config.setSQLCompatible(sqlCompatible);
854
    }
855

    
856
    @Override
857
    public boolean isSQLCompatible() {
858
        return this.config.isSQLCompatible();
859
    }
860
    
861
    @Override
862
    public JComponent asJComponent() {
863
        this.initializeTree();
864
        return this;
865
    }
866
    
867
    private void initializeTree() {
868
        if( this.treeModel == null ) {
869
            I18nManager i18n = ToolsLocator.getI18nManager();
870
            this.treeModel = new ElementsTreeModel(
871
                    this.manager.createGroupElement(
872
                            this.config,
873
                            i18n.getTranslation("_Elements"),
874
                            this.getElements()
875
                    )
876
            );
877
            this.treeElements.setModel(this.treeModel);
878
        }
879
    }
880
    
881
    private void doSetTimeLimit() {
882
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
883
        String s = dialogs.inputDialog(
884
                "Indicate the time limit in seconds for calculating the elements", 
885
                "Time limit", 
886
                JOptionPane.QUESTION_MESSAGE, 
887
                String.valueOf(this.config.getSimpleElementsLimit())
888
        );
889
        if( StringUtils.isBlank(s) ) {
890
            return;
891
        }
892
        try {
893
            int n = Integer.parseInt(s);
894
            this.config.setSimpleElementsLimit(n);
895
            this.treeModel.reload();
896
        } catch(Exception ex) {
897
            dialogs.messageDialog(
898
                "Invalid time limit '"+s+"'.", 
899
                "Time limit", 
900
                JOptionPane.WARNING_MESSAGE
901
            );                    
902
        }
903
    }
904

    
905
    private String load_description_from_resource() {
906
        String lang = Locale.getDefault().getLanguage();
907
        URL url = this.getClass().getResource("/org/gvsig/expressionevaluator/swing/jexpressionbuilder/"+lang+"/description.html");
908
        if( url == null ) {
909
            url = this.getClass().getResource("/org/gvsig/expressionevaluator/swing/jexpressionbuilder/en/description.html");
910
            if( url == null ) {
911
                return null;
912
            }
913
        }
914
        InputStream is = null;
915
        try {
916
            is = url.openStream();
917
            List<String> lines = IOUtils.readLines(is);
918
            return StringUtils.join(lines,  "\n");
919
        } catch (Exception ex) {
920
            return null;
921
        } finally {
922
            IOUtils.closeQuietly(is);
923
        }
924
    }
925
    
926
    @Override
927
    public void expandElement(Element element) {
928
        this.initializeTree();
929
        for (int i = 0; i < this.treeElements.getRowCount(); i++) {
930
            TreePath path = this.treeElements.getPathForRow(i);
931
            if( path.getLastPathComponent()==element ) {
932
                // FIXME: habria que expandir los padres hasta llegar a este.
933
                this.treeElements.expandPath(path);
934
                return;
935
            }
936
        }
937
    }
938
}