Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DefaultFeatureSelection.java

History | View | Annotate | Download (26.4 KB)

1 40559 jjdelcerro
/**
2
 * gvSIG. Desktop Geographic Information System.
3 40435 jjdelcerro
 *
4 40559 jjdelcerro
 * Copyright (C) 2007-2013 gvSIG Association.
5 40435 jjdelcerro
 *
6 43089 jjdelcerro
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10 40435 jjdelcerro
 *
11 43089 jjdelcerro
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15 40435 jjdelcerro
 *
16 43089 jjdelcerro
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 40435 jjdelcerro
 *
20 43089 jjdelcerro
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22 40435 jjdelcerro
 */
23
package org.gvsig.fmap.dal.feature.impl;
24
25
import java.util.ArrayList;
26
import java.util.HashMap;
27 42834 dmartinezizquierdo
import java.util.Iterator;
28 40435 jjdelcerro
import java.util.List;
29
import java.util.Map;
30
import java.util.Map.Entry;
31 47198 jjdelcerro
import org.apache.commons.lang3.builder.ToStringBuilder;
32 40435 jjdelcerro
33
import org.gvsig.fmap.dal.DataStoreNotification;
34
import org.gvsig.fmap.dal.exception.DataException;
35 42821 dmartinezizquierdo
import org.gvsig.fmap.dal.exception.DataRuntimeException;
36 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeature;
37
import org.gvsig.fmap.dal.feature.Feature;
38 44113 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureQuery;
39 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureReference;
40 47184 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureReferenceIterator;
41 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureSelection;
42
import org.gvsig.fmap.dal.feature.FeatureSet;
43
import org.gvsig.fmap.dal.feature.FeatureStore;
44 44113 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
45 40435 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureType;
46
import org.gvsig.fmap.dal.feature.exception.ReversedSelectionIteratorException;
47 43089 jjdelcerro
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection.SelectionData;
48
import org.gvsig.fmap.dal.feature.impl.featureset.AbstractFeatureSet;
49 44113 jjdelcerro
import org.gvsig.fmap.dal.feature.impl.featureset.DefaultFeatureSet;
50 43089 jjdelcerro
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
51 40435 jjdelcerro
import org.gvsig.tools.ToolsLocator;
52
import org.gvsig.tools.dispose.DisposableIterator;
53 43088 jjdelcerro
import org.gvsig.tools.dispose.DisposeUtils;
54 40435 jjdelcerro
import org.gvsig.tools.dynobject.DynStruct;
55
import org.gvsig.tools.exception.BaseException;
56 43089 jjdelcerro
import org.gvsig.tools.observer.Observable;
57
import org.gvsig.tools.observer.Observer;
58 40435 jjdelcerro
import org.gvsig.tools.persistence.PersistenceManager;
59
import org.gvsig.tools.persistence.PersistentState;
60
import org.gvsig.tools.persistence.exception.PersistenceException;
61 43358 jjdelcerro
import org.gvsig.tools.visitor.Visitor;
62 42834 dmartinezizquierdo
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64 40435 jjdelcerro
65
/**
66
 * Default implementation of the FeatureSelection interface. Internally, only
67
 * FeatureReference values are stored.
68 42821 dmartinezizquierdo
 *
69 40435 jjdelcerro
 * This implementation performs better if used with the selection related
70
 * methods: select, deselect and isSelected ones.
71 42821 dmartinezizquierdo
 *
72 40435 jjdelcerro
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
73
 */
