Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_controls / src / org / gvsig / fmap / mapcontrol / dal / feature / swing / table / FeatureTableModel.java @ 37604

History | View | Annotate | Download (14.8 KB)

1 23697 cordinyana
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4 31544 cordinyana
 * of the Valencian Government (CIT)
5 27234 jmvivo
 *
6 23697 cordinyana
 * 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 27234 jmvivo
 *
11 23697 cordinyana
 * 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 27234 jmvivo
 *
16 23697 cordinyana
 * 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 27234 jmvivo
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 23697 cordinyana
 * MA  02110-1301, USA.
20 27234 jmvivo
 *
21 23697 cordinyana
 */
22
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 {DiSiD Technologies}  {Create a JTable TableModel for a FeatureCollection}
26
 */
27 31616 cordinyana
package org.gvsig.fmap.mapcontrol.dal.feature.swing.table;
28 23697 cordinyana
29 33378 cordinyana
import javax.swing.event.TableModelEvent;
30 23697 cordinyana
import javax.swing.table.AbstractTableModel;
31
32 33378 cordinyana
import org.gvsig.fmap.dal.DALLocator;
33 24621 cordinyana
import org.gvsig.fmap.dal.exception.DataException;
34 31034 cordinyana
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 24621 cordinyana
import org.gvsig.fmap.dal.feature.paging.FeaturePagingHelper;
43 33205 cordinyana
import org.gvsig.tools.exception.BaseException;
44 25742 cordinyana
import org.gvsig.tools.observer.Observable;
45
import org.gvsig.tools.observer.Observer;
46 23697 cordinyana
47
/**
48 23799 cordinyana
 * TableModel to access data of Features.
49 33385 cordinyana
 *
50 23991 cordinyana
 * 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 33385 cordinyana
 *
54 23697 cordinyana
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
55
 */
56 25742 cordinyana
public class FeatureTableModel extends AbstractTableModel implements Observer {
57 23697 cordinyana
58
    private static final long serialVersionUID = -2488157521902851301L;
59
60 23715 cordinyana
    private FeaturePagingHelper helper;
61 23697 cordinyana
62 25742 cordinyana
    /** Used to know if a modification in the FeatureStore is created by us. */
63
    private EditableFeature editableFeature;
64
65 23697 cordinyana
    /**
66 24621 cordinyana
     * Constructs a TableModel from the features of a FeatureStore, with the
67
     * default page size.
68 33385 cordinyana
     *
69 24621 cordinyana
     * @param featureStore
70
     *            to extract the features from
71
     * @param featureQuery
72
     *            the query to get the features from the store
73 33385 cordinyana
     * @throws BaseException
74 23697 cordinyana
     *             if there is an error reading data from the FeatureStore
75
     */
76 33385 cordinyana
    public FeatureTableModel(FeatureStore featureStore,
77
        FeatureQuery featureQuery) throws BaseException {
78
        this(featureStore, featureQuery, FeaturePagingHelper.DEFAULT_PAGE_SIZE);
79
    }
80 23697 cordinyana
81
    /**
82 24621 cordinyana
     * Constructs a TableModel from the features of a FeatureStore, with the
83
     * default page size.
84 33385 cordinyana
     *
85 24621 cordinyana
     * @param featureStore
86
     *            to extract the features from
87
     * @param featureQuery
88
     *            the query to get the features from the store
89 23697 cordinyana
     * @param pageSize
90
     *            the number of elements per page data
91 33385 cordinyana
     * @throws BaseException
92 23697 cordinyana
     *             if there is an error reading data from the FeatureStore
93
     */
94 33385 cordinyana
    public FeatureTableModel(FeatureStore featureStore,
95
        FeatureQuery featureQuery, int pageSize) throws BaseException {
96
        this(DALLocator.getDataManager().createFeaturePagingHelper(
97
            featureStore, featureQuery, pageSize));
98
    }
99 23697 cordinyana
100
    /**
101
     * Constructs a TableModel from a FeatureCollection and a Paging helper.
102 33385 cordinyana
     *
103 23697 cordinyana
     * @param featureCollection
104
     *            to extract data from
105
     * @param helper
106
     *            the paging helper
107 23791 cordinyana
     * @throws DataException
108 23697 cordinyana
     *             if there is an error reading data from the FeatureStore
109
     */
110 24621 cordinyana
    protected FeatureTableModel(FeaturePagingHelper helper) {
111 23697 cordinyana
        this.helper = helper;
112 23715 cordinyana
        initialize();
113 23697 cordinyana
    }
114
115
    public int getColumnCount() {
116
        // Return the number of fields of the Features
117
        FeatureType featureType = getFeatureType();
118 23787 cordinyana
        return featureType.size();
119 23697 cordinyana
    }
120
121
    public int getRowCount() {
122 33385 cordinyana
        // 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 23991 cordinyana
        }
130 23697 cordinyana
    }
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 23715 cordinyana
        Feature feature = getFeatureAt(rowIndex);
