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

History | View | Annotate | Download (31.1 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.Iterator;
34
import java.util.List;
35
import java.util.Locale;
36
import java.util.Map;
37
import javax.swing.SwingUtilities;
38
import javax.swing.Timer;
39

    
40
import javax.swing.event.TableModelEvent;
41
import javax.swing.table.AbstractTableModel;
42

    
43
import org.gvsig.fmap.dal.DataTypes;
44
import org.gvsig.fmap.dal.exception.DataException;
45
import org.gvsig.fmap.dal.feature.EditableFeature;
46
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
47
import org.gvsig.fmap.dal.feature.Feature;
48
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
49
import org.gvsig.fmap.dal.feature.FeatureQuery;
50
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
51
import org.gvsig.fmap.dal.feature.FeatureSelection;
52
import org.gvsig.fmap.dal.feature.FeatureStore;
53
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
54
import org.gvsig.fmap.dal.feature.FeatureType;
55
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
56
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
57
import org.gvsig.tools.exception.BaseException;
58
import org.gvsig.tools.observer.ComplexNotification;
59
import org.gvsig.tools.observer.ComplexObserver;
60
import org.gvsig.tools.observer.Observable;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

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

    
66
    private static final long serialVersionUID = -8223987814719746492L;
67
    
68
    private static final Logger logger = LoggerFactory.getLogger(DefaultFeatureTableModel.class);
69

    
70
    private List<String> columnNames;
71

    
72
    private List<String> visibleColumnNames;
73

    
74
    private List<String> visibleColumnNamesOriginal;
75

    
76
    private Map<String, String> name2Alias;
77

    
78
    private Map<String, String> name2AliasOriginal;
79

    
80
    private Map<String,String> patterns = null;
81

    
82
    private Locale localeOfData;    
83

    
84
    private final FeaturePagingHelper featurePager;
85

    
86
    /** Used to know if a modification in the FeatureStore is created by us. */
87
    private EditableFeature editableFeature;
88

    
89
    private boolean selectionLocked=false;
90
    
91
    private final DelayAction delayAction = new DelayAction();
92

    
93

    
94
    public DefaultFeatureTableModel(FeaturePagingHelper featurePager) {
95
        this.featurePager = featurePager;
96
        this.localeOfData = Locale.getDefault();
97
        this.initialize();
98
    }
99

    
100
    private void initialize() {
101
        this.getFeatureStore().addObserver(this);
102
        
103
        int columns = this.getOriginalColumnCount();
104

    
105
        // Initilize visible columns
106
        columnNames = new ArrayList<>(columns);
107
        visibleColumnNames = new ArrayList<>(columns);
108
        for (int i = 0; i < columns; i++) {
109
            FeatureAttributeDescriptor descriptor = this.getInternalColumnDescriptor(i);
110
            String columnName = descriptor.getName();
111
            columnNames.add(columnName);
112

    
113
            // By default, geometry columns will not be visible
114
            if (descriptor.getType() != DataTypes.GEOMETRY) {
115
                visibleColumnNames.add(columnName);
116
            }
117
        }
118
        visibleColumnNamesOriginal = new ArrayList<>(visibleColumnNames);
119
        
120
        // Initialize alias
121
        name2Alias = new HashMap<>(columns);
122
        name2AliasOriginal = new HashMap<>(columns);
123

    
124
        initializeFormatingPatterns();
125
        updatePagerWithHiddenColums();
126
    }
127

    
128
    private void initializeFormatingPatterns() {
129
        int columns = this.getOriginalColumnCount();
130
        
131
        this.patterns = new HashMap<>();
132
        for (int i = 0; i < columns; i++) {
133
            FeatureAttributeDescriptor descriptor = this.getInternalColumnDescriptor(i);
134
            String columnName = descriptor.getName();
135
            switch(descriptor.getDataType().getType()) {
136
            case DataTypes.BYTE:
137
            case DataTypes.INT:
138
            case DataTypes.LONG:
139
                String defaultIntegerPattern = "#,##0";
140
                this.patterns.put(columnName,defaultIntegerPattern);
141
                break;
142
            case DataTypes.DOUBLE:
143
                String defaultDoublePattern = "#,##0.0000000000";
144
                this.patterns.put(columnName,defaultDoublePattern);
145
                break;
146
            case DataTypes.FLOAT:
147
                String defaultFloatPattern = "#,##0.0000";
148
                this.patterns.put(columnName,defaultFloatPattern);
149
                break;
150
            case DataTypes.DATE:
151
                String defaultDatePattern = new SimpleDateFormat().toPattern();
152
                this.patterns.put(columnName,defaultDatePattern);
153
                break;
154
            default:
155
                this.patterns.put(columnName,null);
156
            }
157
        }
158
        
159
    }
160
    
161
    private void updatePagerWithHiddenColums() {
162
        FeatureQuery query = this.getFeaturePager().getFeatureQuery();
163
        if (this.getFeaturePager().getFeatureStore().isEditing()) {
164
            if (query.hasConstantsAttributeNames()) {
165
                query.clearConstantsAttributeNames();
166
            }
167
        } else {
168
            query.setConstantsAttributeNames(this.getHiddenColumnNames());
169
        }
170
        try {
171
            this.getFeaturePager().reload();
172
        } catch (BaseException ex) {
173
            logger.warn("Can't reload paging-helper.", ex);
174
        }
175
    }
176
    
177
    @Override
178
    public FeaturePagingHelper getFeaturePager() {
179
        return this.featurePager;
180
    }
181
        
182
    @Override
183
    public FeatureQuery getFeatureQuery() {
184
        return this.getFeaturePager().getFeatureQuery();
185
    }
186

    
187
    @Override
188
    public FeatureType getFeatureType() {
189
        return this.getFeaturePager().getFeatureType();
190
    }
191
    
192
    @Override
193
    public FeatureStore getFeatureStore() {
194
        return this.getFeaturePager().getFeatureStore();
195
    }
196

    
197
    @Override
198
    public int getColumnCount() {
199
        return visibleColumnNames.size();
200
    }
201

    
202
    public int getOriginalColumnCount() {
203
        FeatureType featureType = getFeatureType();
204
        return featureType.size();
205
    }
206

    
207
    @Override
208
    public String getColumnName(int column) {
209
        String columName = getOriginalColumnName(column);
210
        return this.getColumnAlias(columName);
211
    }
212

    
213
    @Override
214
    public Class<?> getColumnClass(int columnIndex) {
215
        int originalIndex = getOriginalColumnIndex(columnIndex);
216
        
217
        // Return the class of the FeatureAttributeDescriptor for the value
218
        FeatureAttributeDescriptor attributeDesc = this.getInternalColumnDescriptor(originalIndex);
219
        if (attributeDesc == null) {
220
                return super.getColumnClass(originalIndex);
221
        }
222
        Class<?> clazz = attributeDesc.getObjectClass();
223
        return (clazz == null ? super.getColumnClass(originalIndex) : clazz);
224
    }
225

    
226
    @Override
227
    public FeatureAttributeDescriptor getColumnDescriptor(int columnIndex) {
228
        int originalIndex = getOriginalColumnIndex(columnIndex);
229
        return this.getInternalColumnDescriptor(originalIndex);
230
    }
231
    
232
    protected FeatureAttributeDescriptor getInternalColumnDescriptor(int columnIndex) {
233
        FeatureType featureType = getFeatureType();
234
        if( featureType == null ) {
235
            return null;
236
        }
237
        return featureType.getAttributeDescriptor(columnIndex);
238
    }
239

    
240
    @Override
241
    public String getOriginalColumnName(int column) {
242
        return getInternalColumnDescriptor(column).getName();
243
    }
244

    
245
    @Override
246
    public void setColumnVisible(String name, boolean visible) {
247
        if (!columnNames.contains(name)) {
248
            throw new InvalidParameterException(name); // FIXME
249
        }
250
        if( visible ) {
251
            if ( !visibleColumnNames.contains(name) ) {
252
                visibleColumnNames.add(name);
253
                setVisibleColumns(visibleColumnNames);
254
            }
255
        } else {
256
            if ( visibleColumnNames.contains(name) ) {
257
                visibleColumnNames.remove(name);
258
                setVisibleColumns(visibleColumnNames);
259
                fireTableStructureChanged();
260
            }
261
        }
262
    }
263

    
264
    public void setFeatureType(FeatureType featureType) {
265
        // Check if there is a new column name
266
        List<String> newColumns = new ArrayList<>();
267
        List<String> renamedColumnsNewName = new ArrayList<>();
268
        
269
        Iterator<FeatureAttributeDescriptor> attrIter = featureType.iterator();
270
        FeatureAttributeDescriptor fad ;
271
        EditableFeatureAttributeDescriptor efad ;
272
        
273
        String colName;
274
        while (attrIter.hasNext()) {
275
            fad = attrIter.next();
276
            colName = fad.getName();
277
            if (!columnNames.contains(colName)) {
278
                if (fad instanceof EditableFeatureAttributeDescriptor) {
279
                    efad = (EditableFeatureAttributeDescriptor) fad; 
280
                    /*
281
                     * If editable att descriptor,
282
                     * check original name
283
                     */
284
                    if (efad.getOriginalName() != null) {
285
                        if (!columnNames.contains(efad.getOriginalName())) {
286
                            /*
287
                             * Check with original name but add current name
288
                             */
289
                            newColumns.add(colName);
290
                        } else {
291
                            /*
292
                             * List of new names of renamed columns
293
                             */
294
                            renamedColumnsNewName.add(colName);
295
                        }
296
                    } else {
297
                        newColumns.add(colName);
298
                    }
299
                } else {
300
                    newColumns.add(colName);
301
                }
302
            }
303
        }
304

    
305
        // Update column names
306
        columnNames.clear();
307
        @SuppressWarnings("unchecked")
308
        Iterator<FeatureAttributeDescriptor> visibleAttrIter =
309
            featureType.iterator();
310
        while (visibleAttrIter.hasNext()) {
311
            fad = visibleAttrIter.next();
312
            colName = fad.getName();
313
            columnNames.add(colName);
314
            //If the column is added has to be visible
315
            if (!visibleColumnNames.contains(colName)) {
316

    
317
                if (((newColumns.contains(colName)
318
                    || renamedColumnsNewName.contains(colName)))
319
                    &&
320
                    fad.getType() != DataTypes.GEOMETRY) {
321
                    // Add new columns and renamed
322
                    visibleColumnNames.add(colName);
323
                    visibleColumnNamesOriginal.add(colName);
324
                }
325
                /*
326
                if (renamedColumnsNewName.contains(colName)) {
327
                    // Add renamed
328
                    insertWhereOldName(visibleColumnNames, colName, fad);
329
                    insertWhereOldName(visibleColumnNamesOriginal, colName, fad);
330
                }
331
                */
332
            }
333
        }
334

    
335
        // remove from visible columns removed columns
336
        visibleColumnNames = intersectKeepOrder(columnNames, visibleColumnNames);
337
        // instead of: visibleColumnNames.retainAll(columnNames);
338

    
339
        visibleColumnNamesOriginal = intersectKeepOrder(columnNames, visibleColumnNamesOriginal);
340
        // instead of: visibleColumnNamesOriginal.retainAll(columnNames);
341

    
342
        // remove from alias map removed columns
343
        name2Alias.keySet().retainAll(columnNames);
344
        name2AliasOriginal.keySet().retainAll(columnNames);
345

    
346
        initializeFormatingPatterns();    
347
        
348
        getFeatureQuery().setFeatureType(featureType);
349
        reloadFeatures();
350
        //Selection must be locked to avoid losing it when the table is refreshed
351
        selectionLocked=true;
352
        //The table is refreshed
353
        try {
354
            fireTableStructureChanged();
355
        } catch (Exception e) {
356
            logger.warn("Couldn't reload changed table");
357
        }finally{
358
            //The locked selection is unlocked.
359
            selectionLocked=false;
360
        }        
361

    
362
    }
363

    
364
    private void reloadFeatures() {
365
        try {
366
            this.getFeaturePager().reload();
367
        } catch (BaseException ex) {
368
            throw new FeaturesDataReloadException(ex);
369
        }
370
    }
371
    
372
    /**
373
     * keeps order of first parameter
374
     * 
375
     * @param lista
376
     * @param listb
377
     * @return
378
     */
379
    private List<String> intersectKeepOrder(List<String> lista, List<String> listb) {
380
        
381
        List<String> resp = new ArrayList<>();
382
        resp.addAll(lista);
383
        resp.retainAll(listb);
384
        return resp;
385
    }
386

    
387
    public void setVisibleColumns(List<String> names) {
388
        // Recreate the visible column names list
389
        // to maintain the original order        
390
        visibleColumnNames = new ArrayList<>(names.size());
391
        for (int i = 0; i < columnNames.size(); i++) {
392
            String columnName = columnNames.get(i);
393
            if (names.contains(columnName)) {
394
                visibleColumnNames.add(columnName);
395
            }
396
        }
397
        updatePagerWithHiddenColums();
398
        fireTableStructureChanged();
399
    }
400

    
401
    protected String[] getHiddenColumnNames() {
402
        List<String> hiddenColumns = new ArrayList<String>();
403
        hiddenColumns.addAll(columnNames);
404
        
405
        for (int i = 0; i < visibleColumnNames.size(); i++) {
406
            String columnName = visibleColumnNames.get(i);
407
            hiddenColumns.remove(columnName);
408
        }
409
        if( hiddenColumns.size()<1 ) {
410
            return null;
411
        }
412
        return (String[]) hiddenColumns.toArray(new String[hiddenColumns.size()]);
413
    }
414
        
415
    /**
416
     * Changes all columns to be visible.
417
     */
418
    public void setAllVisible() {
419
        visibleColumnNames.clear();
420
        visibleColumnNames.addAll(columnNames);
421
        fireTableStructureChanged();
422
    }
423

    
424
    @Override
425
    public void setColumnOrder(String name, boolean ascending)
426
        throws BaseException {
427
        FeatureQueryOrder order = this.getFeatureQuery().getOrder();
428
        if (order == null) {
429
            order = new FeatureQueryOrder();
430
            this.getFeatureQuery().setOrder(order);
431
        }
432
        order.clear();
433
        order.add(name, ascending);
434
        this.getFeaturePager().reload();
435
        fireTableChanged(new TableModelEvent(this, 0, this.getRowCount() - 1));
436
    }
437

    
438
    @Override
439
    public int getRowCount() {
440
        // Return the total size of the collection
441
        // If the size is bigger than INTEGER.MAX_VALUE, return that instead
442
        try {
443
            long totalSize = this.getFeaturePager().getTotalSize();
444
            if (totalSize > Integer.MAX_VALUE) {
445
                return Integer.MAX_VALUE;
446
            } else {
447
                return (int) totalSize;
448
            }
449
        } catch (ConcurrentDataModificationException e) {
450
            logger.debug("Error while getting the total size of the set", e);
451
            return 0;
452
        }
453
    }
454

    
455
    @Override
456
    public boolean isColumnVisible(String name) {
457
        return visibleColumnNames.contains(name);
458
    }
459

    
460
    @Override
461
    public String getColumnAlias(String name) {
462
        String alias = name2Alias.get(name);
463
        return alias == null ? name : alias;
464
    }
465

    
466
    @Override
467
    public void setColumnAlias(String name, String alias) {
468
        name2Alias.put(name, alias);
469
        fireTableStructureChanged();
470
    }
471

    
472
    @Override
473
    public int getOriginalColumnIndex(int columnIndex) {
474
        String columnName = visibleColumnNames.get(columnIndex);
475
        return columnNames.indexOf(columnName);
476
    }
477

    
478
    @Override
479
    public Object getValueAt(int rowIndex, int columnIndex) {
480
        // Get the Feature at row "rowIndex", and return the value of the
481
        // attribute at "columnIndex"
482
        Feature feature = getFeatureAt(rowIndex);
483
        return feature == null ? null : getFeatureValue(feature, columnIndex);
484
    }
485
    
486
    @Override
487
    public Feature getFeatureAt(int rowIndex) {
488
        try {
489
            return this.getFeaturePager().getFeatureAt(rowIndex);
490
        } catch (BaseException ex) {
491
            throw new GetFeatureAtException(rowIndex, ex);
492
        }
493
    }    
494
    
495
    protected Object getFeatureValue(Feature feature, int columnIndex) {
496
        int realColumnIndex = getOriginalColumnIndex(columnIndex);
497
        return feature.get(realColumnIndex);
498
    }
499

    
500
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
501
        Object value) {
502
        int realColumnIndex = getOriginalColumnIndex(columnIndex);
503
        EditableFeature editableFeature = feature.getEditable();
504
        editableFeature.set(realColumnIndex, value);
505
        return editableFeature;
506
    }
