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

History | View | Annotate | Download (22.5 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<FeatureAttributeDescriptor> attributos = search.getOrderedAttributes(
84
                        Search.BASIC_TYPES_FILTER,
85
                        Search.STR_INT_LONG_LABEL_ORDER,
86
                        12
87
                );
88
                for (FeatureAttributeDescriptor attrdesc : attributos) {
89
                    this.columnNames.add(attrdesc.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.getLabel();
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
            Class theClass = attrdesc.getDataType().getDefaultClass();
137
            if( theClass==null ) {
138
                return String.class;
139
            }
140
            return theClass;
141
        }
142

    
143
        @Override
144
        public boolean isCellEditable(int rowIndex, int columnIndex) {
145
            return false;
146
        }
147

    
148
        @Override
149
        public Object getValueAt(int rowIndex, int columnIndex) {
150
            if (this.features == null) {
151
                return null;
152
            }
153
            Feature feature = this.features.get(rowIndex);
154
            String attrName = this.columnNames.get(columnIndex);
155
            try {
156
                return feature.get(attrName);
157
            } catch (Throwable th) {
158
                return null;
159
            }
160
        }
161

    
162
        @Override
163
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
164

    
165
        }
166
    }
167
    
168
    private class ActionButtons {
169
        
170
        private final DALActionFactory factory;
171
        private final Action action;
172
        private final JButton button;
173
        
174
        public ActionButtons(DALActionFactory factory, Action action, JButton button) {
175
            this.factory = factory;
176
            this.action = action;
177
            this.button = button;
178
        }
179
    }
180

    
181
    public static class SearchActionContext extends AbstractDALActionContext {
182

    
183
        private final DefaultSearchPanel panel;
184
        
185
        public SearchActionContext(DefaultSearchPanel panel) {
186
            super(FeatureStoreSearchPanel.ACTION_CONTEXT_NAME);
187
            this.panel = panel;
188
        }
189
        
190
        @Override
191
        public DataStore getStore() {
192
            return this.panel.getStore();
193
        }
194

    
195
        @Override
196
        public Expression getFilter() {
197
            return this.panel.getCurrentSearch();
198
        }
199

    
200
        @Override
201
        public JComponent getActionButton(String actionName) {
202
            return this.panel.getActionButton(actionName);
203
        }
204
        
205
        @Override
206
        public int getSelectedsCount() {
207
            return this.panel.getSelectedFeatureCount();
208
        }
209
        
210
        @Override
211
        public Expression getFilterForSelecteds() {
212
            return this.panel.getSearchForSelectedFeature();
213
        }
214
    }
215
    
216
    private final FeatureStore store;
217
    private final ActionListenerSupport acctionListeners;
218
    private List<SearchFieldController> searchFields;
219
    private ExpressionPickerController advancedExpression;
220
    private final Map<String, ActionButtons> actions;
221
    private boolean showActions = true;
222
    private int maxSearhFields = 4;
223

    
224
    public DefaultSearchPanel(FeatureStore store) {
225
        this.store = store;
226
        this.acctionListeners = ToolsSwingLocator.getToolsSwingManager().createActionListenerSupport();
227
        this.searchFields = null;
228
        this.actions = new HashMap<>();
229
    }
230

    
231
    @Override
232
    public JComponent asJComponent() {
233
        if( this.searchFields==null ) {
234
            this.initComponents();
235
        }
236
        return this;
237
    }
238

    
239
    private void addActions() {
240
        if( !this.showActions ) {
241
            return;
242
        }
243
        this.pnlActions.removeAll();
244
        this.pnlActions.setLayout(new FlowLayout(FlowLayout.TRAILING, 8, 4));
245
        SearchActionContext actionContext = new SearchActionContext(this);
246
        Collection<DALActionFactory> factories = DALSwingLocator.getSwingManager().getStoreActions();
247
        for (DALActionFactory factory : factories) {
248
            Action action = factory.createAction(actionContext);
249
            JButton button = new JButton(action);
250
            this.actions.put(factory.getName(), new ActionButtons(factory, action, button));
251
            button.setBorder(BorderFactory.createEmptyBorder());
252
            button.setBorderPainted(false);
253
            button.setFocusPainted(false);
254
            button.setContentAreaFilled(false);
255
            button.setCursor(new Cursor(Cursor.HAND_CURSOR));
256
            this.pnlActions.add(button);
257
        }
258
        this.pnlActions.revalidate();
259
        this.pnlActions.repaint();
260
    }
261

    
262
    @Override
263
    public void addActionListener(ActionListener listener) {
264
        this.acctionListeners.addActionListener(listener);
265
    }
266

    
267
    @Override
268
    public ActionListener[] getActionListeners() {
269
        return this.acctionListeners.getActionListeners();
270
    }
271

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

    
277
    @Override
278
    public void removeAllActionListener() {
279
        this.acctionListeners.removeAllActionListener();
280
    }
281

    
282
    @Override