74 43089 jjdelcerro
public class DefaultFeatureSelection extends AbstractFeatureSet
75
        implements FeatureSelection {
76 40435 jjdelcerro
77 43089 jjdelcerro
    public class RemoveFromFeatureSelectionException extends DataRuntimeException {
78 40435 jjdelcerro
79 43089 jjdelcerro
        /**
80
         *
81
         */
82
        private static final long serialVersionUID = 2636692469445838928L;
83
        private final static String MESSAGE_FORMAT = "Can't remove feature from reversed selection.";
84
        private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
85 40435 jjdelcerro
86 43089 jjdelcerro
        public RemoveFromFeatureSelectionException(Throwable cause) {
87
            super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
88
            //setValue("store", store);
89
        }
90
    }
91 40435 jjdelcerro
92 43089 jjdelcerro
    /**
93
     * Facade over a Iterator of FeatureReferences, to return Features instead.
94
     *
95
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
96
     */
97
    private class FeatureIteratorFacade implements DisposableIterator {
98 40435 jjdelcerro
99 43089 jjdelcerro
        private final Logger LOGGER = LoggerFactory
100
                .getLogger(FeatureIteratorFacade.class);
101 40435 jjdelcerro
102 43089 jjdelcerro
        private java.util.Iterator refIterator;
103 40435 jjdelcerro
104 43089 jjdelcerro
        private FeatureStore featureStore;
105
        private Feature currentFeature = null;
106 40435 jjdelcerro
107 43089 jjdelcerro
        public FeatureIteratorFacade(java.util.Iterator iter,
108
                FeatureStore featureStore) {
109
            this.refIterator = iter;
110
            this.featureStore = featureStore;
111
        }
112 40435 jjdelcerro
113 43089 jjdelcerro
        @Override
114
        public boolean hasNext() {
115
            return refIterator.hasNext();
116
        }
117 40435 jjdelcerro
118 43089 jjdelcerro
        @Override
119
        public Object next() {
120
            FeatureReference ref = nextFeatureReference();
121
            try {
122
                currentFeature = featureStore.getFeatureByReference(ref);
123
                return currentFeature;
124
            } catch (DataException ex) {
125
                LOGGER.error(
126
                        "Error loading the Feature with FeatureReference: "
127
                        + ref, ex);
128
                return null;
129
            }
130
        }
131 42821 dmartinezizquierdo
132 43089 jjdelcerro
        /**
133
         * Returns the next FeatureReference.
134
         *
135
         * @return the next FeatureReference
136
         */
137
        public FeatureReference nextFeatureReference() {
138
            return (FeatureReference) refIterator.next();
139
        }
140 40435 jjdelcerro
141 43089 jjdelcerro
        @Override
142
        public void remove() {
143
            try {
144
                featureStore.delete(currentFeature);
145
                refIterator.remove();
146
            } catch (DataException e) {
147
                throw new RemoveFromFeatureSelectionException(e);
148
            }
149
        }
150 40435 jjdelcerro
151 43089 jjdelcerro
        public class RemoveFromFeatureSelectionException extends DataRuntimeException {
152 40435 jjdelcerro
153 43089 jjdelcerro
            /**
154
             *
155
             */
156
            private static final long serialVersionUID = 2636692469445838928L;
157
            private final static String MESSAGE_FORMAT = "Can't remove feature from selection.";
158
            private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
159 40435 jjdelcerro
160 43089 jjdelcerro
            public RemoveFromFeatureSelectionException(Throwable cause) {
161
                super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
162
                //setValue("store", store);
163
            }
164
        }
165 40435 jjdelcerro
166 43089 jjdelcerro
        @Override
167
        public void dispose() {
168
            if (refIterator instanceof DisposableIterator) {
169
                ((DisposableIterator) refIterator).dispose();
170
            }
171
            refIterator = null;
172
            featureStore = null;
173
        }
174
    }
175 40435 jjdelcerro
176 43089 jjdelcerro
    /**
177
     * Facade over a Iterator of FeatureReferences, to return Features instead,
178
     * when the Selection is reversed
179
     *
180
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
181
     */
182
    private class ReversedFeatureIteratorFacade implements DisposableIterator {
183 40435 jjdelcerro
184 43089 jjdelcerro
        private SelectionData selectionData;
185 40435 jjdelcerro
186 43089 jjdelcerro
        private DisposableIterator iterator;
187 40435 jjdelcerro
188 43089 jjdelcerro
        private Feature nextFeature = null;
189
        private Feature currentFeature = null;
190 40435 jjdelcerro
191 43089 jjdelcerro
        private FeatureSet featureSet;
192 40435 jjdelcerro
193 43089 jjdelcerro
        public ReversedFeatureIteratorFacade(SelectionData selectionData,
194
                FeatureStore featureStore, boolean fastIterator) {
195
            this.selectionData = selectionData;
196 40435 jjdelcerro
197 43089 jjdelcerro
            // Load a Set with all the store features
198
            try {
199 44113 jjdelcerro
                featureSet = new IgnoreInsertAndUpdateFeatureSet(
200
                        (DefaultFeatureStore) featureStore,
201
                        new DefaultFeatureQuery(featureStore.getDefaultFeatureType())
202
                );
203 43089 jjdelcerro
                iterator = featureSet.fastIterator();
204
            } catch (DataException ex) {
205
                throw new ReversedSelectionIteratorException(ex);
206
            }
207 40435 jjdelcerro
208 43089 jjdelcerro
            // Filter the features not selected and position in the next
209
            // selected feature
210
            positionInNextElement();
211
        }
212 40435 jjdelcerro
213 43089 jjdelcerro
        @Override
214
        public boolean hasNext() {
215
            return nextFeature != null;
216
        }
217 40435 jjdelcerro
218 43089 jjdelcerro
        @Override
219
        public Object next() {
220
            featureIterators.remove(currentFeature);
221
            currentFeature = nextFeature.getCopy();
222
            featureIterators.put(currentFeature, this);
223
            positionInNextElement();
224
            return currentFeature;
225
        }
226 40435 jjdelcerro
227 43089 jjdelcerro
        @Override
228
        public void remove() {
229
            try {
230
                featureSet.delete(currentFeature);
231
            } catch (DataException e) {
232
                throw new RemoveFromFeatureSelectionException(e);
233 40435 jjdelcerro
234 43089 jjdelcerro
            }
235
        }
236 40435 jjdelcerro
237 43089 jjdelcerro
        private void positionInNextElement() {
238
            nextFeature = null;
239
            while (iterator.hasNext()) {
240
                nextFeature = (Feature) iterator.next();
241
                if (selectionData.contains(nextFeature.getReference())) {
242
                    nextFeature = null;
243
                } else {
244
                    break;
245 43088 jjdelcerro
                }
246
            }
247
        }
248 40435 jjdelcerro
249 43089 jjdelcerro
        @Override
250
        public void dispose() {
251
            this.featureSet.dispose();
252
            this.iterator.dispose();
253
            this.selectionData = null;
254
            this.nextFeature = null;
255
        }
256
    }
257 40435 jjdelcerro
258 43089 jjdelcerro
    private Map featureTypeCounts = new HashMap(1);
259
    private final Map<Feature, Iterator> featureIterators = new HashMap<>();
260
    private final DefaultFeatureReferenceSelection featureReferenceSelection;
261 46914 fdiaz
    private boolean disposed = false;
262 40435 jjdelcerro
263 43089 jjdelcerro
    /**
264
     * Creates a DefaultFeatureSelection, with a FeatureStore.
265
     *
266
     * @param featureStore the FeatureStore to load Features from
267
     * @throws DataException if there is an error while getting the total number
268
     * of Features of the Store.
269
     * @see AbstractSetBasedDataSelection#DefaultSelection(int)
270
     */
271
    public DefaultFeatureSelection(DefaultFeatureStore featureStore)
272
            throws DataException {
273 46914 fdiaz
        DisposeUtils.bind(this);
274 43089 jjdelcerro
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore);
275
    }