507
    
508

    
509
    public void acceptChanges() {
510
            visibleColumnNamesOriginal = new ArrayList<>(visibleColumnNames);
511
            name2AliasOriginal = new HashMap<>(name2Alias);
512
    }
513
    
514
    public void cancelChanges() {
515
            visibleColumnNames = new ArrayList<>(visibleColumnNamesOriginal);
516
            name2Alias = new HashMap<>(name2AliasOriginal);
517
            fireTableStructureChanged();
518
    }
519

    
520
    
521
    @Override
522
    public String getColumnFormattingPattern(int column) {
523
        String columnName = this.visibleColumnNames.get(column);
524
        return this.getColumnFormattingPattern(columnName);
525
    }
526
    
527
    @Override
528
    public String getColumnFormattingPattern(String columnName) {
529
        String pattern = this.patterns.get(columnName);
530
        return pattern;
531
    }
532
    
533
    @Override
534
    public void setColumnFormattingPattern(String columnName, String pattern) {
535
        this.patterns.put(columnName,pattern);
536
    }
537
    
538
    @Override
539
    public Locale getLocaleOfData() {
540
        return this.localeOfData;
541
    }
542
    
543
    @Override
544
    public void setLocaleOfData(Locale locale) {
545
        this.localeOfData = locale;
546
    }
