Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.swing / org.gvsig.fmap.dal.swing.impl / src / main / java / org / gvsig / fmap / dal / swing / impl / searchpanel / DefaultSearchPanel.java @ 44338

History | View | Annotate | Download (23.1 KB)

1
package org.gvsig.fmap.dal.swing.impl.searchpanel;
2

    
3
import java.awt.Cursor;
4
import java.awt.Dimension;
5
import java.awt.FlowLayout;
6
import java.awt.event.ActionEvent;
7
import java.awt.event.ActionListener;
8
import java.net.URL;
9
import java.util.ArrayList;
10
import java.util.Collection;
11
import java.util.HashMap;
12
import java.util.List;
13
import java.util.Map;
14
import javax.swing.Action;
15
import javax.swing.BorderFactory;
16
import javax.swing.ImageIcon;
17
import javax.swing.JButton;
18
import javax.swing.JComponent;
19
import javax.swing.SwingUtilities;
20
import javax.swing.event.ListSelectionEvent;
21
import javax.swing.event.ListSelectionListener;
22
import javax.swing.table.AbstractTableModel;
23
import javax.swing.table.TableModel;
24
import org.apache.commons.io.FilenameUtils;
25
import org.apache.commons.lang.mutable.MutableObject;
26
import org.gvsig.expressionevaluator.Code;
27
import org.gvsig.expressionevaluator.Expression;
28
import org.gvsig.expressionevaluator.ExpressionBuilder;
29
import static org.gvsig.expressionevaluator.ExpressionBuilder.OPERATOR_AND;
30
import static org.gvsig.expressionevaluator.ExpressionBuilder.OPERATOR_OR;
31
import org.gvsig.expressionevaluator.ExpressionUtils;
32
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingLocator;
33
import org.gvsig.expressionevaluator.swing.ExpressionEvaluatorSwingManager;
34
import org.gvsig.expressionevaluator.swing.ExpressionPickerController;
35
import org.gvsig.fmap.dal.DataStore;
36
import org.gvsig.fmap.dal.complements.Search;
37
import org.gvsig.fmap.dal.exception.DataException;
38
import org.gvsig.fmap.dal.feature.Feature;
39
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.dal.feature.FeatureType;
42
import org.gvsig.fmap.dal.swing.AbstractDALActionFactory.AbstractDALActionContext;
43
import org.gvsig.fmap.dal.swing.DALActionFactory;
44
import org.gvsig.fmap.dal.swing.DALSwingLocator;
45
import org.gvsig.fmap.dal.swing.searchpanel.FeatureStoreSearchPanel;
46
import org.gvsig.tools.ToolsLocator;
47
import org.gvsig.tools.swing.api.ActionListenerSupport;
48
import org.gvsig.tools.swing.api.ToolsSwingLocator;
49
import org.gvsig.tools.swing.icontheme.IconTheme;
50
import org.slf4j.Logger;
51
import org.slf4j.LoggerFactory;
52

    
53
/**
54
 *
55
 * @author jjdelcerro
56
 */
57
@SuppressWarnings("UseSpecificCatch")
58
public class DefaultSearchPanel
59
        extends DefaultSearchPanelView
60
        implements FeatureStoreSearchPanel {
61

    
62
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultSearchPanel.class);
63
    private Expression currentSearch;
