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

History | View | Annotate | Download (22.4 KB)

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

    
3
import java.awt.BorderLayout;
4
import java.awt.Component;
5
import java.awt.Dimension;
6
import java.awt.event.ActionEvent;
7
import java.awt.event.ActionListener;
8
import java.awt.event.KeyEvent;
9
import java.awt.event.KeyListener;
10
import java.net.URL;
11
import java.util.ArrayList;
12
import java.util.Collection;
13
import java.util.Date;
14
import java.util.List;
15
import java.util.Objects;
16
import javax.swing.DefaultListCellRenderer;
17
import javax.swing.ImageIcon;
18
import javax.swing.JComponent;
19
import javax.swing.JLabel;
20
import javax.swing.JList;
21
import javax.swing.JTree;
22
import javax.swing.SwingUtilities;
23
import javax.swing.event.ListSelectionEvent;
24
import javax.swing.event.ListSelectionListener;
25
import javax.swing.event.TreeModelListener;
26
import javax.swing.event.TreeSelectionEvent;
27
import javax.swing.event.TreeSelectionListener;
28
import javax.swing.tree.DefaultTreeCellRenderer;
29
import javax.swing.tree.TreeModel;
30
import javax.swing.tree.TreePath;
31
import org.apache.commons.io.FilenameUtils;
32
import org.apache.commons.lang3.StringUtils;
33
import org.apache.commons.lang.StringEscapeUtils;
34
import org.gvsig.expressionevaluator.Expression;
35
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
36
import org.gvsig.expressionevaluator.Function;
37
import org.gvsig.expressionevaluator.SymbolTable;
38
import org.gvsig.expressionevaluator.swing.Element;
39
import org.gvsig.expressionevaluator.swing.Element.ConstantElement;
40
import org.gvsig.expressionevaluator.swing.Element.FunctionElement;
41
import org.gvsig.expressionevaluator.swing.Element.GroupElement;
42
import org.gvsig.expressionevaluator.swing.Element.SimpleElement;
43
import org.gvsig.expressionevaluator.swing.Element.VariableElement;
44
import org.gvsig.expressionevaluator.swing.ExpressionBuilderConfig;
45
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
46
import org.gvsig.expressionevaluator.swing.JExpressionBuilder;
47
import org.gvsig.tools.ToolsLocator;
48
import org.gvsig.tools.script.Script;
49
import org.gvsig.tools.swing.api.ListElement;
50
import org.gvsig.tools.swing.api.ToolsSwingLocator;
51
import org.gvsig.tools.swing.api.ToolsSwingManager;
52
import org.gvsig.tools.swing.api.pickercontroller.PickerController;
53
import org.gvsig.tools.swing.api.script.ScriptSwingManager;
54
import org.gvsig.tools.swing.icontheme.IconTheme;
55

    
56
/**
57
 *
58
 * @author jjdelcerro
59
 */
60
public class DefaultJExpressionBuilder
61
        extends DefaultJExpressionBuilderView