547
    
548
    public boolean isSelectionLocked() {
549
        return selectionLocked;
550
    }    
551

    
552
    @Override
553
    public boolean isSelectionUp() {
554
        return this.getFeaturePager().isSelectionUp();
555
    }    
556

    
557
    @Override
558
    public void setSelectionUp(boolean selectionUp) {
559
        this.getFeaturePager().setSelectionUp(selectionUp);
560
        fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1));
561
    }
562
    
563
    private class DelayAction extends Timer implements ActionListener, Runnable {
564
        private static final int STATE_NONE = 0;
565
        private static final int STATE_NEED_RELOADALL = 1;
566
        private static final int STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED = 2;
567
        private static final int STATE_NEED_RELOAD_IF_FEATURE_UPDATED = 4;
568
        private static final int STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED = 8;
569
        private static final int STATE_NEED_RELOAD_FEATURE_TYPE = 16;
570
        private static final int STATE_NEED_SELECTION_UP = 32;
571
        private static final int STATE_NEED_RELOAD_ALL_FEATURES=64;
572
        
573
        private static final long serialVersionUID = -5692569125344166705L;
574

    
575
        private int state = STATE_NONE;
576
        private Feature feature;
577
        private FeatureType featureType;
578
        private boolean isSelecctionUp;
579

    
580
        public DelayAction() {
581
            super(1000,null);
582
            this.setRepeats(false);
583
            this.reset();
584
            this.addActionListener(this);
585
        }
586

    
587
        private void reset() {
588
            this.state = STATE_NONE;
589
            this.isSelecctionUp = false;
590
            this.feature = null;
591
            this.featureType = null;
592
        }
593

    
594
        public void actionPerformed(ActionEvent ae) {
595
            this.run();
596
        }
597

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

    
638
        public void nextState(int nextstate) {
639
            this.nextState(nextstate, null, null);
640
        }
641

    
642
        public void nextState(int nextstate, Feature feature) {
643
            this.nextState(nextstate, feature, null);
644
        }
645

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

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

    
730
    }
