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 / featuretable / table / DefaultFeatureTableModel.java @ 44435

History | View | Annotate | Download (32.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24

    
25
package org.gvsig.fmap.dal.swing.impl.featuretable.table;
26

    
27
import java.awt.event.ActionEvent;
28
import java.awt.event.ActionListener;
29
import java.security.InvalidParameterException;
30
import java.text.SimpleDateFormat;
31
import java.util.ArrayList;
32
import java.util.HashMap;
33
import java.util.HashSet;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.Locale;
37
import java.util.Map;
38
import java.util.Set;
39

    
40
import javax.swing.SwingUtilities;
41
import javax.swing.Timer;
42
import javax.swing.event.ChangeEvent;
43
import javax.swing.event.ChangeListener;
44
import javax.swing.event.TableModelEvent;
45
import javax.swing.table.AbstractTableModel;
46

    
47
import org.slf4j.Logger;
48
import org.slf4j.LoggerFactory;
49

    
50
import org.gvsig.fmap.dal.DataTypes;
51
import org.gvsig.fmap.dal.exception.DataException;
52
import org.gvsig.fmap.dal.feature.EditableFeature;
53
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.Feature;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
56
import org.gvsig.fmap.dal.feature.FeatureQuery;
57
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
58
import org.gvsig.fmap.dal.feature.FeatureSelection;
59
import org.gvsig.fmap.dal.feature.FeatureStore;
60
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
61
import org.gvsig.fmap.dal.feature.FeatureType;
62
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
63
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
64
import org.gvsig.fmap.dal.swing.impl.featuretable.table.renders.GetFeatureAtException;
65
import org.gvsig.tools.exception.BaseException;
66
import org.gvsig.tools.observer.ComplexNotification;
67
import org.gvsig.tools.observer.ComplexObserver;
68
import org.gvsig.tools.observer.Observable;
69

    
70
public class DefaultFeatureTableModel extends AbstractTableModel implements org.gvsig.fmap.dal.swing.FeatureTableModel,  ComplexObserver  {
71

    
72
    private static final long serialVersionUID = -8223987814719746492L;
73

    
74
    private static final Logger logger = LoggerFactory.getLogger(DefaultFeatureTableModel.class);
75

    
76
    private List<String> columnNames;
77

    
78
    private List<String> visibleColumnNames;
79

    
80
    private List<String> visibleColumnNamesOriginal;
81

    
82
    private Map<String, String> name2Alias;
83

    
84
    private Map<String, String> name2AliasOriginal;
85

    
86
    private Map<String,String> patterns = null;
87

    
88
    private Locale localeOfData;
89

    
90
    private final FeaturePagingHelper featurePager;
91

    
92
    /** Used to know if a modification in the FeatureStore is created by us. */
93
    private EditableFeature editableFeature;
94

    
95
    private boolean selectionLocked=false;
96

    
97
    private final DelayAction delayAction = new DelayAction();
98

    
99
    private FeatureSelection selection = null;
100

    
101
    private Set<ActionListener> changeListeners = null;
102
    
103
    public DefaultFeatureTableModel(FeaturePagingHelper featurePager) {
104
        this.featurePager = featurePager;
105
        this.localeOfData = Locale.getDefault();
106
        this.initialize();
107
    }
108

    
109
    private void initialize() {
110
        this.getFeatureStore().addObserver(this);
111

    
112
        int columns = this.getOriginalColumnCount();
113

    
114
        // Initilize visible columns
115
        columnNames = new ArrayList<>(columns);
116
        visibleColumnNames = new ArrayList<>(columns);
117
        for (int i = 0; i < columns; i++) {
118
            FeatureAttributeDescriptor descriptor = this.getInternalColumnDescriptor(i);
119
            String columnName = descriptor.getName();
120
            columnNames.add(columnName);
121

    
122
            // By default, geometry columns will not be visible
123
            if (descriptor.getType() != DataTypes.GEOMETRY) {
124
                visibleColumnNames.add(columnName);
125
            }
126
        }
127
        visibleColumnNamesOriginal = new ArrayList<>(visibleColumnNames);
128

    
129
        // Initialize alias
130
        name2Alias = new HashMap<>(columns);
131
        name2AliasOriginal = new HashMap<>(columns);
132

    
133
        initializeFormatingPatterns();
134
        updatePagerWithHiddenColums();
135
    }
136

    
137
    private void initializeFormatingPatterns() {
138
        int columns = this.getOriginalColumnCount();
139

    
140
        this.patterns = new HashMap<>();
141
        for (int i = 0; i < columns; i++) {
142
            FeatureAttributeDescriptor descriptor = this.getInternalColumnDescriptor(i);
143
            String columnName = descriptor.getName();
144
            switch(descriptor.getDataType().getType()) {
145
            case DataTypes.BYTE:
146
            case DataTypes.INT:
147
            case DataTypes.LONG:
148
                String defaultIntegerPattern = "#,##0";
149
                this.patterns.put(columnName,defaultIntegerPattern);
150
                break;
151
            case DataTypes.DOUBLE:
152
                String defaultDoublePattern = "#,##0.0000000000";
153
                this.patterns.put(columnName,defaultDoublePattern);
154
                break;
155
            case DataTypes.FLOAT:
156
                String defaultFloatPattern = "#,##0.0000";
157
                this.patterns.put(columnName,defaultFloatPattern);
158
                break;
159
            case DataTypes.DATE:
160
                String defaultDatePattern = new SimpleDateFormat().toPattern();
161
                this.patterns.put(columnName,defaultDatePattern);
162
                break;
163
            default:
164
                this.patterns.put(columnName,null);
165
            }
166
        }
167

    
168
    }
169

    
170
    private void updatePagerWithHiddenColums() {
171
            return;
172
            
173
//        FeatureQuery query = this.getFeaturePager().getFeatureQuery();
174
//        if (this.getFeaturePager().getFeatureStore().isEditing()) {
175
//            if (query.hasConstantsAttributeNames()) {
176
//                query.clearConstantsAttributeNames();
177
//            }
178
//        } else {
179
//            query.setConstantsAttributeNames(this.getHiddenColumnNames());
180
//        }
181
//        try {
182
//            this.getFeaturePager().reload();
183
//        } catch (BaseException ex) {
184
//            logger.warn("Can't reload paging-helper.", ex);
185
//        }
186
    }
187

    
188
    @Override
189
    public FeaturePagingHelper getFeaturePager() {
190
        return this.featurePager;
191
    }
192

    
193
    @Override
194
    public FeatureQuery getFeatureQuery() {
195
        return this.getFeaturePager().getFeatureQuery();
196
    }
197

    
198
    @Override
199
    public FeatureType getFeatureType() {
200
        return this.getFeaturePager().getFeatureType();
201
    }
202

    
203
    @Override
204
    public FeatureStore getFeatureStore() {
205
        return this.getFeaturePager().getFeatureStore();
206
    }
207

    
208
    @Override
209
    public int getColumnCount() {
210
        return visibleColumnNames.size();
211
    }
212

    
213
    public int getOriginalColumnCount() {
214
        FeatureType featureType = getFeatureType();
215
        return featureType.size();
216
    }
217

    
218
    @Override
219
    public String getColumnName(int column) {
220
        String columName = getOriginalColumnName(column);
221
        return this.getColumnAlias(columName);
222
    }
223

    
224
    @Override
225
    public Class<?> getColumnClass(int columnIndex) {
226
        int originalIndex = getOriginalColumnIndex(columnIndex);
227

    
228
        // Return the class of the FeatureAttributeDescriptor for the value
229
        FeatureAttributeDescriptor attributeDesc = this.getInternalColumnDescriptor(originalIndex);
230
        if (attributeDesc == null) {
231
                return super.getColumnClass(originalIndex);
232
        }
233
        Class<?> clazz = attributeDesc.getObjectClass();
234
        return (clazz == null ? super.getColumnClass(originalIndex) : clazz);
235
    }
236

    
237
    @Override
238
    public FeatureAttributeDescriptor getColumnDescriptor(int columnIndex) {
239
        int originalIndex = getOriginalColumnIndex(columnIndex);
240
        return this.getInternalColumnDescriptor(originalIndex);
241
    }
242

    
243
    protected FeatureAttributeDescriptor getInternalColumnDescriptor(int columnIndex) {
244
        FeatureType featureType = getFeatureType();
245
        if( featureType == null ) {
246
            return null;
247
        }
248
        return featureType.getAttributeDescriptor(columnIndex);
249
    }
250

    
251
    @Override
252
    public String getOriginalColumnName(int column) {
253
        return getInternalColumnDescriptor(column).getName();
254
    }
255

    
256
    @Override
257
    public void setColumnVisible(String name, boolean visible) {
258
        if (!columnNames.contains(name)) {
259
            throw new InvalidParameterException(name); // FIXME
260
        }
261
        if( visible ) {
262
            if ( !visibleColumnNames.contains(name) ) {
263
                visibleColumnNames.add(name);
264
                setVisibleColumns(visibleColumnNames);
265
            }
266
        } else {
267
            if ( visibleColumnNames.contains(name) ) {
268
                visibleColumnNames.remove(name);
269
                setVisibleColumns(visibleColumnNames);
270
                fireTableStructureChanged();
271
            }
272
        }
273
    }
274

    
275
    public void setFeatureType(FeatureType featureType) {
276
        // Check if there is a new column name
277
        List<String> newColumns = new ArrayList<>();
278
        List<String> renamedColumnsNewName = new ArrayList<>();
279

    
280
        Iterator<FeatureAttributeDescriptor> attrIter = featureType.iterator();
281
        FeatureAttributeDescriptor fad ;
282
        EditableFeatureAttributeDescriptor efad ;
283

    
284
        String colName;
285
        while (attrIter.hasNext()) {
286
            fad = attrIter.next();
287
            colName = fad.getName();
288
            if (!columnNames.contains(colName)) {
289
                if (fad instanceof EditableFeatureAttributeDescriptor) {
290
                    efad = (EditableFeatureAttributeDescriptor) fad;
291
                    /*
292
                     * If editable att descriptor,
293
                     * check original name
294
                     */
295
                    if (efad.getOriginalName() != null) {
296
                        if (!columnNames.contains(efad.getOriginalName())) {
297
                            /*
298
                             * Check with original name but add current name
299
                             */
300
                            newColumns.add(colName);
301
                        } else {
302
                            /*
303
                             * List of new names of renamed columns
304
                             */
305
                            renamedColumnsNewName.add(colName);
306
                        }
307
                    } else {
308
                        newColumns.add(colName);
309
                    }
310
                } else {
311
                    newColumns.add(colName);
312
                }
313
            }
314
        }
315

    
316
        // Update column names
317
        columnNames.clear();
318
        @SuppressWarnings("unchecked")
319
        Iterator<FeatureAttributeDescriptor> visibleAttrIter =
320
            featureType.iterator();
321
        while (visibleAttrIter.hasNext()) {
322
            fad = visibleAttrIter.next();
323
            colName = fad.getName();
324
            columnNames.add(colName);
325
            //If the column is added has to be visible
326
            if (!visibleColumnNames.contains(colName)) {
327

    
328
                if (((newColumns.contains(colName)
329
                    || renamedColumnsNewName.contains(colName)))
330
                    &&
331
                    fad.getType() != DataTypes.GEOMETRY) {
332
                    // Add new columns and renamed
333
                    visibleColumnNames.add(colName);
334
                    visibleColumnNamesOriginal.add(colName);
335
                }
336
                /*
337
                if (renamedColumnsNewName.contains(colName)) {
338
                    // Add renamed
339
                    insertWhereOldName(visibleColumnNames, colName, fad);
340
                    insertWhereOldName(visibleColumnNamesOriginal, colName, fad);
341
                }
342
                */
343
            }
344
        }
345

    
346
        // remove from visible columns removed columns
347
        visibleColumnNames = intersectKeepOrder(columnNames, visibleColumnNames);
348
        // instead of: visibleColumnNames.retainAll(columnNames);
349

    
350
        visibleColumnNamesOriginal = intersectKeepOrder(columnNames, visibleColumnNamesOriginal);
351
        // instead of: visibleColumnNamesOriginal.retainAll(columnNames);
352

    
353
        // remove from alias map removed columns
354
        name2Alias.keySet().retainAll(columnNames);
355
        name2AliasOriginal.keySet().retainAll(columnNames);
356

    
357
        initializeFormatingPatterns();
358

    
359
        getFeatureQuery().setFeatureType(featureType);
360
        reloadFeatures();
361
        //Selection must be locked to avoid losing it when the table is refreshed
362
        selectionLocked=true;
363
        //The table is refreshed
364
        try {
365
            fireTableStructureChanged();
366
        } catch (Exception e) {
367
            logger.warn("Couldn't reload changed table");
368
        }finally{
369
            //The locked selection is unlocked.
370
            selectionLocked=false;
371
        }
372

    
373
    }
374

    
375
    private void reloadFeatures() {
376
        try {
377
            this.getFeaturePager().reload();
378
        } catch (BaseException ex) {
379
            throw new FeaturesDataReloadException(ex);
380
        }
381
    }
382

    
383
    /**
384
     * keeps order of first parameter
385
     *
386
     * @param lista
387
     * @param listb
388
     * @return
389
     */
390
    private List<String> intersectKeepOrder(List<String> lista, List<String> listb) {
391

    
392
        List<String> resp = new ArrayList<>();
393
        resp.addAll(lista);
394
        resp.retainAll(listb);
395
        return resp;
396
    }
397

    
398
    public void setVisibleColumns(List<String> names) {
399
        // Recreate the visible column names list
400
        // to maintain the original order
401
        visibleColumnNames = new ArrayList<>(names.size());
402
        for (int i = 0; i < columnNames.size(); i++) {
403
            String columnName = columnNames.get(i);
404
            if (names.contains(columnName)) {
405
                visibleColumnNames.add(columnName);
406
            }
407
        }
408
        updatePagerWithHiddenColums();
409
        fireTableStructureChanged();
410
    }
411

    
412
    protected String[] getHiddenColumnNames() {
413
        List<String> hiddenColumns = new ArrayList<String>();
414
        hiddenColumns.addAll(columnNames);
415

    
416
        for (int i = 0; i < visibleColumnNames.size(); i++) {
417
            String columnName = visibleColumnNames.get(i);
418
            hiddenColumns.remove(columnName);
419
        }
420
        if( hiddenColumns.size()<1 ) {
421
            return null;
422
        }
423
        return (String[]) hiddenColumns.toArray(new String[hiddenColumns.size()]);
424
    }
425

    
426
    /**
427
     * Changes all columns to be visible.
428
     */
429
    public void setAllVisible() {
430
        visibleColumnNames.clear();
431
        visibleColumnNames.addAll(columnNames);
432
        fireTableStructureChanged();
433
    }
434

    
435
    @Override
436
    public void setColumnOrder(String name, boolean ascending)
437
        throws BaseException {
438
        FeatureQueryOrder order = this.getFeatureQuery().getOrder();
439
        if (order == null) {
440
            order = new FeatureQueryOrder();
441
            this.getFeatureQuery().setOrder(order);
442
        }
443
        order.clear();
444
        order.add(name, ascending);
445
        this.getFeaturePager().reload();
446
        fireTableChanged(new TableModelEvent(this, 0, this.getRowCount() - 1));
447
    }
448

    
449
    @Override
450
    public int getRowCount() {
451
        // Return the total size of the collection
452
        // If the size is bigger than INTEGER.MAX_VALUE, return that instead
453
        try {
454
            long totalSize = this.getFeaturePager().getTotalSize();
455
            if (totalSize > Integer.MAX_VALUE) {
456
                return Integer.MAX_VALUE;
457
            } else {
458
                return (int) totalSize;
459
            }
460
        } catch (ConcurrentDataModificationException e) {
461
            logger.debug("Error while getting the total size of the set", e);
462
            return 0;
463
        }
464
    }
465

    
466
    @Override
467
    public boolean isColumnVisible(String name) {
468
        return visibleColumnNames.contains(name);
469
    }
470

    
471
    @Override
472
    public String getColumnAlias(String name) {
473
        String alias = name2Alias.get(name);
474
        return alias == null ? name : alias;
475
    }
476

    
477
    @Override
478
    public void setColumnAlias(String name, String alias) {
479
        name2Alias.put(name, alias);
480
        fireTableStructureChanged();
481
    }
482

    
483
    @Override
484
    public int getOriginalColumnIndex(int columnIndex) {
485
        String columnName = visibleColumnNames.get(columnIndex);
486
        return columnNames.indexOf(columnName);
487
    }
488

    
489
    @Override
490
    public Object getValueAt(int rowIndex, int columnIndex) {
491
        // Get the Feature at row "rowIndex", and return the value of the
492
        // attribute at "columnIndex"
493
        Feature feature = getFeatureAt(rowIndex);
494
        return feature == null ? null : getFeatureValue(feature, columnIndex);
495
    }
496

    
497
    @Override
498
    public Feature getFeatureAt(int rowIndex) {
499
        try {
500
            return this.getFeaturePager().getFeatureAt(rowIndex);
501
        } catch (BaseException ex) {
502
            throw new GetFeatureAtException(rowIndex, ex);
503
        }
504
    }
505

    
506
    protected Object getFeatureValue(Feature feature, int columnIndex) {
507
        int realColumnIndex = getOriginalColumnIndex(columnIndex);
508
        return feature.get(realColumnIndex);
509
    }
510

    
511
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
512
        Object value) {
513
        int realColumnIndex = getOriginalColumnIndex(columnIndex);
514
        EditableFeature editableFeature = feature.getEditable();
515
        editableFeature.set(realColumnIndex, value);
516
        return editableFeature;
517
    }
518

    
519

    
520
    public void acceptChanges() {
521
            visibleColumnNamesOriginal = new ArrayList<>(visibleColumnNames);
522
            name2AliasOriginal = new HashMap<>(name2Alias);
523
    }
524

    
525
    public void cancelChanges() {
526
            visibleColumnNames = new ArrayList<>(visibleColumnNamesOriginal);
527
            name2Alias = new HashMap<>(name2AliasOriginal);
528
            fireTableStructureChanged();
529
    }
530

    
531

    
532
    @Override
533
    public String getColumnFormattingPattern(int column) {
534
        String columnName = this.visibleColumnNames.get(column);
535
        return this.getColumnFormattingPattern(columnName);
536
    }
537

    
538
    @Override
539
    public String getColumnFormattingPattern(String columnName) {
540
        String pattern = this.patterns.get(columnName);
541
        return pattern;
542
    }
543

    
544
    @Override
545
    public void setColumnFormattingPattern(String columnName, String pattern) {
546
        this.patterns.put(columnName,pattern);
547
    }
548

    
549
    @Override
550
    public Locale getLocaleOfData() {
551
        return this.localeOfData;
552
    }
553

    
554
    @Override
555
    public void setLocaleOfData(Locale locale) {
556
        this.localeOfData = locale;
557
    }
558

    
559
    public boolean isSelectionLocked() {
560
        if( !this.getFeatureType().supportReferences() ) {
561
            return true;
562
        }
563
        return selectionLocked;
564
    }
565

    
566
    @Override
567
    public boolean isSelectionUp() {
568
        return this.getFeaturePager().isSelectionUp();
569
    }
570

    
571
    @Override
572
    public void setSelectionUp(boolean selectionUp) {
573
        this.getFeaturePager().setSelectionUp(selectionUp);
574
        fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1));
