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 @ 43358

History | View | Annotate | Download (24.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * 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
 *
11
 * 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
 *
16
 * 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
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.dal.feature.impl;
24

    
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.Iterator;
28
import java.util.List;
29
import java.util.Map;
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.exception.DataRuntimeException;
35
import org.gvsig.fmap.dal.feature.EditableFeature;
36
import org.gvsig.fmap.dal.feature.Feature;
37
import org.gvsig.fmap.dal.feature.FeatureReference;
38
import org.gvsig.fmap.dal.feature.FeatureSelection;
39
import org.gvsig.fmap.dal.feature.FeatureSet;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.dal.feature.FeatureType;
42
import org.gvsig.fmap.dal.feature.exception.ReversedSelectionIteratorException;
43
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection.SelectionData;
44
import org.gvsig.fmap.dal.feature.impl.featureset.AbstractFeatureSet;
45
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
46
import org.gvsig.tools.ToolsLocator;
47
import org.gvsig.tools.dispose.DisposableIterator;
48
import org.gvsig.tools.dispose.DisposeUtils;
49
import org.gvsig.tools.dynobject.DynStruct;
50
import org.gvsig.tools.exception.BaseException;
51
import org.gvsig.tools.observer.Observable;
52
import org.gvsig.tools.observer.Observer;
53
import org.gvsig.tools.persistence.PersistenceManager;
54
import org.gvsig.tools.persistence.PersistentState;
55
import org.gvsig.tools.persistence.exception.PersistenceException;
56
import org.gvsig.tools.visitor.Visitor;
57
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
59

    
60
/**
61
 * Default implementation of the FeatureSelection interface. Internally, only
62
 * FeatureReference values are stored.
63
 *
64
 * This implementation performs better if used with the selection related
65
 * methods: select, deselect and isSelected ones.
66
 *
67
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
68
 */
69
public class DefaultFeatureSelection extends AbstractFeatureSet
70
        implements FeatureSelection {
71

    
72
    public class RemoveFromFeatureSelectionException extends DataRuntimeException {
73

    
74
        /**
75
         *
76
         */
77
        private static final long serialVersionUID = 2636692469445838928L;
78
        private final static String MESSAGE_FORMAT = "Can't remove feature from reversed selection.";
79
        private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
80

    
81
        public RemoveFromFeatureSelectionException(Throwable cause) {
82
            super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
83
            //setValue("store", store);
84
        }
85
    }
86

    
87
    /**
88
     * Facade over a Iterator of FeatureReferences, to return Features instead.
89
     *
90
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
91
     */
92
    private class FeatureIteratorFacade implements DisposableIterator {
93

    
94
        private final Logger LOGGER = LoggerFactory
95
                .getLogger(FeatureIteratorFacade.class);
96

    
97
        private java.util.Iterator refIterator;
98

    
99
        private FeatureStore featureStore;
100
        private Feature currentFeature = null;
101

    
102
        public FeatureIteratorFacade(java.util.Iterator iter,
103
                FeatureStore featureStore) {
104
            this.refIterator = iter;
105
            this.featureStore = featureStore;
106
        }
107

    
108
        @Override
109
        public boolean hasNext() {
110
            return refIterator.hasNext();
111
        }
112

    
113
        @Override
114
        public Object next() {
115
            FeatureReference ref = nextFeatureReference();
116
            try {
117
                currentFeature = featureStore.getFeatureByReference(ref);
118
                return currentFeature;
119
            } catch (DataException ex) {
120
                LOGGER.error(
121
                        "Error loading the Feature with FeatureReference: "
122
                        + ref, ex);
123
                return null;
124
            }
125
        }
126

    
127
        /**
128
         * Returns the next FeatureReference.
129
         *
130
         * @return the next FeatureReference
131
         */
132
        public FeatureReference nextFeatureReference() {
133
            return (FeatureReference) refIterator.next();
134
        }
135

    
136
        @Override
137
        public void remove() {
138
            try {
139
                featureStore.delete(currentFeature);
140
                refIterator.remove();
141
            } catch (DataException e) {
142
                throw new RemoveFromFeatureSelectionException(e);
143
            }
144
        }
145

    
146
        public class RemoveFromFeatureSelectionException extends DataRuntimeException {
147

    
148
            /**
149
             *
150
             */
151
            private static final long serialVersionUID = 2636692469445838928L;
152
            private final static String MESSAGE_FORMAT = "Can't remove feature from selection.";
153
            private final static String MESSAGE_KEY = "_RemoveFromFeatureSelectionException";
154

    
155
            public RemoveFromFeatureSelectionException(Throwable cause) {
156
                super(MESSAGE_FORMAT, cause, MESSAGE_KEY, serialVersionUID);
157
                //setValue("store", store);
158
            }
159
        }
160

    
161
        @Override
162
        public void dispose() {
163
            if (refIterator instanceof DisposableIterator) {
164
                ((DisposableIterator) refIterator).dispose();
165
            }
166
            refIterator = null;
167
            featureStore = null;
168
        }
169
    }
170

    
171
    /**
172
     * Facade over a Iterator of FeatureReferences, to return Features instead,
173
     * when the Selection is reversed
174
     *
175
     * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
176
     */
177
    private class ReversedFeatureIteratorFacade implements DisposableIterator {
178

    
179
        private SelectionData selectionData;
180

    
181
        private DisposableIterator iterator;
182

    
183
        private Feature nextFeature = null;
184
        private Feature currentFeature = null;
185

    
186
        private FeatureSet featureSet;
187

    
188
        public ReversedFeatureIteratorFacade(SelectionData selectionData,
189
                FeatureStore featureStore, boolean fastIterator) {
190
            this.selectionData = selectionData;
191

    
192
            // Load a Set with all the store features
193
            try {
194
                featureSet = featureStore.getFeatureSet();
195
                //if (fastIterator) {
196
                iterator = featureSet.fastIterator();
197
//                                } else {
198
//                                        iterator = featureSet.iterator();
199
//                                }
200
            } catch (DataException ex) {
201
                throw new ReversedSelectionIteratorException(ex);
202
            }
203

    
204
            // Filter the features not selected and position in the next
205
            // selected feature
206
            positionInNextElement();
207
        }
208

    
209
        @Override
210
        public boolean hasNext() {
211
            return nextFeature != null;
212
        }
213

    
214
        @Override
215
        public Object next() {
216
            featureIterators.remove(currentFeature);
217
            currentFeature = nextFeature.getCopy();
218
            featureIterators.put(currentFeature, this);
219
            positionInNextElement();
220
            return currentFeature;
221
        }
222

    
223
        @Override
224
        public void remove() {
225
            try {
226
                featureSet.delete(currentFeature);
227
            } catch (DataException e) {
228
                throw new RemoveFromFeatureSelectionException(e);
229

    
230
            }
231
        }
232

    
233
        private void positionInNextElement() {
234
            nextFeature = null;
235
            while (iterator.hasNext()) {
236
                nextFeature = (Feature) iterator.next();
237
                if (selectionData.contains(nextFeature.getReference())) {
238
                    nextFeature = null;
239
                } else {
240
                    break;
241
                }
242
            }
243
        }
244

    
245
        @Override
246
        public void dispose() {
247
            this.featureSet.dispose();
248
            this.iterator.dispose();
249
            this.selectionData = null;
250
            this.nextFeature = null;
251
        }
252
    }
253

    
254
    private Map featureTypeCounts = new HashMap(1);
255
    private final Map<Feature, Iterator> featureIterators = new HashMap<>();
256
    private final DefaultFeatureReferenceSelection featureReferenceSelection;
257

    
258
    /**
259
     * Creates a DefaultFeatureSelection, with a FeatureStore.
260
     *
261
     * @param featureStore the FeatureStore to load Features from
262
     * @throws DataException if there is an error while getting the total number
263
     * of Features of the Store.
264
     * @see AbstractSetBasedDataSelection#DefaultSelection(int)
265
     */
266
    public DefaultFeatureSelection(DefaultFeatureStore featureStore)
267
            throws DataException {
268
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore);
269
    }
270

    
271
    /**
272
     * Creates a new Selection with the total size of Features from which the
273
     * selection will be performed.
274
     *
275
     * @param featureStore the FeatureStore of the selected FeatureReferences
276
     * @param helper to get some information of the Store
277
     * @throws DataException if there is an error while getting the total number
278
     * of Features of the Store.
279
     */
280
    public DefaultFeatureSelection(FeatureStore featureStore,
281
            FeatureSelectionHelper helper) throws DataException {
282
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection(featureStore, helper);
283
    }
284

    
285
    /**
286
     * Constructor used by the persistence manager. Don't use directly. After to
287
     * invoke this method, the persistence manager calls the the method
288
     * {@link #loadFromState(PersistentState)} to set the values of the internal
289
     * attributes that this class needs to work.
290
     */
291
    public DefaultFeatureSelection() {
292
        this.featureReferenceSelection = new DefaultFeatureReferenceSelection();
293
    }
294

    
295
    @Override
296
    public FeatureStore getFeatureStore() {
297
        return this.featureReferenceSelection.getFeatureStore();
298
    }
299

    
300
    private void notifyObservers(String notificationType) {
301
        this.featureReferenceSelection.notifyObservers(notificationType);
302
    }
303

    
304
    public FeatureCommandsStack getCommands() {
305
        return this.featureReferenceSelection.getCommands();
306
    }
307

    
308
    @Override
309
    public void enableNotifications() {
310
        this.featureReferenceSelection.enableNotifications();
311
    }
312

    
313
    @Override
314
    public void disableNotifications() {
315
        this.featureReferenceSelection.disableNotifications();
316
    }
317

    
318
    public boolean isReversed() {
319
        return this.featureReferenceSelection.isReversed();
320
    }
321

    
322
    @Override
323
    public long getSelectedCount() {
324
        return this.featureReferenceSelection.getSelectedCount();
325
    }
326

    
327
    public DefaultFeatureReferenceSelection.SelectionData getData() {
328
        return this.featureReferenceSelection.getData();
329
    }
330

    
331
    @Override
332
    public boolean select(FeatureReference reference) {
333
        return this.featureReferenceSelection.select(reference);
334
    }
335

    
336
    public boolean select(FeatureReference reference, boolean undoable) {
337
        return this.featureReferenceSelection.select(reference, undoable);
338
    }
339

    
340
    @Override
341
    public boolean deselect(FeatureReference reference) {
342
        return this.featureReferenceSelection.deselect(reference);
343
    }
344

    
345
    public boolean deselect(FeatureReference reference, boolean undoable) {
346
        return this.featureReferenceSelection.deselect(reference, undoable);
347
    }
348

    
349
    @Override
350
    public Iterator referenceIterator() {
351
        return this.featureReferenceSelection.referenceIterator();
352
    }
353

    
354
    @Override
355
    public void selectAll() throws DataException {
356
        this.featureReferenceSelection.selectAll();
357
    }
358

    
359
    @Override
360
    public void deselectAll() throws DataException {
361
        this.featureReferenceSelection.deselectAll();
362
    }
363
    
364
    public void deselectAll(boolean undoable) throws DataException {
365
        this.featureReferenceSelection.deselectAll(undoable);
366
    }
367
    
368
    @Override
369
    public boolean isSelected(FeatureReference reference) {
370
        return this.featureReferenceSelection.isSelected(reference);
371
    }
372

    
373
    @Override
374
    public void reverse() {
375
        this.featureReferenceSelection.reverse();
376
    }
377

    
378
    @Override
379
    public void dispose() {
380
        this.featureReferenceSelection.dispose();
381
    }
382

    
383
    @Override
384
    public void update(Observable o, Object o1) {
385
        this.featureReferenceSelection.update(o, o1);
386
    }
387

    
388
    @Override
389
    public void addObserver(Observer obsrvr) {
390
        this.featureReferenceSelection.addObserver(obsrvr);
391
    }
392

    
393
    @Override
394
    public void deleteObserver(Observer obsrvr) {
395
        this.featureReferenceSelection.deleteObserver(obsrvr);
396
    }
397

    
398
    @Override
399
    public void deleteObservers() {
400
        this.featureReferenceSelection.deleteObservers();
401
    }
402

    
403
    @Override
404
    public void beginComplexNotification() {
405
        this.featureReferenceSelection.beginComplexNotification();
406
    }
407

    
408
    @Override
409
    public void endComplexNotification() {
410
        this.featureReferenceSelection.endComplexNotification();
411
    }
412

    
413
    @Override
414
    public void saveToState(PersistentState ps) throws PersistenceException {
415
        this.featureReferenceSelection.saveToState(ps);
416
    }
417

    
418
    @Override
419
    public boolean select(Feature feature) {
420
        return select(feature, true);
421
    }
422

    
423
    /**
424
     * @param feature
425
     * @return
426
     * @see #select(Feature)
427
     * @param undoable if the action must be undoable
428
     */
429
    public boolean select(Feature feature, boolean undoable) {
430
        // TODO: should we check if the feature is from the same FeatureStore??
431
        if (feature == null) {
432
            return false;
433
        }
434

    
435
        // LOGGER.debug("Selected feature: {}", feature);
436
        if (isReversed()) {
437
            removeFeatureTypeCount(feature.getType());
438
        } else {
439
            addFeatureTypeCount(feature.getType());
440
        }
441
        return select(feature.getReference(), undoable);
442
    }
443

    
444
    @Override
445
    public boolean select(FeatureSet features) throws DataException {
446
        return select(features, true);
447
    }
448

    
449
    /**
450
     * @param features
451
     * @return
452
     * @throws org.gvsig.fmap.dal.exception.DataException
453
     * @see #select(FeatureSet)
454
     * @param undoable if the action must be undoable
455
     */
456
    public boolean select(FeatureSet features, boolean undoable)
457
            throws DataException {
458
        boolean change = false;
459
        boolean inComplex = false;
460
        if (undoable && this.featureReferenceSelection.getFeatureStore().isEditing()
461
                && !this.featureReferenceSelection.getCommands().inComplex()) {
462

    
463
            this.featureReferenceSelection.getCommands().startComplex("_selectionSelectFeatureSet");
464
            inComplex = this.featureReferenceSelection.getCommands().inComplex();
465
        }
466

    
467
        disableNotifications();
468
        DisposableIterator iter = null;
469
        try {
470
            for (iter = features.fastIterator(); iter.hasNext();) {
471
                change |= select((Feature) iter.next(), undoable);
472
            }
473
        } finally {
474
            DisposeUtils.disposeQuietly(iter);
475
        }
476
        enableNotifications();
477
        if (undoable && getFeatureStore().isEditing() && inComplex) {
478
            getCommands().endComplex();
479
        }
480
        if (change) {
481
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
482
        }
483
        return change;
484
    }
485

    
486
    @Override
487
    public boolean deselect(Feature feature) {
488
        return deselect(feature, true);
489
    }
490

    
491
    /**
492
     * @param feature
493
     * @return
494
     * @see #deselect(Feature)
495
     * @param undoable if the action must be undoable
496
     */
497
    public boolean deselect(Feature feature, boolean undoable) {
498
        if (feature == null) {
499
            return false;
500
        }
501

    
502
        LOG.debug("Deselected feature: {}", feature);
503

    
504
        if (isReversed()) {
505
            addFeatureTypeCount(feature.getType());
506
        } else {
507
            removeFeatureTypeCount(feature.getType());
508
        }
509
        return deselect(feature.getReference(), undoable);
510
    }
511

    
512
    @Override
513
    public boolean deselect(FeatureSet features) throws DataException {
514
        return deselect(features, true);
515
    }
516

    
517
    /**
518
     * @param features
519
     * @return
520
     * @throws org.gvsig.fmap.dal.exception.DataException
521
     * @see #deselect(FeatureSet)
522
     * @param undoable if the action must be undoable
523
     */
524
    public boolean deselect(FeatureSet features, boolean undoable)
525
            throws DataException {
526
        boolean change = false;
527
        if (undoable && getFeatureStore().isEditing()) {
528
            getCommands().startComplex("_selectionDeselectFeatureSet");
529
        }
530
        disableNotifications();
531
        DisposableIterator iter = null;
532
        try {
533
            for (iter = features.fastIterator(); iter.hasNext();) {
534
                change |= deselect((Feature) iter.next(), undoable);
535
            }
536
        } finally {
537
            DisposeUtils.disposeQuietly(iter);
538
        }
539
        enableNotifications();
540
        if (undoable && getFeatureStore().isEditing()) {
541
            getCommands().endComplex();
542
        }
543
        if (change) {
544
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
545
        }
546
        return change;
547
    }
548

    
549
    @Override
550
    public boolean isSelected(Feature feature) {
551
        if (feature == null) {
552
            return false;
553
        }
554

    
555
        // Use the selection data size as a small optimization for the most
556
        // common case, when nothing is selected and every feature is checked
557
        // while drawing or painting the table document.
558
        if (getData().isReversed()) {
559
            return getData().getSize() == 0
560
                    || !getData().contains(feature.getReference());
561
        } else {
562
            return getData().getSize() > 0
563
                    && getData().contains(feature.getReference());
564
        }
565
    }
566

    
567
    @Override
568
    public FeatureType getDefaultFeatureType() {
569
        try {
570
            return getFeatureStore().getDefaultFeatureType();
571
        } catch (DataException ex) {
572
            LOG.error("Error getting the default feature type "
573
                    + "of the FeatureStore: " + getFeatureStore(), ex);
574
        }
575
        return null;
576
    }
577

    
578
    @Override
579
    public List getFeatureTypes() {
580
        // Go through the map of FeatureTypes, and return only the ones that
581
        // have at least a Feature.
582
        List types = new ArrayList();
583
        for (java.util.Iterator iterator = featureTypeCounts.entrySet()
584
                .iterator(); iterator.hasNext();) {
585
            Map.Entry entry = (Entry) iterator.next();
586
            FeatureType type = (FeatureType) entry.getKey();
587
            Long count = (Long) entry.getValue();
588

    
589
            if (count > 0) {
590
                types.add(type);
591
            }
592
        }
593

    
594
        return types;
595
    }
596

    
597
    @Override
598
    public long getSize() throws DataException {
599
        return getSelectedCount();
600
    }
601

    
602
    /**
603
     * Returns the list of selected values, or the deselected ones if the
604
     * selection has been reversed.
605
     *
606
     * WARN: not very good performance implementation.
607
     */
608
    @Override
609
        public DisposableIterator iterator(long index) {
610
                return iterator(index, 0, false);
611
        }
612

    
613
    @Override
614
        public DisposableIterator iterator(long index, long elements) {
615
                return iterator(index, elements, false);
616
        }
617

    
618
    /**
619
     * Returns the list of selected values, or the deselected ones if the
620
     * selection has been reversed.
621
     *
622
     * WARN: not really a fast implementation.
623
     */
624
    @Override
625
        public DisposableIterator fastIterator(long index) {
626
            return fastIterator(index, 0);
627
        }
628

    
629
    @Override
630
    public DisposableIterator fastIterator(long index, long elements) {
631
        return iterator(index, elements, true);
632
    }
633

    
634

    
635
    protected void clearFeatureReferences() {
636
        this.featureReferenceSelection.clearFeatureReferences();
637
        featureTypeCounts.clear();
638
    }
639

    
640
    /**
641
     * Creates an iterator for the Selection.
642
     */
643
    private DisposableIterator iterator(long index, long elements, boolean fastIterator) {
644
        if (isReversed()) {
645
            DisposableIterator iter = new ReversedFeatureIteratorFacade(
646
                    getData(), getFeatureStore(), fastIterator);
647
            for (long l = 0; l < index && iter.hasNext(); l++) {
648
                iter.next();
649
            }
650
            return iter;
651

    
652
        } else {
653
            // TODO: maybe we could add a new referenceIterator(int index)
654
            // method that could be implemented in a more performant way
655

    
656
            java.util.Iterator iter = getData().getSelected().iterator();
657
            for (long l = 0; l < index && iter.hasNext(); l++) {
658
                iter.next();
659
            }
660
            return new FeatureIteratorFacade(iter, getFeatureStore());
661
        }
662
    }
663

    
664
    private Long removeFeatureTypeCount(FeatureType featureType) {
665
        Long count = (Long) featureTypeCounts.get(featureType);
666
        if (count == null) {
667
            count = new Long(-1);
668
        } else {
669
            count = count - 1;
670
        }
671
        featureTypeCounts.put(featureType, count);
672
        return count;
673
    }
674

    
675
    private Long addFeatureTypeCount(FeatureType featureType) {
676
        Long count = (Long) featureTypeCounts.get(featureType);
677
        if (count == null) {
678
            count = new Long(1);
679
        } else {
680
            count = count + 1;
681
        }
682
        featureTypeCounts.put(featureType, count);
683
        return count;
684
    }
685

    
686
    @Override
687
    public void delete(Feature feature) throws DataException {
688
        Iterator it = this.featureIterators.get(feature);
689
        if (it != null) {
690
            it.remove();
691
            return;
692
        }
693
        feature.getStore().delete(feature);
694
    }
695

    
696
    @Override
697
    public void insert(EditableFeature feature) throws DataException {
698
        feature.getStore().insert(feature);
699
    }
700

    
701
    @Override
702
    public void update(EditableFeature feature) throws DataException {
703
        feature.getStore().update(feature);
704
    }
705

    
706
    /*
707
     * (non-Javadoc)
708
     *
709
     * @seeorg.gvsig.fmap.dal.feature.impl.DefaultFeatureReferenceSelection#
710
     * loadFromState(org.gvsig.tools.persistence.PersistentState)
711
     */
712
    @Override
713
    public void loadFromState(PersistentState state)
714
            throws PersistenceException {
715
        this.featureReferenceSelection.loadFromState(state);
716
    }
717

    
718
    protected void doDispose() throws BaseException {
719
        this.featureReferenceSelection.doDispose();
720
        featureTypeCounts.clear();
721
    }
722

    
723
    public static void registerPersistent() {
724
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
725
        DynStruct definition = manager.addDefinition(
726
                DefaultFeatureSelection.class, "DefaultFeatureSelection",
727
                "DefaultFeatureSelection Persistent definition", null, null);
728

    
729
        definition.extend(manager.getDefinition(DefaultFeatureReferenceSelection.DYNCLASS_PERSISTENT_NAME));
730
        definition.addDynFieldMap("featureTypeCounts")
731
                .setClassOfItems(Long.class).setMandatory(false);
732

    
733
    }
734

    
735
    @Override
736
    public Object clone() throws CloneNotSupportedException {
737
        DefaultFeatureSelection clone = (DefaultFeatureSelection) super.clone();
738
        clone.featureTypeCounts = new HashMap(featureTypeCounts);
739
        return clone;
740
    }
741

    
742
    @Override
743
    protected void doAccept(Visitor visitor, long firstValueIndex, long elements) throws BaseException {
744
        DisposableIterator iterator = fastIterator(firstValueIndex, elements);
745
        if (iterator != null) {
746
            try {
747
                while (iterator.hasNext()) {
748
                    Feature feature = (Feature) iterator.next();
749
                    visitor.visit(feature);
750
                }
751
            } finally {
752
                iterator.dispose();
753
            }
754
        }
755
    }
756

    
757
}