276 40435 jjdelcerro
277 43089 jjdelcerro
    /**
278
     * Creates a new Selection with the total size of Features from which the
279
     * selection will be performed.
280
     *
281
     * @param featureStore the FeatureStore of the selected FeatureReferences
282
     * @param helper to get some information of the Store
283
     * @throws DataException if there is an error while getting the total number
284
     * of Features of the Store.
285
     */
286
    public DefaultFeatureSelection(FeatureStore featureStore,
287
            FeatureSelectionHelper helper) throws DataException {
288 46914 fdiaz
        DisposeUtils.bind(this);
289 43089 jjdelcerro
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore, helper);
290
    }
291 40435 jjdelcerro
292 43089 jjdelcerro
    /**
293
     * Constructor used by the persistence manager. Don't use directly. After to
294
     * invoke this method, the persistence manager calls the the method
295
     * {@link #loadFromState(PersistentState)} to set the values of the internal
296
     * attributes that this class needs to work.
297
     */
298
    public DefaultFeatureSelection() {
299 46914 fdiaz
        DisposeUtils.bind(this);
300 43089 jjdelcerro
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection();
301
    }
302 40435 jjdelcerro
303 43089 jjdelcerro
    @Override
304
    public FeatureStore getFeatureStore() {
305
        return this.featureReferenceSelection.getFeatureStore();
306
    }
