Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.fmap.control / src / main / java / org / gvsig / fmap / mapcontrol / dal / feature / swing / table / FeatureTableModel.java @ 42775

History | View | Annotate | Download (26.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
 * AUTHORS (In addition to CIT):
26
 * 2008 {DiSiD Technologies}  {Create a JTable TableModel for a FeatureCollection}
27
 */
28
package org.gvsig.fmap.mapcontrol.dal.feature.swing.table;
29

    
30
import java.awt.event.ActionEvent;
31
import java.awt.event.ActionListener;
32

    
33
import javax.swing.SwingUtilities;
34
import javax.swing.Timer;
35
import javax.swing.event.TableModelEvent;
36
import javax.swing.table.AbstractTableModel;
37

    
38
import org.gvsig.fmap.dal.DALLocator;
39
import org.gvsig.fmap.dal.EditingNotification;
40
import org.gvsig.fmap.dal.EditingNotificationManager;
41
import org.gvsig.fmap.dal.exception.DataException;
42
import org.gvsig.fmap.dal.feature.EditableFeature;
43
import org.gvsig.fmap.dal.feature.Feature;
44
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
45
import org.gvsig.fmap.dal.feature.FeatureQuery;
46
import org.gvsig.fmap.dal.feature.FeatureStore;
47
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
48
import org.gvsig.fmap.dal.feature.FeatureType;
49
import org.gvsig.fmap.dal.feature.exception.ConcurrentDataModificationException;
50
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
51
import org.gvsig.fmap.dal.swing.DALSwingLocator;
52
import org.gvsig.tools.exception.BaseException;
53
import org.gvsig.tools.observer.ComplexNotification;
54
import org.gvsig.tools.observer.ComplexObserver;
55
import org.gvsig.tools.observer.Observable;
56
import org.slf4j.Logger;
57
import org.slf4j.LoggerFactory;
58

    
59
/**
60
 * TableModel to access data of Features.
61
 *
62
 * This table model can't handle a FeatureSet with more than Integer.MAX_VALUE
63
 * elements. In that case, only the first Integer.MAX_VALUE elements will be
64
 * shown.
65
 *
66
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
67
 */
68
public class FeatureTableModel extends AbstractTableModel implements ComplexObserver {
69

    
70

    
71
        private static final Logger logger = LoggerFactory
72
                        .getLogger(FeatureTableModel.class);
73

    
74
    private static final long serialVersionUID = -2488157521902851301L;
75

    
76
    private FeaturePagingHelper helper;
77

    
78
    /** Used to know if a modification in the FeatureStore is created by us. */
79
    private EditableFeature editableFeature;
80

    
81
    private boolean selectionLocked=false;
82

    
83
    /**
84
     * Constructs a TableModel from the features of a FeatureStore, with the
85
     * default page size.
86
     *
87
     * @param featureStore
88
     *            to extract the features from
89
     * @param featureQuery
90
     *            the query to get the features from the store
91
     * @throws BaseException
92
     *             if there is an error reading data from the FeatureStore
93
     */
94
    public FeatureTableModel(FeatureStore featureStore,
95
        FeatureQuery featureQuery) throws BaseException {
96
        this(featureStore, featureQuery, FeaturePagingHelper.DEFAULT_PAGE_SIZE);
97
    }
98

    
99
    /**
100
     * Constructs a TableModel from the features of a FeatureStore, with the
101
     * default page size.
102
     *
103
     * @param featureStore
104
     *            to extract the features from
105
     * @param featureQuery
106
     *            the query to get the features from the store
107
     * @param pageSize
108
     *            the number of elements per page data
109
     * @throws BaseException
110
     *             if there is an error reading data from the FeatureStore
111
     */
112
    public FeatureTableModel(FeatureStore featureStore,
113
        FeatureQuery featureQuery, int pageSize) throws BaseException {
114
        this(DALLocator.getDataManager().createFeaturePagingHelper(
115
            featureStore, featureQuery, pageSize));
116
    }
117

    
118
    /**
119
     * Constructs a TableModel from a FeatureCollection and a Paging helper.
120
     *
121
     * @param featureCollection
122
     *            to extract data from
123
     * @param helper
124
     *            the paging helper
125
     * @throws DataException
126
     *             if there is an error reading data from the FeatureStore
127
     */
128
    protected FeatureTableModel(FeaturePagingHelper helper) {
129
        this.helper = helper;
130
        initialize();
131
    }
132

    
133
    public int getColumnCount() {
134
        // Return the number of fields of the Features
135
        FeatureType featureType = getFeatureType();
136
        return featureType.size();
137
    }
138

    
139
    public int getRowCount() {
140
        // Return the total size of the collection
141
        // If the size is bigger than INTEGER.MAX_VALUE, return that instead
142
            try {
143
                long totalSize = getHelper().getTotalSize();
144
                if (totalSize > Integer.MAX_VALUE) {
145
                    return Integer.MAX_VALUE;
146
                } else {
147
                    return (int) totalSize;
148
                }
149
            } catch (ConcurrentDataModificationException e) {
150
                        logger.debug("Error while getting the total size of the set", e);
151
                        return 0;
152
                }
153
    }
154

    
155
    public Object getValueAt(int rowIndex, int columnIndex) {
156
        // Get the Feature at row "rowIndex", and return the value of the
157
        // attribute at "columnIndex"
158
        Feature feature = getFeatureAt(rowIndex);
159
        return feature == null ? null : getFeatureValue(feature, columnIndex);
160
    }
161

    
162
    /**
163
     * Returns the value for a row position.
164
     *
165
     * @param rowIndex
166
     *            the row position
167
     * @return the Feature
168
     */
169
    public Feature getFeatureAt(int rowIndex) {
170
        try {
171
            return getHelper().getFeatureAt(rowIndex);
172
        } catch (BaseException ex) {
173
            throw new GetFeatureAtException(rowIndex, ex);
174
        }
175
    }
176

    
177
    public Class<?> getColumnClass(int columnIndex) {
178
        // Return the class of the FeatureAttributeDescriptor for the value
179
        FeatureAttributeDescriptor attributeDesc =
180
            internalGetFeatureDescriptorForColumn(columnIndex);
181
        if (attributeDesc == null) {
182
                return super.getColumnClass(columnIndex);
183
        }
184
        Class<?> clazz = attributeDesc.getObjectClass();
185
        return (clazz == null ? super.getColumnClass(columnIndex) : clazz);
186
    }
187

    
188
    public String getColumnName(int column) {
189
        // Return the Feature attribute name
190
        FeatureAttributeDescriptor attributeDesc =
191
            internalGetFeatureDescriptorForColumn(column);
192
        return attributeDesc.getName();
193
    }
194

    
195
    @Override
196
    public boolean isCellEditable(int rowIndex, int columnIndex) {
197
        if (getFeatureStore().isEditing()) {
198
            FeatureAttributeDescriptor attributeDesc =
199
                internalGetFeatureDescriptorForColumn(columnIndex);
200
            return !attributeDesc.isReadOnly();
201
        }
202

    
203
        return false;
204
    }
205

    
206
    @Override
207
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
208
        // Get the feature at rowIndex
209
        Feature feature = getFeatureAt(rowIndex);
210
        // Only set the value if the feature exists
211
        if (feature != null) {
212
            // We only need to update if the value to set is not equal to the
213
            // current value
214
            Object currentValue = getFeatureValue(feature, columnIndex);
215
            if (value != currentValue
216
                && (value == null || !value.equals(currentValue))) {
217
                try {
218
                    // Store the editable feature to ignore the related store
219
                    // change notification
220
                    editableFeature =
221
                        setFeatureValue(feature, columnIndex, value);
222
                    EditingNotificationManager editingNotificationManager = DALSwingLocator.getEditingNotificationManager();
223
                    EditingNotification notification = editingNotificationManager.notifyObservers(
224
                            this,
225
                            EditingNotification.BEFORE_UPDATE_FEATURE,
226
                            null,
227
                            this.getHelper().getFeatureStore(),
228
                            editableFeature);
229
                    if( notification.isCanceled() ) {
230
                        return;
231
                    }
232
                    if( notification.shouldValidateTheFeature() ) {
233
                        if ( !editingNotificationManager.validateFeature(feature) ) {
234
                            return;
235
                        }
236
                    }
237
                    this.getHelper().update(editableFeature);
238
                    // We'll have already received the event, so we can forget
239
                    // about it
240
                    getHelper().reloadCurrentPage();
241
                    fireTableCellUpdated(rowIndex, columnIndex);
242

    
243
                    editingNotificationManager.notifyObservers(
244
                            this,
245
                            EditingNotification.AFTER_UPDATE_FEATURE,
246
                            null,
247
                            this.getHelper().getFeatureStore(),
248
                            editableFeature);
249
                    editableFeature = null;
250

    
251
                } catch (BaseException ex) {
252
                    throw new SetFeatureValueException(rowIndex, columnIndex,
253
                        value, ex);
254
                } finally {
255
                    // Just in case
256
                    editableFeature = null;
257
                }
258
            }
259
        }
260
    }
261

    
262
    /**
263
     * Returns a reference to the Paging Helper used to load the data from the
264
     * DataStore.
265
     *
266
     * @return the paging helper
267
     */
268
    public FeaturePagingHelper getHelper() {
269
        return helper;
270
    }
271

    
272
    /**
273
     * Sets the FeatureType to show in the table. Used for FeatureStores with
274
     * many simultaneous FeatureTypes supported. Will cause a reload of the
275
     * current data.
276
     *
277
     * @param featureType
278
     *            the FeatureType of the Features
279
     * @throws DataException
280
     *             if there is an error loading the data
281
     */
282
    public void setFeatureType(FeatureType featureType) {
283
        getFeatureQuery().setFeatureType(featureType);
284
        reloadFeatures();
285
        //Selection must be locked to avoid losing it when the table is refreshed
286
        selectionLocked=true;
287
        //The table is refreshed
288
        try {
289
            fireTableStructureChanged();
290
        } catch (Exception e) {
291
            logger.warn("Couldn't reload changed table");
292
        }finally{
293
            //The locked selection is unlocked.
294
            selectionLocked=false;
295
        }
296
    }
297

    
298
    /**
299
     * Sets that the selected Features get returned first.
300
     */
301
    public void setSelectionUp(boolean selectionUp) {
302
        getHelper().setSelectionUp(selectionUp);
303
        fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1));