64

    
65
    private class FeaturesTableModel extends AbstractTableModel {
66

    
67
        private final List<Feature> features;
68
        private final List<String> columnNames;
69
        private final FeatureType featureType;
70

    
71
        public FeaturesTableModel(FeatureType featureType) {
72
            this(featureType, null, null);
73
        }
74
        
75
        public FeaturesTableModel(FeatureType featureType, List<String> columnNames, List<Feature> features) {
76
            this.features = features;
77
            this.featureType = featureType;
78
            if (columnNames == null || columnNames.isEmpty()) {
79
                this.columnNames = new ArrayList<>();
80
                Search search = (Search) ToolsLocator.getComplementsManager().get(
81
                        Search.COMPLEMENT_MANE, featureType
82
                );
83
                List<Search.OrderedAttribute> attributos = search.getOrderedAttributes(
84
                        Search.BASIC_TYPES_FILTER,
85
                        Search.STR_INT_LONG_LABEL_ORDER,
86
                        12
87
                );
88
                for (Search.OrderedAttribute attrdesc : attributos) {
89
                    this.columnNames.add(attrdesc.getDescriptor().getName());
90
                }
91
            } else {
92
                this.columnNames = columnNames;
93
            }
94
        }
95

    
96
        public List<Feature> getFeatures() {
97
            return this.features;
98
        }
99

    
100
        @Override
101
        public int getRowCount() {
102
            if (this.features == null) {
103
                return 0;
104
            }
105
            return this.features.size();
106
        }
107

    
108
        @Override
109
        public int getColumnCount() {
110
            return this.columnNames.size();
111
        }
112

    
113
        @Override
114
        public String getColumnName(int columnIndex) {
115
            String attrName = this.columnNames.get(columnIndex);
116
            if (this.featureType == null) {
117
                return attrName;
118
            }
119
            FeatureAttributeDescriptor attrdesc = this.featureType.getAttributeDescriptor(attrName);
120
            if (attrdesc == null) {
121
                return "C" + columnIndex;
122
            }
123
            return attrdesc.getLocalizedShortLabel();
124
        }
125

    
126
        @Override
127
        public Class<?> getColumnClass(int columnIndex) {
128
            if (this.featureType == null) {
129
                return String.class;
130
            }
131
            String attrName = this.columnNames.get(columnIndex);
132
            FeatureAttributeDescriptor attrdesc = this.featureType.getAttributeDescriptor(attrName);
133
            if (attrdesc == null) {
134
                return String.class;
135
            }
136
            if( attrdesc.isForeingKey() && attrdesc.getForeingKey().isClosedList() ) {
137
                return String.class;
138
            }
139
            Class theClass = attrdesc.getDataType().getDefaultClass();
140
            if( theClass==null ) {
141
                return String.class;
142
            }
143
            return theClass;
144
        }
145

    
146
        @Override
147
        public boolean isCellEditable(int rowIndex, int columnIndex) {
148
            return false;
149
        }
150

    
151
        @Override
152
        public Object getValueAt(int rowIndex, int columnIndex) {
153
            if (this.features == null) {
154
                return null;
155
            }
156
            try {
157
                Feature feature = this.features.get(rowIndex);
158
                String attrName = this.columnNames.get(columnIndex);
159
                Object value = feature.get(attrName);
160
                FeatureAttributeDescriptor attrdesc = this.featureType.getAttributeDescriptor(attrName);
161
                if (attrdesc != null) {
162
                    if( attrdesc.isForeingKey() && attrdesc.getForeingKey().isClosedList() ) {
163
                        value = attrdesc.getForeingKey().getLabelForValue(value);
164
                    }
165
                }
166
                return value;
167
            } catch (Throwable th) {
168
                return null;
169
            }
170
        }
171

    
172
        @Override
173
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
174

    
175
        }
176
    }
177
    
178
    private class ActionButtons {
179
        
180
        private final DALActionFactory factory;
181
        private final Action action;
182
        private final JButton button;
183
        
184
        public ActionButtons(DALActionFactory factory, Action action, JButton button) {
185
            this.factory = factory;
186
            this.action = action;
187
            this.button = button;
188
        }
189
    }