62
        implements JExpressionBuilder {
63

    
64
    private final ExpressionEvaluatorSwingManager manager;
65
    private GroupElement currentGroup;
66
    private PickerController<List<Script>> scriptPicker;
67
    private ScriptSwingManager.ScriptEditor scriptEditor;
68
    
69
    private final ExpressionBuilderConfig config;
70
    
71
    private class ElementsTreeModel implements TreeModel {
72

    
73
        private final GroupElement root;
74

    
75
        public ElementsTreeModel(GroupElement root) {
76
            this.root = root;
77
        }
78

    
79
        @Override
80
        public Object getRoot() {
81
            return this.root;
82
        }
83

    
84
        private List<Element> getChilds(final GroupElement node) {
85
            List<Element> x = new ArrayList<>();
86
            for (Element element : node.getElements()) {
87
                if (element instanceof GroupElement) {
88
                    x.add(element);
89
                }
90
            }
91
            return x; //node.getElements();
92
        }
93

    
94
        @Override
95
        public Object getChild(Object parent, int index) {
96
            List<Element> childs = getChilds((GroupElement) parent);
97
            Element child = childs.get(index);
98
            return child;
99
        }
100

    
101
        @Override
102
        public int getChildCount(Object parent) {
103
            List<Element> childs = getChilds((GroupElement) parent);
104
            return childs.size();
105
        }
106

    
107
        @Override
108
        public boolean isLeaf(Object node) {
109
            if( node instanceof GroupElement ) {
110
                return !((GroupElement) node).hasSubgroups();
111
            }
112
            return false;
113
        }
114

    
115
        @Override
116
        public void valueForPathChanged(TreePath path, Object newValue) {
117
        }
118

    
119
        @Override
120
        public int getIndexOfChild(Object parent, Object child) {
121
            List<Element> childs = getChilds((GroupElement) parent);
122
            int n = childs.indexOf(child);
123
            return n;
124
        }
125

    
126
        @Override
127
        public void addTreeModelListener(TreeModelListener l) {
128
        }
129

    
130
        @Override
131
        public void removeTreeModelListener(TreeModelListener l) {
132
        }
133

    
134
    }
135

    
136
    public DefaultJExpressionBuilder(ExpressionEvaluatorSwingManager manager, ExpressionBuilderConfig config) {
137
        this.manager = manager;
138
        this.config = new DefaultExpressionBuilderConfig(manager);
139
        this.initComponents();
140
    }
141
    
142
    @Override
143
    public ImageIcon loadImage(String imageName) {
144
        String name = FilenameUtils.getBaseName(imageName);
145
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getDefault();
146
        if (theme.exists(name)) {
147
            return theme.get(name);
148
        }
149
        URL url = this.getClass().getResource(name + ".png");
150
        if (url == null) {
151
            return null;
152
        }
153
        return new ImageIcon(url);
154
    }
155

    
156
    private void initComponents() {
157
        ToolsSwingManager toolsSwingManager = ToolsSwingLocator.getToolsSwingManager();
158
        final IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
159
        
160
        toolsSwingManager.setDefaultPopupMenu(this.txtExpression);
161
        toolsSwingManager.setDefaultPopupMenu(this.txtGroupElement);
162
        toolsSwingManager.setDefaultPopupMenu(this.txtSimpleElementFilter);
163
        toolsSwingManager.setDefaultPopupMenu(this.txtDescription);
164
        toolsSwingManager.addClearButton(this.txtExpression);
165
        toolsSwingManager.addClearButton(this.txtSimpleElementFilter, new ActionListener() {
166
            @Override
167
            public void actionPerformed(ActionEvent e) {
168
                txtSimpleElementFilter.setText("");
169
                doFilter();
170
            }
171
        });
172
        
173
        this.treeElements.setCellRenderer(new DefaultTreeCellRenderer() {
174
            @Override
175
            public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
176
                JLabel label = (JLabel) super.getTreeCellRendererComponent(tree,value, selected, expanded, leaf, row, hasFocus);
177
                if( value instanceof Element ) {
178
                    Element element = (Element) value;
179
                    label.setIcon(element.getIcon());
180
                    label.setText(element.getName());
181
                } else {
182
                    label.setIcon(null);
183
                    label.setText(Objects.toString(value, ""));
184
                }
185
                return label;
186
            }
187
        });
188
        
189
        this.treeElements.addTreeSelectionListener(new TreeSelectionListener() {
190
            @Override
191
            public void valueChanged(TreeSelectionEvent e) {
192
                TreePath path = e.getPath();
193
                Element element = (Element) path.getLastPathComponent();
194
                if (element instanceof GroupElement) {
195
                    updateSimpleElementsList((GroupElement) element);
196
                }
197
            }
198
        });
199
        this.btnGroupElementInsert.addActionListener(new ActionListener() {
200
            @Override
201
            public void actionPerformed(ActionEvent e) {
202
                doInsert(txtGroupElement.getText());
203
            }
204
        });
205
        this.btnSimpleElementInsert.addActionListener(new ActionListener() {
206
            @Override
207
            public void actionPerformed(ActionEvent e) {
208
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
209
                if (element != null) {
210
                    doInsert(element.getValue());
211
                }
212
            }
213
        });
214
        this.btnSimpleElementFilter.addActionListener(new ActionListener() {
215
            @Override
216
            public void actionPerformed(ActionEvent e) {
217
                doFilter();
218
            }
219
        });
220
        this.lstSimpleElement.setCellRenderer(new DefaultListCellRenderer() {
221
            @Override
222
            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
223
                JLabel label = (JLabel)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
224
                Element element = null;
225
                if( value instanceof ListElement ) {
226
                    if( ((ListElement) value).getValue() instanceof Element ) {
227
                        element = (Element) ((ListElement) value).getValue();
228
                    }
229
                }
230
                if( element !=null ) {
231
                    label.setIcon(element.getIcon());
232
                    label.setText(element.getName());
233
                } else {
234
                    label.setIcon(null);
235
                    label.setText(Objects.toString(value, ""));
236
                }
237
                return label;
238
            }
239
        });
240
        this.lstSimpleElement.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
241
            @Override