575
    }
576

    
577
    private class DelayAction extends Timer implements ActionListener, Runnable {
578
        private static final int STATE_NONE = 0;
579
        private static final int STATE_NEED_RELOADALL = 1;
580
        private static final int STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED = 2;
581
        private static final int STATE_NEED_RELOAD_IF_FEATURE_UPDATED = 4;
582
        private static final int STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED = 8;
583
        private static final int STATE_NEED_RELOAD_FEATURE_TYPE = 16;
584
        private static final int STATE_NEED_SELECTION_UP = 32;
585
        private static final int STATE_NEED_RELOAD_ALL_FEATURES=64;
586

    
587
        private static final long serialVersionUID = -5692569125344166705L;
588

    
589
        private int state = STATE_NONE;
590
        private Feature feature;
591
        private FeatureType featureType;
592
        private boolean isSelecctionUp;
593

    
594
        public DelayAction() {
595
            super(1000,null);
596
            this.setRepeats(false);
597
            this.reset();
598
            this.addActionListener(this);
599
        }
600

    
601
        private void reset() {
602
            this.state = STATE_NONE;
603
            this.isSelecctionUp = false;
604
            this.feature = null;
605
            this.featureType = null;
606
        }
607

    
608
        public void actionPerformed(ActionEvent ae) {
609
            this.run();
610
        }
611

    
612
        public void run() {
613
            if( !SwingUtilities.isEventDispatchThread() ) {
614
                SwingUtilities.invokeLater(this);
615
                return;
616
            }
617
            this.stop();
618
            logger.info("DelayAction.run["+this.state+"] begin");
619
            switch(this.state) {
620
            case STATE_NEED_RELOADALL:
621
                reloadAll();
622
                break;
623
            case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
624
                reloadIfFeatureCountChanged(feature);
625
                break;
626
            case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
627
                reloadIfFeatureUpdated(feature);
628
                break;
629
            case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
630
                reloadIfTypeChanged(featureType);
631
                break;
632
            case STATE_NEED_RELOAD_FEATURE_TYPE:
633
                reloadFeatureType();
634
                updatePagerWithHiddenColums();
635
                break;
636
            case STATE_NEED_RELOAD_ALL_FEATURES:
637
                reloadFeatures();
638
                fireTableChanged(new TableModelEvent(DefaultFeatureTableModel.this, 0, getRowCount()));
639
                break;
640
            case STATE_NEED_SELECTION_UP:
641
            case STATE_NONE:
642
            default:
643
                break;
644
            }
645
            if( isSelecctionUp ) {
646
                getFeaturePager().setSelectionUp(true);
647
            }
648
            this.reset();
649
            logger.info("DelayAction.run["+this.state+"] end");
650
        }
651

    
652
        public void nextState(int nextstate) {
653
            this.nextState(nextstate, null, null);
654
        }
655

    
656
        public void nextState(int nextstate, Feature feature) {
657
            this.nextState(nextstate, feature, null);
658
        }
659

    
660
        public void nextState(int nextstate, FeatureType featureType) {
661
            this.nextState(nextstate, null, featureType);
662
        }
663

    
664
        public void nextState(int nextstate, Feature feature, FeatureType featureType) {
665
            this.feature = feature;
666
            this.featureType = featureType;
667
            switch(nextstate) {
668
            case STATE_NEED_RELOADALL:
669
            case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
670
            case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
671
                switch(this.state) {
672
                case STATE_NEED_RELOADALL:
673
                case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
674
                //case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
675
                    this.state = STATE_NEED_RELOADALL;
676
                    break;
677
                case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
678
                case STATE_NEED_RELOAD_FEATURE_TYPE:
679
                    this.state = STATE_NEED_RELOAD_FEATURE_TYPE;
680
                    break;
681
                case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
682
                case STATE_NEED_RELOAD_ALL_FEATURES:
683
                    this.state=STATE_NEED_RELOAD_ALL_FEATURES;
684
                    break;
685
                case STATE_NEED_SELECTION_UP:
686
                    this.state = nextstate;
687
                    this.isSelecctionUp = true;
688
                    break;
689
                case STATE_NONE:
690
                default:
691
                    this.state = nextstate;
692
                    break;
693
                }
694
                break;
695
            case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
696
            case STATE_NEED_RELOAD_FEATURE_TYPE:
697
                switch(this.state) {
698
                case STATE_NEED_RELOADALL:
699
                case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
700
                case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
701
                case STATE_NEED_RELOAD_ALL_FEATURES:
702
                case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
703
                case STATE_NEED_RELOAD_FEATURE_TYPE:
704
                    this.state = STATE_NEED_RELOAD_FEATURE_TYPE;
705
                    break;
706
                case STATE_NEED_SELECTION_UP:
707
                    this.state = nextstate;
708
                    this.isSelecctionUp = true;
709
                    break;
710
                case STATE_NONE:
711
                default:
712
                    this.state = nextstate;
713
                    break;
714
                }
715
                break;
716
            case STATE_NEED_SELECTION_UP:
717
                switch(this.state) {
718
                case STATE_NEED_RELOADALL:
719
                case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
720
                case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
721
                case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
722
                case STATE_NEED_RELOAD_ALL_FEATURES:
723
                case STATE_NEED_RELOAD_FEATURE_TYPE:
724
                case STATE_NEED_SELECTION_UP:
725
                    this.isSelecctionUp = true;
726
                    break;
727
                case STATE_NONE:
728
                default:
729
                    this.state = nextstate;
730
                    this.isSelecctionUp = true;
731
                    break;
732
                }
733
                break;
734
            case STATE_NONE:
735
            default:
736
                this.state = STATE_NONE;
737
                break;
738
            }
739
            if( this.state != STATE_NONE ) {
740
                this.start();
741
            }
742
        }
743

    
744
    }