307 40435 jjdelcerro
308 43089 jjdelcerro
    private void notifyObservers(String notificationType) {
309
        this.featureReferenceSelection.notifyObservers(notificationType);
310
    }
311 40435 jjdelcerro
312 43089 jjdelcerro
    public FeatureCommandsStack getCommands() {
313
        return this.featureReferenceSelection.getCommands();
314
    }
315 40435 jjdelcerro
316 43089 jjdelcerro
    @Override
317
    public void enableNotifications() {
318
        this.featureReferenceSelection.enableNotifications();
319
    }
320 40435 jjdelcerro
321 43089 jjdelcerro
    @Override
322
    public void disableNotifications() {
323
        this.featureReferenceSelection.disableNotifications();
324
    }
325 40435 jjdelcerro
326 43089 jjdelcerro
    public boolean isReversed() {
327
        return this.featureReferenceSelection.isReversed();
328
    }
329 40435 jjdelcerro
330 43089 jjdelcerro
    @Override
331
    public long getSelectedCount() {
332
        return this.featureReferenceSelection.getSelectedCount();
333
    }
334 40435 jjdelcerro
335 43089 jjdelcerro
    public DefaultFeatureReferenceSelection.SelectionData getData() {
336
        return this.featureReferenceSelection.getData();
337
    }
338 40435 jjdelcerro
339 43089 jjdelcerro
    @Override
340
    public boolean select(FeatureReference reference) {
341
        return this.featureReferenceSelection.select(reference);
342
    }
343 40435 jjdelcerro
344 43089 jjdelcerro
    public boolean select(FeatureReference reference, boolean undoable) {
345
        return this.featureReferenceSelection.select(reference, undoable);
346
    }
347 40435 jjdelcerro
348 43089 jjdelcerro
    @Override
349
    public boolean deselect(FeatureReference reference) {
350
        return this.featureReferenceSelection.deselect(reference);
351
    }
352 40435 jjdelcerro
353 43089 jjdelcerro
    public boolean deselect(FeatureReference reference, boolean undoable) {
354
        return this.featureReferenceSelection.deselect(reference, undoable);
355
    }
356 42834 dmartinezizquierdo
357 43089 jjdelcerro
    @Override
358 47184 jjdelcerro
    public FeatureReferenceIterator referenceIterator() {
359 43089 jjdelcerro
        return this.featureReferenceSelection.referenceIterator();
360
    }
361 42834 dmartinezizquierdo
362 43089 jjdelcerro
    @Override
363 46309 jjdelcerro
    public Iterable<FeatureReference> referenceIterable() {
364
        return this.featureReferenceSelection.referenceIterable();
365
    }
366
367
    @Override
368 43089 jjdelcerro
    public void selectAll() throws DataException {
369
        this.featureReferenceSelection.selectAll();
370
    }
371 42834 dmartinezizquierdo
372 43089 jjdelcerro
    @Override
373
    public void deselectAll() throws DataException {
374
        this.featureReferenceSelection.deselectAll();
375
    }
376
377
    public void deselectAll(boolean undoable) throws DataException {
378
        this.featureReferenceSelection.deselectAll(undoable);
379
    }
380
381
    @Override
382
    public boolean isSelected(FeatureReference reference) {
383
        return this.featureReferenceSelection.isSelected(reference);
384
    }
385 40435 jjdelcerro
386 43089 jjdelcerro
    @Override
