Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_dal / src / org / gvsig / fmap / dal / feature / impl / DefaultFeatureReferenceSelection.java @ 33281

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

    
29
import java.lang.ref.Reference;
30
import java.util.Collections;
31
import java.util.HashSet;
32
import java.util.Iterator;
33
import java.util.Set;
34

    
35
import org.gvsig.fmap.dal.DataStore;
36
import org.gvsig.fmap.dal.DataStoreNotification;
37
import org.gvsig.fmap.dal.exception.DataException;
38
import org.gvsig.fmap.dal.feature.FeatureReference;
39
import org.gvsig.fmap.dal.feature.FeatureReferenceSelection;
40
import org.gvsig.fmap.dal.feature.FeatureStore;
41
import org.gvsig.fmap.dal.feature.FeatureStoreNotification;
42
import org.gvsig.fmap.dal.feature.impl.undo.FeatureCommandsStack;
43
import org.gvsig.tools.ToolsLocator;
44
import org.gvsig.tools.dispose.impl.AbstractDisposable;
45
import org.gvsig.tools.dynobject.DynStruct;
46
import org.gvsig.tools.exception.BaseException;
47
import org.gvsig.tools.observer.Observable;
48
import org.gvsig.tools.observer.Observer;
49
import org.gvsig.tools.observer.impl.BaseWeakReferencingObservable;
50
import org.gvsig.tools.observer.impl.DelegateWeakReferencingObservable;
51
import org.gvsig.tools.persistence.PersistentState;
52
import org.gvsig.tools.persistence.exception.PersistenceException;
53
import org.gvsig.tools.visitor.Visitor;
54

    
55
/**
56
 * Default implementation of a FeatureReferenceSelection, based on the usage of
57
 * a java.util.Set to store individual selected or not selected
58
 * FeatureReferences, depending on the usage of the {@link #reverse()} method.
59
 *
60
 * @author <a href="mailto:cordin@disid.com">C?sar Ordi?ana</a>
61
 */
