Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_controls / src / org / gvsig / fmap / mapcontrol / dal / feature / swing / table / FeatureTableModel.java @ 38383

History | View | Annotate | Download (14.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
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 2
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
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {DiSiD Technologies}  {Create a JTable TableModel for a FeatureCollection}
26
 */
27
package org.gvsig.fmap.mapcontrol.dal.feature.swing.table;
28

    
29
import javax.swing.event.TableModelEvent;
30
import javax.swing.table.AbstractTableModel;
31

    
32
import org.gvsig.fmap.dal.DALLocator;
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.feature.EditableFeature;
35
import org.gvsig.fmap.dal.feature.Feature;
36
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
37
import org.gvsig.fmap.dal.feature.FeatureQuery;
38
import org.gvsig.fmap.dal.feature.FeatureSet;
39
import org.gvsig.fmap.dal.feature.FeatureStore;
40
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
41
import org.gvsig.fmap.dal.feature.FeatureType;
42
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
43
import org.gvsig.tools.exception.BaseException;
44
import org.gvsig.tools.observer.Observable;
45
import org.gvsig.tools.observer.Observer;
46

    
47
/**
48
 * TableModel to access data of Features.
49
 * 
50
 * This table model can't handle a FeatureSet with more than Integer.MAX_VALUE
51
 * elements. In that case, only the first Integer.MAX_VALUE elements will be
52
 * shown.
53
 * 
54
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
55
 */
56
public class FeatureTableModel extends AbstractTableModel implements Observer {
57

    
58
    private static final long serialVersionUID = -2488157521902851301L;
59

    
60
    private FeaturePagingHelper helper;
61

    
62
    /** Used to know if a modification in the FeatureStore is created by us. */
63
    private EditableFeature editableFeature;
64

    
65
    /**
66
     * Constructs a TableModel from the features of a FeatureStore, with the
67
     * default page size.
68
     * 
69
     * @param featureStore
70
     *            to extract the features from
71
     * @param featureQuery
72
     *            the query to get the features from the store
73
     * @throws BaseException
74
     *             if there is an error reading data from the FeatureStore
75
     */
76
    public FeatureTableModel(FeatureStore featureStore,
77
        FeatureQuery featureQuery) throws BaseException {
78
        this(featureStore, featureQuery, FeaturePagingHelper.DEFAULT_PAGE_SIZE);
79
    }
80

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

    
100
    /**
101
     * Constructs a TableModel from a FeatureCollection and a Paging helper.
102
     * 
103
     * @param featureCollection
104
     *            to extract data from
105
     * @param helper
106
     *            the paging helper
107
     * @throws DataException
108
     *             if there is an error reading data from the FeatureStore
109
     */
110
    protected FeatureTableModel(FeaturePagingHelper helper) {
111
        this.helper = helper;
112
        initialize();
113
    }
114

    
115
    public int getColumnCount() {
116
        // Return the number of fields of the Features
117
        FeatureType featureType = getFeatureType();
118
        return featureType.size();
119
    }
120

    
121
    public int getRowCount() {
122
        // Return the total size of the collection
123
        // If the size is bigger than INTEGER.MAX_VALUE, return that instead
124
        long totalSize = getHelper().getTotalSize();
125
        if (totalSize > Integer.MAX_VALUE) {
126
            return Integer.MAX_VALUE;
127
        } else {
128
            return (int) totalSize;
129
        }
130
    }
131

    
132
    public Object getValueAt(int rowIndex, int columnIndex) {
133
        // Get the Feature at row "rowIndex", and return the value of the
134
        // attribute at "columnIndex"
135
        Feature feature = getFeatureAt(rowIndex);
136
        return getFeatureValue(feature, columnIndex);
137
    }
138

    
139
    /**
140
     * Returns the value for a row position.
141
     * 
142
     * @param rowIndex
143
     *            the row position
144
     * @return the Feature
145
     */
146
    public Feature getFeatureAt(int rowIndex) {
147
        try {
148
            return getHelper().getFeatureAt(rowIndex);
149
        } catch (BaseException ex) {
150
            throw new GetFeatureAtException(rowIndex, ex);
151
        }
152
    }
153

    
154
    public Class<?> getColumnClass(int columnIndex) {
155
        // Return the class of the FeatureAttributeDescriptor for the value
156
        FeatureAttributeDescriptor attributeDesc =
157
            internalGetFeatureDescriptorForColumn(columnIndex);
158
        Class<?> clazz = attributeDesc.getObjectClass();
159
        return (clazz == null ? super.getColumnClass(columnIndex) : clazz);
160
    }
161

    
162
    public String getColumnName(int column) {
163
        // Return the Feature attribute name
164
        FeatureAttributeDescriptor attributeDesc =
165
            internalGetFeatureDescriptorForColumn(column);
166
        return attributeDesc.getName();
167
    }
168

    
169
    @Override
170
    public boolean isCellEditable(int rowIndex, int columnIndex) {
171
        if (getFeatureStore().isEditing()) {
172
            FeatureAttributeDescriptor attributeDesc =
173
                internalGetFeatureDescriptorForColumn(columnIndex);
174
            return !attributeDesc.isReadOnly();
175
        }
176

    
177
        return false;
178
    }
179

    
180
    @Override
181
    public void setValueAt(Object value, int rowIndex, int columnIndex) {
182
        // Get the feature at rowIndex
183
        Feature feature = getFeatureAt(rowIndex);
184
        // Only set the value if the feature exists
185
        if (feature != null) {
186
            // We only need to update if the value to set is not equal to the
187
            // current value
188
            Object currentValue = getFeatureValue(feature, columnIndex);
189
            if (value != currentValue
190
                && (value == null || !value.equals(currentValue))) {
191
                try {
192
                    // Store the editable feature to ignore the related store
193
                    // change notification
194
                    editableFeature =
195
                        setFeatureValue(feature, columnIndex, value);
196
                    this.getHelper().update(editableFeature);
197
                    // We'll have already received the event, so we can forget
198
                    // about it
199
                    editableFeature = null;
200
                    getHelper().reloadCurrentPage();
201
                    fireTableCellUpdated(rowIndex, columnIndex);
202
                } catch (BaseException ex) {
203
                    throw new SetFeatureValueException(rowIndex, columnIndex,
204
                        value, ex);
205
                } finally {
206
                    // Just in case
207
                    editableFeature = null;
208
                }
209
            }
210
        }
211
    }
212

    
213
    /**
214
     * Returns a reference to the Paging Helper used to load the data from the
215
     * DataStore.
216
     * 
217
     * @return the paging helper
218
     */
219
    public FeaturePagingHelper getHelper() {
220
        return helper;
221
    }
222

    
223
    /**
224
     * Sets the FeatureType to show in the table. Used for FeatureStores with
225
     * many simultaneous FeatureTypes supported. Will cause a reload of the
226
     * current data.
227
     * 
228
     * @param featureType
229
     *            the FeatureType of the Features
230
     * @throws DataException
231
     *             if there is an error loading the data
232
     */
233
    public void setFeatureType(FeatureType featureType) {
234
        getFeatureQuery().setFeatureType(featureType);
235
        reloadFeatures();
236
        fireTableStructureChanged();
237
    }
238

    
239
    /**
240
     * Sets that the selected Features get returned first.
241
     */
242
    public void setSelectionUp(boolean selectionUp) {
243
        getHelper().setSelectionUp(selectionUp);
244
        fireTableChanged(new TableModelEvent(this, 0, getRowCount() - 1));
245
    }
246

    
247
    public void update(Observable observable, Object notification) {
248
        if (observable.equals(getFeatureStore())
249
            && notification instanceof FeatureStoreNotification) {
250
            FeatureStoreNotification fsNotification =
251
                (FeatureStoreNotification) notification;
252
            String type = fsNotification.getType();
253

    
254
            // If there are new, updated or deleted features
255
            // reload the table data
256
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
257
                || FeatureStoreNotification.AFTER_INSERT.equals(type)) {
258

    
259
                reloadIfFeatureCountChanged(fsNotification.getFeature());
260

    
261
            } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
262
                    
263
                    reloadIfFeatureUpdated(fsNotification.getFeature());
264
                    
265
            } else
266
                if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
267

    
268
                    reloadIfTypeChanged(fsNotification.getFeatureType());
269

    
270
                } else
271
                    if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)