745

    
746
    /**
747
     * Reloads the table data if a feature has been changed, not through the
748
     * table.
749
     */
750
    private void reloadIfFeatureCountChanged(Feature feature) {
751
        // Is any data is changed in the FeatureStore, notify the model
752
        // listeners. Ignore the case where the updated feature is
753
        // changed through us.
754
        if (editableFeature == null || !editableFeature.equals(feature)) {
755
            reloadFeatures();
756
            //Selection must be locked to avoid losing it when the table is refreshed
757
            selectionLocked=true;
758
            //The table is refreshed
759
            try {
760
                fireTableDataChanged();
761
            } catch (Exception e) {
762
                logger.warn("Couldn't reload changed table");
763
            }finally{
764
                //The locked selection is unlocked.
765
                selectionLocked=false;
766
            }
767
        }
768
    }
769

    
770
    private void reloadIfFeatureUpdated(Feature feature) {
771
        // Is any data is changed in the FeatureStore, notify the model
772
        // listeners. Ignore the case where the updated feature is
773
        // changed through us.
774
        if (editableFeature == null || !editableFeature.equals(feature)) {
775
            reloadFeatures();
776
            fireTableChanged(new TableModelEvent(this, 0, getRowCount()));
777
        }
778
    }
779

    
780
    /**
781
     * Reloads data and structure if the {@link FeatureType} of the features
782
     * being shown has changed.
783
     */