190

    
191
    public static class SearchActionContext extends AbstractDALActionContext {
192

    
193
        private final DefaultSearchPanel panel;
194
        
195
        public SearchActionContext(DefaultSearchPanel panel) {
196
            super(FeatureStoreSearchPanel.ACTION_CONTEXT_NAME);
197
            this.panel = panel;
198
        }
199
        
200
        @Override
201
        public DataStore getStore() {
202
            return this.panel.getStore();
203
        }
204

    
205
        @Override
206
        public Expression getFilter() {
207
            return this.panel.getCurrentSearch();
208
        }
209

    
210
        @Override
211
        public JComponent getActionButton(String actionName) {
212
            return this.panel.getActionButton(actionName);
213
        }
214
        
215
        @Override
216
        public int getSelectedsCount() {
217
            return this.panel.getSelectedFeatureCount();
218
        }
219
        
220
        @Override
221
        public Expression getFilterForSelecteds() {
222
            return this.panel.getSearchForSelectedFeature();
223
        }
224
    }
225
    
226
    private final FeatureStore store;
227
    private final ActionListenerSupport acctionListeners;
228
    private List<SearchFieldController> searchFields;
229
    private ExpressionPickerController advancedExpression;
230
    private final Map<String, ActionButtons> actions;
231
    private boolean showActions = true;
232
    private int maxSearhFields = 4;
233

    
234
    public DefaultSearchPanel(FeatureStore store) {
235
        this.store = store;
236
        this.acctionListeners = ToolsSwingLocator.getToolsSwingManager().createActionListenerSupport();
237
        this.searchFields = null;
238
        this.actions = new HashMap<>();
239
    }
240

    
241
    @Override
242
    public JComponent asJComponent() {
243
        if( this.searchFields==null ) {
244
            this.initComponents();
245
        }
246
        return this;
247
    }
248

    
249
    private void addActions() {
250
        if( !this.showActions ) {
251
            return;
252
        }
253
        this.pnlActions.removeAll();
254
        this.pnlActions.setLayout(new FlowLayout(FlowLayout.TRAILING, 8, 4));
255
        SearchActionContext actionContext = new SearchActionContext(this);
256
        Collection<DALActionFactory> factories = DALSwingLocator.getSwingManager().getStoreActions();
257
        for (DALActionFactory factory : factories) {
258
            Action action = factory.createAction(actionContext);
259
            JButton button = new JButton(action);
260
            this.actions.put(factory.getName(), new ActionButtons(factory, action, button));
261
            button.setBorder(BorderFactory.createEmptyBorder());
262
            button.setBorderPainted(false);
263
            button.setFocusPainted(false);
264
            button.setContentAreaFilled(false);
265
            button.setCursor(new Cursor(Cursor.HAND_CURSOR));
266
            this.pnlActions.add(button);
267
        }
268
        this.pnlActions.revalidate();
269
        this.pnlActions.repaint();
270
    }
271

    
272
    @Override
273
    public void addActionListener(ActionListener listener) {
274
        this.acctionListeners.addActionListener(listener);
275
    }
276

    
277
    @Override
278
    public ActionListener[] getActionListeners() {
279
        return this.acctionListeners.getActionListeners();
280
    }
281

    
282
    @Override
283
    public void removeActionListener(ActionListener listener) {
284
        this.acctionListeners.removeActionListener(listener);
285
    }
286

    
287
    @Override
288
    public void removeAllActionListener() {
289
        this.acctionListeners.removeAllActionListener();
290
    }
291

    
292
    @Override
293
    public void fireActionEvent(ActionEvent event) {
294
        this.acctionListeners.fireActionEvent(event);
295
    }
296

    
297
    @Override
298
    public boolean hasActionListeners() {
299
        return this.acctionListeners.hasActionListeners();
300
    }