272
                        // || FeatureStoreNotification.AFTER_UNDO.equals(type)
273
                        || FeatureStoreNotification.AFTER_REFRESH.equals(type)) {
274
                        
275
                        reloadFeatureType();
276

    
277
                    } else
278
                        if (FeatureStoreNotification.AFTER_FINISHEDITING.equals(type)
279
                            || FeatureStoreNotification.AFTER_CANCELEDITING.equals(type)) {
280
                            
281
                            reloadFeatureType();
282
                        }
283

    
284
        }
285
    }
286

    
287
    /**
288
     * Returns the FeatureStore of the Collection.
289
     * 
290
     * @return the FeatureStore
291
     */
292
    public FeatureStore getFeatureStore() {
293
        return getHelper().getFeatureStore();
294
    }
295

    
296
    /**
297
     * Returns the descriptor of a Feature attribute for a table column.
298
     * 
299
     * @param columnIndex
300
     *            the column index
301
     */
302
    public FeatureAttributeDescriptor getDescriptorForColumn(int columnIndex) {
303
        return internalGetFeatureDescriptorForColumn(columnIndex);
304
    }
305

    
306
    /**
307
     * @param columnIndex
308
     * @return
309
     */
310
    protected FeatureAttributeDescriptor internalGetFeatureDescriptorForColumn(
311
        int columnIndex) {
312
        return getFeatureType().getAttributeDescriptor(columnIndex);
313
    }