387
    public void reverse() {
388
        this.featureReferenceSelection.reverse();
389
    }
390 40435 jjdelcerro
391 43089 jjdelcerro
    @Override
392 46914 fdiaz
    public synchronized final void dispose() {
393
        // Check if we have already been disposed, and don't do it again
394
        if (!disposed) {
395
            if (DisposeUtils.release(this)) {
396
                try {
397
                    doDispose();
398
                } catch (Exception ex) {
399
                    LOG.error("Error performing dispose", ex);
400
                } finally {
401
                    disposed = true;
402
                }
403
            }
404
        }
405 43089 jjdelcerro
    }
406 40435 jjdelcerro
407 46914 fdiaz
408
409 43089 jjdelcerro
    @Override
410
    public void update(Observable o, Object o1) {
411
        this.featureReferenceSelection.update(o, o1);
412
    }
413 40435 jjdelcerro
414 43089 jjdelcerro
    @Override
415
    public void addObserver(Observer obsrvr) {
416
        this.featureReferenceSelection.addObserver(obsrvr);
417
    }
418 40435 jjdelcerro
419 43089 jjdelcerro
    @Override
420
    public void deleteObserver(Observer obsrvr) {
421
        this.featureReferenceSelection.deleteObserver(obsrvr);
422
    }
423 40435 jjdelcerro
424 43089 jjdelcerro
    @Override
425
    public void deleteObservers() {
426
        this.featureReferenceSelection.deleteObservers();
427
    }
428 40435 jjdelcerro
429 43089 jjdelcerro
    @Override
430
    public void beginComplexNotification() {
431
        this.featureReferenceSelection.beginComplexNotification();
432
    }
433 40435 jjdelcerro
434 43089 jjdelcerro
    @Override
435
    public void endComplexNotification() {
436
        this.featureReferenceSelection.endComplexNotification();
437
    }
438 40435 jjdelcerro
439 43089 jjdelcerro
    @Override
440
    public void saveToState(PersistentState ps) throws PersistenceException {
441
        this.featureReferenceSelection.saveToState(ps);
442
    }
443 40435 jjdelcerro
444 43089 jjdelcerro
    @Override
445
    public boolean select(Feature feature) {
446
        return select(feature, true);
447
    }
448 40435 jjdelcerro
449 43089 jjdelcerro
    /**
450
     * @param feature
451
     * @return
452
     * @see #select(Feature)
453
     * @param undoable if the action must be undoable
454
     */
455
    public boolean select(Feature feature, boolean undoable) {
456
        // TODO: should we check if the feature is from the same FeatureStore??
457
        if (feature == null) {
458
            return false;
459
        }
460 42821 dmartinezizquierdo
461 43089 jjdelcerro
        // LOGGER.debug("Selected feature: {}", feature);
462
        if (isReversed()) {
463
            removeFeatureTypeCount(feature.getType());
464
        } else {
465
            addFeatureTypeCount(feature.getType());
466
        }
467
        return select(feature.getReference(), undoable);
468
    }
469
470
    @Override
471
    public boolean select(FeatureSet features) throws DataException {
472
        return select(features, true);
473
    }
474
475
    /**
476
     * @param features
477
     * @return
478
     * @throws org.gvsig.fmap.dal.exception.DataException
479
     * @see #select(FeatureSet)
480
     * @param undoable if the action must be undoable
481
     */
482
    public boolean select(FeatureSet features, boolean undoable)
483
            throws DataException {
484
        boolean change = false;
485
        boolean inComplex = false;
486
        if (undoable && this.featureReferenceSelection.getFeatureStore().isEditing()
487
                && !this.featureReferenceSelection.getCommands().inComplex()) {
488
489
            this.featureReferenceSelection.getCommands().startComplex("_selectionSelectFeatureSet");
490
            inComplex = this.featureReferenceSelection.getCommands().inComplex();
491
        }
492
493
        disableNotifications();
494
        DisposableIterator iter = null;
495
        try {
496
            for (iter = features.fastIterator(); iter.hasNext();) {
497
                change |= select((Feature) iter.next(), undoable);
498 42821 dmartinezizquierdo
            }
499 43089 jjdelcerro
        } finally {
500
            DisposeUtils.disposeQuietly(iter);
501
        }
502
        enableNotifications();
503
        if (undoable && getFeatureStore().isEditing() && inComplex) {
504
            getCommands().endComplex();
505
        }
506
        if (change) {
507
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
508
        }
509
        return change;
510
    }
