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

History | View | Annotate | Download (16.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
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

    
46
@SuppressWarnings("UseSpecificCatch")
47
public class FeatureManager {
48

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

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

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

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

    
105
        int pos = expansionAdapter.addObject(feature);
106
        added.put(feature.getReference(), pos);
107
        deleted.remove(feature.getReference());
108
        deltaSize++;
109
    }
110

    
111
    public Feature deleteLastFeature() {
112
        expansionAdapter.deleteLastObject();
113
        Feature feature = (Feature) expansionAdapter.getObject(expansionAdapter.getSize() - 1);
114
        added.remove(feature.getReference());
115
        modifiedFromOriginal.remove(feature.getReference());
116
        deltaSize--;
117
        return feature;
118
    }
119
    
120
    public DefaultFeature get(FeatureProvider data){
121
        FeatureReference ref = FeatureReferenceFactory.createFromFeatureProvider(store, data);
122
        try {
123
            return get(ref, store);
124
        } catch (DataException ex) {
125
            return null;
126
        }
127
    }
128

    
129
    /**
130
     * Returns a Feature of the default type.
131
     *
132
     * @param id the feature reference
133
     * @param store the store to get the feature from
134
     * @return a Feature with the given reference
135
     * @throws DataException if there is an error getting the Feature
136
     */
137
    public DefaultFeature get(FeatureReference id, FeatureStore store)
138
            throws DataException {
139
        return get(id, store, null);
140
    }
141

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

    
186
    public int update(EditableFeature feature, Feature oldFeature) {
187
        FeatureReference id = feature.getReference();
188
        if(!original.containsKey(id)){
189
            int n = expansionAdapter.addObject(oldFeature);
190
            original.put(id, n);
191
        }
192
        int oldNum = -1;
193
        int num = expansionAdapter.addObject(feature);
194
        if (added.containsKey(id)) {
195
            oldNum = (added.get(id));
196
            added.put(id, num);
197
        } else {
198
            if (modifiedFromOriginal.get(id) != null) {
199
                oldNum = (modifiedFromOriginal.get(id));
200
            }
201
            modifiedFromOriginal.put(id, num);
202
        }
203
        return oldNum;
204
    }
205

    
206
    public void restore(FeatureReference id) {
207
        deleted.remove(id);
208
        deltaSize++;
209
    }
210

    
211
    public void restore(FeatureReference id, int num) {
212
        if (added.containsKey(id)) {
213
            added.put(id, num);
214
        } else {
215
            modifiedFromOriginal.put(id, num);
216
        }
217
    }
218

    
219
    public boolean isDeleted(Feature feature) {
220
        return deleted.contains(feature.getReference());
221
    }
222

    
223
    public boolean isDeleted(FeatureProvider data) {
224
        FeatureReference ref = FeatureReferenceFactory.createFromFeatureProvider(store, data);
225
        return deleted.contains(ref);
226
    }
227

    
228
    public boolean isDeleted(FeatureReference featureID) {
229
        return deleted.contains(featureID);
230
    }
231

    
232
    public void clear() {
233
        added.clear();
234
        modifiedFromOriginal.clear();
235
        expansionAdapter.close();
236
        deleted.clear();
237
        addedAndDeleted.clear();
238
        deltaSize = 0;
239
    }
240

    
241
    public boolean hasChanges() {
242
        return added.size() > 0 || modifiedFromOriginal.size() > 0 || deleted.size() > 0;
243
    }
244

    
245
    public boolean hasDeleteds() {
246
        return deleted.size() > 0;
247
    }
248

    
249
    public long getPendingChangesCount() {
250
        long count = 0;
251
        if( this.added!=null ) {
252
            count += this.added.size();
253
        }
254
        if( this.deleted!=null ) {
255
            count += this.deleted.size();
256
        }
257
        if( this.modifiedFromOriginal!=null ) {
258
            count += this.modifiedFromOriginal.size();
259
        }
260
        return count;
261
    }
262

    
263
    public Iterator<FeatureReference> getDeleted() {
264
        return new DeletedsFeatureReferencesIterator();
265

    
266
    }
267

    
268
    private class DeletedsFeatureReferencesIterator implements Iterator<FeatureReference> {
269

    
270
        private Boolean hasnext = null;
271
        private final Iterator iter;
272
        private FeatureReference reference;
273

    
274
        public DeletedsFeatureReferencesIterator() {
275
            iter = deleted.iterator();
276
        }
277

    
278
        @Override
279
        public boolean hasNext() {
280
            if (hasnext != null) {
281
                return hasnext;
282
            }
283
            hasnext = false;
284
            while (iter.hasNext()) {
285
                reference = (FeatureReference) iter.next();
286
                if (!reference.isNewFeature()) {
287
                  hasnext = true;
288
                  break;
289
                }
290
            }
291
            return hasnext;
292
        }
293

    
294
        @Override
295
        public FeatureReference next() {
296
            if (!hasNext()) {
297
                throw new NoSuchElementException();
298
            }
299
            hasnext = null;
300
            return reference;
301
        }
302

    
303
        @Override
304
        public void remove() {
305
            throw new UnsupportedOperationException();
306
        }
307

    
308
    }
309

    
310
    public Iterator<FeatureProvider> getInserted() {
311
        Iterator<EditableFeature> it = new InsertedFeaturesIterator();
312
        return new Iterator<FeatureProvider>() {
313
          @Override
314
          public boolean hasNext() {
315
            return it.hasNext();
316
          }
317

    
318
          @Override
319
          public FeatureProvider next() {
320
            return ((DefaultFeature)it.next()).getData();
321
          }
322
        };
323
    }
324

    
325
    public Iterator<EditableFeature> getInsertedFeatures() {
326
        return new InsertedFeaturesIterator();
327
    }
328

    
329
    private class InsertedFeaturesIterator implements Iterator<EditableFeature> {
330

    
331
        private final Iterator addedIter;
332
        private EditableFeature feature;
333
        private Boolean hasnext = null;
334

    
335
        public InsertedFeaturesIterator() {
336
            addedIter = added.values().iterator();
337
        }
338

    
339
        @Override
340
        public boolean hasNext() {
341
            if (hasnext != null) {
342
                return hasnext;
343
            }
344
            hasnext = false;
345
            int pos;
346
            while (addedIter.hasNext()) {
347
                pos = ((Integer) addedIter.next());
348
                feature = (EditableFeature) expansionAdapter.getObject(pos);
349
                if (!deleted.contains(feature.getReference())) {
350
                    hasnext = true;
351
                    break;
352
                }
353
            }
354
            return hasnext;
355
        }
356

    
357
        @Override
358
        public EditableFeature next() {
359
            if (!hasNext()) {
360
                throw new NoSuchElementException();
361
            }
362
            hasnext = null;
363
            return feature;
364
        }
365

    
366
        @Override
367
        public void remove() {
368
            addedIter.remove();
369
        }
370

    
371
    }
372
    
373
    public List<FeatureReference> getAddedAndUpdatedFeatures() {
374
        List<FeatureReference> references = new ArrayList<>();
375
        references.addAll(this.modifiedFromOriginal.keySet());
376
        references.addAll(this.added.keySet());
377
        return references;
378
    }
379

    
380
    public List<FeatureReference> getAddedAndUpdatedFeaturesNotValidated(DefaultFeatureRules rules, int checks) {
381
        List<FeatureReference> references = new ArrayList<>();
382
        for (FeatureReference ref : this.modifiedFromOriginal.keySet()) {
383
            Integer index = this.modifiedFromOriginal.get(ref);
384
            if( index!=null ) {
385
                EditableFeature feature = (EditableFeature) this.expansionAdapter.getObject(index);
386
                try {
387
                    rules.validate(feature, checks);
388
                } catch (DataException ex) {
389
                    references.add(ref);
390
                }
391
            }
392
        }
393
        for (FeatureReference ref : this.added.keySet()) {
394
            Integer index = this.added.get(ref);
395
            if( index!=null ) {
396
                EditableFeature feature = (EditableFeature) this.expansionAdapter.getObject(index);
397
                try {
398
                    rules.validate(feature, checks);
399
                } catch (Exception ex) {
400
                    references.add(ref);
401
                }
402
            }
403
        }
404
        return references;
405
    }
406

    
407
    public Iterator<EditableFeature> getUpdatedFeatures() {
408
        return new UpdatedFeaturesIterator();
409
    }
410

    
411
    public Iterator<FeatureProvider> getUpdated() {
412
        Iterator<EditableFeature> it = new UpdatedFeaturesIterator();
413
        return new Iterator<FeatureProvider>() {
414
          @Override
415
          public boolean hasNext() {
416
            return it.hasNext();
417
          }
418

    
419
          @Override
420
          public FeatureProvider next() {
421
            return ((DefaultFeature)it.next()).getData();
422
          }
423
        };
424
    }
425

    
426
    private class UpdatedFeaturesIterator implements Iterator<EditableFeature> {
427

    
428
        private Boolean hasnext = null;
429
        private final Iterator iter;
430
        private EditableFeature feature;
431
        private int pos;
432

    
433
        public UpdatedFeaturesIterator() {
434
            iter = expansionAdapter.iterator();
435
            pos = -1;
436
        }
437

    
438
        @Override
439
        public boolean hasNext() {
440
            if (hasnext != null) {
441
                return hasnext;
442
            }
443
            hasnext = false;
444
            while (iter.hasNext()) {
445
                pos++;
446
                Feature f = (Feature) iter.next();
447
                if ( f != null &&
448
                     !deleted.contains(f.getReference()) &&
449
                     modifiedFromOriginal.containsValue(pos)) {
450
                    hasnext = true;
451
                    feature = (EditableFeature) f;
452
                    break;
453
                }
454
            }
455
            return hasnext;
456
        }
457

    
458
        @Override
459
        public EditableFeature next() {
460
            if (!hasNext()) {
461
                throw new NoSuchElementException();
462
            }
463
            hasnext = null;
464
            return feature;
465
        }
466

    
467
        @Override
468
        public void remove() {
469
            throw new UnsupportedOperationException();
470

    
471
        }
472
    }
473

    
474
    public boolean hasNews() {
475
        return !added.isEmpty();
476
    }
477

    
478
    public long getDeltaSize() {
479
        return deltaSize;
480
    }
481

    
482
    /**
483
     * Indicates if any operation has comprimised the selected features.
484
     *
485
     * @return
486
     */
487
    public boolean isSelectionCompromised() {
488
        //Only deleted features can change order, as added features are added at the end.
489
        return !deleted.isEmpty() || !added.isEmpty();
490
    }
491
    
492
    public Feature getOriginal(FeatureReference id){
493
        Integer n = original.get(id);
494
        if(n == null){
495
            return null;
496
        }
497
        return (Feature) this.expansionAdapter.getObject(n);
498
    }
499
    
500
    public boolean isFeatureModified(FeatureReference id) {
501
        return original.containsKey(id);
502
    }
503
    
504
}