304
    }
305

    
306
    private class DelayAction extends Timer implements ActionListener, Runnable {
307
        private static final int STATE_NONE = 0;
308
        private static final int STATE_NEED_RELOADALL = 1;
309
        private static final int STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED = 2;
310
        private static final int STATE_NEED_RELOAD_IF_FEATURE_UPDATED = 4;
311
        private static final int STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED = 8;
312
        private static final int STATE_NEED_RELOAD_FEATURE_TYPE = 16;
313
        private static final int STATE_NEED_SELECTION_UP = 32;
314
        private static final int STATE_NEED_RELOAD_ALL_FEATURES=64;
315

    
316
        private int state = STATE_NONE;
317
        private Feature feature;
318
        private FeatureType featureType;
319
        private boolean isSelecctionUp;
320

    
321
        public DelayAction() {
322
            super(1000,null);
323
            this.setRepeats(false);
324
            this.reset();
325
            this.addActionListener(this);
326
        }
327

    
328
        public void reset() {
329
            this.state = STATE_NONE;
330
            this.isSelecctionUp = false;
331
            this.feature = null;
332
            this.featureType = null;
333
        }
334

    
335
        public void actionPerformed(ActionEvent ae) {
336
            this.run();
337
        }
338

    
339
        public void run() {
340
            if( !SwingUtilities.isEventDispatchThread() ) {
341
                SwingUtilities.invokeLater(this);
342
                return;
343
            }
344
            this.stop();
345
            logger.info("DelayAction.run["+this.state+"] begin");
346
            switch(this.state) {
347
            case STATE_NEED_RELOADALL:
348
                reloadAll();
349
                break;
350
            case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
351
                reloadIfFeatureCountChanged(feature);
352
                break;
353
            case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
354
                reloadIfFeatureUpdated(feature);
355
                break;
356
            case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
357
                reloadIfTypeChanged(featureType);
358
                break;
359
            case STATE_NEED_RELOAD_FEATURE_TYPE:
360
                reloadFeatureType();
361
                updatePaginHelperWithHiddenColums();
362
                break;
363
            case STATE_NEED_RELOAD_ALL_FEATURES:
364
                reloadFeatures();
365
                fireTableChanged(new TableModelEvent(FeatureTableModel.this, 0, getRowCount()));
366
                break;
367
            case STATE_NEED_SELECTION_UP:
368
            case STATE_NONE:
369
            default:
370
                break;
371
            }
372
            if( isSelecctionUp ) {
373
                getHelper().setSelectionUp(true);
374
            }
375
            this.reset();
376
            logger.info("DelayAction.run["+this.state+"] end");
377
        }
378

    
379
        public void nextState(int nextstate) {
380
            this.nextState(nextstate, null, null);
381
        }
382

    
383
        public void nextState(int nextstate, Feature feature) {
384
            this.nextState(nextstate, feature, null);
385
        }
386

    
387
        public void nextState(int nextstate, FeatureType featureType) {
388
            this.nextState(nextstate, null, featureType);
389
        }
390

    
391
        public void nextState(int nextstate, Feature feature, FeatureType featureType) {
392
            this.feature = feature;
393
            this.featureType = featureType;
394
            switch(nextstate) {
395
            case STATE_NEED_RELOADALL:
396
            case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
397
            case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
398
                switch(this.state) {
399
                case STATE_NEED_RELOADALL:
400
                case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
401
                //case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
402
                    this.state = STATE_NEED_RELOADALL;
403
                    break;
404
                case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
405
                case STATE_NEED_RELOAD_FEATURE_TYPE:
406
                    this.state = STATE_NEED_RELOAD_FEATURE_TYPE;
407
                    break;
408
                case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
409
                case STATE_NEED_RELOAD_ALL_FEATURES:
410
                    this.state=STATE_NEED_RELOAD_ALL_FEATURES;
411
                    break;
412
                case STATE_NEED_SELECTION_UP:
413
                    this.state = nextstate;
414
                    this.isSelecctionUp = true;
415
                    break;
416
                case STATE_NONE:
417
                default:
418
                    this.state = nextstate;
419
                    break;
420
                }
421
                break;
422
            case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
423
            case STATE_NEED_RELOAD_FEATURE_TYPE:
424
                switch(this.state) {
425
                case STATE_NEED_RELOADALL:
426
                case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
427
                case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
428
                case STATE_NEED_RELOAD_ALL_FEATURES:
429
                case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
430
                case STATE_NEED_RELOAD_FEATURE_TYPE:
431
                    this.state = STATE_NEED_RELOAD_FEATURE_TYPE;
432
                    break;
433
                case STATE_NEED_SELECTION_UP:
434
                    this.state = nextstate;
435
                    this.isSelecctionUp = true;
436
                    break;
437
                case STATE_NONE:
438
                default:
439
                    this.state = nextstate;
440
                    break;
441
                }
442
                break;
443
            case STATE_NEED_SELECTION_UP:
444
                switch(this.state) {
445
                case STATE_NEED_RELOADALL:
446
                case STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED:
447
                case STATE_NEED_RELOAD_IF_FEATURE_UPDATED:
448
                case STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED:
449
                case STATE_NEED_RELOAD_ALL_FEATURES:
450
                case STATE_NEED_RELOAD_FEATURE_TYPE:
451
                case STATE_NEED_SELECTION_UP:
452
                    this.isSelecctionUp = true;
453
                    break;
454
                case STATE_NONE:
455
                default:
456
                    this.state = nextstate;
457
                    this.isSelecctionUp = true;
458
                    break;
459
                }
460
                break;
461
            case STATE_NONE:
462
            default:
463
                this.state = STATE_NONE;
464
                break;
465
            }
466
            if( this.state != STATE_NONE ) {
467
                this.start();
468
            }
469
        }
470

    
471
    }