511 40435 jjdelcerro
512 43089 jjdelcerro
    @Override
513
    public boolean deselect(Feature feature) {
514
        return deselect(feature, true);
515
    }
516 42821 dmartinezizquierdo
517 43089 jjdelcerro
    /**
518
     * @param feature
519
     * @return
520
     * @see #deselect(Feature)
521
     * @param undoable if the action must be undoable
522
     */
523
    public boolean deselect(Feature feature, boolean undoable) {
524
        if (feature == null) {
525
            return false;
526
        }
527 42821 dmartinezizquierdo
528 43089 jjdelcerro
        LOG.debug("Deselected feature: {}", feature);
529 42821 dmartinezizquierdo
530 43089 jjdelcerro
        if (isReversed()) {
531
            addFeatureTypeCount(feature.getType());
532
        } else {
533
            removeFeatureTypeCount(feature.getType());
534
        }
535
        return deselect(feature.getReference(), undoable);
536
    }
537 42821 dmartinezizquierdo
538 43089 jjdelcerro
    @Override
539
    public boolean deselect(FeatureSet features) throws DataException {
540
        return deselect(features, true);
541
    }
542 40435 jjdelcerro
543 43089 jjdelcerro
    /**
544
     * @param features
545
     * @return
546
     * @throws org.gvsig.fmap.dal.exception.DataException
547
     * @see #deselect(FeatureSet)
548
     * @param undoable if the action must be undoable
549
     */
550
    public boolean deselect(FeatureSet features, boolean undoable)
551
            throws DataException {
552
        boolean change = false;
553
        if (undoable && getFeatureStore().isEditing()) {
554
            getCommands().startComplex("_selectionDeselectFeatureSet");
555
        }
556
        disableNotifications();
557
        DisposableIterator iter = null;
558
        try {
559
            for (iter = features.fastIterator(); iter.hasNext();) {
560
                change |= deselect((Feature) iter.next(), undoable);
561
            }
562
        } finally {
563
            DisposeUtils.disposeQuietly(iter);
564
        }
565
        enableNotifications();
566
        if (undoable && getFeatureStore().isEditing()) {
567
            getCommands().endComplex();
568
        }
569
        if (change) {
570
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
571
        }
572
        return change;
573
    }
574 40435 jjdelcerro
575 43089 jjdelcerro
    @Override
576
    public boolean isSelected(Feature feature) {
577
        if (feature == null) {
578
            return false;
579
        }
580 43646 jjdelcerro
        if( this.featureReferenceSelection.isEmpty() ) {
581
            return false;
582
        }
583 43089 jjdelcerro
        // Use the selection data size as a small optimization for the most
584
        // common case, when nothing is selected and every feature is checked
585
        // while drawing or painting the table document.
586
        if (getData().isReversed()) {
587
            return getData().getSize() == 0
588
                    || !getData().contains(feature.getReference());
589
        } else {
590
            return getData().getSize() > 0
591
                    && getData().contains(feature.getReference());
592
        }
593 42834 dmartinezizquierdo
    }
594 40435 jjdelcerro
595 43089 jjdelcerro
    @Override
596
    public FeatureType getDefaultFeatureType() {
597
        try {
598
            return getFeatureStore().getDefaultFeatureType();
599
        } catch (DataException ex) {
600
            LOG.error("Error getting the default feature type "
601
                    + "of the FeatureStore: " + getFeatureStore(), ex);
602
        }
603
        return null;
604 42834 dmartinezizquierdo
    }
605 40435 jjdelcerro
606 43089 jjdelcerro
    @Override