136
        return getFeatureValue(feature, columnIndex);
137 23697 cordinyana
    }
138
139 25742 cordinyana
    /**
140
     * Returns the value for a row position.
141 33385 cordinyana
     *
142 25742 cordinyana
     * @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 33385 cordinyana
        } catch (BaseException ex) {
150 25742 cordinyana
            throw new GetFeatureAtException(rowIndex, ex);
151
        }
152
    }
153
154 24801 cordinyana
    public Class<?> getColumnClass(int columnIndex) {
155 23697 cordinyana
        // Return the class of the FeatureAttributeDescriptor for the value
156 33385 cordinyana
        FeatureAttributeDescriptor attributeDesc =
157
            internalGetFeatureDescriptorForColumn(columnIndex);
158 24801 cordinyana
        Class<?> clazz = attributeDesc.getObjectClass();
159 23697 cordinyana
        return (clazz == null ? super.getColumnClass(columnIndex) : clazz);
160
    }
161 23715 cordinyana
162 23697 cordinyana
    public String getColumnName(int column) {
163
        // Return the Feature attribute name
164 33385 cordinyana
        FeatureAttributeDescriptor attributeDesc =
165
            internalGetFeatureDescriptorForColumn(column);
166 23697 cordinyana
        return attributeDesc.getName();
167
    }
168
169 23715 cordinyana
    @Override
170
    public boolean isCellEditable(int rowIndex, int columnIndex) {
171 25848 cordinyana
        if (getFeatureStore().isEditing()) {
172 33385 cordinyana
            FeatureAttributeDescriptor attributeDesc =
173
                internalGetFeatureDescriptorForColumn(columnIndex);
174 25848 cordinyana
            return !attributeDesc.isReadOnly();
175
        }
176
177
        return false;
178 23715 cordinyana
    }
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 33385 cordinyana
                && (value == null || !value.equals(currentValue))) {
191 23715 cordinyana
                try {
192 25742 cordinyana
                    // Store the editable feature to ignore the related store
193
                    // change notification
194 33385 cordinyana
                    editableFeature =
195
                        setFeatureValue(feature, columnIndex, value);
196 27234 jmvivo
                    this.getHelper().update(editableFeature);
197 25742 cordinyana
                    // We'll have already received the event, so we can forget
198
                    // about it
199
                    editableFeature = null;
200 23787 cordinyana
                    getHelper().reloadCurrentPage();
201 23715 cordinyana
                    fireTableCellUpdated(rowIndex, columnIndex);
202 33385 cordinyana
                } catch (BaseException ex) {
203 23715 cordinyana
                    throw new SetFeatureValueException(rowIndex, columnIndex,
204 33385 cordinyana
                        value, ex);
205 25742 cordinyana
                } finally {
206
                    // Just in case
207
                    editableFeature = null;
208 23715 cordinyana
                }
209
            }
210
        }
211
    }
212
213
    /**
214 23697 cordinyana
     * Returns a reference to the Paging Helper used to load the data from the
215
     * DataStore.
216 33385 cordinyana
     *
217 23697 cordinyana
     * @return the paging helper
218
     */
219 23715 cordinyana
    public FeaturePagingHelper getHelper() {
220 23697 cordinyana
        return helper;
221
    }