301

    
302
    private void initComponents() {
303
        this.searchFields = new ArrayList<>();
304
        SearchFieldController controller = new SearchFieldController(
305
                store,
306
                lblField1,
307
                lblExtraFields1,
308
                lblRelationalOperator1,
309
                cboValue1,
310
                lblLogicalOperators1
311
        );
312
        this.searchFields.add(controller);
313
        controller = new SearchFieldController(
314
                store,
315
                lblField2,
316
                lblExtraFields2,
317
                lblRelationalOperator2,
318
                cboValue2,
319
                lblLogicalOperators2
320
        );
321
        this.searchFields.add(controller);
322
        controller = new SearchFieldController(
323
                store,
324
                lblField3,
325
                lblExtraFields3,
326
                lblRelationalOperator3,
327
                cboValue3,
328
                lblLogicalOperators3
329
        );
330
        this.searchFields.add(controller);
331
        controller = new SearchFieldController(
332
                store,
333
                lblField4,
334
                lblExtraFields4,
335
                lblRelationalOperator4,
336
                cboValue4,
337
                null
338
        );
339
        this.searchFields.add(controller);
340
        try {
341
            Search search = (Search) ToolsLocator.getComplementsManager().get(
342
                    Search.COMPLEMENT_MANE, this.store.getDefaultFeatureType()
343
            );
344
            List<Search.OrderedAttribute> orderedAttributes = search.getOrderedAttributes(
345
                    Search.BASIC_TYPES_FILTER,
346
                    Search.STR_INT_LONG_LABEL_ORDER,
347
                    5
348
            );
349
            this.maxSearhFields = Integer.min(orderedAttributes.size(), 4);
350
            int n = 0;
351
            for (SearchFieldController searchField : searchFields) {
352
                if( n<this.maxSearhFields ) {
353
                    searchField.setAttribute(orderedAttributes.get(n++).getDescriptor().getName());
354
                } else {
355
                    searchField.setEnabled(false);
356
                }
357
            }
358
        } catch (DataException ex) {
359
            LOGGER.warn("Can't determine order of attributes", ex);
360
        }
361

    
362
        ExpressionEvaluatorSwingManager expressionSwingManager = ExpressionEvaluatorSwingLocator.getManager();
363
        this.advancedExpression = expressionSwingManager.createExpressionPickerController(
364
                txtAdvancedExpression, 
365
                btnAdvancedExpression,
366
                btnAdvancedExpressionHistory,
367
                btnAdvancedExpressionBookmarks
368
        );
369
        this.advancedExpression.addElement(
370
            DALSwingLocator.getSwingManager().createFeatureStoreElement(store)
371
        );
372

    
373
        this.btnSearch.addActionListener(new ActionListener() {
374
            @Override
375
            public void actionPerformed(ActionEvent e) {
376
                doSearch();
377
            }
378
        });
379

    
380
        this.tblResults.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
381
            @Override
382
            public void valueChanged(ListSelectionEvent e) {
383
                for (ActionButtons actionButton : actions.values()) {
384
                    if( actionButton.action instanceof ListSelectionListener) {
385
                        ((ListSelectionListener) actionButton.action).valueChanged(e);
386
                    }
387
                }
388
            }
389
        });
390
        this.btnClear.addActionListener(new ActionListener() {
391
            @Override
392
            public void actionPerformed(ActionEvent e) {
393
                clear();
394
            }
395
        });
396
        addActions();
397
        this.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
398

    
399
        doSearch(null);
400
    }
401

    
402
    @Override
403
    public void setEnabled(boolean enabled) {
404
        if( this.searchFields==null ) {
405
            initComponents();
406
        }
407
        int n=0;
408
        for (SearchFieldController searchField : searchFields) {
409
            if( n<this.maxSearhFields ) {
410
                searchField.setEnabled(enabled);
411
            } else {
412
                searchField.setEnabled(false);
413
            }
414
            n++;
415
        }
416
        this.btnClear.setEnabled(enabled);
417
        this.btnSearch.setEnabled(enabled);
418
        this.advancedExpression.setEnabled(enabled);
419
        for (ActionButtons actionButton : actions.values()) {
420
            actionButton.action.setEnabled(enabled);
421
        }
422
    }
423

    
424
    public void clear() {
425
        if( this.searchFields==null ) {
426
            return;
427
        }
428
        for (SearchFieldController searchField : searchFields) {
429
            searchField.clear();
430
        }
431
        this.advancedExpression.set(null);
432
    }