784
    private void reloadIfTypeChanged(FeatureType updatedType) {
785
        // If the updated featured type is the one currently being
786
        // shown, reload the table.
787
        if (updatedType != null
788
            && updatedType.getId().equals(getFeatureType().getId())) {
789
            setFeatureType(updatedType);
790
        }
791
    }
792

    
793
    private void reloadAll() {
794
            reloadFeatureType();
795
    }
796

    
797
    private void reloadFeatureType() {
798
        try {
799
            FeatureType featureType = this.getFeaturePager().getFeatureType();
800
            FeatureStore store = this.getFeaturePager().getFeatureStore();
801
            this.setFeatureType( store.getFeatureType(featureType.getId()) );
802
        } catch (DataException e) {
803
            throw new FeaturesDataReloadException(e);
804
        }
805
    }
806

    
807
    @Override
808
    public void update(final Observable observable, final Object notification) {
809
        if (notification instanceof ComplexNotification) {
810
            // A lot of things might have happened in the store, so don't
811
            // bother looking into each notification.
812
            this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
813
//            reloadAll();
814
        } else if (observable.equals(getFeatureStore())
815
                && notification instanceof FeatureStoreNotification) {
816
            FeatureStoreNotification fsNotification
817
                    = (FeatureStoreNotification) notification;
818
            String type = fsNotification.getType();
819

    
820
            // If there are new, updated or deleted features
821
            // reload the table data
822
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
823
                    || FeatureStoreNotification.AFTER_INSERT.equals(type)) {
824
//                reloadIfFeatureCountChanged(fsNotification.getFeature());
825
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED, fsNotification.getFeature());
826

    
827
            } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
