Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_controls / src / org / gvsig / fmap / data / feature / swing / table / FeatureTableModel.java @ 27382

History | View | Annotate | Download (13.5 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Gobernment (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.data.feature.swing.table;
28

    
29
import javax.swing.table.AbstractTableModel;
30

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

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

    
56
    private static final long serialVersionUID = -2488157521902851301L;
57

    
58
    private FeaturePagingHelper helper;
59

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

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

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

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

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

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

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

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

    
155
    public Class<?> getColumnClass(int columnIndex) {
156
        // Return the class of the FeatureAttributeDescriptor for the value
157
        FeatureAttributeDescriptor attributeDesc = getDescriptorForColumn(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 = getDescriptorForColumn(column);
165
        return attributeDesc.getName();
166
    }
167

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

    
175
        return false;
176
    }
177

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

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

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

    
238
    public void update(Observable observable, Object notification) {
239
        if (observable.equals(getFeatureStore())
240
                && notification instanceof FeatureStoreNotification) {
241
            FeatureStoreNotification fsNotification = (FeatureStoreNotification) notification;
242
            String type = fsNotification.getType();
243

    
244
            System.out.println("FeatureTableModel.update(): " + type);
245
            // If there are new, updated or deleted features
246
            // reload the table data
247
            if (FeatureStoreNotification.AFTER_DELETE.equals(type)
248
                    || FeatureStoreNotification.AFTER_INSERT.equals(type)
249
                    || FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
250

    
251
                reloadIfFeatureChanged(fsNotification.getFeature());
252

    
253
            } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
254

    
255
                reloadIfTypeChanged(fsNotification.getFeatureType());
256

    
257
            } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)) {
258
                reloadIfTypeTransformed();
259

    
260
            } else if (FeatureStoreNotification.AFTER_FINISHEDITING
261
                                        .equals(type)
262
                                        || FeatureStoreNotification.AFTER_CANCELEDITING
263
                                                        .equals(type)) {
264
                    reloadIfTypeTransformed();
265
            }
266

    
267
        }
268
    }
269

    
270
    /**
271
     * Returns the FeatureStore of the Collection.
272
     *
273
     * @return the FeatureStore
274
     */
275
    public FeatureStore getFeatureStore() {
276
        return getHelper().getFeatureStore();
277
    }
278

    
279
    /**
280
     * Returns the descriptor of a Feature attribute for a table column.
281
     *
282
     * @param columnIndex
283
     *            the column index
284
     */
285
    public FeatureAttributeDescriptor getDescriptorForColumn(int columnIndex) {
286
        return getFeatureType().getAttributeDescriptor(columnIndex);
287
    }
288

    
289
    /**
290
     * Initialize the TableModel
291
     */
292
    protected void initialize() {
293
        // Add as observable to the FeatureStore, to detect data and selection
294
        // changes
295
        helper.getFeatureStore().addObserver(this);
296
    }
297

    
298
    /**
299
     * Returns the value of a Feature attribute, at the given position.
300
     *
301
     * @param feature
302
     *            the feature to get the value from
303
     * @param columnIndex
304
     *            the Feature attribute position
305
     * @return the value
306
     */
307
    protected Object getFeatureValue(Feature feature, int columnIndex) {
308
        return feature.get(columnIndex);
309
    }
310

    
311
    /**
312
     * Sets the value of an Feature attribute at the given position.
313
     *
314
     * @param feature
315
     *            the feature to update
316
     * @param columnIndex
317
     *            the attribute position
318
     * @param value
319
     *            the value to set
320
     * @throws IsNotFeatureSettingException
321
     *             if there is an error setting the value
322
     */
323
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
324
            Object value) {
325
        EditableFeature editableFeature = feature.getEditable();
326
        editableFeature.set(columnIndex, value);
327
        return editableFeature;
328
    }
329

    
330
    /**
331
     * Returns the FeatureSet used to get the data.
332
     *
333
     * @return the FeatureSet
334
     */
335
    protected FeatureSet getFeatureSet() {
336
        return getHelper().getFeatureSet();
337
    }
338

    
339
    /**
340
     * Returns the FeatureQuery used to get the Features.
341
     *
342
     * @return the FeatureQuery
343
     */
344
    protected FeatureQuery getFeatureQuery() {
345
        return getHelper().getFeatureQuery();
346
    }
347

    
348
    /**
349
     * Returns the type of the features.
350
     */
351
    private FeatureType getFeatureType() {
352
        return getHelper().getFeatureType();
353
    }
354

    
355
    /**
356
     * Reloads the table data if a feature has been changed, not through the
357
     * table.
358
     */
359
    private void reloadIfFeatureChanged(Feature feature) {
360
        // Is any data is changed in the FeatureStore, notify the model
361
                // listeners. Ignore the case where the updated feature is
362
                // changed through us.
363
                if (editableFeature == null || !editableFeature.equals(feature)) {
364
                        reloadFeatures();
365
                        fireTableDataChanged();
366
                }
367
    }
368

    
369
    /**
370
     * Reloads data and structure if the {@link FeatureType} of the features
371
     * being shown has changed.
372
     */
373
    private void reloadIfTypeChanged(FeatureType updatedType) {
374
        // If the updated featured type is the one currently being
375
        // shown, reload the table.
376
                if (updatedType != null
377
                                && updatedType.getId().equals(getFeatureType().getId())) {
378
            setFeatureType(updatedType);
379
        }
380
    }
381

    
382
    /**
383
     * Reloads data and structure if the {@link FeatureType} of the features
384
     * being shown has been transformed.
385
     */
386
    private void reloadIfTypeTransformed() {
387
                try {
388
                        setFeatureType(getHelper().getFeatureStore().getFeatureType(
389
                                        getHelper().getFeatureType().getId()));
390
                } catch (DataException e) {
391
                        throw new FeaturesDataReloadException(e);
392
                }
393
    }
394

    
395
    /**
396
     * Reloads the features shown on the table.
397
     */
398
    private void reloadFeatures() {
399
        try {
400
            getHelper().reload();
401
        } catch (DataException ex) {
402
            throw new FeaturesDataReloadException(ex);
403
        }
404
    }
405
}