607
    public List getFeatureTypes() {
608
        // Go through the map of FeatureTypes, and return only the ones that
609
        // have at least a Feature.
610
        List types = new ArrayList();
611
        for (java.util.Iterator iterator = featureTypeCounts.entrySet()
612
                .iterator(); iterator.hasNext();) {
613
            Map.Entry entry = (Entry) iterator.next();
614
            FeatureType type = (FeatureType) entry.getKey();
615
            Long count = (Long) entry.getValue();
616 40435 jjdelcerro
617 43089 jjdelcerro
            if (count > 0) {
618
                types.add(type);
619
            }
620
        }
621 40435 jjdelcerro
622 43089 jjdelcerro
        return types;
623
    }
624 40435 jjdelcerro
625 43089 jjdelcerro
    @Override
626
    public long getSize() throws DataException {
627
        return getSelectedCount();
628
    }
629 40435 jjdelcerro
630 43089 jjdelcerro
    /**
631
     * Returns the list of selected values, or the deselected ones if the
632
     * selection has been reversed.
633
     *
634
     * WARN: not very good performance implementation.
635
     */
636
    @Override
637 43358 jjdelcerro
        public DisposableIterator iterator(long index) {
638
                return iterator(index, 0, false);
639
        }
640 40435 jjdelcerro
641 43358 jjdelcerro
    @Override
642
        public DisposableIterator iterator(long index, long elements) {
643
                return iterator(index, elements, false);
644
        }
645
646 43089 jjdelcerro
    /**
647
     * Returns the list of selected values, or the deselected ones if the
648
     * selection has been reversed.
649
     *
650
     * WARN: not really a fast implementation.
651
     */
652
    @Override
653 43358 jjdelcerro
        public DisposableIterator fastIterator(long index) {
654
            return fastIterator(index, 0);
655
        }
656
657
    @Override
658
    public DisposableIterator fastIterator(long index, long elements) {
659
        return iterator(index, elements, true);
660 43089 jjdelcerro
    }
661 40435 jjdelcerro
662 43358 jjdelcerro
663 43089 jjdelcerro
    protected void clearFeatureReferences() {
664
        this.featureReferenceSelection.clearFeatureReferences();
665
        featureTypeCounts.clear();
666
    }
667 40435 jjdelcerro
668 43089 jjdelcerro
    /**
669
     * Creates an iterator for the Selection.
670
     */
671 43358 jjdelcerro
    private DisposableIterator iterator(long index, long elements, boolean fastIterator) {
672 43089 jjdelcerro
        if (isReversed()) {
673
            DisposableIterator iter = new ReversedFeatureIteratorFacade(
674
                    getData(), getFeatureStore(), fastIterator);
675
            for (long l = 0; l < index && iter.hasNext(); l++) {
676
                iter.next();
677
            }
678
            return iter;
679 40435 jjdelcerro
680 43089 jjdelcerro
        } else {
681
            // TODO: maybe we could add a new referenceIterator(int index)
682
            // method that could be implemented in a more performant way
683 40435 jjdelcerro
684 43089 jjdelcerro
            java.util.Iterator iter = getData().getSelected().iterator();
685
            for (long l = 0; l < index && iter.hasNext(); l++) {
686
                iter.next();
687
            }
688
            return new FeatureIteratorFacade(iter, getFeatureStore());
689
        }
690
    }
691 40435 jjdelcerro
692 43089 jjdelcerro
    private Long removeFeatureTypeCount(FeatureType featureType) {
693
        Long count = (Long) featureTypeCounts.get(featureType);
694
        if (count == null) {
695
            count = new Long(-1);
696
        } else {
697
            count = count - 1;
698
        }
699
        featureTypeCounts.put(featureType, count);
700
        return count;
701
    }
702 40435 jjdelcerro
703 43089 jjdelcerro
    private Long addFeatureTypeCount(FeatureType featureType) {
704
        Long count = (Long) featureTypeCounts.get(featureType);
705
        if (count == null) {
706
            count = new Long(1);
707
        } else {
708
            count = count + 1;
709
        }
710
        featureTypeCounts.put(featureType, count);
711
        return count;
712 40435 jjdelcerro
    }