62
public class DefaultFeatureReferenceSelection extends AbstractDisposable
63
                implements FeatureReferenceSelection {
64

    
65
        public static final String DYNCLASS_PERSISTENT_NAME =
66
                        "DefaultFeatureReferenceSelection";
67

    
68
    protected SelectionData selectionData = new SelectionData();
69

    
70
    private FeatureStore featureStore;
71

    
72
    private FeatureSelectionHelper helper;
73

    
74
        private DelegateWeakReferencingObservable delegateObservable =
75
                        new DelegateWeakReferencingObservable(this);
76

    
77
        /**
78
         * Creates a new Selection with the total size of Features from which the
79
         * selection will be performed.
80
         *
81
         * @param featureStore
82
         *            the FeatureStore of the selected FeatureReferences
83
         * @throws DataException
84
         *             if there is an error while getting the total number of
85
         *             Features of the Store.
86
         */
87
    public DefaultFeatureReferenceSelection(DefaultFeatureStore featureStore)
88
            throws DataException {
89
        super();
90
        this.featureStore = featureStore;
91
        this.helper = new DefaultFeatureSelectionHelper(featureStore);
92
        selectionData.setTotalSize(featureStore.getFeatureCount());
93
    }
94

    
95
    /**
96
     * Creates a new Selection with the total size of Features from which the
97
     * selection will be performed.
98
     *
99
     * @param featureStore
100
     *            the FeatureStore of the selected FeatureReferences
101
     * @param helper
102
     *            to get some information of the Store
103
     * @throws DataException
104
     *             if there is an error while getting the total number of
105
     *             Features of the Store.
106
     */
107
    public DefaultFeatureReferenceSelection(FeatureStore featureStore,
108
            FeatureSelectionHelper helper)
109
            throws DataException {
110
        super();
111
        this.featureStore = featureStore;
112
        this.helper = helper;
113
        selectionData.setTotalSize(featureStore.getFeatureCount());
114
    }
115

    
116
        /**
117
         * Constructor used by the persistence manager. Don't use directly. After to
118
         * invoke this method, the persistence manager calls the the method
119
         * {@link #loadFromState(PersistentState)} to set the values of the internal
120
         * attributes that this class needs to work.
121
         */
122
        public DefaultFeatureReferenceSelection() {
123
                super();
124
        }
125

    
126
    public boolean select(FeatureReference reference) {
127
        return select(reference, true);
128
    }
129

    
130
    /**
131
     * @see #select(FeatureReference)
132
     * @param undoable
133
     *            if the action must be undoable
134
     */
135
    public boolean select(FeatureReference reference, boolean undoable) {
136
        if (isSelected(reference)) {
137
            return false;
138
        }
139

    
140
        if (undoable && getFeatureStore().isEditing()) {
141
            getCommands().select(this, reference);
142
        }
143
        boolean change = false;
144
        if (selectionData.isReversed()) {
145
            change = selectionData.remove(reference);
146
        } else {
147
            change = selectionData.add(reference);
148
        }
149

    
150
        if (change) {
151
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
152
        }
153

    
154
        return change;
155
    }
156

    
157
    public boolean deselect(FeatureReference reference) {
158
        return deselect(reference, true);
159
    }
160

    
161
    /**
162
     * @see #deselect(FeatureReference)
163
     * @param undoable
164
     *            if the action must be undoable
165
     */
166
    public boolean deselect(FeatureReference reference, boolean undoable) {
167
        if (!isSelected(reference)) {
168
            return false;
169
        }
170

    
171
        if (undoable && getFeatureStore().isEditing()) {
172
            getCommands().deselect(this, reference);
173
        }
174
        boolean change = false;
175
        if (selectionData.isReversed()) {
176
            change = selectionData.add(reference);
177
        } else {
178
            change = selectionData.remove(reference);
179
        }
180

    
181
        if (change) {
182
            notifyObservers(DataStoreNotification.SELECTION_CHANGE);
183
        }
184

    
185
        return change;
186
    }
187

    
188
    public void selectAll() throws DataException {
189
        selectAll(true);
190
    }
191

    
192
    /**
193
     * @see #selectAll()
194
     * @param undoable
195
     *            if the action must be undoable
196
     */
197
    public void selectAll(boolean undoable) throws DataException {
198
        if (undoable && getFeatureStore().isEditing()) {
199
            getCommands().startComplex("_selectionSelectAll");
200
            getCommands().selectAll(this);
201
        }
202
        if (!selectionData.isReversed()) {
203
            selectionData.setReversed(true);
204
        }
205
        clearFeatureReferences();
206
        if (undoable && getFeatureStore().isEditing()) {
207
            getCommands().endComplex();
208
        }
209
        notifyObservers(DataStoreNotification.SELECTION_CHANGE);
210
    }
211

    
212
    public void deselectAll() throws DataException {
213
        deselectAll(true);
214
    }
215

    
216
    /**
217
     * @see #deselectAll()
218
     * @param undoable
219
     *            if the action must be undoable
220
     */
221
    public void deselectAll(boolean undoable) throws DataException {
222
        if (undoable && getFeatureStore().isEditing()) {
223
            getCommands().startComplex("_selectionDeselectAll");
224
            getCommands().deselectAll(this);
225
        }
226
        if (selectionData.isReversed()) {
227
            selectionData.setReversed(false);
228
        }
229
        clearFeatureReferences();
230
        if (undoable && getFeatureStore().isEditing()) {
231
            getCommands().endComplex();
232
        }
233

    
234
        notifyObservers(DataStoreNotification.SELECTION_CHANGE);
235
    }
236

    
237
    public boolean isSelected(FeatureReference reference) {
238
        if (selectionData.isReversed()) {
239
            return !selectionData.contains(reference);
240
        } else {
241
            return selectionData.contains(reference);
242
        }
243
    }
244

    
245
    public void reverse() {
246
        reverse(true);
247
    }
248

    
249
    /**
250
     * @see #reverse()
251
     * @param undoable
252
     *            if the action must be undoable
253
     */
254
    public void reverse(boolean undoable) {
255
        if (undoable && getFeatureStore().isEditing()) {
256
            getCommands().selectionReverse(this);
257
        }
258
        selectionData.setReversed(!selectionData.isReversed());
259
        notifyObservers(DataStoreNotification.SELECTION_CHANGE);
260
    }
261

    
262
    public long getSelectedCount() {
263
        if (selectionData.isReversed()) {
264
                return selectionData.getTotalSize() - selectionData.getSize()
265
                        + helper.getFeatureStoreDeltaSize();
266
        } else {
267
            return selectionData.getSize();
268
        }
269
    }
270

    
271
    public Iterator referenceIterator() {
272
        return Collections.unmodifiableSet(selectionData.getSelected())
273
                .iterator();
274
    }
275

    
276
        protected void doDispose() throws BaseException {
277
                delegateObservable.deleteObservers();
278
                deselectAll(false);
279
    }
280

    
281
    public boolean isFromStore(DataStore store) {
282
        return featureStore.equals(store);
283
    }
284

    
285
    public void accept(Visitor visitor) throws BaseException {
286
        for (Iterator iter = selectionData.getSelected().iterator(); iter
287
                .hasNext();) {
288
            visitor.visit(iter.next());
289
        }
290
    }
291

    
292
    public void update(Observable observable,
293
                        Object notification) {
294
        // If a Feature is deleted, remove it from the selection Set.
295
        if (notification instanceof FeatureStoreNotification) {
296
            FeatureStoreNotification storeNotif = (FeatureStoreNotification) notification;
297
            if (FeatureStoreNotification.AFTER_DELETE
298
                    .equalsIgnoreCase(storeNotif.getType())) {
299
                selectionData.remove(storeNotif.getFeature().getReference());
300
            }
301
        }
302
    }
303

    
304
    public SelectionData getData() {
305
        return selectionData;
306
    }
307

    
308
    public void setData(SelectionData selectionData) {
309
        this.selectionData = selectionData;
310
        notifyObservers(DataStoreNotification.SELECTION_CHANGE);
311
    }
312

    
313
    public String toString() {
314
        return getClass().getName() + ": " + getSelectedCount()
315
                + " features selected, reversed = "
316
                + selectionData.isReversed() + ", featureIds contained: "
317
                + selectionData.getSelected();
318
    }
319

    
320
    protected boolean isReversed() {
321
        return selectionData.isReversed();
322
    }
323

    
324
    /**
325
     * Removes all the stored FeatureRefence objects.
326
     */
327
    protected void clearFeatureReferences() {
328
        selectionData.clear();
329
    }
330

    
331
        /**
332
         * Returns the FeatureStore of the selected FeatureReferences.
333
         *
334
         * @return the featureStore
335
         */
336
    protected FeatureStore getFeatureStore() {
337
        return featureStore;
338
    }
339

    
340
        /**
341
         * Returns the reference to the commands record.
342
         *
343
         * @return the reference to the commands record
344
         */
345
    protected FeatureCommandsStack getCommands() {
346
        return helper.getFeatureStoreCommandsStack();
347
    }
348

    
349
    public static class SelectionData {
350
        private Set selected = new HashSet();
351

    
352
        /**
353
         * Sets how the Set of selected values has to be dealt.
354
         * <p>
355
         * If selected is FALSE, then values into the Set are the selected ones,
356
         * anything else is not selected.
357
         * </p>
358
         * <p>
359
         * If selected is TRUE, then values into the Set are values not
360
         * selected, anything else is selected.
361
         * </p>
362
         */
363
        private boolean reversed = false;
364

    
365
        private long totalSize;
366

    
367
        /**
368
         * @return the selected
369
         */
370
        public Set getSelected() {
371
            return selected;
372
        }
373

    
374
        /**
375
         * @param selected
376
         *            the selected to set
377
         */
378
        public void setSelected(Set selected) {
379
            this.selected = selected;
380
        }
381

    
382
        /**
383
         * @return the reversed
384
         */
385
        public boolean isReversed() {
386
            return reversed;
387
        }
388

    
389
        /**
390
         * @param reversed
391
         *            the reversed to set
392
         */
393
        public void setReversed(boolean reversed) {
394
            this.reversed = reversed;
395
        }
396

    
397
        /**
398
         * @return the totalSize
399
         */
400
        public long getTotalSize() {
401
            return totalSize;
402
        }
403

    
404
        /**
405
         * @param totalSize
406
         *            the totalSize to set
407
         */
408
        public void setTotalSize(long totalSize) {
409
            this.totalSize = totalSize;
410
        }
411

    
412
        public boolean add(FeatureReference reference) {
413
            return selected.add(reference);
414
        }
415

    
416
        public boolean remove(FeatureReference reference) {
417
            return selected.remove(reference);
418
        }
419

    
420
        public void clear() {
421
            selected.clear();
422
        }
423

    
424
        public boolean contains(FeatureReference reference) {
425
            return selected.contains(reference);
426
        }
427

    
428
        public int getSize() {
429
            return selected.size();
430
        }
431

    
432
        public Object clone() throws CloneNotSupportedException {
433
            SelectionData clone = new SelectionData();
434
            clone.setReversed(isReversed());
435
            clone.setTotalSize(getTotalSize());
436
            clone.setSelected(new HashSet(getSelected()));
437
            return clone;
438
        }
439
    }
440

    
441
    // *** Persistence ***
442

    
443
        public void saveToState(PersistentState state) throws PersistenceException {
444
                state.set("store", featureStore);
445
                state.set("reversed", selectionData.isReversed());
446
                state.set("totalSize", selectionData.getTotalSize());
447
                state.set("selected", selectionData.getSelected().iterator());
448
        }
449

    
450
        public void loadFromState(PersistentState state)
451
                        throws PersistenceException {
452
                featureStore = (FeatureStore)state.get("store");
453
                selectionData.setReversed(state.getBoolean("reversed"));
454
                selectionData.setTotalSize(state.getLong("totalSize"));
455
                Iterator it = state.getIterator("selected");
456
                while (it.hasNext()) {
457
                        DefaultFeatureReference ref = (DefaultFeatureReference) it.next();
458
                        selectionData.add(ref);
459
                }
460
        }
461

    
462
        public static void registerPersistent() {
463
                DynStruct definition = ToolsLocator.getPersistenceManager().addDefinition(
464
                                DefaultFeatureReferenceSelection.class, 
465
                                DYNCLASS_PERSISTENT_NAME, 
466
                                "DefaultFeatureReferenceSelection Persistent definition",
467
                                null, 
468
                                null
469
                        );
470

    
471
                definition.addDynFieldObject("store").setClassOfValue(FeatureStore.class).setMandatory(true);
472
                definition.addDynFieldBoolean("reversed").setMandatory(true);
473
                definition.addDynFieldLong("totalSize").setMandatory(true);
474
                definition.addDynFieldList("selected").setClassOfItems(DefaultFeatureReference.class).setMandatory(true);
475

    
476
        }
477

    
478
        public void addObserver(Observer observer) {
479
                delegateObservable.addObserver(observer);
480
        }
481

    
482
        public void addObserver(Reference ref) {
483
                delegateObservable.addObserver(ref);
484
        }
485

    
486
        public void addObservers(BaseWeakReferencingObservable observable) {
487
                delegateObservable.addObservers(observable);
488
        }
489

    
490
        public void beginComplexNotification() {
491
                delegateObservable.beginComplexNotification();
492
        }
493

    
494
        public int countObservers() {
495
                return delegateObservable.countObservers();
496
        }
497

    
498
        public void deleteObserver(Observer observer) {
499
                delegateObservable.deleteObserver(observer);
500
        }
501

    
502
        public void deleteObserver(Reference ref) {
503
                delegateObservable.deleteObserver(ref);
504
        }
505

    
506
        public void deleteObservers() {
507
                delegateObservable.deleteObservers();
508
        }
509

    
510
        public void disableNotifications() {
511
                delegateObservable.disableNotifications();
512
        }
513

    
514
        public void enableNotifications() {
515
                delegateObservable.enableNotifications();
516
        }
517

    
518
        public void endComplexNotification() {
519
                delegateObservable.endComplexNotification();
520
        }
521

    
522
        public boolean inComplex() {
523
                return delegateObservable.inComplex();
524
        }
525

    
526
        public boolean isEnabledNotifications() {
527
                return delegateObservable.isEnabledNotifications();
528
        }
529

    
530
        public void notifyObservers() {
531
                delegateObservable.notifyObservers();
532
        }
533

    
534
        public void notifyObservers(Object arg) {
535
                delegateObservable.notifyObservers(arg);
536
        }
537
}