433

    
434
    @Override
435
    public Expression getFilter() {
436
        Expression filter;
437
        int searchMode = this.tabSearchMode.getSelectedIndex();
438
        if (searchMode == 1) { // Avanzada
439
            filter = this.advancedExpression.get();
440
        } else {
441
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
442
            String relational = OPERATOR_OR;
443
            for (SearchFieldController searchField : searchFields) {
444
                if (searchField.getAttribute() != null && searchField.getValue() != null) {
445
                    ExpressionBuilder.BinaryOperator cond = builder.binaryOperator(
446
                            searchField.getRelationalOperator(),
447
                            searchField.isAttributeAnExpression()
448
                            ? builder.custom(searchField.getAttribute())
449
                            : builder.column(searchField.getAttribute()),
450
                            builder.constant(searchField.getValue())
451
                    );
452
                    if (relational.equals(OPERATOR_AND)) {
453
                        builder.and(cond);
454
                    } else {
455
                        builder.or(cond);
456
                    }
457
                    relational = searchField.getLogicalOperator();
458
                }
459
            }
460
            if (builder.isEmpty()) {
461
                filter = null;
462
            } else {
463
                filter = ExpressionUtils.createExpression(builder.toString());
464
            }
465
        }
466
        if (ExpressionUtils.isPhraseEmpty(filter)) {
467
            return null;
468
        }
469
        return filter;
470
    }
471
    
472
    private void doSearch() {
473
        Expression filter = this.getFilter();
474
        doSearch(filter);
475
    }
476

    
477
    private void doSearch(final Expression exp) {
478
        final MutableObject model = new MutableObject(null);
479
        
480
        lblMsg.setText("Searching...");
481
        setEnabled(false);
482
        Thread th = new Thread(new Runnable() {
483
            @Override
484
            public void run() {
485
                try {
486
                    final List<Feature> features;
487
                    if (exp == null) {
488
                        features = store.getFeatures();
489
                    } else {
490
                        features = store.getFeatures(exp);
491
                    }
492
                    currentSearch = exp;
493
                    model.setValue( new FeaturesTableModel(
494
                            store.getDefaultFeatureType(),
495
                            null,
496
                            features
497
                        )
498
                    );
499
                } catch (DataException ex) {
500
                    LOGGER.warn("Can't get features or create table model",ex);
501
                } finally {
502
                    SwingUtilities.invokeLater(new Runnable() {
503
                        @Override
504
                        public void run() {
505
                            TableModel m = (TableModel) model.getValue();
506
                            tblResults.setModel(m);
507
                            lblMsg.setText(String.format("%d elementos", m.getRowCount()));
508
                            setEnabled(true);
509
                        }
510
                    });
511
                }
512
            }
513
        });
514
        th.start();
515
    }
516

    
517
    @Override
518
    public Expression getCurrentSearch() {
519
        return this.currentSearch;
520
    }
521

    
522
    @Override
523
    public boolean setFilter(Expression filter) {
524
        try {
525
            if( this.advancedExpression==null ) {
526
                this.initComponents();
527
            }
528
            if( ExpressionUtils.isPhraseEmpty(filter) ) {
529
                this.clear();
530
                return true;
531
            }
532
            this.advancedExpression.set(filter);
533
            this.tabSearchMode.setSelectedIndex(1);
534
            
535
            Code code = filter.getCode();
536
            if( code.code()==Code.CALLER) {
537
                SearchFieldController searchField = this.searchFields.get(0);
538
                Code.Caller caller = (Code.Caller)code;
539
                if( searchField.isAValidRelationOperator(caller.name())) {
540
                    Code op1 = caller.parameters().get(0);
541
                    Code op2 = caller.parameters().get(1);
542
                    if( op1.code()==Code.IDENTIFIER && op2.code()==Code.CONSTANT ) {
543
                        if( searchField.setAttribute(((Code.Identifier)op1).name())>=0 ) {
544
                            searchField.setRelationalOperator(caller.name());
545
                            searchField.setValue(((Code.Constant)op2).value());
546
                            this.tabSearchMode.setSelectedIndex(0);
547
                        }
548
                    }
549
                }
550
            }
551
            FeaturesTableModel model = new FeaturesTableModel(this.getStore().getDefaultFeatureType());
552
            tblResults.setModel(model);
553
            lblMsg.setText("");
554
            return true;
555
        } catch(Exception ex) {
556
            LOGGER.warn("Can't set current search", ex);
557
            return false;
558
        }
559
    }
