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

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

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

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

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

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

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

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

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

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

    
187
    private class ElementsTreeModel implements TreeModel {
188

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
751
    }
752

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

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

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

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

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

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

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

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

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

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

    
857
    @Override
858
    public boolean isSQLCompatible() {
859
        return this.config.isSQLCompatible();
860
    }
861

    
862
    @Override
863
    public Object getProperty(String string) {
864
        return this.config.getProperty(string);
865
    }
866

    
867
    @Override
868
    public void setProperty(String string, Object o) {
869
        this.config.setProperty(string, o);
870
    }
871

    
872
    @Override
873
    public Map<String, Object> getProperties() {
874
        return this.config.getProperties();
875
    }
876
    
877
    @Override
878
    public JComponent asJComponent() {
879
        this.initializeTree();
880
        return this;
881
    }
882
    
883
    private void initializeTree() {
884
        if( this.treeModel == null ) {
885
            I18nManager i18n = ToolsLocator.getI18nManager();
886
            this.treeModel = new ElementsTreeModel(
887
                    this.manager.createGroupElement(
888
                            this.config,
889
                            i18n.getTranslation("_Elements"),
890
                            this.getElements()
891
                    )
892
            );
893
            this.treeElements.setModel(this.treeModel);
894
        }
895
    }
896
    
897
    private void doSetTimeLimit() {
898
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
899
        String s = dialogs.inputDialog(
900
                "Indicate the time limit in seconds for calculating the elements", 
901
                "Time limit", 
902
                JOptionPane.QUESTION_MESSAGE, 
903
                String.valueOf(this.config.getSimpleElementsLimit())
904
        );
905
        if( StringUtils.isBlank(s) ) {
906
            return;
907
        }
908
        try {
909
            int n = Integer.parseInt(s);
910
            this.config.setSimpleElementsLimit(n);
911
            this.treeModel.reload();
912
        } catch(Exception ex) {
913
            dialogs.messageDialog(
914
                "Invalid time limit '"+s+"'.", 
915
                "Time limit", 
916
                JOptionPane.WARNING_MESSAGE
917
            );                    
918
        }
919
    }
920

    
921
    private String load_description_from_resource() {
922
        String lang = Locale.getDefault().getLanguage();
923
        URL url = this.getClass().getResource("/org/gvsig/expressionevaluator/swing/jexpressionbuilder/"+lang+"/description.html");
924
        if( url == null ) {
925
            url = this.getClass().getResource("/org/gvsig/expressionevaluator/swing/jexpressionbuilder/en/description.html");
926
            if( url == null ) {
927
                return null;
928
            }
929
        }
930
        InputStream is = null;
931
        try {
932
            is = url.openStream();
933
            List<String> lines = IOUtils.readLines(is);
934
            return StringUtils.join(lines,  "\n");
935
        } catch (Exception ex) {
936
            return null;
937
        } finally {
938
            IOUtils.closeQuietly(is);
939
        }
940
    }
941
    
942
    @Override
943
    public void expandElement(Element element) {
944
        this.initializeTree();
945
        for (int i = 0; i < this.treeElements.getRowCount(); i++) {
946
            TreePath path = this.treeElements.getPathForRow(i);
947
            if( path.getLastPathComponent()==element ) {
948
                // FIXME: habria que expandir los padres hasta llegar a este.
949
                this.treeElements.expandPath(path);
950
                return;
951
            }
952
        }
953
    }
954
}