222 23715 cordinyana
223 23697 cordinyana
    /**
224 23787 cordinyana
     * 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 33385 cordinyana
     *
228 23787 cordinyana
     * @param featureType
229
     *            the FeatureType of the Features
230
     * @throws DataException
231
     *             if there is an error loading the data
232
     */
233 25842 cordinyana
    public void setFeatureType(FeatureType featureType) {
234 23787 cordinyana
        getFeatureQuery().setFeatureType(featureType);
235 25842 cordinyana
        reloadFeatures();
236 23787 cordinyana
        fireTableStructureChanged();
237
    }
238
239 33385 cordinyana
    /**
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 33378 cordinyana
247 25742 cordinyana
    public void update(Observable observable, Object notification) {
248
        if (observable.equals(getFeatureStore())
249 33385 cordinyana
            && notification instanceof FeatureStoreNotification) {
250
            FeatureStoreNotification fsNotification =
251
                (FeatureStoreNotification) notification;
252 25742 cordinyana
            String type = fsNotification.getType();
253
254 25842 cordinyana
            // If there are new, updated or deleted features
255
            // reload the table data
256
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
257 37604 jpiera
                || FeatureStoreNotification.AFTER_INSERT.equals(type)) {
258 25842 cordinyana
259 37604 jpiera
                reloadIfFeatureCountChanged(fsNotification.getFeature());
260 25842 cordinyana
261 37604 jpiera
            } else if (FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
262
263
                    reloadIfFeatureUpdated(fsNotification.getFeature());
264 33385 cordinyana
            } else
265
                if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
266 25842 cordinyana
267 33385 cordinyana
                    reloadIfTypeChanged(fsNotification.getFeatureType());
268 25842 cordinyana
269 33385 cordinyana
                } else
270
                    if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)) {
271
                        reloadIfTypeTransformed();
272 25842 cordinyana
273 33385 cordinyana
                    } else
274
                        if (FeatureStoreNotification.AFTER_FINISHEDITING
275
                            .equals(type)
276
                            || FeatureStoreNotification.AFTER_CANCELEDITING
277
                                .equals(type)) {
278
                            reloadIfTypeTransformed();
279
                        }
280 25842 cordinyana
281 25742 cordinyana
        }
282
    }
283
284 23787 cordinyana
    /**
285 25742 cordinyana
     * Returns the FeatureStore of the Collection.
286 33385 cordinyana
     *
287 25742 cordinyana
     * @return the FeatureStore
288 23715 cordinyana
     */
289 25742 cordinyana
    public FeatureStore getFeatureStore() {
290
        return getHelper().getFeatureStore();
291 23715 cordinyana
    }
292
293
    /**
294 25838 cordinyana
     * Returns the descriptor of a Feature attribute for a table column.
295 33385 cordinyana
     *
296 25838 cordinyana
     * @param columnIndex
297
     *            the column index
298
     */
299
    public FeatureAttributeDescriptor getDescriptorForColumn(int columnIndex) {
300 27897 cordinyana
        return internalGetFeatureDescriptorForColumn(columnIndex);
301
    }
302
303
    /**
304
     * @param columnIndex
305
     * @return
306
     */
307
    protected FeatureAttributeDescriptor internalGetFeatureDescriptorForColumn(
308 33385 cordinyana
        int columnIndex) {
309 25838 cordinyana
        return getFeatureType().getAttributeDescriptor(columnIndex);
310
    }
311
312
    /**
313 25742 cordinyana
     * Initialize the TableModel
314 23715 cordinyana
     */
315 25742 cordinyana
    protected void initialize() {
316
        // Add as observable to the FeatureStore, to detect data and selection
317
        // changes
318
        helper.getFeatureStore().addObserver(this);
319 23715 cordinyana
    }
320
321
    /**
322
     * Returns the value of a Feature attribute, at the given position.
323 33385 cordinyana
     *
324 23715 cordinyana
     * @param feature
325
     *            the feature to get the value from
326
     * @param columnIndex
327
     *            the Feature attribute position
328
     * @return the value
329
     */
330
    protected Object getFeatureValue(Feature feature, int columnIndex) {
331
        return feature.get(columnIndex);
332
    }
