Statistics
| Revision:

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

History | View | Annotate | Download (14 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 DataException
74
     *             if there is an error reading data from the FeatureStore
75
     */
76
        public FeatureTableModel(FeatureStore featureStore,
77
                        FeatureQuery featureQuery) throws DataException {
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 DataException
92
     *             if there is an error reading data from the FeatureStore
93
     */
94
        public FeatureTableModel(FeatureStore featureStore,
95
                        FeatureQuery featureQuery, int pageSize) throws DataException {
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
        try {
123
            // Return the total size of the collection
124
            // If the size is bigger than INTEGER.MAX_VALUE, return that instead
125
            long totalSize = getHelper().getTotalSize();
126
            if (totalSize > Integer.MAX_VALUE) {
127
                return Integer.MAX_VALUE;
128
            } else {
129
                return (int) totalSize;
130
            }
131
                } catch (BaseException ex) {
132
            throw new GetRowCountException(ex);
133
        }
134
    }
135

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

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

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

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

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

    
178
        return false;
179
    }
180

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

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

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

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

    
248
    public void update(Observable observable, Object notification) {
249
        if (observable.equals(getFeatureStore())
250
                && notification instanceof FeatureStoreNotification) {
251
            FeatureStoreNotification fsNotification = (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
                    || FeatureStoreNotification.AFTER_UPDATE.equals(type)) {
259

    
260
                reloadIfFeatureChanged(fsNotification.getFeature());
261

    
262
            } else if (FeatureStoreNotification.AFTER_UPDATE_TYPE.equals(type)) {
263

    
264
                reloadIfTypeChanged(fsNotification.getFeatureType());
265

    
266
            } else if (FeatureStoreNotification.TRANSFORM_CHANGE.equals(type)) {
267
                reloadIfTypeTransformed();
268

    
269
            } else if (FeatureStoreNotification.AFTER_FINISHEDITING
270
                                        .equals(type)
271
                                        || FeatureStoreNotification.AFTER_CANCELEDITING
272
                                                        .equals(type)) {
273
                    reloadIfTypeTransformed();
274
            }
275

    
276
        }
277
    }
278

    
279
    /**
280
     * Returns the FeatureStore of the Collection.
281
     *
282
     * @return the FeatureStore
283
     */
284
    public FeatureStore getFeatureStore() {
285
        return getHelper().getFeatureStore();
286
    }
287

    
288
    /**
289
     * Returns the descriptor of a Feature attribute for a table column.
290
     *
291
     * @param columnIndex
292
     *            the column index
293
     */
294
    public FeatureAttributeDescriptor getDescriptorForColumn(int columnIndex) {
295
        return internalGetFeatureDescriptorForColumn(columnIndex);
296
    }
297

    
298
    /**
299
     * @param columnIndex
300
     * @return
301
     */
302
    protected FeatureAttributeDescriptor internalGetFeatureDescriptorForColumn(
303
            int columnIndex) {
304
        return getFeatureType().getAttributeDescriptor(columnIndex);
305
    }
306

    
307
    /**
308
     * Initialize the TableModel
309
     */
310
    protected void initialize() {
311
        // Add as observable to the FeatureStore, to detect data and selection
312
        // changes
313
        helper.getFeatureStore().addObserver(this);
314
    }
315

    
316
    /**
317
     * Returns the value of a Feature attribute, at the given position.
318
     *
319
     * @param feature
320
     *            the feature to get the value from
321
     * @param columnIndex
322
     *            the Feature attribute position
323
     * @return the value
324
     */
325
    protected Object getFeatureValue(Feature feature, int columnIndex) {
326
        return feature.get(columnIndex);
327
    }
328

    
329
    /**
330
     * Sets the value of an Feature attribute at the given position.
331
     *
332
     * @param feature
333
     *            the feature to update
334
     * @param columnIndex
335
     *            the attribute position
336
     * @param value
337
     *            the value to set
338
     * @throws IsNotFeatureSettingException
339
     *             if there is an error setting the value
340
     */
341
    protected EditableFeature setFeatureValue(Feature feature, int columnIndex,
342
            Object value) {
343
        EditableFeature editableFeature = feature.getEditable();
344
        editableFeature.set(columnIndex, value);
345
        return editableFeature;
346
    }
347

    
348
    /**
349
     * Returns the FeatureSet used to get the data.
350
     *
351
     * @return the FeatureSet
352
     */
353
    protected FeatureSet getFeatureSet() {
354
        return getHelper().getFeatureSet();
355
    }
356

    
357
    /**
358
     * Returns the FeatureQuery used to get the Features.
359
     *
360
     * @return the FeatureQuery
361
     */
362
    protected FeatureQuery getFeatureQuery() {
363
        return getHelper().getFeatureQuery();
364
    }
365

    
366
    /**
367
     * Returns the type of the features.
368
     */
369
    private FeatureType getFeatureType() {
370
        return getHelper().getFeatureType();
371
    }
372

    
373
    /**
374
     * Reloads the table data if a feature has been changed, not through the
375
     * table.
376
     */
377
    private void reloadIfFeatureChanged(Feature feature) {
378
        // Is any data is changed in the FeatureStore, notify the model
379
                // listeners. Ignore the case where the updated feature is
380
                // changed through us.
381
                if (editableFeature == null || !editableFeature.equals(feature)) {
382
                        reloadFeatures();
383
                        fireTableDataChanged();
384
                }
385
    }
386

    
387
    /**
388
     * Reloads data and structure if the {@link FeatureType} of the features
389
     * being shown has changed.
390
     */
391
    private void reloadIfTypeChanged(FeatureType updatedType) {
392
        // If the updated featured type is the one currently being
393
        // shown, reload the table.
394
                if (updatedType != null
395
                                && updatedType.getId().equals(getFeatureType().getId())) {
396
            setFeatureType(updatedType);
397
        }
398
    }
399

    
400
    /**
401
     * Reloads data and structure if the {@link FeatureType} of the features
402
     * being shown has been transformed.
403
     */
404
    private void reloadIfTypeTransformed() {
405
                try {
406
                        setFeatureType(getHelper().getFeatureStore().getFeatureType(
407
                                        getHelper().getFeatureType().getId()));
408
                } catch (DataException e) {
409
                        throw new FeaturesDataReloadException(e);
410
                }
411
    }
412

    
413
    /**
414
     * Reloads the features shown on the table.
415
     */
416
    private void reloadFeatures() {
417
        try {
418
            getHelper().reload();
419
                } catch (BaseException ex) {
420
            throw new FeaturesDataReloadException(ex);
421
        }
422
    }
423
}