472

    
473
    private DelayAction delayAction = new DelayAction();
474

    
475
    public void update(final Observable observable, final Object notification) {
476
        if (notification instanceof ComplexNotification) {
477
            // A lot of things might have happened in the store, so don't
478
            // bother looking into each notification.
479
            this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
480
//            reloadAll();
481
        } else if (observable.equals(getFeatureStore())
482
                && notification instanceof FeatureStoreNotification) {
483
            FeatureStoreNotification fsNotification
484
                    = (FeatureStoreNotification) notification;
485
            String type = fsNotification.getType();
486

    
487
            // If there are new, updated or deleted features
488
            // reload the table data
489
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
490
                    || FeatureStoreNotification.AFTER_INSERT.equals(type)) {
491
//                reloadIfFeatureCountChanged(fsNotification.getFeature());
492
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_COUNT_CHANGED, fsNotification.getFeature());
493

    
494
            } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
495
//                reloadIfFeatureUpdated(fsNotification.getFeature());
496
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_UPDATED, fsNotification.getFeature());
497

    
498
            } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
499
//                reloadIfTypeChanged(fsNotification.getFeatureType());
500
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_IF_FEATURE_TYPE_CHANGED, fsNotification.getFeatureType());
501

    
502
            } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)
503
                    || FeatureStoreNotification.AFTER_UNDO.equals(type)