242
            public void valueChanged(ListSelectionEvent e) {
243
                ListElement<SimpleElement> element = (ListElement<SimpleElement>) lstSimpleElement.getSelectedValue();
244
                if (element != null) {
245
                    doSelectElement(element.getValue());
246
                }
247
            }
248
        });
249
        this.btnSimpleElementSortDown.addActionListener(new ActionListener() {
250
            @Override
251
            public void actionPerformed(ActionEvent e) {
252
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
253
                model.sort(false);
254
            }
255
        });
256
        this.btnSimpleElementSortUp.addActionListener(new ActionListener() {
257
            @Override
258
            public void actionPerformed(ActionEvent e) {
259
                FilteredListModel model = (FilteredListModel) lstSimpleElement.getModel();
260
                model.sort(true);
261
            }
262
        });
263
        this.txtSimpleElementFilter.addKeyListener(new KeyListener() {
264
            @Override
265
            public void keyTyped(KeyEvent e) {
266
                if (e.getKeyChar() == '\n') {
267
                    doFilter();
268
                }
269
            }
270

    
271
            @Override
272
            public void keyPressed(KeyEvent e) {
273
            }
274

    
275
            @Override
276
            public void keyReleased(KeyEvent e) {
277
            }
278
        });
279
        this.btnAdd.addActionListener(new ActionListener() {
280
            @Override
281
            public void actionPerformed(ActionEvent e) {
282
                doInsert(" + ");
283
            }
284
        });
285
        this.btnDiv.addActionListener(new ActionListener() {
286
            @Override
287
            public void actionPerformed(ActionEvent e) {
288
                doInsert(" / ");
289
            }
290
        });
291
        this.btnEq.addActionListener(new ActionListener() {
292
            @Override
293
            public void actionPerformed(ActionEvent e) {
294
                doInsert(" = ");
295
            }
296
        });
297
        this.btnMult.addActionListener(new ActionListener() {
298
            @Override
299
            public void actionPerformed(ActionEvent e) {
300
                doInsert(" * ");
301
            }
302
        });
303
        this.btnNeq.addActionListener(new ActionListener() {
304
            @Override
305
            public void actionPerformed(ActionEvent e) {
306
                doInsert(" <> ");
307
            }
308
        });
309
        this.btnParentClose.addActionListener(new ActionListener() {
310
            @Override
311
            public void actionPerformed(ActionEvent e) {
312
                doInsert(" ) ");
313
            }
314
        });
315
        this.btnParentOpen.addActionListener(new ActionListener() {
316
            @Override
317
            public void actionPerformed(ActionEvent e) {
318
                doInsert(" ( ");
319
            }
320
        });
321
        this.btnSubst.addActionListener(new ActionListener() {
322
            @Override
323
            public void actionPerformed(ActionEvent e) {
324
                doInsert(" - ");
325
            }
326
        });
327
        ScriptSwingManager scriptSwingManager = ToolsSwingLocator.getScriptSwingManager();
328
        this.scriptPicker = scriptSwingManager.createListScriptPickerController(
329
                cboPickerScripts,
330
                btnPickerRemove,
331
                btnPickerSelectScript
332
        );
333
        this.scriptEditor = scriptSwingManager.createScriptEditor();
334
        this.pnlScriptEditorContainer.setLayout(new BorderLayout());
335
        this.pnlScriptEditorContainer.add(this.scriptEditor.asJComponent(), BorderLayout.CENTER);
336
    
337
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
338
        this.setPreferredSize(new Dimension(750, 500));
339
    }
340

    
341
    private String removeCursorMark(String s) {
342
        s = s.replace("{{", "");
343
        s = s.replace("}}", "");
344
        return s;
345
    }
346

    
347
    private void doInsert(String s) {
348
        this.txtExpression.replaceSelection(s);
349
        String ss = this.txtExpression.getText();
350
        int start = ss.indexOf("{{");
351
        int end = ss.indexOf("}}");
352
        if (start > 0 && end > 0) {
353
            this.txtExpression.replaceRange("", end, end + 2);
354
            this.txtExpression.replaceRange("", start, start + 2);
355
            this.txtExpression.setSelectionStart(start);
356
            this.txtExpression.setSelectionEnd(end - 2);
357
        }
358
        this.txtExpression.requestFocusInWindow();
359
    }
