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

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
            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
        return selectionLocked;
561
    }
562

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

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

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

    
584
        private static final long serialVersionUID = -5692569125344166705L;
585

    
586
        private int state = STATE_NONE;
587
        private Feature feature;
588
        private FeatureType featureType;
589
        private boolean isSelecctionUp;
590

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

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

    
605
        public void actionPerformed(ActionEvent ae) {
606
            this.run();
607
        }
608

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

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

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

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

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

    
741
    }
742

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

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

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

    
790
    private void reloadAll() {
791
            reloadFeatureType();
792
    }
793

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

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

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

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

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

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

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

    
910

    
911
}