504
                    || FeatureStoreNotification.AFTER_REDO.equals(type)
505
                    || FeatureStoreNotification.AFTER_REFRESH.equals(type))  {
506
//                reloadAll();
507
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOADALL);
508

    
509
            } else if (FeatureStoreNotification.AFTER_FINISHEDITING.equals(type)
510
                    || FeatureStoreNotification.AFTER_STARTEDITING.equals(type)
511
                    || FeatureStoreNotification.AFTER_CANCELEDITING.equals(type)) {
512
                /*
513
                No tengo nada claro por que es necesario llamar al reloadFeatureType
514
                pero si no se incluye hay problemas si durante la edicion se a?aden
515
                campos a la tabla. Sin esto, al cerrar la edicion, los campos a?adidos
516
                desaparecen de la tabla aunque estan en el fichero.
517
                Ver ticket #2434 https://devel.gvsig.org/redmine/issues/2434
518
                */
519
//                reloadFeatureType();
520
//                updatePaginHelperWithHiddenColums();
521
                this.delayAction.nextState(DelayAction.STATE_NEED_RELOAD_FEATURE_TYPE, fsNotification.getFeatureType());
522
            } else if (FeatureStoreNotification.SELECTION_CHANGE.equals(type)) {
523
                if( this.getHelper().isSelectionUp() ) {
524
                    getHelper().setSelectionUp(true);
525
                    this.delayAction.nextState(DelayAction.STATE_NEED_SELECTION_UP);
526
                }
527
            }