828
//                reloadIfFeatureUpdated(fsNotification.getFeature());
829
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_UPDATED, fsNotification.getFeature());
830

    
831
            } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
832
//                reloadIfTypeChanged(fsNotification.getFeatureType());
833
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED, fsNotification.getFeatureType());
834

    
835
            } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)
836
                    || FeatureStoreNotification.AFTER_UNDO.equals(type)
837
                    || FeatureStoreNotification.AFTER_REDO.equals(type)
838
                    || FeatureStoreNotification.AFTER_REFRESH.equals(type))  {
839
//                reloadAll();
840
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
841

    
842
            } else if (FeatureStoreNotification.AFTER_FINISHEDITING.equals(type)
843
                    || FeatureStoreNotification.AFTER_STARTEDITING.equals(type)
844
                    || FeatureStoreNotification.AFTER_CANCELEDITING.equals(type)) {
845
                /*
846
                No tengo nada claro por que es necesario llamar al reloadFeatureType
847
                pero si no se incluye hay problemas si durante la edicion se a?aden
848
                campos a la tabla. Sin esto, al cerrar la edicion, los campos a?adidos
849
                desaparecen de la tabla aunque estan en el fichero.
850
                Ver ticket #2434 https://devel.gvsig.org/redmine/issues/2434
851
                */
852
//                reloadFeatureType();
853
//                updatePaginHelperWithHiddenColums();
854
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_FEATURE_TYPE, fsNotification.getFeatureType());
855
            } else if (FeatureStoreNotification.SELECTION_CHANGE.equals(type)) {
856
                if( this.isSelectionUp() ) {
857
                    this.setSelectionUp(true);
858
                    this.delayAction.nextState(DelayAction.STATE_NEED_SELECTION_UP);
859
                }
860
            }