360

    
361
    private void doInsert(SimpleElement element) {
362
        if( element instanceof FunctionElement ) {
363
            Function function = ((FunctionElement)element).getFunction();
364
            if (function == null) {
365
                doInsert(element.getName());
366
            } else {
367
                doInsert(function.template() == null ? function.name() + "({{}})" : function.template());
368
            }
369
        } else if( element instanceof ConstantElement) {
370
            doInsert(" "+repr(((ConstantElement) element).getValue())+" ");
371
        } else {
372
            doInsert(" "+element.getName()+" ");
373
        }
374
    }
375

    
376
    private void doFilter() {
377
        FilteredListModel model = (FilteredListModel) this.lstSimpleElement.getModel();
378
        model.setFilter(this.txtSimpleElementFilter.getText());
379
    }
380

    
381
    private void doSelectElement(SimpleElement element) {
382
        StringBuilder html = new StringBuilder();
383
        html.append("<html>\n");
384
        if( element instanceof ConstantElement ) {
385
            Object value = ((ConstantElement)element).getValue();
386
            if( value == null ) {
387
                html.append("<b>Constant</b><br>\n<br>\n");
388
                html.append("<b>Value</b> NULL<br>\n");
389
            } else {
390
                html.append("<b>Constant</b><br>\n<br>\n");
391
                html.append("<b>Value</b> ").append(repr(value)).append("<br>\n<br>\n");
392
                html.append("<b>Type</b> ").append(value.getClass().getSimpleName()).append("<br>\n<br>\n");
393
            }
394
            
395
        } else if( element instanceof VariableElement ) {
396
                VariableElement var = (VariableElement)element;
397
                html.append("<b>").append(var.getLabel()).append("</b><br>\n<br>\n\n");
398
                html.append("<b>Source</b> ").append(var.getSource()).append("<br>\n<br>\n");
399
                html.append("<b>Name</b> ").append(var.getName()).append("<br>\n<br>\n");
400
                html.append("<b>Type</b> ").append(var.getTypeName()).append("<br>\n<br>\n");
401
            
402
        } else if( element instanceof FunctionElement ) {
403
            Function function = ((FunctionElement)element).getFunction();
404
            if (function == null) {
405
                html.append("<b>Function</b> ").append(element.getName()).append("<br>\n<br>\n");
406
                html.append("<b>Return</b> Object<br>\n<br>\n");
407
                html.append("<b>Template:</b> ").append(element.getName()).append("()<br>\n<br>\n");
408
            } else {
409
                html.append("<b>Function</b> ").append(element.getName()).append("<br>\n<br>\n");
410
                html.append("<b>Return</b> ");
411
                html.append(StringUtils.isEmpty(function.returnType())?"Objec": function.returnType());
412
                html.append("<br>\n<br>\n");
413
                html.append("<b>Template</b> ");
414
                html.append(StringUtils.isEmpty(function.template())?element.getName()+"()": removeCursorMark(function.template()));
415
                html.append("<br>\n<br>\n");
416

    
417
                String[] args = function.descriptionArgs();
418
                if (args != null) {
419
                    html.append("<b>Arguments:</b> ").append("<ul>\n");
420
                    for (String arg : args) {
421
                        html.append("<li>").append(arg).append("</li>\n");
422
                    }
423
                    html.append("</ul>\n");
424
                    html.append("<br>\n");
425
                }
426
            }
427
        } else {
428
            html.append("<b>Generic element<br>\n<br>\n");
429
            html.append("<b>Name</b> ").append(element.getName()).append("</br>\n</br>\n");
430
            
431
        }
432

    
433
        if( element.getDescription()!=null ) {
434
            html.append("<b>Description</b><br>\n");
435
            html.append(element.getDescription().replace("\n", "<br>")).append("<br>\n");
436
        }
437
        html.append("</html>\n");
438
        this.txtDescription.setContentType("text/html");
439
        this.txtDescription.setText(html.toString());
440
        this.txtDescription.setCaretPosition(0);
441
    }
442

    
443
    private void updateSimpleElementsList(GroupElement group) {
444
        FilteredListModel model = new FilteredListModel();
445
        model.addElement("Loading...");
446
        this.currentGroup = group;
447
        this.txtGroupElement.setText(group.getName());
448
        this.txtSimpleElementFilter.setText("");
449
        this.txtDescription.setText("");
450
        if (group instanceof SimpleElement) {
451
            this.btnGroupElementInsert.setEnabled(true);
452
        } else {
453
            this.btnGroupElementInsert.setEnabled(false);
454
        }
455
        this.lstSimpleElement.setEnabled(false);
456
        this.lstSimpleElement.setModel(model);
457

    
458
        Thread th = new Thread(new Runnable() {
459
            @Override
460
            public void run() {
461
                simpleElementsUpdater();
462
            }
463
        }, "ExpressionBuilderSimpleElementsUpdater");
464
        th.start();
465
    }
