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 / editing / memory / FeatureManager.java @ 46714

History | View | Annotate | Download (17 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
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl.editing.memory;
25

    
26
import java.util.ArrayList;
27
import java.util.Collection;
28
import java.util.HashMap;
29
import java.util.Iterator;
30
import java.util.LinkedHashMap;
31
import java.util.LinkedHashSet;
32
import java.util.List;
33
import java.util.Map;
34
import java.util.NoSuchElementException;
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.feature.EditableFeature;
37
import org.gvsig.fmap.dal.feature.Feature;
38
import org.gvsig.fmap.dal.feature.FeatureReference;
39
import org.gvsig.fmap.dal.feature.FeatureStore;
40
import org.gvsig.fmap.dal.feature.FeatureType;
41
import org.gvsig.fmap.dal.feature.impl.DefaultFeature;
42
import org.gvsig.fmap.dal.feature.impl.DefaultFeatureRules;
43
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory;
44
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
45
import org.gvsig.tools.util.Rewind;
46
import org.gvsig.tools.util.Size;
47

    
48
@SuppressWarnings("UseSpecificCatch")
49
public class FeatureManager {
50

    
51
    private int deltaSize;
52
    private final ExpansionAdapter expansionAdapter;
53
    private final Collection<FeatureReference> deleted;
54
    private final Map<FeatureReference, Integer> added;
55
    private final Map<FeatureReference, Integer> addedAndDeleted;
56
    private final Map<FeatureReference, Integer> modifiedFromOriginal;
57
    private final Map<FeatureReference, Integer> original;
58
    private final FeatureStore store;
59

    
60
    public FeatureManager(FeatureStore store) {
61
        deltaSize = 0;
62
        expansionAdapter = new MemoryExpansionAdapter();
63
        deleted = new LinkedHashSet<>();
64
        added = new LinkedHashMap<>();
65
        addedAndDeleted = new LinkedHashMap<>();
66
        modifiedFromOriginal = new HashMap<>();
67
        original = new HashMap<>();
68
        this.store = store;
69
    }
70

    
71
    /**
72
     * Deletes feature from this manager.
73
     *
74
     * @param id
75
     * @return The deleted feature or null if the feature had not been edited or
76
     * previously added in the editing session
77
     */
78
    public Feature delete(Feature feature) {
79
        FeatureReference id = feature.getReference();
80
        if(!original.containsKey(id)){
81
            int n = expansionAdapter.addObject(feature);
82
            original.put(id, n);
83
        }
84
        deleted.add(id);
85
        Integer num = added.remove(id);
86
        Feature previousFeature = null;
87
        if (num == null || num == -1) {
88
            num = modifiedFromOriginal.remove(id);
89
            if (num != null) {
90
                previousFeature = (Feature) expansionAdapter.getObject(num);
91
            }
92
            // if num is null here, method returns null
93
        } else {
94
            previousFeature = (Feature) expansionAdapter.getObject(num);
95
            addedAndDeleted.put(id, num);
96
        }
97
        deltaSize--;
98
        return previousFeature;
99
    }
100

    
101
    public void add(EditableFeature feature) {
102
        FeatureReference id = feature.getReference();
103
        if(!original.containsKey(id)){
104
            original.put(id, null);
105
        }
106

    
107
        int pos = expansionAdapter.addObject(feature);
108
        added.put(feature.getReference(), pos);
109
        deleted.remove(feature.getReference());
110
        deltaSize++;
111
    }
112
    
113
    public void undoAdd(EditableFeature feature) {
114
        FeatureReference id = feature.getReference();
115
        if(added.remove(id)!=null){
116
            deltaSize--;
117
        };
118
    }
119

    
120
    public Feature deleteLastFeature() {
121
        expansionAdapter.deleteLastObject();
122
        Feature feature = (Feature) expansionAdapter.getObject(expansionAdapter.getSize() - 1);
123
        added.remove(feature.getReference());
124
        modifiedFromOriginal.remove(feature.getReference());
125
        deltaSize--;
126
        return feature;
127
    }
128
    
129
    public DefaultFeature get(FeatureProvider data){
130
        FeatureReference ref = FeatureReferenceFactory.createFromFeatureProvider(store, data);
131
        try {
132
            return get(ref, store);
133
        } catch (DataException ex) {
134
            return null;
135
        }
136
    }
137

    
138
    /**
139
     * Returns a Feature of the default type.
140
     *
141
     * @param id the feature reference
142
     * @param store the store to get the feature from
143
     * @return a Feature with the given reference
144
     * @throws DataException if there is an error getting the Feature
145
     */
146
    public DefaultFeature get(FeatureReference id, FeatureStore store)
147
            throws DataException {
148
        return get(id, store, null);
149
    }
150

    
151
    /**
152
     * Returns a Feature of the given type.
153
     *
154
     * @param id the feature reference
155
     * @param store the store to get the feature from
156
     * @param featureType the type of the feature to return
157
     * @return a Feature with the given reference
158
     * @throws DataException if there is an error getting the Feature
159
     */
160
    public DefaultFeature get(FeatureReference id, FeatureStore store,
161
            FeatureType featureType) throws DataException {
162
        // FIXME: y si el featuretype que paso esta modificado.
163
        //        Deberia buscarlo en el featuretypemanager ?
164
        //
165
        //        Si no existe feature con ese id... ? retorna null ?
166
        //        en EditedDefaultIterator se hace uso de ese comportamiento.
167
        //
168
        boolean isNewFeature = false;
169
        Integer intNum = (added.get(id));
170
        if (intNum == null) {
171
            intNum = (modifiedFromOriginal.get(id));
172
            if (intNum == null) {
173
                //If the feature has been added and deleted
174
                intNum = addedAndDeleted.get(id);
175
                if (intNum == null) {
176
                    return null;
177
                }
178
            }
179
        } else {
180
            isNewFeature = true;
181
        }
182
        int num = intNum;
183
        if (num == -1) {
184
            return null;
185
        }
186
        Feature feature = (Feature) expansionAdapter.getObject(num);
187
        if (featureType == null) {
188
            featureType = store.getDefaultFeatureType();
189
        }
190
        DefaultFeature feat = new DefaultFeature(featureType, feature);
191
        feat.getData().setNew(isNewFeature);
192
        return feat;
193
    }
194

    
195
    public int update(EditableFeature feature, Feature oldFeature) {
196
        FeatureReference id = feature.getReference();
197
        if(id == null){
198
            throw new IllegalArgumentException("Can't update feature without references support.");
199
        }
200
        if(!original.containsKey(id)){
201
            int n = expansionAdapter.addObject(oldFeature);
202
            original.put(id, n);
203
        }
204
        int oldNum = -1;
205
        int num = expansionAdapter.addObject(feature);
206
        if (added.containsKey(id)) {
207
            oldNum = (added.get(id));
208
            added.put(id, num);
209
        } else {
210
            if (modifiedFromOriginal.get(id) != null) {
211
                oldNum = (modifiedFromOriginal.get(id));
212
            }
213
            modifiedFromOriginal.put(id, num);
214
        }
215
        return oldNum;
216
    }
217

    
218
    public void restore(FeatureReference id) {
219
        deleted.remove(id);
220
        deltaSize++;
221
    }
222

    
223
    public void restore(FeatureReference id, int num) {
224
        if (added.containsKey(id)) {
225
            added.put(id, num);
226
        } else {
227
            modifiedFromOriginal.put(id, num);
228
        }
229
    }
230

    
231
    public boolean isDeleted(Feature feature) {
232
        return deleted.contains(feature.getReference());
233
    }
234

    
235
    public boolean isDeleted(FeatureProvider data) {
236
        FeatureReference ref = FeatureReferenceFactory.createFromFeatureProvider(store, data);
237
        return deleted.contains(ref);
238
    }
239

    
240
    public boolean isDeleted(FeatureReference featureID) {
241
        return deleted.contains(featureID);
242
    }
243

    
244
    public void clear() {
245
        added.clear();
246
        modifiedFromOriginal.clear();
247
        expansionAdapter.close();
248
        deleted.clear();
249
        addedAndDeleted.clear();
250
        deltaSize = 0;
251
    }
252

    
253
    public boolean hasChanges() {
254
        return added.size() > 0 || modifiedFromOriginal.size() > 0 || deleted.size() > 0;
255
    }
256

    
257
    public boolean hasDeleteds() {
258
        return deleted.size() > 0;
259
    }
260

    
261
    public long getPendingChangesCount() {
262
        long count = 0;
263
        if( this.added!=null ) {
264
            count += this.added.size();
265
        }
266
        if( this.deleted!=null ) {
267
            count += this.deleted.size();
268
        }
269
        if( this.modifiedFromOriginal!=null ) {
270
            count += this.modifiedFromOriginal.size();
271
        }
272
        return count;
273
    }
274

    
275
    public Iterator<FeatureReference> getDeleted() {
276
        return new DeletedsFeatureReferencesIterator();
277

    
278
    }
279

    
280
    private class DeletedsFeatureReferencesIterator implements Iterator<FeatureReference> {
281

    
282
        private Boolean hasnext = null;
283
        private final Iterator iter;
284
        private FeatureReference reference;
285

    
286
        public DeletedsFeatureReferencesIterator() {
287
            iter = deleted.iterator();
288
        }
289

    
290
        @Override
291
        public boolean hasNext() {
292
            if (hasnext != null) {
293
                return hasnext;
294
            }
295
            hasnext = false;
296
            while (iter.hasNext()) {
297
                reference = (FeatureReference) iter.next();
298
                if (!reference.isNewFeature()) {
299
                  hasnext = true;
300
                  break;
301
                }
302
            }
303
            return hasnext;
304
        }
305

    
306
        @Override
307
        public FeatureReference next() {
308
            if (!hasNext()) {
309
                throw new NoSuchElementException();
310
            }
311
            hasnext = null;
312
            return reference;
313
        }
314

    
315
        @Override
316
        public void remove() {
317
            throw new UnsupportedOperationException();
318
        }
319

    
320
    }
321

    
322
    public Iterator<FeatureProvider> getInserted() {
323
        Iterator<EditableFeature> it = new InsertedFeaturesIterator();
324
        return new Iterator<FeatureProvider>() {
325
          @Override
326
          public boolean hasNext() {
327
            return it.hasNext();
328
          }
329

    
330
          @Override
331
          public FeatureProvider next() {
332
            return ((DefaultFeature)it.next()).getData();
333
          }
334
        };
335
    }
336

    
337
    public Iterator<EditableFeature> getInsertedFeatures() {
338
        return new InsertedFeaturesIterator();
339
    }
340

    
341
    private class InsertedFeaturesIterator implements Iterator<EditableFeature>, Size, Rewind {
342

    
343
        private Iterator addedIter;
344
        private EditableFeature feature;
345
        private Boolean hasnext = null;
346

    
347
        public InsertedFeaturesIterator() {
348
            addedIter = added.values().iterator();
349
        }
350

    
351
        @Override
352
        public boolean hasNext() {
353
            if (hasnext != null) {
354
                return hasnext;
355
            }
356
            hasnext = false;
357
            int pos;
358
            while (addedIter.hasNext()) {
359
                pos = ((Integer) addedIter.next());
360
                feature = (EditableFeature) expansionAdapter.getObject(pos);
361
                if (!deleted.contains(feature.getReference())) {
362
                    hasnext = true;
363
                    break;
364
                }
365
            }
366
            return hasnext;
367
        }
368

    
369
        @Override
370
        public EditableFeature next() {
371
            if (!hasNext()) {
372
                throw new NoSuchElementException();
373
            }
374
            hasnext = null;
375
            return feature;
376
        }
377

    
378
        @Override
379
        public void remove() {
380
            addedIter.remove();
381
        }
382

    
383
        @Override
384
        public int size() {
385
            return added.size();
386
        }
387
        
388
        @Override
389
        public void rewind() {
390
            addedIter = added.values().iterator();
391
            hasnext = null;
392
        }
393

    
394
    }
395
    
396
    public List<FeatureReference> getAddedAndUpdatedFeatures() {
397
        List<FeatureReference> references = new ArrayList<>();
398
        references.addAll(this.modifiedFromOriginal.keySet());
399
        references.addAll(this.added.keySet());
400
        return references;
401
    }
402

    
403
    public List<FeatureReference> getAddedAndUpdatedFeaturesNotValidated(DefaultFeatureRules rules, int checks) {
404
        List<FeatureReference> references = new ArrayList<>();
405
        for (FeatureReference ref : this.modifiedFromOriginal.keySet()) {
406
            Integer index = this.modifiedFromOriginal.get(ref);
407
            if( index!=null ) {
408
                EditableFeature feature = (EditableFeature) this.expansionAdapter.getObject(index);
409
                try {
410
                    rules.validate(feature, checks);
411
                } catch (DataException ex) {
412
                    references.add(ref);
413
                }
414
            }
415
        }
416
        for (FeatureReference ref : this.added.keySet()) {
417
            Integer index = this.added.get(ref);
418
            if( index!=null ) {
419
                EditableFeature feature = (EditableFeature) this.expansionAdapter.getObject(index);
420
                try {
421
                    rules.validate(feature, checks);
422
                } catch (Exception ex) {
423
                    references.add(ref);
424
                }
425
            }
426
        }
427
        return references;
428
    }
429

    
430
    public Iterator<EditableFeature> getUpdatedFeatures() {
431
        return new UpdatedFeaturesIterator();
432
    }
433

    
434
    public Iterator<FeatureProvider> getUpdated() {
435
        Iterator<EditableFeature> it = new UpdatedFeaturesIterator();
436
        return new Iterator<FeatureProvider>() {
437
          @Override
438
          public boolean hasNext() {
439
            return it.hasNext();
440
          }
441

    
442
          @Override
443
          public FeatureProvider next() {
444
            return ((DefaultFeature)it.next()).getData();
445
          }
446
        };
447
    }
448

    
449
    private class UpdatedFeaturesIterator implements Iterator<EditableFeature>, Size, Rewind {
450

    
451
        private Boolean hasnext = null;
452
        private Iterator iter;
453
        private EditableFeature feature;
454
        private int pos;
455

    
456
        public UpdatedFeaturesIterator() {
457
            iter = expansionAdapter.iterator();
458
            pos = -1;
459
        }
460

    
461
        @Override
462
        public boolean hasNext() {
463
            if (hasnext != null) {
464
                return hasnext;
465
            }
466
            hasnext = false;
467
            while (iter.hasNext()) {
468
                pos++;
469
                Feature f = (Feature) iter.next();
470
                if ( f != null &&
471
                     !deleted.contains(f.getReference()) &&
472
                     modifiedFromOriginal.containsValue(pos)) {
473
                    hasnext = true;
474
                    feature = (EditableFeature) f;
475
                    break;
476
                }
477
            }
478
            return hasnext;
479
        }
480

    
481
        @Override
482
        public EditableFeature next() {
483
            if (!hasNext()) {
484
                throw new NoSuchElementException();
485
            }
486
            hasnext = null;
487
            return feature;
488
        }
489

    
490
        @Override
491
        public void remove() {
492
            throw new UnsupportedOperationException();
493
        }
494
        
495
        @Override
496
        public int size() {
497
            return expansionAdapter.getSize();
498
        }
499
        
500
        @Override
501
        public void rewind() {
502
            iter = expansionAdapter.iterator();
503
            pos = -1;
504
            hasnext = null;
505
        }
506
    }
507

    
508
    public boolean hasNews() {
509
        return !added.isEmpty();
510
    }
511

    
512
    public long getDeltaSize() {
513
        return deltaSize;
514
    }
515

    
516
    /**
517
     * Indicates if any operation has comprimised the selected features.
518
     *
519
     * @return
520
     */
521
    public boolean isSelectionCompromised() {
522
        //Only deleted features can change order, as added features are added at the end.
523
        return !deleted.isEmpty() || !added.isEmpty();
524
    }
525
    
526
    public Feature getOriginal(FeatureReference id){
527
        Integer n = original.get(id);
528
        if(n == null){
529
            return null;
530
        }
531
        return (Feature) this.expansionAdapter.getObject(n);
532
    }
533
    
534
    public boolean isFeatureModified(FeatureReference id) {
535
        return original.containsKey(id);
536
    }
537
    
538
}