713
714 43089 jjdelcerro
    @Override
715
    public void delete(Feature feature) throws DataException {
716
        Iterator it = this.featureIterators.get(feature);
717
        if (it != null) {
718
            it.remove();
719
            return;
720
        }
721
        feature.getStore().delete(feature);
722 40435 jjdelcerro
    }
723
724 43089 jjdelcerro
    @Override
725
    public void insert(EditableFeature feature) throws DataException {
726
        feature.getStore().insert(feature);
727
    }
728
729
    @Override
730
    public void update(EditableFeature feature) throws DataException {
731
        feature.getStore().update(feature);
732
    }
733 44097 omartinez
734
735
    @Override
736
    public void commitChanges() throws DataException {
737
    }
738 43089 jjdelcerro
739
    /*
740
     * (non-Javadoc)
741
     *
742
     * @seeorg.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection#
743
     * loadFromState(org.gvsig.tools.persistence.PersistentState)
744
     */
745
    @Override
746
    public void loadFromState(PersistentState state)
747
            throws PersistenceException {
748
        this.featureReferenceSelection.loadFromState(state);
749
    }
750
751
    protected void doDispose() throws BaseException {
752 47038 fdiaz
        DisposeUtils.disposeQuietly(this.featureReferenceSelection);
753 43089 jjdelcerro
        featureTypeCounts.clear();
754
    }
755
756
    public static void registerPersistent() {
757
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
758
        DynStruct definition = manager.addDefinition(
759
                DefaultFeatureSelection.class, "DefaultFeatureSelection",
760
                "DefaultFeatureSelection Persistent definition", null, null);
761
762
        definition.extend(manager.getDefinition(DefaultFeatureReferenceSelection.DYNCLASS_PERSISTENT_NAME));
763
        definition.addDynFieldMap("featureTypeCounts")
764
                .setClassOfItems(Long.class).setMandatory(false);
765
766
    }
767
768
    @Override
769
    public Object clone() throws CloneNotSupportedException {
770
        DefaultFeatureSelection clone = (DefaultFeatureSelection) super.clone();
771
        clone.featureTypeCounts = new HashMap(featureTypeCounts);
772
        return clone;
773
    }
774
775 43358 jjdelcerro
    @Override
776
    protected void doAccept(Visitor visitor, long firstValueIndex, long elements) throws BaseException {
777 43646 jjdelcerro
        if( this.featureReferenceSelection.isEmpty() ) {
778
            return;
779
        }
780 43358 jjdelcerro
        DisposableIterator iterator = fastIterator(firstValueIndex, elements);
781
        if (iterator != null) {
782
            try {
783
                while (iterator.hasNext()) {
784
                    Feature feature = (Feature) iterator.next();
785
                    visitor.visit(feature);
786
                }
787
            } finally {
788
                iterator.dispose();
789
            }
790
        }
791
    }
792
793 44113 jjdelcerro
    private static class IgnoreInsertAndUpdateFeatureSet extends DefaultFeatureSet {
794
795
        public IgnoreInsertAndUpdateFeatureSet(DefaultFeatureStore store, FeatureQuery query) throws DataException {
796
            super(store, query);
797
        }
798
799
        public void update(Observable obsevable, Object notification) {
800
            String type = ((FeatureStoreNotification) notification).getType();
801
            if (type.equalsIgnoreCase(FeatureStoreNotification.AFTER_INSERT)
802
                    || type.equalsIgnoreCase(FeatureStoreNotification.AFTER_UPDATE)) {
803
                return;
804
            }
805
            super.update(obsevable, notification);
806
        }
807
808
    }
809
810 44435 jjdelcerro
    @Override
811
    public boolean isAvailable() {
812
        return this.featureReferenceSelection.isAvailable();
813
    }
814 44113 jjdelcerro
815 47198 jjdelcerro
    @Override
816
    public String toString() {
817
        ToStringBuilder builder = new ToStringBuilder(this);
818
        builder.append("store", this.featureReferenceSelection.getFeatureStore(), true);
819
        return builder.toString();
820
    }
821
822 40767 jjdelcerro
}