528
        }
529
    }
530

    
531
    protected void updatePaginHelperWithHiddenColums() {
532
        FeatureQuery query = this.getHelper().getFeatureQuery();
533
        if (this.getHelper().getFeatureStore().isEditing()) {
534
            if (query.hasConstantsAttributeNames()) {
535
                query.clearConstantsAttributeNames();
536
            }
537
        } else {
538
            query.setConstantsAttributeNames(this.getHiddenColumnNames());
539
        }
540
        try {
541
            this.getHelper().reload();
542
        } catch (BaseException ex) {
543
            logger.warn("Can't reload paging-helper.", ex);
544
        }
545
    }
546

    
547
    protected String[] getHiddenColumnNames() {
548
        return null;
549
    }
550

    
551
    /**
552
     * Returns the FeatureStore of the Collection.
553
     *
554
     * @return the FeatureStore
555
     */
556
    public FeatureStore getFeatureStore() {
557
        return getHelper().getFeatureStore();
558
    }
559

    
560
    /**
561
     * Returns the descriptor of a Feature attribute for a table column.
562
     *
563
     * @param columnIndex
564
     *            the column index
565
     */
566
    public FeatureAttributeDescriptor getDescriptorForColumn(int columnIndex) {
567
        return internalGetFeatureDescriptorForColumn(columnIndex);
568
    }
569

    
570
    /**
571
     * @param columnIndex
572
     * @return
573
     */
574
        protected FeatureAttributeDescriptor internalGetFeatureDescriptorForColumn(
575
                        int columnIndex) {
576
                FeatureType featureType = getFeatureType();
577
                return featureType == null ? null : featureType
578
                                .getAttributeDescriptor(columnIndex);
579
        }
