Statistics
| Revision:

root / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / impl / DefaultFeatureSelection.java @ 27264

History | View | Annotate | Download (14.1 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}  {Implement data selection}
26
 */
27
package org.gvsig.fmap.dal.feature.impl;
28

    
29
import java.util.*;
30
import java.util.Map.Entry;
31

    
32
import org.gvsig.fmap.dal.DataStoreNotification;
33
import org.gvsig.fmap.dal.exception.DataException;
34
import org.gvsig.fmap.dal.feature.*;
35
import org.gvsig.fmap.dal.feature.exception.ReversedSelectionIteratorException;
36
import org.gvsig.tools.persistence.PersistenceException;
37
import org.gvsig.tools.persistence.PersistentState;
38
import org.slf4j.Logger;
39
import org.slf4j.LoggerFactory;
40

    
41
/**
42
 * Default implementation of the FeatureSelection interface. Internally, only
43
 * FeatureReference values are stored.
44
 *
45
 * This implementation performs better if used with the selection related
46
 * methods: select, deselect and isSelected ones.
47
 *
48
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
49
 */
50
public class DefaultFeatureSelection extends DefaultFeatureReferenceSelection
51
        implements FeatureSelection {
52

    
53
    private static final Logger LOGGER = LoggerFactory
54
            .getLogger(DefaultFeatureSelection.class);
55

    
56
    private Map featureTypeCounts = new HashMap(1);
57

    
58
    /**
59
     * Creates a DefaultFeatureSelection, with a FeatureStore.
60
     *
61
     * @param featureStore
62
     *            the FeatureStore to load Features from
63
     * @throws DataException
64
     *             if there is an error while getting the total number of
65
     *             Features of the Store.
66
     * @see AbstractSetBasedDataSelection#DefaultSelection(int)
67
     */
68
    public DefaultFeatureSelection(DefaultFeatureStore featureStore)
69
            throws DataException {
70
        super(featureStore);
71
    }
72

    
73
    public boolean select(Feature feature) {
74
        return select(feature, true);
75
    }
76

    
77
    /**
78
     * @see #select(Feature)
79
     * @param undoable
80
     *            if the action must be undoable
81
     */
82
    public boolean select(Feature feature, boolean undoable) {
83
        // TODO: should we check if the feature is from the same FeatureStore??
84
        if (feature == null) {
85
            return false;
86
        }
87

    
88
//        LOGGER.debug("Selected feature: {}", feature);
89

    
90
        if (isReversed()) {
91
            getFeatureTypeCount(feature.getType()).remove();
92
        } else {
93
            getFeatureTypeCount(feature.getType()).add();
94
        }
95
        return select(feature.getReference(), undoable);
96
    }
97

    
98
    public boolean select(FeatureSet features) throws DataException {
99
        return select(features, true);
100
    }
101

    
102
    /**
103
     * @see #select(FeatureSet)
104
     * @param undoable
105
     *            if the action must be undoable
106
     */
107
    public boolean select(FeatureSet features, boolean undoable)
108
            throws DataException {
109
        boolean change = false;
110
        if (undoable && getFeatureStore().isEditing()) {
111
            getCommands().startComplex("_selectionSelectFeatureSet");
112
        }
113

    
114
        disableNotifications();
115
        for (Iterator iter = features.fastIterator(); iter.hasNext();) {
116
            change |= select((Feature) iter.next(), undoable);
117
        }
118
        enableNotifications();
119
        if (undoable && getFeatureStore().isEditing()) {
120
            getCommands().endComplex();
121
        }
122
        if (change) {
123
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
124
        }
125
        return change;
126
    }
127

    
128
    public boolean deselect(Feature feature) {
129
        return deselect(feature, true);
130
    }
131

    
132
    /**
133
     * @see #deselect(Feature)
134
     * @param undoable
135
     *            if the action must be undoable
136
     */
137
    public boolean deselect(Feature feature, boolean undoable) {
138
        if (feature == null) {
139
            return false;
140
        }
141

    
142
        LOGGER.debug("Deselected feature: {}", feature);
143

    
144
        if (isReversed()) {
145
            getFeatureTypeCount(feature.getType()).add();
146
        } else {
147
            getFeatureTypeCount(feature.getType()).remove();
148
        }
149
        return deselect(feature.getReference(), undoable);
150
    }
151

    
152
    public boolean deselect(FeatureSet features) throws DataException {
153
        return deselect(features, true);
154
    }
155

    
156
    /**
157
     * @see #deselect(FeatureSet)
158
     * @param undoable
159
     *            if the action must be undoable
160
     */
161
    public boolean deselect(FeatureSet features, boolean undoable)
162
            throws DataException {
163
        boolean change = false;
164
        if (undoable && getFeatureStore().isEditing()) {
165
            getCommands().startComplex("_selectionDeselectFeatureSet");
166
        }
167
        disableNotifications();
168
        for (Iterator iter = features.fastIterator(); iter.hasNext();) {
169
            change |= deselect((Feature) iter.next(), undoable);
170
        }
171
        enableNotifications();
172
        if (undoable && getFeatureStore().isEditing()) {
173
            getCommands().endComplex();
174
        }
175
        if (change) {
176
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
177
        }
178
        return change;
179
    }
180

    
181
    public boolean isSelected(Feature feature) {
182
        if (feature == null) {
183
            return false;
184
        }
185
        return isSelected(feature.getReference());
186
    }
187

    
188
    public FeatureType getDefaultFeatureType() {
189
        try {
190
            return getFeatureStore().getDefaultFeatureType();
191
        } catch (DataException ex) {
192
            LOGGER.error("Error getting the default feature type "
193
                    + "of the FeatureStore: " + getFeatureStore(), ex);
194
        }
195
        return null;
196
    }
197

    
198
    public List getFeatureTypes() {
199
        // Go through the map of FeatureTypes, and return only the ones that
200
        // have at least a Feature.
201
        List types = new ArrayList();
202
        for (Iterator iterator = featureTypeCounts.entrySet().iterator(); iterator
203
                .hasNext();) {
204
            Map.Entry entry = (Entry) iterator.next();
205
            FeatureType type = (FeatureType) entry.getKey();
206
            FeatureTypeCount count = (FeatureTypeCount) entry.getValue();
207

    
208
            if (count.getCount() > 0) {
209
                types.add(type);
210
            }
211
        }
212

    
213
        return types;
214
    }
215

    
216
    public long getSize() throws DataException {
217
        return getSelectedCount();
218
    }
219

    
220
    public boolean isEmpty() throws DataException {
221
        return getSelectedCount() == 0;
222
    }
223

    
224
    /**
225
     * Returns the list of selected values, or the deselected ones if the
226
     * selection has been reversed.
227
     */
228
    public Iterator iterator() {
229
        return iterator(0);
230
    }
231

    
232
    /**
233
     * Returns the list of selected values, or the deselected ones if the
234
     * selection has been reversed.
235
     *
236
     * WARN: not very good performance implementation.
237
     */
238
    public Iterator iterator(long index) {
239
        return iterator(index, false);
240
    }
241

    
242
    /**
243
     * Returns the list of selected values, or the deselected ones if the
244
     * selection has been reversed.
245
     *
246
     * WARN: not really a fast implementation.
247
     */
248
    public Iterator fastIterator() {
249
        return fastIterator(0);
250
    }
251

    
252
    /**
253
     * Returns the list of selected values, or the deselected ones if the
254
     * selection has been reversed.
255
     *
256
     * WARN: not really a fast implementation.
257
     */
258
    public Iterator fastIterator(long index) {
259
        return iterator(index, true);
260
    }
261

    
262
    public void loadState(PersistentState state) throws PersistenceException {
263
        super.loadState(state);
264
        for (Iterator iterator = fastIterator(); iterator.hasNext();) {
265
            Feature feature = (Feature) iterator.next();
266
            getFeatureTypeCount(feature.getType()).add();
267
        }
268
    }
269

    
270
    protected void clearFeatureReferences() {
271
        super.clearFeatureReferences();
272
        featureTypeCounts.clear();
273
    }
274

    
275
    /**
276
     * Creates an iterator for the Selection.
277
     */
278
    private Iterator iterator(long index, boolean fastIterator) {
279
        if (isReversed()) {
280
            Iterator iter = new ReversedFeatureIteratorFacade(getData(),
281
                    getFeatureStore(), fastIterator);
282
            for (long l = 0; l < index && iter.hasNext(); l++) {
283
                iter.next();
284
            }
285
            return iter;
286

    
287
        } else {
288
            // TODO: maybe we could add a new referenceIterator(int index)
289
            // method that could be implemented in a more performant way
290

    
291
            Iterator iter = referenceIterator();
292
            for (long l = 0; l < index && iter.hasNext(); l++) {
293
                iter.next();
294
            }
295
            return new FeatureIteratorFacade(iter, getFeatureStore());
296
        }
297
    }
298

    
299
    private FeatureTypeCount getFeatureTypeCount(FeatureType featureType) {
300
        FeatureTypeCount count = (FeatureTypeCount) featureTypeCounts
301
                .get(featureType);
302
        if (count == null) {
303
            count = new FeatureTypeCount();
304
            featureTypeCounts.put(featureType, count);
305
        }
306
        return count;
307
    }
308

    
309
    /**
310
     * Facade over a Iterator of FeatureReferences, to return Features instead.
311
     *
312
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
313
     */
314
    private class FeatureIteratorFacade implements Iterator {
315

    
316
        final Logger logger = LoggerFactory
317
                .getLogger(FeatureIteratorFacade.class);
318

    
319
        private Iterator refIterator;
320

    
321
        private DefaultFeatureStore featureStore;
322

    
323
        public FeatureIteratorFacade(Iterator refIterator,
324
                DefaultFeatureStore featureStore) {
325
            this.refIterator = refIterator;
326
            this.featureStore = featureStore;
327
        }
328

    
329
        public boolean hasNext() {
330
            return refIterator.hasNext();
331
        }
332

    
333
        public Object next() {
334
            FeatureReference ref = nextFeatureReference();
335
            try {
336
                return featureStore.getFeatureByReference(ref);
337
            } catch (DataException ex) {
338
                logger.error(
339
                        "Error loading the Feature with FeatureReference: "
340
                                + ref, ex);
341
                return null;
342
            }
343
        }
344

    
345
        /**
346
         * Returns the next FeatureReference.
347
         *
348
         * @return the next FeatureReference
349
         */
350
        public FeatureReference nextFeatureReference() {
351
            return (FeatureReference) refIterator.next();
352
        }
353

    
354
        public void remove() {
355
            refIterator.remove();
356
        }
357

    
358
        /**
359
         * Returns a Feature for the FeatureReference.
360
         */
361
        protected Feature getFeature(FeatureReference ref) throws DataException {
362
            return ref.getFeature();
363
        }
364
    }
365

    
366
    /**
367
     * Facade over a Iterator of FeatureReferences, to return Features instead,
368
     * when the Selection is reversed
369
     *
370
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
371
     */
372
    private class ReversedFeatureIteratorFacade implements Iterator {
373

    
374
        final Logger logger = LoggerFactory
375
                .getLogger(ReversedFeatureIteratorFacade.class);
376

    
377
        private Iterator refIterator;
378

    
379
        private SelectionData selectionData;
380

    
381
        private Iterator iterator;
382

    
383
        private Feature nextFeature = null;
384

    
385
        public ReversedFeatureIteratorFacade(SelectionData selectionData,
386
                DefaultFeatureStore featureStore, boolean fastIterator) {
387
            this.selectionData = selectionData;
388

    
389
            // Load a Set with all the store features
390
            try {
391
                FeatureSet featureSet = featureStore.getFeatureSet();
392
                if (fastIterator) {
393
                    iterator = featureSet.fastIterator();
394
                } else {
395
                    iterator = featureSet.iterator();
396
                }
397
            } catch (DataException ex) {
398
                throw new ReversedSelectionIteratorException(ex);
399
            }
400

    
401
            // Filter the features not selected and position in the next
402
            // selected feature
403
            positionInNextElement();
404
        }
405

    
406
        public boolean hasNext() {
407
            return nextFeature != null;
408
        }
409

    
410
        public Object next() {
411
            Feature tmp = nextFeature;
412
            positionInNextElement();
413
            return tmp;
414
        }
415

    
416
        /**
417
         * Returns the next FeatureReference.
418
         *
419
         * @return the next FeatureReference
420
         */
421
        public FeatureReference nextFeatureReference() {
422
            return (FeatureReference) refIterator.next();
423
        }
424

    
425
        public void remove() {
426
            iterator.remove();
427
        }
428

    
429
        private void positionInNextElement() {
430
            nextFeature = null;
431
            while (iterator.hasNext()) {
432
                nextFeature = (Feature) iterator.next();
433
                if (selectionData.contains(nextFeature.getReference())) {
434
                    nextFeature = null;
435
                } else {
436
                    break;
437
                }
438
            }
439
        }
440
    }
441

    
442
    private class FeatureTypeCount {
443
        private long count = 0;
444

    
445
        public void add() {
446
            count++;
447
        }
448

    
449
        public void remove() {
450
            count--;
451
        }
452

    
453
        public long getCount() {
454
            return count;
455
        }
456
    }
457

    
458
    public void delete(Feature feature) throws DataException {
459
        throw new UnsupportedOperationException();
460
    }
461

    
462
    public void insert(EditableFeature feature) throws DataException {
463
        throw new UnsupportedOperationException();
464
    }
465

    
466
    public void update(EditableFeature feature) throws DataException {
467
        throw new UnsupportedOperationException();
468
    }
469
}