560
   
561
    @Override
562
    public void setCurrentSearch(Expression filter) {
563
        if( this.setFilter(filter) ) {
564
            doSearch();
565
        }
566
    }
567
    
568
    @Override
569
    public Expression getSearchForSelectedFeature() {
570
        if( this.searchFields==null ) {
571
            return null;
572
        }
573
        int selectedRow = this.tblResults.getSelectedRow();
574
        if (selectedRow < 0) {
575
            return null;
576
        }
577
        try {
578
            List<Feature> features = ((FeaturesTableModel) this.tblResults.getModel()).getFeatures();
579
            Feature feature = features.get(selectedRow);
580
            
581
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
582
            FeatureType ftype = this.store.getDefaultFeatureType();
583
            for (FeatureAttributeDescriptor attrdesc : ftype.getPrimaryKey()) {
584
                builder.and(
585
                        builder.eq(
586
                                builder.column(attrdesc.getName()),
587
                                builder.constant(feature.get(attrdesc.getName()))
588
                        )
589
                );
590
            }
591
            Expression filter = ExpressionUtils.createExpression(builder.toString());
592
            return filter;
593
        } catch (Exception ex) {
594
            LOGGER.warn("Can't build search for the selected feature.", ex);
595
            return null;
596
        }
597
    }
598

    
599
    @Override
600
    public FeatureStore getStore() {
601
        return store;
602
    }
603
    
604
    @Override
605
    public ImageIcon loadImage(String imageName) {
606
        String name = FilenameUtils.getBaseName(imageName);
607
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getDefault();
608
        if (theme.exists(name)) {
609
            return theme.get(name);
610
        }
611
        URL url = this.getClass().getResource(name + ".png");
612
        if (url == null) {
613
            return null;
614
        }
615
        return new ImageIcon(url);
616
    }
617

    
618
    public static void selfRegister() {
619
        String[][] iconNames = new String[][]{
620
            new String[]{"dalswing", "featurestore-column"},
621
            new String[]{"dalswing", "featurestore-foreing-key"},
622
            new String[]{"dalswing", "featurestore-table"},
623
            new String[]{"dalswing", "search-action-showform"},
624
            new String[]{"dalswing", "search-action-select"},
625
            new String[]{"dalswing", "search-action-select-add"},
626
            new String[]{"dalswing", "search-action-select-filter"}
627
        };
628
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
629
        for (String[] icon : iconNames) {
630
            URL url = DefaultSearchPanel.class.getResource(icon[1] + ".png");
631
            theme.registerDefault("DALSwing", icon[0], icon[1], null, url);
632
        }
633

    
634
    }
635

    
636
    @Override
637
    public int getSelectedFeatureCount() {
638
        if( this.searchFields==null ) {
639
            return 0;
640
        }
641
        return this.tblResults.getSelectedRowCount();
642
    }
643
    
644
    @Override
645
    public JComponent getActionButton(String name) {
646
        ActionButtons actionButton = this.actions.get(name);
647
        if( actionButton==null ) {
648
            return null;
649
        }
650
        return actionButton.button;
651
    }
652

    
653
    @Override
654
    public void setShowActions(boolean showActions) {
655
        this.showActions = showActions;
656
    }
657
    
658
    @Override
659
    public boolean isShowActions() {
660
        return this.showActions;
661
    }
662
}