466

    
467
    private void simpleElementsUpdater() {
468
        final GroupElement group = this.currentGroup;
469
        final FilteredListModel model = new FilteredListModel();
470
        for (Element child : group) {
471
            if (group != this.currentGroup) {
472
                return;
473
            }
474
            if (child instanceof SimpleElement) {
475
                String label = child.getName();
476
                Function function = child instanceof FunctionElement?  ((FunctionElement)child).getFunction(): null;
477
                if (function != null && !StringUtils.isEmpty(function.returnType())) {
478
                    label = "<html><b>" + label + "</b> return " + function.returnType() + "</html>";
479
//                    label = label + " return " + function.returnType();
480
                }
481
                model.addElement(new ListElement<>(label, child));
482
            }
483
        }
484
        model.sort(true);
485
        SwingUtilities.invokeLater(new Runnable() {
486
            @Override
487
            public void run() {
488
                if (group != currentGroup) {
489
                    return;
490
                }
491
                if( group.hasMoreElements() ) {
492
                    lblSimpleElementsMsg.setText("More elements...");
493
                } else {
494
                    lblSimpleElementsMsg.setText("");
495
                }
496
                lstSimpleElement.setEnabled(true);
497
                lstSimpleElement.setModel(model);
498
            }
499
        });
500

    
501
    }
502

    
503
    @Override
504
    public Expression getExpression() {
505
        String phrase = this.txtExpression.getText();
506
        if (StringUtils.isEmpty(phrase)) {
507
            return null;
508
        }
509
        Expression expression = ExpressionEvaluatorLocator.getManager().createExpression();
510
        expression.setPhrase(phrase);
511
        Script script = ToolsLocator.getScriptManager().createScript("UserScript", "", "python");
512
        this.scriptEditor.fetch(script);
513
        if( !StringUtils.isEmpty(script.getCode()) ) {
514
            expression.setUserScript(script);
515
        }
516
        return expression;
517
    }
518

    
519
    @Override
520
    public void setExpression(Expression expression) {
521
        this.txtExpression.setText(expression.getPhrase());
522
        if( expression.getUserScript()!=null ) {
523
            this.scriptEditor.set(expression.getUserScript());
524
        }
525
        if( expression.getScripts()!=null ) {
526
            this.scriptPicker.set(expression.getScripts().toList());
527
        }
528
    }
529
    
530
    @Override
531
    public int getSimpleElementsLimit() {
532
        return this.config.getSimpleElementsLimit();
533
    }
534

    
535
    @Override
536
    public void setSimpleElementsLimit(int limit) {
537
        this.config.setSimpleElementsLimit(limit);
538
    }
539
    
540
    @Override
541
    public List<Element> getElements() {
542
        return this.config.getElements();
543
    }
544

    
545
    @Override
546
    public Collection<SymbolTable> getSymbolTables() {
547
        return this.config.getSymbolTables();
548
    }
549
    
550
    @Override
551
    public void addSymbolTable(SymbolTable symbolTable) {
552
        this.config.addSymbolTable(symbolTable);
553
    }
554

    
555
    @Override
556
    public void removeAllSymbolTables() {
557
        this.config.removeAllSymbolTables();
558
    }
559

    
560
    @Override
561
    public void removeSymbolTable(String name) {
562
        this.config.removeSymbolTable(name);
563
    }
564

    
565
    @Override
566
    public void setScriptsEnabled(boolean enabled) {
567
        this.config.setScriptsEnabled(enabled);
568
        this.tabExpressionBuilder.setEnabledAt(0, this.config.getScriptsEnabled());
569
    }
570

    
571
    @Override
572
    public boolean getScriptsEnabled() {
573
        return this.config.getScriptsEnabled();
574
    }
575
    
576
    @Override
577
    public JComponent asJComponent() {
578
        TreeModel model = new ElementsTreeModel(
579
                this.manager.createGroupElement("Elements", this.getElements())
580
        );
581
        this.treeElements.setModel(model);
582
        return this;
583
    }
584

    
585
    private String repr(Object value)  {
586
        if (value == null) {
587
            return "NULL";
588
        } else if (value instanceof Date) {
589
            return "DATE('" + value + "')";
590
        } else if (value instanceof Boolean) {
591
            return value.toString();
592
        } else if (value instanceof String) {
593
            return "'" + StringEscapeUtils.escapeSql((String) value) + "'";
594
        } else {
595
            return StringEscapeUtils.escapeSql(value.toString());
596
        }
597
        
598
    }
599
    
600
}