333
334
    /**
335
     * Sets the value of an Feature attribute at the given position.
336 33385 cordinyana
     *
337 23715 cordinyana
     * @param feature
338
     *            the feature to update
339
     * @param columnIndex
340
     *            the attribute position
341
     * @param value
342
     *            the value to set
343
     * @throws IsNotFeatureSettingException
344
     *             if there is an error setting the value
345
     */
346 23787 cordinyana
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
347 33385 cordinyana
        Object value) {
348 23787 cordinyana
        EditableFeature editableFeature = feature.getEditable();
349
        editableFeature.set(columnIndex, value);
350
        return editableFeature;
351 23715 cordinyana
    }
352
353
    /**
354 23991 cordinyana
     * Returns the FeatureSet used to get the data.
355 33385 cordinyana
     *
356 23991 cordinyana
     * @return the FeatureSet
357 23697 cordinyana
     */
358 23991 cordinyana
    protected FeatureSet getFeatureSet() {
359
        return getHelper().getFeatureSet();
360 23697 cordinyana
    }
361
362
    /**
363 23715 cordinyana
     * Returns the FeatureQuery used to get the Features.
364 33385 cordinyana
     *
365 23715 cordinyana
     * @return the FeatureQuery
366
     */
367 36479 cordinyana
    public FeatureQuery getFeatureQuery() {
368 23715 cordinyana
        return getHelper().getFeatureQuery();
369
    }
370 23787 cordinyana
371 23715 cordinyana
    /**
372 23697 cordinyana
     * Returns the type of the features.
373
     */
374
    private FeatureType getFeatureType() {
375 27234 jmvivo
        return getHelper().getFeatureType();
376 23697 cordinyana
    }
377 25842 cordinyana
378
    /**
379
     * Reloads the table data if a feature has been changed, not through the
380
     * table.
381
     */
382 37604 jpiera
    private void reloadIfFeatureCountChanged(Feature feature) {
383 25842 cordinyana
        // Is any data is changed in the FeatureStore, notify the model
384 33385 cordinyana
        // listeners. Ignore the case where the updated feature is
385
        // changed through us.
386
        if (editableFeature == null || !editableFeature.equals(feature)) {
387 37604 jpiera
            reloadFeatures();
388 33385 cordinyana
            fireTableDataChanged();
389
        }
390 25842 cordinyana
    }
391 37604 jpiera
392
    private void reloadIfFeatureUpdated(Feature feature) {
393
        // Is any data is changed in the FeatureStore, notify the model
394
        // listeners. Ignore the case where the updated feature is
395
        // changed through us.
396
        if (editableFeature == null || !editableFeature.equals(feature)) {
397
            reloadFeatures();
398
            fireTableChanged(new TableModelEvent(this, 0, getRowCount()));
399
        }
400
    }
401 25842 cordinyana
402
    /**
403
     * Reloads data and structure if the {@link FeatureType} of the features
404
     * being shown has changed.
405
     */
406
    private void reloadIfTypeChanged(FeatureType updatedType) {
407
        // If the updated featured type is the one currently being
408
        // shown, reload the table.
409 33385 cordinyana
        if (updatedType != null
410
            && updatedType.getId().equals(getFeatureType().getId())) {
411 25842 cordinyana
            setFeatureType(updatedType);
412
        }
413
    }
414
415
    /**
416
     * Reloads data and structure if the {@link FeatureType} of the features
417
     * being shown has been transformed.
418
     */
419 27310 jmvivo
    private void reloadIfTypeTransformed() {
420 33385 cordinyana
        try {
421
            setFeatureType(getHelper().getFeatureStore().getFeatureType(
422
                getHelper().getFeatureType().getId()));
423
        } catch (DataException e) {
424
            throw new FeaturesDataReloadException(e);
425
        }
426 25842 cordinyana
    }
427
428
    /**
429
     * Reloads the features shown on the table.
430
     */
431
    private void reloadFeatures() {
432
        try {
433
            getHelper().reload();
434 33385 cordinyana
        } catch (BaseException ex) {
435 25842 cordinyana
            throw new FeaturesDataReloadException(ex);
436
        }
437
    }
438 33385 cordinyana
}