861
        }
862
    }
863
    
864
    @Override
865
    public FeatureSelection getFeatureSelection() {
866
        if (selection == null) {
867
            try {
868
                return getFeatureStore().getFeatureSelection();
869
            } catch (Exception e) {
870
                logger.warn("Error getting the selection", e);
871
            }
872
        }
873
        return selection;
874
    }
875
    
876
    @Override
877
    public void setFeatureSelection(FeatureSelection selection) {
878
        this.selection = selection;
879
        this.featurePager.setSelection(selection);
880
        this.fireChangeListeners(new ActionEvent(this, 0,CHANGE_SELECTION));
881
    }
882
    
883
    public void addChangeListener(ActionListener listener) {
884
        if( this.changeListeners==null) {
885
            this.changeListeners = new HashSet<>();
886
        }
887
        this.changeListeners.add(listener);
888
    }
889
    
890
    public void fireChangeListeners(ActionEvent event) {
891
        if( this.changeListeners == null ) {
892
            return;
893
        }
894
        for( ActionListener listener : this.changeListeners ) {
895
            try {
896
                listener.actionPerformed(event);
897
            } catch(Exception ex) {
898
                // Ignore
899
            }
900
        }
901
    }
902
    
903
    @Override
904
    public int getSelectionCount() {
905
        try {
906
            FeatureSelection selection = this.getFeatureSelection();
907
            return (int) selection.getSize();
908
        } catch (DataException ex) {
909
            throw new RuntimeException("Can't get selection of the FeatureTableModel",ex);
910
        }
911
    }
912

    
913

    
914
}