580

    
581
    /**
582
     * Initialize the TableModel
583
     */
584
    protected void initialize() {
585
        // Add as observable to the FeatureStore, to detect data and selection
586
        // changes
587
        helper.getFeatureStore().addObserver(this);
588
    }
589

    
590
    /**
591
     * Returns the value of a Feature attribute, at the given position.
592
     *
593
     * @param feature
594
     *            the feature to get the value from
595
     * @param columnIndex
596
     *            the Feature attribute position
597
     * @return the value
598
     */
599
    protected Object getFeatureValue(Feature feature, int columnIndex) {
600
        return feature.get(columnIndex);
601
    }
602

    
603
    /**
604
     * Sets the value of an Feature attribute at the given position.
605
     *
606
     * @param feature
607
     *            the feature to update
608
     * @param columnIndex
609
     *            the attribute position
610
     * @param value
611
     *            the value to set
612
     * @throws IsNotFeatureSettingException
613
     *             if there is an error setting the value
614
     */
615
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
616
        Object value) {
617
        EditableFeature editableFeature = feature.getEditable();
618
        editableFeature.set(columnIndex, value);
619
        return editableFeature;
620
    }
621

    
622
    /**
623
     * Returns the FeatureQuery used to get the Features.
624
     *
625
     * @return the FeatureQuery
626
     */
627
    public FeatureQuery getFeatureQuery() {
628
        return getHelper().getFeatureQuery();
629
    }
630

    
631
    /**
632
     * Returns the type of the features.
633
     */
634
    protected FeatureType getFeatureType() {
635
        return getHelper().getFeatureType();
636
    }
637

    
638
    /**
639
     * Reloads the table data if a feature has been changed, not through the
640
     * table.
641
     */
642
    private void reloadIfFeatureCountChanged(Feature feature) {
643
        // Is any data is changed in the FeatureStore, notify the model
644
        // listeners. Ignore the case where the updated feature is
645
        // changed through us.
646
        if (editableFeature == null || !editableFeature.equals(feature)) {
647
            reloadFeatures();
648
            //Selection must be locked to avoid losing it when the table is refreshed
649
            selectionLocked=true;
650
            //The table is refreshed
651
            try {
652
                fireTableDataChanged();
653
            } catch (Exception e) {
654
                logger.warn("Couldn't reload changed table");
655
            }finally{
656
                //The locked selection is unlocked.
657
                selectionLocked=false;
658
            }
659
        }
660
    }
661

    
662
    private void reloadIfFeatureUpdated(Feature feature) {
663
        // Is any data is changed in the FeatureStore, notify the model
664
        // listeners. Ignore the case where the updated feature is
665
        // changed through us.
666
        if (editableFeature == null || !editableFeature.equals(feature)) {
667
            reloadFeatures();
668
            fireTableChanged(new TableModelEvent(this, 0, getRowCount()));
669
        }
670
    }
671

    
672
    /**
673
     * Reloads data and structure if the {@link FeatureType} of the features
674
     * being shown has changed.
675
     */
676
    private void reloadIfTypeChanged(FeatureType updatedType) {
677
        // If the updated featured type is the one currently being
678
        // shown, reload the table.
679
        if (updatedType != null
680
            && updatedType.getId().equals(getFeatureType().getId())) {
681
            setFeatureType(updatedType);
682
        }
683
    }
684

    
685
    private void reloadAll() {
686
            reloadFeatureType();
687
    }
688

    
689
    private void reloadFeatureType() {
690
        try {
691
            setFeatureType(getHelper().getFeatureStore().getFeatureType(
692
                getHelper().getFeatureType().getId()));
693
        } catch (DataException e) {
694
            throw new FeaturesDataReloadException(e);
695
        }
696
    }
697

    
698
    /**
699
     * Reloads the features shown on the table.
700
     */
701
    private void reloadFeatures() {
702
        try {
703
            getHelper().reload();
704
        } catch (BaseException ex) {
705
            throw new FeaturesDataReloadException(ex);
706
        }
707
    }
708

    
709
    /**
710
     * Returns true if selection must not be changed.
711
     * @return
712
     */
713
    public boolean isSelectionLocked() {
714
        return selectionLocked;
715
    }
716

    
717
}