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

History | View | Annotate | Download (32.3 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
        FeatureQuery query = this.getFeaturePager().getFeatureQuery();
172
        if (this.getFeaturePager().getFeatureStore().isEditing()) {
173
            if (query.hasConstantsAttributeNames()) {
174
                query.clearConstantsAttributeNames();
175
            }
176
        } else {
177
            query.setConstantsAttributeNames(this.getHiddenColumnNames());
178
        }
179
        try {
180
            this.getFeaturePager().reload();
181
        } catch (BaseException ex) {
182
            logger.warn("Can't reload paging-helper.", ex);
183
        }
184
    }
185

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
348
        visibleColumnNamesOriginal = intersectKeepOrder(columnNames, visibleColumnNamesOriginal);
349
        // instead of: visibleColumnNamesOriginal.retainAll(columnNames);
350

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

    
355
        initializeFormatingPatterns();
356

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

    
371
    }
372

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
517

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

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

    
529

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

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

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

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

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

    
557
    public boolean isSelectionLocked() {
558
        return selectionLocked;
559
    }
560

    
561
    @Override
562
    public boolean isSelectionUp() {
563
        return this.getFeaturePager().isSelectionUp();
564
    }
565

    
566
    @Override
567
    public void setSelectionUp(boolean selectionUp) {
568
        this.getFeaturePager().setSelectionUp(selectionUp);
569
        fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1));
570
    }
571

    
572
    private class DelayAction extends Timer implements ActionListener, Runnable {
573
        private static final int STATE_NONE = 0;
574
        private static final int STATE_NEED_RELOADALL = 1;
575
        private static final int STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED = 2;
576
        private static final int STATE_NEED_RELOAD_IF_FEATURE_UPDATED = 4;
577
        private static final int STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED = 8;
578
        private static final int STATE_NEED_RELOAD_FEATURE_TYPE = 16;
579
        private static final int STATE_NEED_SELECTION_UP = 32;
580
        private static final int STATE_NEED_RELOAD_ALL_FEATURES=64;
581

    
582
        private static final long serialVersionUID = -5692569125344166705L;
583

    
584
        private int state = STATE_NONE;
585
        private Feature feature;
586
        private FeatureType featureType;
587
        private boolean isSelecctionUp;
588

    
589
        public DelayAction() {
590
            super(1000,null);
591
            this.setRepeats(false);
592
            this.reset();
593
            this.addActionListener(this);
594
        }
595

    
596
        private void reset() {
597
            this.state = STATE_NONE;
598
            this.isSelecctionUp = false;
599
            this.feature = null;
600
            this.featureType = null;
601
        }
602

    
603
        public void actionPerformed(ActionEvent ae) {
604
            this.run();
605
        }
606

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

    
647
        public void nextState(int nextstate) {
648
            this.nextState(nextstate, null, null);
649
        }
650

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

    
655
        public void nextState(int nextstate, FeatureType featureType) {
656
            this.nextState(nextstate, null, featureType);
657
        }
658

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

    
739
    }
740

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

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

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

    
788
    private void reloadAll() {
789
            reloadFeatureType();
790
    }
791

    
792
    private void reloadFeatureType() {
793
        try {
794
            FeatureType featureType = this.getFeaturePager().getFeatureType();
795
            FeatureStore store = this.getFeaturePager().getFeatureStore();
796
            this.setFeatureType( store.getFeatureType(featureType.getId()) );
797
        } catch (DataException e) {
798
            throw new FeaturesDataReloadException(e);
799
        }
800
    }
801

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

    
815
            // If there are new, updated or deleted features
816
            // reload the table data
817
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
818
                    || FeatureStoreNotification.AFTER_INSERT.equals(type)) {
819
//                reloadIfFeatureCountChanged(fsNotification.getFeature());
820
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED, fsNotification.getFeature());
821

    
822
            } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
823
//                reloadIfFeatureUpdated(fsNotification.getFeature());
824
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_UPDATED, fsNotification.getFeature());
825

    
826
            } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
827
//                reloadIfTypeChanged(fsNotification.getFeatureType());
828
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED, fsNotification.getFeatureType());
829

    
830
            } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)
831
                    || FeatureStoreNotification.AFTER_UNDO.equals(type)
832
                    || FeatureStoreNotification.AFTER_REDO.equals(type)
833
                    || FeatureStoreNotification.AFTER_REFRESH.equals(type))  {
834
//                reloadAll();
835
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
836

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

    
908

    
909
}