731

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

    
756
    private void reloadIfFeatureUpdated(Feature feature) {
757
        // Is any data is changed in the FeatureStore, notify the model
758
        // listeners. Ignore the case where the updated feature is
759
        // changed through us.
760
        if (editableFeature == null || !editableFeature.equals(feature)) {
761
            reloadFeatures();
762
            fireTableChanged(new TableModelEvent(this, 0, getRowCount()));
763
        }
764
    }
765

    
766
    /**
767
     * Reloads data and structure if the {@link FeatureType} of the features
768
     * being shown has changed.
769
     */
770
    private void reloadIfTypeChanged(FeatureType updatedType) {
771
        // If the updated featured type is the one currently being
772
        // shown, reload the table.
773
        if (updatedType != null
774
            && updatedType.getId().equals(getFeatureType().getId())) {
775
            setFeatureType(updatedType);
776
        }
777
    }
778

    
779
    private void reloadAll() {
780
            reloadFeatureType();
781
    }
782

    
783
    private void reloadFeatureType() {
784
        try {
785
            FeatureType featureType = this.getFeaturePager().getFeatureType();
786
            FeatureStore store = this.getFeaturePager().getFeatureStore();
787
            this.setFeatureType( store.getFeatureType(featureType.getId()) );
788
        } catch (DataException e) {
789
            throw new FeaturesDataReloadException(e);
790
        }
791
    }