283
    public void fireActionEvent(ActionEvent event) {
284
        this.acctionListeners.fireActionEvent(event);
285
    }
286

    
287
    @Override
288
    public boolean hasActionListeners() {
289
        return this.acctionListeners.hasActionListeners();
290
    }
291

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

    
352
        ExpressionEvaluatorSwingManager expressionSwingManager = ExpressionEvaluatorSwingLocator.getManager();
353
        this.advancedExpression = expressionSwingManager.createExpressionPickerController(
354
                txtAdvancedExpression, 
355
                btnAdvancedExpression,
356
                btnAdvancedExpressionHistory,
357
                btnAdvancedExpressionBookmarks
358
        );
359
        this.advancedExpression.addElement(
360
            DALSwingLocator.getSwingManager().createFeatureStoreElement(store)
361
        );
362

    
363
        this.btnSearch.addActionListener(new ActionListener() {
364
            @Override
365
            public void actionPerformed(ActionEvent e) {
366
                doSearch();
367
            }
368
        });
369

    
370
        this.tblResults.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
371
            @Override
372
            public void valueChanged(ListSelectionEvent e) {
373
                for (ActionButtons actionButton : actions.values()) {
374
                    if( actionButton.action instanceof ListSelectionListener) {
375
                        ((ListSelectionListener) actionButton.action).valueChanged(e);
376
                    }
377
                }
378
            }
379
        });
380
        this.btnClear.addActionListener(new ActionListener() {
381
            @Override
382
            public void actionPerformed(ActionEvent e) {
383
                clear();
384
            }
385
        });
386
        addActions();
387
        this.setPreferredSize(new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
388

    
389
        doSearch(null);
390
    }
391

    
392
    @Override
393
    public void setEnabled(boolean enabled) {
394
        if( this.searchFields==null ) {
395
            initComponents();
396
        }
397
        int n=0;
398
        for (SearchFieldController searchField : searchFields) {
399
            if( n<this.maxSearhFields ) {
400
                searchField.setEnabled(enabled);
401
            } else {
402
                searchField.setEnabled(false);
403
            }
404
            n++;
405
        }
406
        this.btnClear.setEnabled(enabled);
407
        this.btnSearch.setEnabled(enabled);
408
        this.advancedExpression.setEnabled(enabled);
409
        for (ActionButtons actionButton : actions.values()) {
410
            actionButton.action.setEnabled(enabled);
411
        }
412
    }
413

    
414
    public void clear() {
415
        if( this.searchFields==null ) {
416
            return;
417
        }
418
        for (SearchFieldController searchField : searchFields) {
419
            searchField.clear();
420
        }
421
        this.advancedExpression.set(null);
422
    }
423

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

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

    
507
    @Override
508
    public Expression getCurrentSearch() {
509
        return this.currentSearch;
510
    }
511

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

    
589
    @Override
590
    public FeatureStore getStore() {
591
        return store;
592
    }
593
    
594
    @Override
595
    public ImageIcon loadImage(String imageName) {
596
        String name = FilenameUtils.getBaseName(imageName);
597
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getDefault();
598
        if (theme.exists(name)) {
599
            return theme.get(name);
600
        }
601
        URL url = this.getClass().getResource(name + ".png");
602
        if (url == null) {
603
            return null;
604
        }
605
        return new ImageIcon(url);
606
    }
607

    
608
    public static void selfRegister() {
609
        String[][] iconNames = new String[][]{
610
            new String[]{"dalswing", "featurestore-column"},
611
            new String[]{"dalswing", "featurestore-foreing-key"},
612
            new String[]{"dalswing", "featurestore-table"},
613
            new String[]{"dalswing", "search-action-showform"},
614
            new String[]{"dalswing", "search-action-select"},
615
            new String[]{"dalswing", "search-action-select-add"},
616
            new String[]{"dalswing", "search-action-select-filter"}
617
        };
618
        IconTheme theme = ToolsSwingLocator.getIconThemeManager().getCurrent();
619
        for (String[] icon : iconNames) {
620
            URL url = DefaultSearchPanel.class.getResource(icon[1] + ".png");
621
            theme.registerDefault("DALSwing", icon[0], icon[1], null, url);
622
        }
623

    
624
    }
625

    
626
    @Override
627
    public int getSelectedFeatureCount() {
628
        if( this.searchFields==null ) {
629
            return 0;
630
        }
631
        return this.tblResults.getSelectedRowCount();
632
    }
633
    
634
    @Override
635
    public JComponent getActionButton(String name) {
636
        ActionButtons actionButton = this.actions.get(name);
637
        if( actionButton==null ) {
638
            return null;
639
        }
640
        return actionButton.button;
641
    }
642

    
643
    @Override
644
    public void setShowActions(boolean showActions) {
645
        this.showActions = showActions;
646
    }
647
    
648
    @Override
649
    public boolean isShowActions() {
650
        return this.showActions;
651
    }
652
}