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

History | View | Annotate | Download (38.8 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 java.util.function.Function;
24
import java.util.function.Predicate;
25
import javax.swing.DefaultListCellRenderer;
26
import javax.swing.ImageIcon;
27
import javax.swing.JComponent;
28
import javax.swing.JEditorPane;
29
import javax.swing.JLabel;
30
import javax.swing.JList;
31
import javax.swing.JMenuItem;
32
import javax.swing.JOptionPane;
33
import javax.swing.JPanel;
34
import javax.swing.JPopupMenu;
35
import javax.swing.JScrollPane;
36
import javax.swing.JTabbedPane;
37
import javax.swing.JTree;
38
import javax.swing.SwingUtilities;
39
import javax.swing.event.CaretEvent;
40
import javax.swing.event.CaretListener;
41
import javax.swing.event.ListSelectionEvent;
42
import javax.swing.event.ListSelectionListener;
43
import javax.swing.event.TreeModelEvent;
44
import javax.swing.event.TreeModelListener;
45
import javax.swing.event.TreeSelectionEvent;
46
import javax.swing.event.TreeSelectionListener;
47
import javax.swing.tree.DefaultTreeCellRenderer;
48
import javax.swing.tree.TreeModel;
49
import javax.swing.tree.TreePath;
50
import org.apache.commons.io.FilenameUtils;
51
import org.apache.commons.io.IOUtils;
52
import org.apache.commons.lang3.StringUtils;
53
import org.gvsig.configurableactions.ConfigurableActionsMamager;
54
import org.gvsig.expressionevaluator.Expression;
55
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
56
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
57
import org.gvsig.expressionevaluator.SymbolTable;
58
import org.gvsig.expressionevaluator.swing.Element;
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.ToolsSwingLocator;
69
import org.gvsig.tools.swing.api.ToolsSwingManager;
70
import org.gvsig.tools.swing.api.bookmarkshistory.ActionEventWithCurrentValue;
71
import static org.gvsig.tools.swing.api.bookmarkshistory.ActionEventWithCurrentValue.ID_GETVALUE;
72
import static org.gvsig.tools.swing.api.bookmarkshistory.ActionEventWithCurrentValue.ID_SETVALUE;
73
import org.gvsig.tools.swing.api.bookmarkshistory.BookmarksController;
74
import org.gvsig.tools.swing.api.bookmarkshistory.HistoryController;
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.icontheme.IconTheme;
79
import org.gvsig.tools.util.Factory;
80
import org.gvsig.tools.util.ToolsUtilLocator;
81

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

    
91
    private final ExpressionEvaluatorSwingManager manager;
92
    private Element currentElement;
93
    private PickerController<List<Script>> scriptPicker;
94
    private ScriptSwingManager.ScriptEditor scriptEditor;
95
    
96
    private final ExpressionBuilderConfig builderConfig;
97
    private ElementsTreeModel treeModel;
98
    private ImageIcon defaultIconGroup;
99
    private ImageIcon defaultIconElement;
100
    private InfoPanel infoPanel;
101
    private AbstractAutomaticExpressionChecker automaticExpressionChecker;
102
    private HistoryController<Expression> historyController;
103
    private BookmarksController<Expression> bookmarksController;
104

    
105
    private static class InfoPanel implements Component {
106

    
107
        private final JEditorPane txtDescription;
108
        private final JScrollPane scrDescription;
109
        private final JTabbedPane tab;
110

    
111
        private final String labelDescription;
112
        private final String labelAdditionalPanel;
113
        private final JPanel pnlContainer;
114
        
115
        private final String defautltDescription;
116

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

    
150
        @Override
151
        public JComponent asJComponent() {
152
            this.txtDescription.setContentType("text/html");
153
            this.txtDescription.setText(this.description);
154
            this.txtDescription.setCaretPosition(0);
155

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

    
187
        public void repaint() {
188
            this.pnlContainer.removeAll();
189
            this.pnlContainer.add(this.asJComponent(), BorderLayout.CENTER);
190
            this.pnlContainer.revalidate();
191
            this.pnlContainer.repaint();
192
        }
193
    }
194

    
195
    private class ElementsTreeModel implements TreeModel {
196

    
197
        private final GroupElement root;
198
        private final HashSet<TreeModelListener> listeners;
199

    
200
        public ElementsTreeModel(GroupElement root) {
201
            this.root = root;
202
            this.listeners = new HashSet<>();
203
        }
204

    
205
        @Override
206
        public Object getRoot() {
207
            return this.root;
208
        }
209

    
210
        public void reload() {
211
            this.reload(this.root);
212
            this.fireTreeChanged();
213
        }
214
        
215
        private void reload(Element element) {
216
            if (element instanceof Element) {
217
//                if (element instanceof GroupElement) {
218
                    reload(element);
219
//                }
220
                element.reload();
221
            }
222
        }
223
        
224
        private List<Element> getChilds(final GroupElement node) {
225
            List<Element> x = new ArrayList<>();
226
            for (Element element : node.getElements()) {
227
//                if (element instanceof GroupElement) {
228
                    x.add(element);
229
//                }
230
            }
231
            return x; //node.getElements();
232
        }
233

    
234
        @Override
235
        public Object getChild(Object parent, int index) {
236
            List<Element> childs = getChilds((GroupElement) parent);
237
            Element child = childs.get(index);
238
            return child;
239
        }
240

    
241
        @Override
242
        public int getChildCount(Object parent) {
243
            List<Element> childs = getChilds((GroupElement) parent);
244
            return childs.size();
245
        }
246

    
247
        @Override
248
        public boolean isLeaf(Object node) {
249
            return !(node instanceof GroupElement);
250
        }
251

    
252
        @Override
253
        public void valueForPathChanged(TreePath path, Object newValue) {
254
        }
255

    
256
        @Override
257
        public int getIndexOfChild(Object parent, Object child) {
258
            List<Element> childs = getChilds((GroupElement) parent);
259
            int n = childs.indexOf(child);
260
            return n;
261
        }
262

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

    
268
        @Override
269
        public void removeTreeModelListener(TreeModelListener l) {
270
            this.listeners.remove(l);
271
        }
272

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

    
306
    @SuppressWarnings("Convert2Lambda")
307
    private void initComponents() {
308
        ConfigurableActionsMamager cfgActionsManager = ToolsUtilLocator.getConfigurableActionsMamager();
309
        JComponent c = cfgActionsManager.getConfigurableActionsComponent(CONFIGURABLE_PANEL_ID, this);
310
        pnlCfgActions.setLayout(new BorderLayout(0,0));
311
        pnlCfgActions.add(c, BorderLayout.LINE_END);
312
        
313
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
314
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
315
        final I18nManager i18n = ToolsLocator.getI18nManager();
316
        
317
        this.automaticExpressionChecker = new AbstractAutomaticExpressionChecker(
318
                builderConfig, txtExpression
319
            ) {
320
            @Override
321
            protected Expression getExpression() {
322
                return DefaultJExpressionBuilder.this.getExpressionWithOutHistory();
323
            }
324

    
325
            @Override
326
            protected void setMessage(int mode, String text) {
327
                super.setMessage(mode, text); 
328
                message(text);
329
            }
330

    
331
            @Override
332
            protected void setPreview(Object value) {
333
                super.setPreview(value);
334
                message(this.getPreview());
335
            }
336

    
337
            @Override
338
            protected void setTip(String theTip) {
339
                super.setTip(theTip); 
340
                btnTip.setToolTipText(toHTML(this.getTip()));
341
                btnTip.setVisible(this.isTipEnabled());
342
            }
343

    
344
            @Override
345
            protected String getSuggestion() {
346
              return builderConfig.getSuggestion(this.getExpression());
347
            }
348
            
349
        };
350
        this.infoPanel = new InfoPanel(this.pnlDescription, load_description_from_resource());
351
        
352
        this.btnTip.setVisible(false);
353
        this.btnTip.addActionListener(new ActionListener() {
354
            @Override
355
            public void actionPerformed(ActionEvent e) {
356
                ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
357
                dialogs.messageDialog(
358
                        btnTip.getToolTipText(), 
359
                        "Tip", 
360
                        JOptionPane.INFORMATION_MESSAGE
361
                );
362
            }
363
        });
364

    
365
        this.defaultIconGroup = theme.get("expressionbuilder-element-group");
366
        this.defaultIconElement = theme.get("expressionbuilder-element");
367
        
368
        toolsSwingManager.translate(this.tabExpressionBuilder);
369
        toolsSwingManager.setDefaultPopupMenu(this.txtGroupElement);
370
        toolsSwingManager.setDefaultPopupMenu(this.txtSimpleElementFilter);
371
        toolsSwingManager.addClearButton(this.txtSimpleElementFilter, new ActionListener() {
372
            @Override
373
            public void actionPerformed(ActionEvent e) {
374
                txtSimpleElementFilter.setText("");
375
                doFilter();
376
            }
377
        });
378
        JMenuItem msgMenuTextEditor = new JMenuItem(i18n.getTranslation("text_editor"));
379
        msgMenuTextEditor.addActionListener(new ActionListener() {
380
            @Override
381
            public void actionPerformed(ActionEvent e) {
382
                automaticExpressionChecker.showMessageDialog();
383
            }
384
        });
385
        JMenuItem msgMenuCopy = new JMenuItem(i18n.getTranslation("copy"));
386
        msgMenuTextEditor.addActionListener(new ActionListener() {
387
            @Override
388
            public void actionPerformed(ActionEvent e) {
389
                StringSelection selection = new StringSelection(automaticExpressionChecker.getMessage());
390
                Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
391
                clipboard.setContents(selection, selection);                
392
            }
393
        });
394
        
395
        JPopupMenu msgMenu = new JPopupMenu();
396
        msgMenu.add(msgMenuTextEditor);
397
        msgMenu.addSeparator();
398
        msgMenu.add(msgMenuCopy);
399
        this.lblMsg.setComponentPopupMenu(msgMenu);
400

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

    
545
        this.btnSimpleElementTimeLimit.addActionListener(new ActionListener() {
546
            @Override
547
            public void actionPerformed(ActionEvent e) {
548
                doSetTimeLimit();
549
            }
550
        });
551
        this.btnSimpleElementSortDown.addActionListener(new ActionListener() {
552
            @Override
553
            public void actionPerformed(ActionEvent e) {
554
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
555
                model.sort(false);
556
            }
557
        });
558
        this.btnSimpleElementSortUp.addActionListener(new ActionListener() {
559
            @Override
560
            public void actionPerformed(ActionEvent e) {
561
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
562
                model.sort(true);
563
            }
564
        });
565
        this.txtSimpleElementFilter.addKeyListener(new KeyAdapter() {
566
            @Override
567
            public void keyTyped(KeyEvent e) {
568
                if (e.getKeyChar() == '\n') {
569
                    doFilter();
570
                }
571
            }
572
        });
573
        this.btnAdd.addActionListener(new ActionListener() {
574
            @Override
575
            public void actionPerformed(ActionEvent e) {
576
                doInsert(" + ");
577
            }
578
        });
579
        this.btnDiv.addActionListener(new ActionListener() {
580
            @Override
581
            public void actionPerformed(ActionEvent e) {
582
                doInsert(" / ");
583
            }
584
        });
585
        this.btnEq.addActionListener(new ActionListener() {
586
            @Override
587
            public void actionPerformed(ActionEvent e) {
588
                doInsert(" = ");
589
            }
590
        });
591
        this.btnMult.addActionListener(new ActionListener() {
592
            @Override
593
            public void actionPerformed(ActionEvent e) {
594
                doInsert(" * ");
595
            }
596
        });
597
        this.btnNeq.addActionListener(new ActionListener() {
598
            @Override
599
            public void actionPerformed(ActionEvent e) {
600
                doInsert(" <> ");
601
            }
602
        });
603
        this.btnParentClose.addActionListener(new ActionListener() {
604
            @Override
605
            public void actionPerformed(ActionEvent e) {
606
                doInsert(" ) ");
607
            }
608
        });
609
        this.btnParentOpen.addActionListener(new ActionListener() {
610
            @Override
611
            public void actionPerformed(ActionEvent e) {
612
                doInsert(" ( ");
613
            }
614
        });
615
        this.btnSubst.addActionListener(new ActionListener() {
616
            @Override
617
            public void actionPerformed(ActionEvent e) {
618
                doInsert(" - ");
619
            }
620
        });
621
//        ScriptSwingManager scriptSwingManager = ToolsSwingLocator.getScriptSwingManager();
622
//        this.scriptPicker = scriptSwingManager.createListScriptPickerController(
623
//                cboPickerScripts,
624
//                btnPickerRemove,
625
//                btnPickerSelectScript
626
//        );
627
//        this.scriptEditor = scriptSwingManager.createScriptEditor();
628
//        this.pnlScriptEditorContainer.setLayout(new BorderLayout());
629
//        this.pnlScriptEditorContainer.add(this.scriptEditor.asJComponent(), BorderLayout.CENTER);
630
//    
631
//        this.tabExpressionBuilder.setEnabledAt(0, this.builderConfig.getPreferences().getScriptsEnabled());
632
        
633
        ActionListener historyAndBookmarkListener = new ActionListener() {
634
            @Override
635
            public void actionPerformed(ActionEvent e) {
636
                ActionEventWithCurrentValue<Expression> ee = (ActionEventWithCurrentValue<Expression>)e;
637
                switch(ee.getID()) {
638
                    case ID_SETVALUE:
639
                        setExpression(ee.getCurrentValue());
640
                        break;
641
                    case ID_GETVALUE:
642
                        ee.setCurrentValue(getExpressionWithOutHistory());
643
                        break;
644
                }
645
            }
646
        };
647
        this.historyController = toolsSwingManager.createHistoryController(
648
                ExpressionEvaluatorLocator.getManager().getHistory(), 
649
                btnHistory
650
        );
651
        this.historyController.addActionListener(historyAndBookmarkListener);
652
        
653
        this.bookmarksController = toolsSwingManager.createBookmarksController(
654
                ExpressionEvaluatorLocator.getManager().getBookmarks(), 
655
                btnBookmarks
656
        );
657
        this.bookmarksController.addActionListener(historyAndBookmarkListener);        
658
        
659
        this.infoPanel.repaint();
660
        
661
        this.setPreferredSize(new Dimension(750, 450));
662
        
663

    
664
        Dimension dim = this.getPreferredSize();
665
        this.spnlExpression.setDividerLocation(dim.height/5);
666
        this.spnlBottom.setDividerLocation(dim.width/3);
667
        this.spnlItem.setDividerLocation(dim.width/3);
668
    }
669

    
670
    private void message(String text) {
671
      if( StringUtils.isBlank(text) ) {
672
        lblMsg.setText("");
673
        return;
674
      }
675
      String msg = text;
676
      String tail = "";
677
      if( StringUtils.contains(msg, "\n") ) {
678
        String[] ss = StringUtils.split(msg, "\n");
679
        if( ss.length>1 ) {
680
          tail = String.format("(%d lines more)", ss.length);
681
          msg = ss[0];
682
        }
683
      }
684
      lblMsg.setText(toHTML(StringUtils.abbreviate(msg,70)+tail));      
685
    }
686

    
687
    private String toHTML(String s) {
688
      s = StringUtils.replace(s, "\n", "\n<br>");
689
      s = StringUtils.replace(s, "<html>", "");
690
      s = StringUtils.replace(s, "</html>", "");
691
      s = "<html>"+s+"</html>";
692
      return s;
693
    }
694
    
695
    private String removeCursorMark(String s) {
696
        if( s == null ) {
697
            return null;
698
        }
699
        s = s.replace("{{", "");
700
        s = s.replace("}}", "");
701
        return s;
702
    }
703

    
704
    @Override
705
    public void insertText(String text) {
706
        doInsert(text);
707
    }
708

    
709
    @Override
710
    public String getText() {
711
        return this.txtExpression.getText();
712
    }
713
    
714
    @Override
715
    public void setText(String text) {
716
        this.txtExpression.setText(text);
717
    }
718
    
719
    private void doInsert(String s) {
720
        this.txtExpression.replaceSelection(s);
721
        String ss = this.txtExpression.getText();
722
        int start = ss.indexOf("{{");
723
        int end = ss.indexOf("}}");
724
        if (start > 0 && end > 0) {
725
            this.txtExpression.replaceRange("", end, end + 2);
726
            this.txtExpression.replaceRange("", start, start + 2);
727
            this.txtExpression.setSelectionStart(start);
728
            this.txtExpression.setSelectionEnd(end - 2);
729
        }
730
        this.txtExpression.requestFocusInWindow();
731
    }
732

    
733
    private void doInsert(Element element) {
734
        doInsert(element.getRenderedValue());
735
        element.used();
736
    }
737

    
738
    private void doFilter() {
739
        FilteredListModel model = (FilteredListModel) this.lstSimpleElement.getModel();
740
        model.setFilter(this.txtSimpleElementFilter.getText());
741
    }
742

    
743
    private void doSelectElement(Element element) {
744
//        if( !element.isEnabled() ) {
745
//            this.infoPanel.clean();
746
//        } else {
747
            this.infoPanel.setDescription(removeCursorMark(element.getDescription()));
748
            this.infoPanel.setAdditionalPanel(element.getAditionalPanel(this));
749
            this.infoPanel.repaint();
750
//        }        
751
    }
752

    
753
    private void updateSimpleElementsList(Element element) {
754
        FilteredListModel model = new FilteredListModel();
755
        model.addElement("Loading...");
756
        this.currentElement = element;
757
        this.txtGroupElement.setText(element.getName());
758
        this.txtSimpleElementFilter.setText("");
759
//        this.infoPanel.clean();
760
//        this.infoPanel.repaint();
761
        if (element instanceof SimpleElement) {
762
            this.btnGroupElementInsert.setEnabled(true);
763
        } else {
764
            this.btnGroupElementInsert.setEnabled(false);
765
        }
766
        this.lstSimpleElement.setEnabled(false);
767
        this.lstSimpleElement.setModel(model);
768

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

    
778
    private void simpleElementsUpdater() {
779
        final Element element = this.currentElement;
780
        final FilteredListModel model = new FilteredListModel();
781
        for (Element value : element.getValues()) {
782
            if (element != this.currentElement) {
783
                // Como estamos en otro hilo, cuando el usuario cambia de elemento,
784
                // cancelamos las actualizaciones que teniamos en curso.
785
                return;
786
            }
787
            if (value instanceof SimpleElement) {
788
                model.addElement(value);
789
            }
790
        }
791
        model.sort(true);
792
        SwingUtilities.invokeLater(new Runnable() {
793
            @Override
794
            public void run() {
795
                if (element != currentElement) {
796
                    return;
797
                }
798
                if( element.hasMoreValues()) {
799
                    lblSimpleElementsMsg.setText("More elements...");
800
                } else {
801
                    lblSimpleElementsMsg.setText("");
802
                }
803
                lstSimpleElement.setEnabled(true);
804
                lstSimpleElement.setModel(model);
805
            }
806
        });
807

    
808
    }
809

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

    
834
    @Override
835
    public void setExpression(Expression expression) {
836
        if( expression==null ) {
837
            this.txtExpression.setText("");
838
        } else {
839
            this.txtExpression.setText(expression.getPhrase());
840
        }
841
//            try { this.scriptEditor.set(null); } catch(Exception ex) {}
842
//            this.scriptPicker.set(null);
843
//        } else {
844
//            this.txtExpression.setText(expression.getPhrase());
845
//            if( expression.getUserScript()!=null ) {
846
//                this.scriptEditor.set(expression.getUserScript());
847
//            }
848
//            if( expression.getScripts()!=null ) {
849
//                this.scriptPicker.set(expression.getScripts().toList());
850
//            }
851
//        }
852
    }
853

    
854
    @Override
855
    public Preferences getPreferences() {
856
        return this.builderConfig.getPreferences();
857
    }
858
    
859
    @Override
860
    public List<Element> getElements() {
861
        return this.builderConfig.getElements();
862
    }
863
    
864
    @Override
865
    public void addElement(Element element) {
866
        this.builderConfig.addElement(element);
867
    }
868
    
869
    @Override
870
    public Collection<SymbolTable> getSymbolTables() {
871
        return this.builderConfig.getSymbolTables();
872
    }
873
    
874
    @Override
875
    public void addSymbolTable(String name) {
876
        this.builderConfig.addSymbolTable(name);
877
    }
878
    
879
    @Override
880
    public void addSymbolTable(SymbolTable symbolTable) {
881
        this.builderConfig.addSymbolTable(symbolTable);
882
    }
883

    
884
    @Override
885
    public void removeAllSymbolTables() {
886
        this.builderConfig.removeAllSymbolTables();
887
    }
888

    
889
    @Override
890
    public void removeSymbolTable(String name) {
891
        this.builderConfig.removeSymbolTable(name);
892
    }
893

    
894
    @Override
895
    public SymbolTable getPreviewSymbolTable() {
896
        return this.builderConfig.getPreviewSymbolTable();
897
    }
898

    
899
    @Override
900
    public void setPreviewSymbolTable(SymbolTable symbolTable) {
901
        this.builderConfig.setPreviewSymbolTable(symbolTable);
902
    }
903
    
904
    @Override
905
    public JComponent asJComponent() {
906
        this.initializeTree();
907
        SwingUtilities.invokeLater(new Runnable() {
908
            @Override
909
            public void run() {
910
               txtExpression.requestFocusInWindow();
911
            }
912
        });
913
        return this;
914
    }
915
    
916
    private void initializeTree() {
917
        if( this.treeModel == null ) {
918
            I18nManager i18n = ToolsLocator.getI18nManager();
919
            this.treeModel = new ElementsTreeModel( (GroupElement)
920
                    this.manager.createGroupElement(
921
                            i18n.getTranslation("_Elements"),
922
                            this.getElements()
923
                    ).setConfig(this));
924
            this.treeElements.setModel(this.treeModel);
925
            for (int i = 0; i < this.treeElements.getRowCount(); i++) {
926
                TreePath pathRow = this.treeElements.getPathForRow(i);
927
                Element element = (Element) pathRow.getLastPathComponent();
928
                if (i18n.getTranslation("_Functions").equals(element.getName())) {
929
                    this.treeElements.setSelectionPath(pathRow);
930
                    doSelectElement(element);
931
                    updateSimpleElementsList(element);
932
                    break;
933
                }
934
            }
935
        }
936
    }
937
    
938
    private void doSetTimeLimit() {
939
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
940
        String s = dialogs.inputDialog(
941
                "Indicate the time limit in seconds for calculating the elements", 
942
                "Time limit", 
943
                JOptionPane.QUESTION_MESSAGE, 
944
                String.valueOf(this.builderConfig.getPreferences().getSimpleElementsLimit())
945
        );
946
        if( StringUtils.isBlank(s) ) {
947
            return;
948
        }
949
        try {
950
            int n = Integer.parseInt(s);
951
            this.builderConfig.getPreferences().setSimpleElementsLimit(n);
952
            this.treeModel.reload();
953
        } catch(Exception ex) {
954
            dialogs.messageDialog(
955
                "Invalid time limit '"+s+"'.", 
956
                "Time limit", 
957
                JOptionPane.WARNING_MESSAGE
958
            );                    
959
        }
960
    }
961

    
962
    private String load_description_from_resource() {
963
        String lang = Locale.getDefault().getLanguage();
964
        URL url = this.getClass().getResource("/org/gvsig/expressionevaluator/swing/jexpressionbuilder/"+lang+"/description.html");
965
        if( url == null ) {
966
            url = this.getClass().getResource("/org/gvsig/expressionevaluator/swing/jexpressionbuilder/en/description.html");
967
            if( url == null ) {
968
                return null;
969
            }
970
        }
971
        InputStream is = null;
972
        try {
973
            is = url.openStream();
974
            List<String> lines = IOUtils.readLines(is);
975
            return StringUtils.join(lines,  "\n");
976
        } catch (Exception ex) {
977
            return null;
978
        } finally {
979
            IOUtils.closeQuietly(is);
980
        }
981
    }
982
    
983
    @Override
984
    public void expandElement(Element element) {
985
        this.initializeTree();
986
        for (int i = 0; i < this.treeElements.getRowCount(); i++) {
987
            TreePath path = this.treeElements.getPathForRow(i);
988
            if( path.getLastPathComponent()==element ) {
989
                // FIXME: habria que expandir los padres hasta llegar a este.
990
                this.treeElements.expandPath(path);
991
                return;
992
            }
993
        }
994
    }
995

    
996
    @Override
997
    public void expandElement(Predicate<Element> condition) {
998
        if( condition == null ) {
999
          return;
1000
        }
1001
        this.initializeTree();
1002
        for (int i = 0; i < this.treeElements.getRowCount(); i++) {
1003
            TreePath path = this.treeElements.getPathForRow(i);
1004
            if( condition.test((Element) path.getLastPathComponent()) ) {
1005
                // FIXME: habria que expandir los padres hasta llegar a este.
1006
                this.treeElements.expandPath(path);
1007
                return;
1008
            }
1009
        }
1010
    }
1011

    
1012
    @Override
1013
    public Object getProperty(String name) {
1014
        return this.builderConfig.getProperty(name);
1015
    }
1016

    
1017
    @Override
1018
    public void setProperty(String name, Object value) {
1019
        this.builderConfig.setProperty(name, value);
1020
    }
1021

    
1022
    @Override
1023
    public Map<String, Object> getProperties() {
1024
        return this.builderConfig.getProperties();
1025
    }
1026

    
1027
    @Override
1028
    public boolean allowAggregates() {
1029
      return this.builderConfig.allowAggregates();
1030
    }
1031

    
1032
    @Override
1033
    public boolean allowAggregates(boolean allow) {
1034
      return this.builderConfig.allowAggregates(allow);
1035
    }
1036

    
1037
    @Override
1038
    public java.util.function.Function<String, Integer> isFunctionAllowed() {
1039
      return this.builderConfig.isFunctionAllowed();
1040
    }
1041

    
1042
    @Override
1043
    public void setAllowedFunctions(java.util.function.Function<String, Integer> allow) {
1044
      this.builderConfig.setAllowedFunctions(allow);
1045
    }
1046
    
1047
    @Override
1048
    public void addSuggestionFactory(Factory factory) {
1049
      this.builderConfig.addSuggestionFactory(factory);
1050
    }
1051

    
1052
    @Override
1053
    public String getSuggestion(Expression expression) {
1054
      return this.builderConfig.getSuggestion(expression);
1055
    }
1056

    
1057
    @Override
1058
    public void copyConfigFrom(ExpressionBuilderConfig other) {
1059
      this.builderConfig.copyConfigFrom(other);
1060
    }
1061
    
1062
    @Override
1063
    public Function<String, Integer> getAllowedFunctions() {
1064
      return this.builderConfig.getAllowedFunctions();
1065
    }
1066

    
1067
    @Override
1068
    public Collection<Factory> getSuggestionFactories() {
1069
      return this.builderConfig.getSuggestionFactories();
1070
    }
1071

    
1072
    @Override
1073
    public void removeAllElements() {
1074
      this.builderConfig.removeAllElements();
1075
    }
1076

    
1077
}