792

    
793
    @Override
794
    public void update(final Observable observable, final Object notification) {
795
        if (notification instanceof ComplexNotification) {
796
            // A lot of things might have happened in the store, so don't
797
            // bother looking into each notification.
798
            this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
799
//            reloadAll();
800
        } else if (observable.equals(getFeatureStore())
801
                && notification instanceof FeatureStoreNotification) {
802
            FeatureStoreNotification fsNotification
803
                    = (FeatureStoreNotification) notification;
804
            String type = fsNotification.getType();
805

    
806
            // If there are new, updated or deleted features
807
            // reload the table data
808
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
809
                    || FeatureStoreNotification.AFTER_INSERT.equals(type)) {
810
//                reloadIfFeatureCountChanged(fsNotification.getFeature());
811
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED, fsNotification.getFeature());
812

    
813
            } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
814
//                reloadIfFeatureUpdated(fsNotification.getFeature());
815
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_UPDATED, fsNotification.getFeature());
816

    
817
            } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
818
//                reloadIfTypeChanged(fsNotification.getFeatureType());
819
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED, fsNotification.getFeatureType());
820

    
821
            } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)
822
                    || FeatureStoreNotification.AFTER_UNDO.equals(type)
823
                    || FeatureStoreNotification.AFTER_REDO.equals(type)