314

    
315
    /**
316
     * Initialize the TableModel
317
     */
318
    protected void initialize() {
319
        // Add as observable to the FeatureStore, to detect data and selection
320
        // changes
321
        helper.getFeatureStore().addObserver(this);
322
    }
323

    
324
    /**
325
     * Returns the value of a Feature attribute, at the given position.
326
     * 
327
     * @param feature
328
     *            the feature to get the value from
329
     * @param columnIndex
330
     *            the Feature attribute position
331
     * @return the value
332
     */
333
    protected Object getFeatureValue(Feature feature, int columnIndex) {
334
        return feature.get(columnIndex);
335
    }
336

    
337
    /**
338
     * Sets the value of an Feature attribute at the given position.
339
     * 
340
     * @param feature
341
     *            the feature to update
342
     * @param columnIndex
343
     *            the attribute position
344
     * @param value
345
     *            the value to set
346
     * @throws IsNotFeatureSettingException
347
     *             if there is an error setting the value
348
     */
349
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
350
        Object value) {
351
        EditableFeature editableFeature = feature.getEditable();
352
        editableFeature.set(columnIndex, value);
353
        return editableFeature;
354
    }
355

    
356
    /**
357
     * Returns the FeatureSet used to get the data.
358
     * 
359
     * @return the FeatureSet
360
     */
361
    protected FeatureSet getFeatureSet() {
362
        return getHelper().getFeatureSet();
363
    }
364

    
365
    /**
366
     * Returns the FeatureQuery used to get the Features.
367
     * 
368
     * @return the FeatureQuery
369
     */
370
    public FeatureQuery getFeatureQuery() {
371
        return getHelper().getFeatureQuery();
372
    }
373

    
374
    /**
375
     * Returns the type of the features.
376
     */
377
    private FeatureType getFeatureType() {
378
        return getHelper().getFeatureType();
379
    }
380

    
381
    /**
382
     * Reloads the table data if a feature has been changed, not through the
383
     * table.
384
     */
385
    private void reloadIfFeatureCountChanged(Feature feature) {
386
        // Is any data is changed in the FeatureStore, notify the model
387
        // listeners. Ignore the case where the updated feature is
388
        // changed through us.
389
        if (editableFeature == null || !editableFeature.equals(feature)) {
390
            reloadFeatures();            
391
            fireTableDataChanged();
392
        }
393
    }
394
    
395
    private void reloadIfFeatureUpdated(Feature feature) {
396
        // Is any data is changed in the FeatureStore, notify the model
397
        // listeners. Ignore the case where the updated feature is
398
        // changed through us.
399
        if (editableFeature == null || !editableFeature.equals(feature)) {
400
            reloadFeatures();
401
            fireTableChanged(new TableModelEvent(this, 0, getRowCount()));            
402
        }
403
    }
404

    
405
    /**
406
     * Reloads data and structure if the {@link FeatureType} of the features
407
     * being shown has changed.
408
     */
409
    private void reloadIfTypeChanged(FeatureType updatedType) {
410
        // If the updated featured type is the one currently being
411
        // shown, reload the table.
412
        if (updatedType != null
413
            && updatedType.getId().equals(getFeatureType().getId())) {
414
            setFeatureType(updatedType);
415
        }
416
    }
417

    
418

    
419

    
420
    private void reloadFeatureType() {
421
        try {
422
            setFeatureType(getHelper().getFeatureStore().getFeatureType(
423
                getHelper().getFeatureType().getId()));
424
        } catch (DataException e) {
425
            throw new FeaturesDataReloadException(e);
426
        }
427
    }
428

    
429
    /**
430
     * Reloads the features shown on the table.
431
     */
432
    private void reloadFeatures() {
433
        try {
434
            getHelper().reload();
435
        } catch (BaseException ex) {
436
            throw new FeaturesDataReloadException(ex);
437
        }
438
    }
439
}