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
/* 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
            } else
265
                if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
266

    
267
                    reloadIfTypeChanged(fsNotification.getFeatureType());
268

    
269
                } else
270
                    if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)) {
271
                        reloadIfTypeTransformed();
272

    
273
                    } else
274
                        if (FeatureStoreNotification.AFTER_FINISHEDITING
275
                            .equals(type)
276
                            || FeatureStoreNotification.AFTER_CANCELEDITING
277
                                .equals(type)) {
278
                            reloadIfTypeTransformed();
279
                        }
280

    
281
        }
282
    }
283

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

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

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

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

    
321
    /**
322
     * Returns the value of a Feature attribute, at the given position.
323
     * 
324
     * @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
     * 
337
     * @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
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
347
        Object value) {
348
        EditableFeature editableFeature = feature.getEditable();
349
        editableFeature.set(columnIndex, value);
350
        return editableFeature;
351
    }
352

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

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

    
371
    /**
372
     * Returns the type of the features.
373
     */
374
    private FeatureType getFeatureType() {
375
        return getHelper().getFeatureType();
376
    }
377

    
378
    /**
379
     * Reloads the table data if a feature has been changed, not through the
380
     * table.
381
     */
382
    private void reloadIfFeatureCountChanged(Feature feature) {
383
        // Is any data is changed in the FeatureStore, notify the model
384
        // listeners. Ignore the case where the updated feature is
385
        // changed through us.
386
        if (editableFeature == null || !editableFeature.equals(feature)) {
387
            reloadFeatures();            
388
            fireTableDataChanged();
389
        }
390
    }
391
    
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

    
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
        if (updatedType != null
410
            && updatedType.getId().equals(getFeatureType().getId())) {
411
            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
    private void reloadIfTypeTransformed() {
420
        try {
421
            setFeatureType(getHelper().getFeatureStore().getFeatureType(
422
                getHelper().getFeatureType().getId()));
423
        } catch (DataException e) {
424
            throw new FeaturesDataReloadException(e);
425
        }
426
    }
427

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