824
                    || FeatureStoreNotification.AFTER_REFRESH.equals(type))  {
825
//                reloadAll();
826
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
827

    
828
            } else if (FeatureStoreNotification.AFTER_FINISHEDITING.equals(type)
829
                    || FeatureStoreNotification.AFTER_STARTEDITING.equals(type)
830
                    || FeatureStoreNotification.AFTER_CANCELEDITING.equals(type)) {
831
                /*
832
                No tengo nada claro por que es necesario llamar al reloadFeatureType
833
                pero si no se incluye hay problemas si durante la edicion se a?aden
834
                campos a la tabla. Sin esto, al cerrar la edicion, los campos a?adidos
835
                desaparecen de la tabla aunque estan en el fichero.
836
                Ver ticket #2434 https://devel.gvsig.org/redmine/issues/2434
837
                */
838
//                reloadFeatureType();
839
//                updatePaginHelperWithHiddenColums();
840
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_FEATURE_TYPE, fsNotification.getFeatureType());
841
            } else if (FeatureStoreNotification.SELECTION_CHANGE.equals(type)) {
842
                if( this.isSelectionUp() ) {
843
                    this.setSelectionUp(true);
844
                    this.delayAction.nextState(DelayAction.STATE_NEED_SELECTION_UP);
845
                }
846
            }
847
        }
848
    }
849

    
850
    @Override
851
    public int getSelectionCount() {
852
        try {
853
            FeatureSelection selection = this.getFeatureStore().getFeatureSelection();
854
            return (int) selection.getSize();
855
        } catch (DataException ex) {
856
            throw new RuntimeException("Can't get selection of the FeatureTableModel",ex);
857
        }
858
    }
859
    
860
    
861
}