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

History | View | Annotate | Download (39.5 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.text.JTextComponent;
48
import javax.swing.tree.DefaultTreeCellRenderer;
49
import javax.swing.tree.TreeModel;
50
import javax.swing.tree.TreePath;
51
import org.apache.commons.io.FilenameUtils;
52
import org.apache.commons.io.IOUtils;
53
import org.apache.commons.lang3.StringUtils;
54
import org.gvsig.configurableactions.ConfigurableActionsMamager;
55
import org.gvsig.expressionevaluator.Expression;
56
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
57
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
58
import org.gvsig.expressionevaluator.SymbolTable;
59
import org.gvsig.expressionevaluator.swing.Element;
60
import org.gvsig.expressionevaluator.swing.Element.GroupElement;
61
import org.gvsig.expressionevaluator.swing.Element.SimpleElement;
62
import org.gvsig.expressionevaluator.swing.ExpressionBuilderConfig;
63
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
64
import org.gvsig.expressionevaluator.swing.JExpressionBuilder;
65
import org.gvsig.tools.ToolsLocator;
66
import org.gvsig.tools.i18n.I18nManager;
67
import org.gvsig.tools.script.Script;
68
import org.gvsig.tools.swing.api.Component;
69
import org.gvsig.tools.swing.api.ToolsSwingLocator;
70
import org.gvsig.tools.swing.api.ToolsSwingManager;
71
import org.gvsig.tools.swing.api.bookmarkshistory.ActionEventWithCurrentValue;
72
import static org.gvsig.tools.swing.api.bookmarkshistory.ActionEventWithCurrentValue.ID_GETVALUE;
73
import static org.gvsig.tools.swing.api.bookmarkshistory.ActionEventWithCurrentValue.ID_SETVALUE;
74
import org.gvsig.tools.swing.api.bookmarkshistory.BookmarksController;
75
import org.gvsig.tools.swing.api.bookmarkshistory.HistoryController;
76
import org.gvsig.tools.swing.api.pickercontroller.PickerController;
77
import org.gvsig.tools.swing.api.script.ScriptSwingManager;
78
import org.gvsig.tools.swing.api.threadsafedialogs.ThreadSafeDialogsManager;
79
import org.gvsig.tools.swing.icontheme.IconTheme;
80
import org.gvsig.tools.util.Factory;
81
import org.gvsig.tools.util.ToolsUtilLocator;
82

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

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

    
108
    private static class InfoPanel implements Component {
109

    
110
        private final JEditorPane txtDescription;
111
        private final JScrollPane scrDescription;
112
        private final JTabbedPane tab;
113

    
114
        private final String labelDescription;
115
        private final String labelAdditionalPanel;
116
        private final JPanel pnlContainer;
117
        
118
        private final String defautltDescription;
119

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

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

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

    
190
        public void repaint() {
191
            this.pnlContainer.removeAll();
192
            this.pnlContainer.add(this.asJComponent(), BorderLayout.CENTER);
193
            this.pnlContainer.revalidate();
194
            this.pnlContainer.repaint();
195
        }
196
    }
197

    
198
    private class ElementsTreeModel implements TreeModel {
199

    
200
        private final GroupElement root;
201
        private final HashSet<TreeModelListener> listeners;
202

    
203
        public ElementsTreeModel(GroupElement root) {
204
            this.root = root;
205
            this.listeners = new HashSet<>();
206
        }
207

    
208
        @Override
209
        public Object getRoot() {
210
            return this.root;
211
        }
212

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

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

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

    
250
        @Override
251
        public boolean isLeaf(Object node) {
252
            return !(node instanceof GroupElement);
253
        }
254

    
255
        @Override
256
        public void valueForPathChanged(TreePath path, Object newValue) {
257
        }
258

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

    
266
        @Override
267
        public void addTreeModelListener(TreeModelListener l) {
268
            this.listeners.add(l);
269
        }
270

    
271
        @Override
272
        public void removeTreeModelListener(TreeModelListener l) {
273
            this.listeners.remove(l);
274
        }
275

    
276
        protected void fireTreeChanged() {
277
            for (TreeModelListener listener : listeners) {
278
                TreeModelEvent e = new TreeModelEvent(this, new Object[] {this.root});
279
                listener.treeNodesChanged(e);
280
            }
281
        }
282
    }
283
    
284
    public DefaultJExpressionBuilder(
285
            ExpressionEvaluatorSwingManager manager, 
286
            ExpressionBuilderConfig config,
287
            DefaultJExpressionBuilderView2 view
288
      ) {
289
        this.manager = manager;
290
        if( config == null ) {
291
            this.builderConfig = new DefaultExpressionBuilderConfig(manager);
292
        } else {
293
            this.builderConfig = config;
294
        }
295
        this.view = view;
296
        this.initComponents();
297
    }
298
    
299
    @SuppressWarnings("Convert2Lambda")
300
    private void initComponents() {
301
        ConfigurableActionsMamager cfgActionsManager = ToolsUtilLocator.getConfigurableActionsMamager();
302
        JComponent c = cfgActionsManager.getConfigurableActionsComponent(CONFIGURABLE_PANEL_ID, this);
303
        this.view.pnlCfgActions.setLayout(new BorderLayout(0,0));
304
        this.view.pnlCfgActions.add(c, BorderLayout.LINE_END);
305
        
306
        final ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
307
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
308
        final I18nManager i18n = ToolsLocator.getI18nManager();
309
        
310
        this.infoPanel = new InfoPanel(this.view.pnlDescription, load_description_from_resource());
311
        
312
        this.view.btnTip.setVisible(false);
313
        this.view.btnTip.addActionListener(new ActionListener() {
314
            @Override
315
            public void actionPerformed(ActionEvent e) {
316
                ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
317
                dialogs.messageDialog(
318
                        view.btnTip.getToolTipText(), 
319
                        "Tip", 
320
                        JOptionPane.INFORMATION_MESSAGE
321
                );
322
            }
323
        });
324

    
325
        this.defaultIconGroup = theme.get("expressionbuilder-element-group");
326
        this.defaultIconElement = theme.get("expressionbuilder-element");
327
        
328
//        toolsSwingManager.translate(this.tabExpressionBuilder);
329
        toolsSwingManager.setDefaultPopupMenu(this.view.txtGroupElement);
330
        toolsSwingManager.setDefaultPopupMenu(this.view.txtSimpleElementFilter);
331
        toolsSwingManager.addClearButton(this.view.txtSimpleElementFilter, new ActionListener() {
332
            @Override
333
            public void actionPerformed(ActionEvent e) {
334
                view.txtSimpleElementFilter.setText("");
335
                doFilter();
336
            }
337
        });
338
        JMenuItem msgMenuTextEditor = new JMenuItem(i18n.getTranslation("text_editor"));
339
        msgMenuTextEditor.addActionListener(new ActionListener() {
340
            @Override
341
            public void actionPerformed(ActionEvent e) {
342
                if( automaticExpressionChecker!=null ) {
343
                  automaticExpressionChecker.showMessageDialog();
344
                }
345
            }
346
        });
347
        JMenuItem msgMenuCopy = new JMenuItem(i18n.getTranslation("copy"));
348
        msgMenuTextEditor.addActionListener(new ActionListener() {
349
            @Override
350
            public void actionPerformed(ActionEvent e) {
351
                if( automaticExpressionChecker!=null ) {
352
                  StringSelection selection = new StringSelection(automaticExpressionChecker.getMessage());
353
                  Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
354
                  clipboard.setContents(selection, selection);                
355
                }
356
            }
357
        });
358
        
359
        JPopupMenu msgMenu = new JPopupMenu();
360
        msgMenu.add(msgMenuTextEditor);
361
        msgMenu.addSeparator();
362
        msgMenu.add(msgMenuCopy);
363
        this.view.lblMsg.setComponentPopupMenu(msgMenu);
364

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

    
509
        this.view.btnSimpleElementTimeLimit.addActionListener(new ActionListener() {
510
            @Override
511
            public void actionPerformed(ActionEvent e) {
512
                doSetTimeLimit();
513
            }
514
        });
515
        this.view.btnSimpleElementSortDown.addActionListener(new ActionListener() {
516
            @Override
517
            public void actionPerformed(ActionEvent e) {
518
                FilteredListModel model = (FilteredListModel) view.lstSimpleElement.getModel();
519
                model.sort(false);
520
            }
521
        });
522
        this.view.btnSimpleElementSortUp.addActionListener(new ActionListener() {
523
            @Override
524
            public void actionPerformed(ActionEvent e) {
525
                FilteredListModel model = (FilteredListModel) view.lstSimpleElement.getModel();
526
                model.sort(true);
527
            }
528
        });
529
        this.view.txtSimpleElementFilter.addKeyListener(new KeyAdapter() {
530
            @Override
531
            public void keyTyped(KeyEvent e) {
532
                if (e.getKeyChar() == '\n') {
533
                    doFilter();
534
                }
535
            }
536
        });
537
        this.view.btnAdd.addActionListener(new ActionListener() {
538
            @Override
539
            public void actionPerformed(ActionEvent e) {
540
                doInsert(" + ");
541
            }
542
        });
543
        this.view.btnDiv.addActionListener(new ActionListener() {
544
            @Override
545
            public void actionPerformed(ActionEvent e) {
546
                doInsert(" / ");
547
            }
548
        });
549
        this.view.btnEq.addActionListener(new ActionListener() {
550
            @Override
551
            public void actionPerformed(ActionEvent e) {
552
                doInsert(" = ");
553
            }
554
        });
555
        this.view.btnMult.addActionListener(new ActionListener() {
556
            @Override
557
            public void actionPerformed(ActionEvent e) {
558
                doInsert(" * ");
559
            }
560
        });
561
        this.view.btnNeq.addActionListener(new ActionListener() {
562
            @Override
563
            public void actionPerformed(ActionEvent e) {
564
                doInsert(" <> ");
565
            }
566
        });
567
        this.view.btnParentClose.addActionListener(new ActionListener() {
568
            @Override
569
            public void actionPerformed(ActionEvent e) {
570
                doInsert(" ) ");
571
            }
572
        });
573
        this.view.btnParentOpen.addActionListener(new ActionListener() {
574
            @Override
575
            public void actionPerformed(ActionEvent e) {
576
                doInsert(" ( ");
577
            }
578
        });
579
        this.view.btnSubst.addActionListener(new ActionListener() {
580
            @Override
581
            public void actionPerformed(ActionEvent e) {
582
                doInsert(" - ");
583
            }
584
        });
585
//        ScriptSwingManager scriptSwingManager = ToolsSwingLocator.getScriptSwingManager();
586
//        this.scriptPicker = scriptSwingManager.createListScriptPickerController(
587
//                cboPickerScripts,
588
//                btnPickerRemove,
589
//                btnPickerSelectScript
590
//        );
591
//        this.scriptEditor = scriptSwingManager.createScriptEditor();
592
//        this.pnlScriptEditorContainer.setLayout(new BorderLayout());
593
//        this.pnlScriptEditorContainer.add(this.scriptEditor.asJComponent(), BorderLayout.CENTER);
594
//    
595
//        this.tabExpressionBuilder.setEnabledAt(0, this.builderConfig.getPreferences().getScriptsEnabled());
596
        
597
        ActionListener historyAndBookmarkListener = new ActionListener() {
598
            @Override
599
            public void actionPerformed(ActionEvent e) {
600
                ActionEventWithCurrentValue<Expression> ee = (ActionEventWithCurrentValue<Expression>)e;
601
                switch(ee.getID()) {
602
                    case ID_SETVALUE:
603
                        setExpression(ee.getCurrentValue());
604
                        break;
605
                    case ID_GETVALUE:
606
                        ee.setCurrentValue(getExpressionWithOutHistory());
607
                        break;
608
                }
609
            }
610
        };
611
        this.historyController = toolsSwingManager.createHistoryController(
612
                ExpressionEvaluatorLocator.getManager().getHistory(), 
613
                view.btnHistory
614
        );
615
        this.historyController.addActionListener(historyAndBookmarkListener);
616
        
617
        this.bookmarksController = toolsSwingManager.createBookmarksController(
618
                ExpressionEvaluatorLocator.getManager().getBookmarks(), 
619
                view.btnBookmarks
620
        );
621
        this.bookmarksController.addActionListener(historyAndBookmarkListener);        
622
        
623
        this.infoPanel.repaint();
624
        
625
        this.view.setPreferredSize(new Dimension(750, 450));
626
        
627

    
628
        Dimension dim = this.view.getPreferredSize();
629
        this.view.spnlExpression.setDividerLocation(dim.height/5);
630
        this.view.spnlBottom.setDividerLocation(dim.width/3);
631
        this.view.spnlItem.setDividerLocation(dim.width/3);
632
    }
633

    
634
    private void message(String text) {
635
      if( StringUtils.isBlank(text) ) {
636
        view.lblMsg.setText("");
637
        return;
638
      }
639
      String msg = text;
640
      String tail = "";
641
      if( StringUtils.contains(msg, "\n") ) {
642
        String[] ss = StringUtils.split(msg, "\n");
643
        if( ss.length>1 ) {
644
          tail = String.format("(%d lines more)", ss.length);
645
          msg = ss[0];
646
        }
647
      }
648
      view.lblMsg.setText(toHTML(StringUtils.abbreviate(msg,70)+tail));      
649
    }
650

    
651
    private String toHTML(String s) {
652
      s = StringUtils.replace(s, "\n", "\n<br>");
653
      s = StringUtils.replace(s, "<html>", "");
654
      s = StringUtils.replace(s, "</html>", "");
655
      s = "<html>"+s+"</html>";
656
      return s;
657
    }
658
    
659
    private String removeCursorMark(String s) {
660
        if( s == null ) {
661
            return null;
662
        }
663
        s = s.replace("{{", "");
664
        s = s.replace("}}", "");
665
        return s;
666
    }
667

    
668
    @Override
669
    public void insertText(String text) {
670
        doInsert(text);
671
    }
672

    
673
    @Override
674
    public String getText() {
675
        return this.view.getExpressionComponent().getText();
676
    }
677
    
678
    @Override
679
    public void setText(String text) {
680
        this.view.getExpressionComponent().setText(text);
681
    }
682
    
683
    private void doInsert(String s) {
684
        int start = s.indexOf("{{");
685
        int end = s.indexOf("}}");
686
        if (start > 0 && end > 0) {
687
          s = s.replace("{{", "");
688
          s = s.replace("}}", "");
689
        }
690
        JTextComponent jtext = this.view.getExpressionComponent();
691
        int selstart = this.view.getExpressionComponent().getSelectionStart();
692
        jtext.replaceSelection(s);
693
        if (start > 0 && end > 0) {
694
            jtext.setSelectionStart(selstart+start);
695
            jtext.setSelectionEnd(selstart+end - 2);
696
        }
697
        jtext.requestFocusInWindow();
698
    }
699

    
700
    private void doInsert(Element element) {
701
        doInsert(element.getRenderedValue());
702
        element.used();
703
    }
704

    
705
    private void doFilter() {
706
        FilteredListModel model = (FilteredListModel) this.view.lstSimpleElement.getModel();
707
        model.setFilter(this.view.txtSimpleElementFilter.getText());
708
    }
709

    
710
    private void doSelectElement(Element element) {
711
//        if( !element.isEnabled() ) {
712
//            this.infoPanel.clean();
713
//        } else {
714
            this.infoPanel.setDescription(removeCursorMark(element.getDescription()));
715
            this.infoPanel.setAdditionalPanel(element.getAditionalPanel(this));
716
            this.infoPanel.repaint();
717
//        }        
718
    }
719

    
720
    private void updateSimpleElementsList(Element element) {
721
        FilteredListModel model = new FilteredListModel();
722
        model.addElement("Loading...");
723
        this.currentElement = element;
724
        this.view.txtGroupElement.setText(element.getName());
725
        this.view.txtSimpleElementFilter.setText("");
726
//        this.infoPanel.clean();
727
//        this.infoPanel.repaint();
728
        if (element instanceof SimpleElement) {
729
            this.view.btnGroupElementInsert.setEnabled(true);
730
        } else {
731
            this.view.btnGroupElementInsert.setEnabled(false);
732
        }
733
        this.view.lstSimpleElement.setEnabled(false);
734
        this.view.lstSimpleElement.setModel(model);
735

    
736
        Thread th = new Thread(new Runnable() {
737
            @Override
738
            public void run() {
739
                simpleElementsUpdater();
740
            }
741
        }, "ExpressionBuilderSimpleElementsUpdater");
742
        th.start();
743
    }
744

    
745
    private void simpleElementsUpdater() {
746
        final Element element = this.currentElement;
747
        final FilteredListModel model = new FilteredListModel();
748
        for (Element value : element.getValues()) {
749
            if (element != this.currentElement) {
750
                // Como estamos en otro hilo, cuando el usuario cambia de elemento,
751
                // cancelamos las actualizaciones que teniamos en curso.
752
                return;
753
            }
754
            if (value instanceof SimpleElement) {
755
                model.addElement(value);
756
            }
757
        }
758
        model.sort(true);
759
        SwingUtilities.invokeLater(new Runnable() {
760
            @Override
761
            public void run() {
762
                if (element != currentElement) {
763
                    return;
764
                }
765
                if( element.hasMoreValues()) {
766
                    view.lblSimpleElementsMsg.setText("More elements...");
767
                } else {
768
                    view.lblSimpleElementsMsg.setText("");
769
                }
770
                view.lstSimpleElement.setEnabled(true);
771
                view.lstSimpleElement.setModel(model);
772
            }
773
        });
774

    
775
    }
776

    
777
    @Override
778
    public Expression getExpression() {
779
        Expression expression = this.getExpressionWithOutHistory();
780
        ExpressionEvaluatorManager theManager = ExpressionEvaluatorLocator.getManager();
781
        theManager.getHistory().add(expression);
782
        return expression;
783
    }
784
    
785
    @Override
786
    public Expression getExpressionWithOutHistory() {
787
        String phrase = this.view.getExpressionComponent().getText();
788
        if (StringUtils.isEmpty(phrase)) {
789
            return null;
790
        }
791
        Expression expression = ExpressionEvaluatorLocator.getManager().createExpression();
792
        expression.setPhrase(phrase);
793
//        Script script = ToolsLocator.getScriptManager().createScript("UserScript", "", "python");
794
//        this.scriptEditor.fetch(script);
795
//        if( !StringUtils.isEmpty(script.getCode()) ) {
796
//            expression.setUserScript(script);
797
//        }
798
        return expression;
799
    }
800

    
801
    @Override
802
    public void setExpression(Expression expression) {
803
        if( expression==null ) {
804
            this.view.getExpressionComponent().setText("");
805
        } else {
806
            this.view.getExpressionComponent().setText(expression.getPhrase());
807
        }
808
//            try { this.scriptEditor.set(null); } catch(Exception ex) {}
809
//            this.scriptPicker.set(null);
810
//        } else {
811
//            this.txtExpression.setText(expression.getPhrase());
812
//            if( expression.getUserScript()!=null ) {
813
//                this.scriptEditor.set(expression.getUserScript());
814
//            }
815
//            if( expression.getScripts()!=null ) {
816
//                this.scriptPicker.set(expression.getScripts().toList());
817
//            }
818
//        }
819
    }
820

    
821
    @Override
822
    public Preferences getPreferences() {
823
        return this.builderConfig.getPreferences();
824
    }
825
    
826
    @Override
827
    public List<Element> getElements() {
828
        return this.builderConfig.getElements();
829
    }
830
    
831
    @Override
832
    public void addElement(Element element) {
833
        this.builderConfig.addElement(element);
834
    }
835
    
836
    @Override
837
    public Collection<SymbolTable> getSymbolTables() {
838
        return this.builderConfig.getSymbolTables();
839
    }
840
    
841
    @Override
842
    public void addSymbolTable(String name) {
843
        this.builderConfig.addSymbolTable(name);
844
    }
845
    
846
    @Override
847
    public void addSymbolTable(SymbolTable symbolTable) {
848
        this.builderConfig.addSymbolTable(symbolTable);
849
    }
850

    
851
    @Override
852
    public void removeAllSymbolTables() {
853
        this.builderConfig.removeAllSymbolTables();
854
    }
855

    
856
    @Override
857
    public void removeSymbolTable(String name) {
858
        this.builderConfig.removeSymbolTable(name);
859
    }
860

    
861
    @Override
862
    public SymbolTable getPreviewSymbolTable() {
863
        return this.builderConfig.getPreviewSymbolTable();
864
    }
865

    
866
    @Override
867
    public void setPreviewSymbolTable(SymbolTable symbolTable) {
868
        this.builderConfig.setPreviewSymbolTable(symbolTable);
869
    }
870
    
871
    public void setAutomaticExpressionCheckerEnabled(boolean enabled) {
872
      if( this.automaticExpressionChecker==null ) {
873
        this.automaticExpressionCheckerEnabled = enabled;
874
      }
875
    }
876
    
877
    public boolean isAutomaticExpressionCheckerEnabled() {
878
      return this.automaticExpressionCheckerEnabled;
879
    }
880
    
881
    @Override
882
    public JComponent asJComponent() {
883
      if (this.automaticExpressionChecker == null && this.automaticExpressionCheckerEnabled ) {
884
        this.automaticExpressionChecker = new AbstractAutomaticExpressionChecker(
885
                builderConfig, this.view.getExpressionComponent()
886
        ) {
887
          @Override
888
          protected Expression getExpression() {
889
            return DefaultJExpressionBuilder.this.getExpressionWithOutHistory();
890
          }
891

    
892
          @Override
893
          protected void setMessage(int mode, String text) {
894
            super.setMessage(mode, text);
895
            message(text);
896
          }
897

    
898
          @Override
899
          protected void setPreview(Object value) {
900
            super.setPreview(value);
901
            message(this.getPreview());
902
          }
903

    
904
          @Override
905
          protected void setTip(String theTip) {
906
            super.setTip(theTip);
907
            view.btnTip.setToolTipText(toHTML(this.getTip()));
908
            view.btnTip.setVisible(this.isTipEnabled());
909
          }
910

    
911
          @Override
912
          protected String getSuggestion() {
913
            return builderConfig.getSuggestion(this.getExpression());
914
          }
915

    
916
        };
917

    
918
      }
919
      this.initializeTree();
920
      SwingUtilities.invokeLater(() -> {
921
        view.getExpressionComponent().requestFocusInWindow();
922
      });
923
      return this.view;
924
    }
925

    
926
    private void initializeTree() {
927
        if( this.treeModel == null ) {
928
            I18nManager i18n = ToolsLocator.getI18nManager();
929
            this.treeModel = new ElementsTreeModel( (GroupElement)
930
                    this.manager.createGroupElement(
931
                            i18n.getTranslation("_Elements"),
932
                            this.getElements()
933
                    ).setConfig(this));
934
            this.view.treeElements.setModel(this.treeModel);
935
            for (int i = 0; i < this.view.treeElements.getRowCount(); i++) {
936
                TreePath pathRow = this.view.treeElements.getPathForRow(i);
937
                Element element = (Element) pathRow.getLastPathComponent();
938
                if (i18n.getTranslation("_Functions").equals(element.getName())) {
939
                    this.view.treeElements.setSelectionPath(pathRow);
940
                    doSelectElement(element);
941
                    updateSimpleElementsList(element);
942
                    break;
943
                }
944
            }
945
        }
946
    }
947
    
948
    private void doSetTimeLimit() {
949
        ThreadSafeDialogsManager dialogs = ToolsSwingLocator.getThreadSafeDialogsManager();
950
        String s = dialogs.inputDialog(
951
                "Indicate the time limit in seconds for calculating the elements", 
952
                "Time limit", 
953
                JOptionPane.QUESTION_MESSAGE, 
954
                String.valueOf(this.builderConfig.getPreferences().getSimpleElementsLimit())
955
        );
956
        if( StringUtils.isBlank(s) ) {
957
            return;
958
        }
959
        try {
960
            int n = Integer.parseInt(s);
961
            this.builderConfig.getPreferences().setSimpleElementsLimit(n);
962
            this.treeModel.reload();
963
        } catch(Exception ex) {
964
            dialogs.messageDialog(
965
                "Invalid time limit '"+s+"'.", 
966
                "Time limit", 
967
                JOptionPane.WARNING_MESSAGE
968
            );                    
969
        }
970
    }
971

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

    
1006
    @Override
1007
    public void expandElement(Predicate<Element> condition) {
1008
        if( condition == null ) {
1009
          return;
1010
        }
1011
        this.initializeTree();
1012
        for (int i = 0; i < this.view.treeElements.getRowCount(); i++) {
1013
            TreePath path = this.view.treeElements.getPathForRow(i);
1014
            if( condition.test((Element) path.getLastPathComponent()) ) {
1015
                // FIXME: habria que expandir los padres hasta llegar a este.
1016
                this.view.treeElements.expandPath(path);
1017
                return;
1018
            }
1019
        }
1020
    }
1021

    
1022
    @Override
1023
    public Object getProperty(String name) {
1024
        return this.builderConfig.getProperty(name);
1025
    }
1026

    
1027
    @Override
1028
    public void setProperty(String name, Object value) {
1029
        this.builderConfig.setProperty(name, value);
1030
    }
1031

    
1032
    @Override
1033
    public Map<String, Object> getProperties() {
1034
        return this.builderConfig.getProperties();
1035
    }
1036

    
1037
    @Override
1038
    public boolean allowAggregates() {
1039
      return this.builderConfig.allowAggregates();
1040
    }
1041

    
1042
    @Override
1043
    public boolean allowAggregates(boolean allow) {
1044
      return this.builderConfig.allowAggregates(allow);
1045
    }
1046

    
1047
    @Override
1048
    public java.util.function.Function<String, Integer> isFunctionAllowed() {
1049
      return this.builderConfig.isFunctionAllowed();
1050
    }
1051

    
1052
    @Override
1053
    public void setAllowedFunctions(java.util.function.Function<String, Integer> allow) {
1054
      this.builderConfig.setAllowedFunctions(allow);
1055
    }
1056
    
1057
    @Override
1058
    public void addSuggestionFactory(Factory factory) {
1059
      this.builderConfig.addSuggestionFactory(factory);
1060
    }
1061

    
1062
    @Override
1063
    public String getSuggestion(Expression expression) {
1064
      return this.builderConfig.getSuggestion(expression);
1065
    }
1066

    
1067
    @Override
1068
    public void copyConfigFrom(ExpressionBuilderConfig other) {
1069
      this.builderConfig.copyConfigFrom(other);
1070
    }
1071
    
1072
    @Override
1073
    public Function<String, Integer> getAllowedFunctions() {
1074
      return this.builderConfig.getAllowedFunctions();
1075
    }
1076

    
1077
    @Override
1078
    public Collection<Factory> getSuggestionFactories() {
1079
      return this.builderConfig.getSuggestionFactories();
1080
    }
1081

    
1082
    @Override
1083
    public void removeAllElements() {
1084
      this.builderConfig.removeAllElements();
1085
    }
1086

    
1087
}