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 @ 45647
History | View | Annotate | Download (14.2 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 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | 40559 | jjdelcerro | * as published by the Free Software Foundation; either version 3
|
9 | 40435 | jjdelcerro | * 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 | 40559 | jjdelcerro | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
19 | * MA 02110-1301, USA.
|
||
20 | 40435 | jjdelcerro | *
|
21 | 40559 | jjdelcerro | * For any additional information, do not hesitate to contact us
|
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | 40435 | jjdelcerro | */
|
24 | 43840 | jjdelcerro | package org.gvsig.fmap.dal.feature.impl.editing.memory; |
25 | 40435 | jjdelcerro | |
26 | import java.util.Collection; |
||
27 | import java.util.HashMap; |
||
28 | import java.util.Iterator; |
||
29 | import java.util.LinkedHashMap; |
||
30 | import java.util.LinkedHashSet; |
||
31 | import java.util.Map; |
||
32 | import java.util.NoSuchElementException; |
||
33 | import org.gvsig.fmap.dal.exception.DataException; |
||
34 | import org.gvsig.fmap.dal.feature.Feature; |
||
35 | import org.gvsig.fmap.dal.feature.FeatureReference; |
||
36 | import org.gvsig.fmap.dal.feature.FeatureStore; |
||
37 | import org.gvsig.fmap.dal.feature.FeatureType; |
||
38 | 43840 | jjdelcerro | import org.gvsig.fmap.dal.feature.impl.DefaultFeature; |
39 | 45647 | fdiaz | import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory; |
40 | 44871 | jjdelcerro | import org.gvsig.fmap.dal.feature.spi.FeatureProvider; |
41 | 40435 | jjdelcerro | |
42 | public class FeatureManager { |
||
43 | 42639 | dmartinezizquierdo | |
44 | 43840 | jjdelcerro | private int deltaSize; |
45 | 43838 | jjdelcerro | private final ExpansionAdapter expansionAdapter; |
46 | 43840 | jjdelcerro | private final Collection<FeatureReference> deleted; |
47 | private final Map<FeatureReference, Integer> added; |
||
48 | private final Map<FeatureReference, Integer> addedAndDeleted; |
||
49 | private final Map<FeatureReference, Integer> modifiedFromOriginal; |
||
50 | 45521 | fdiaz | private final Map<FeatureReference, Integer> original; |
51 | 45647 | fdiaz | private final FeatureStore store; |
52 | 43838 | jjdelcerro | |
53 | 45647 | fdiaz | public FeatureManager(FeatureStore store) {
|
54 | 43840 | jjdelcerro | deltaSize = 0;
|
55 | expansionAdapter = new MemoryExpansionAdapter();
|
||
56 | deleted = new LinkedHashSet<>(); |
||
57 | added = new LinkedHashMap<>(); |
||
58 | addedAndDeleted = new LinkedHashMap<>(); |
||
59 | modifiedFromOriginal = new HashMap<>(); |
||
60 | 45521 | fdiaz | original = new HashMap<>(); |
61 | 45647 | fdiaz | this.store = store;
|
62 | 40435 | jjdelcerro | } |
63 | |||
64 | 43838 | jjdelcerro | /**
|
65 | * Deletes feature from this manager.
|
||
66 | *
|
||
67 | * @param id
|
||
68 | * @return The deleted feature or null if the feature had not been edited or
|
||
69 | * previously added in the editing session
|
||
70 | */
|
||
71 | 45521 | fdiaz | public Feature delete(Feature feature) {
|
72 | FeatureReference id = feature.getReference(); |
||
73 | if(!original.containsKey(id)){
|
||
74 | int n = expansionAdapter.addObject(feature);
|
||
75 | original.put(id, n); |
||
76 | } |
||
77 | 40435 | jjdelcerro | deleted.add(id); |
78 | 43838 | jjdelcerro | Integer num = added.remove(id);
|
79 | 45521 | fdiaz | Feature previousFeature = null;
|
80 | 43838 | jjdelcerro | if (num == null || num == -1) { |
81 | num = modifiedFromOriginal.remove(id); |
||
82 | 40435 | jjdelcerro | if (num != null) { |
83 | 45521 | fdiaz | previousFeature = (Feature) expansionAdapter.getObject(num); |
84 | 40435 | jjdelcerro | } |
85 | // if num is null here, method returns null
|
||
86 | 43838 | jjdelcerro | } else {
|
87 | 45521 | fdiaz | previousFeature = (Feature) expansionAdapter.getObject(num); |
88 | 43838 | jjdelcerro | addedAndDeleted.put(id, num); |
89 | } |
||
90 | 40435 | jjdelcerro | deltaSize--; |
91 | 45521 | fdiaz | return previousFeature;
|
92 | 40435 | jjdelcerro | } |
93 | |||
94 | public void add(Feature feature) { |
||
95 | 45521 | fdiaz | FeatureReference id = feature.getReference(); |
96 | if(!original.containsKey(id)){
|
||
97 | original.put(id, null);
|
||
98 | } |
||
99 | |||
100 | 40435 | jjdelcerro | int pos = expansionAdapter.addObject(feature);
|
101 | 43838 | jjdelcerro | added.put(feature.getReference(), pos); |
102 | 40435 | jjdelcerro | deleted.remove(feature.getReference()); |
103 | deltaSize++; |
||
104 | } |
||
105 | |||
106 | public Feature deleteLastFeature() {
|
||
107 | expansionAdapter.deleteLastObject(); |
||
108 | 43838 | jjdelcerro | Feature feature = (Feature) expansionAdapter.getObject(expansionAdapter.getSize() - 1);
|
109 | 40435 | jjdelcerro | added.remove(feature.getReference()); |
110 | modifiedFromOriginal.remove(feature.getReference()); |
||
111 | deltaSize--; |
||
112 | return feature;
|
||
113 | } |
||
114 | 45647 | fdiaz | |
115 | public DefaultFeature get(FeatureProvider data){
|
||
116 | FeatureReference ref = FeatureReferenceFactory.createFromFeatureProvider(store, data); |
||
117 | try {
|
||
118 | return get(ref, store);
|
||
119 | } catch (DataException ex) {
|
||
120 | return null; |
||
121 | } |
||
122 | } |
||
123 | 40435 | jjdelcerro | |
124 | /**
|
||
125 | * Returns a Feature of the default type.
|
||
126 | *
|
||
127 | 43838 | jjdelcerro | * @param id the feature reference
|
128 | * @param store the store to get the feature from
|
||
129 | 40435 | jjdelcerro | * @return a Feature with the given reference
|
130 | 43838 | jjdelcerro | * @throws DataException if there is an error getting the Feature
|
131 | 40435 | jjdelcerro | */
|
132 | 45647 | fdiaz | public DefaultFeature get(FeatureReference id, FeatureStore store)
|
133 | 40435 | jjdelcerro | throws DataException {
|
134 | return get(id, store, null); |
||
135 | } |
||
136 | |||
137 | /**
|
||
138 | * Returns a Feature of the given type.
|
||
139 | *
|
||
140 | 43838 | jjdelcerro | * @param id the feature reference
|
141 | * @param store the store to get the feature from
|
||
142 | * @param featureType the type of the feature to return
|
||
143 | 40435 | jjdelcerro | * @return a Feature with the given reference
|
144 | 43838 | jjdelcerro | * @throws DataException if there is an error getting the Feature
|
145 | 40435 | jjdelcerro | */
|
146 | 45647 | fdiaz | public DefaultFeature get(FeatureReference id, FeatureStore store,
|
147 | 43838 | jjdelcerro | FeatureType featureType) throws DataException {
|
148 | // FIXME: y si el featuretype que paso esta modificado.
|
||
149 | // Deberia buscarlo en el featuretypemanager ?
|
||
150 | //
|
||
151 | // Si no existe feature con ese id... ? retorna null ?
|
||
152 | // en EditedDefaultIterator se hace uso de ese comportamiento.
|
||
153 | //
|
||
154 | 45521 | fdiaz | boolean isNewFeature = false; |
155 | 43838 | jjdelcerro | Integer intNum = (added.get(id));
|
156 | if (intNum == null) { |
||
157 | intNum = (modifiedFromOriginal.get(id)); |
||
158 | if (intNum == null) { |
||
159 | //If the feature has been added and deleted
|
||
160 | intNum = addedAndDeleted.get(id); |
||
161 | if (intNum == null) { |
||
162 | return null; |
||
163 | } |
||
164 | } |
||
165 | 45521 | fdiaz | } else {
|
166 | isNewFeature = true;
|
||
167 | 40435 | jjdelcerro | } |
168 | 43838 | jjdelcerro | int num = intNum;
|
169 | if (num == -1) { |
||
170 | return null; |
||
171 | } |
||
172 | Feature feature = (Feature) expansionAdapter.getObject(num); |
||
173 | if (featureType == null) { |
||
174 | featureType = store.getDefaultFeatureType(); |
||
175 | } |
||
176 | 45521 | fdiaz | DefaultFeature feat = new DefaultFeature(featureType, feature);
|
177 | feat.getData().setNew(isNewFeature); |
||
178 | return feat;
|
||
179 | 40435 | jjdelcerro | } |
180 | |||
181 | public int update(Feature feature, Feature oldFeature) { |
||
182 | 45521 | fdiaz | FeatureReference id = feature.getReference(); |
183 | if(!original.containsKey(id)){
|
||
184 | int n = expansionAdapter.addObject(oldFeature);
|
||
185 | original.put(id, n); |
||
186 | } |
||
187 | 43838 | jjdelcerro | int oldNum = -1; |
188 | 40435 | jjdelcerro | int num = expansionAdapter.addObject(feature);
|
189 | 43838 | jjdelcerro | if (added.containsKey(id)) {
|
190 | oldNum = (added.get(id)); |
||
191 | added.put(id, num); |
||
192 | } else {
|
||
193 | if (modifiedFromOriginal.get(id) != null) { |
||
194 | oldNum = (modifiedFromOriginal.get(id)); |
||
195 | } |
||
196 | modifiedFromOriginal.put(id, num); |
||
197 | 40435 | jjdelcerro | } |
198 | return oldNum;
|
||
199 | } |
||
200 | |||
201 | public void restore(FeatureReference id) { |
||
202 | deleted.remove(id); |
||
203 | deltaSize++; |
||
204 | } |
||
205 | 43838 | jjdelcerro | |
206 | public void restore(FeatureReference id, int num) { |
||
207 | if (added.containsKey(id)) {
|
||
208 | added.put(id, num); |
||
209 | } else {
|
||
210 | modifiedFromOriginal.put(id, num); |
||
211 | 40435 | jjdelcerro | } |
212 | } |
||
213 | |||
214 | 43838 | jjdelcerro | public boolean isDeleted(Feature feature) { |
215 | return deleted.contains(feature.getReference());
|
||
216 | 40435 | jjdelcerro | } |
217 | |||
218 | 45647 | fdiaz | public boolean isDeleted(FeatureProvider data) { |
219 | FeatureReference ref = FeatureReferenceFactory.createFromFeatureProvider(store, data); |
||
220 | return deleted.contains(ref);
|
||
221 | } |
||
222 | |||
223 | 40435 | jjdelcerro | public boolean isDeleted(FeatureReference featureID) { |
224 | 43838 | jjdelcerro | return deleted.contains(featureID);
|
225 | } |
||
226 | 40435 | jjdelcerro | |
227 | 43838 | jjdelcerro | public void clear() { |
228 | added.clear(); |
||
229 | modifiedFromOriginal.clear(); |
||
230 | expansionAdapter.close(); |
||
231 | deleted.clear(); |
||
232 | addedAndDeleted.clear(); |
||
233 | deltaSize = 0;
|
||
234 | } |
||
235 | 40435 | jjdelcerro | |
236 | 43838 | jjdelcerro | public boolean hasChanges() { |
237 | return added.size() > 0 || modifiedFromOriginal.size() > 0 || deleted.size() > 0; |
||
238 | } |
||
239 | 40435 | jjdelcerro | |
240 | 44111 | jjdelcerro | public long getPendingChangesCount() { |
241 | long count = 0; |
||
242 | if( this.added!=null ) { |
||
243 | count += this.added.size();
|
||
244 | } |
||
245 | if( this.deleted!=null ) { |
||
246 | count += this.deleted.size();
|
||
247 | } |
||
248 | if( this.modifiedFromOriginal!=null ) { |
||
249 | count += this.modifiedFromOriginal.size();
|
||
250 | } |
||
251 | return count;
|
||
252 | } |
||
253 | |||
254 | 44871 | jjdelcerro | public Iterator<FeatureReference> getDeleted() { |
255 | return new DeletedsFeatureReferencesIterator(); |
||
256 | 40435 | jjdelcerro | |
257 | 44871 | jjdelcerro | } |
258 | |||
259 | private class DeletedsFeatureReferencesIterator implements Iterator<FeatureReference> { |
||
260 | |||
261 | 43838 | jjdelcerro | private Boolean hasnext = null; |
262 | private final Iterator iter; |
||
263 | 44871 | jjdelcerro | private FeatureReference reference;
|
264 | 40435 | jjdelcerro | |
265 | 44871 | jjdelcerro | public DeletedsFeatureReferencesIterator() {
|
266 | 43838 | jjdelcerro | iter = deleted.iterator(); |
267 | } |
||
268 | 40435 | jjdelcerro | |
269 | 43838 | jjdelcerro | @Override
|
270 | public boolean hasNext() { |
||
271 | if (hasnext != null) { |
||
272 | return hasnext;
|
||
273 | } |
||
274 | hasnext = false;
|
||
275 | while (iter.hasNext()) {
|
||
276 | 44871 | jjdelcerro | reference = (FeatureReference) iter.next(); |
277 | if (!reference.isNewFeature()) {
|
||
278 | hasnext = true;
|
||
279 | break;
|
||
280 | 43838 | jjdelcerro | } |
281 | } |
||
282 | return hasnext;
|
||
283 | } |
||
284 | 40435 | jjdelcerro | |
285 | 43838 | jjdelcerro | @Override
|
286 | 44871 | jjdelcerro | public FeatureReference next() {
|
287 | 43838 | jjdelcerro | if (!hasNext()) {
|
288 | throw new NoSuchElementException(); |
||
289 | } |
||
290 | hasnext = null;
|
||
291 | 44871 | jjdelcerro | return reference;
|
292 | 43838 | jjdelcerro | } |
293 | 40435 | jjdelcerro | |
294 | 43838 | jjdelcerro | @Override
|
295 | public void remove() { |
||
296 | throw new UnsupportedOperationException(); |
||
297 | } |
||
298 | 40435 | jjdelcerro | |
299 | 43838 | jjdelcerro | } |
300 | 40435 | jjdelcerro | |
301 | 44871 | jjdelcerro | public Iterator<FeatureProvider> getInserted() { |
302 | Iterator<Feature> it = new InsertedFeaturesIterator(); |
||
303 | return new Iterator<FeatureProvider>() { |
||
304 | @Override
|
||
305 | public boolean hasNext() { |
||
306 | return it.hasNext();
|
||
307 | } |
||
308 | |||
309 | @Override
|
||
310 | public FeatureProvider next() {
|
||
311 | return ((DefaultFeature)it.next()).getData();
|
||
312 | } |
||
313 | }; |
||
314 | 43838 | jjdelcerro | } |
315 | 40435 | jjdelcerro | |
316 | 44871 | jjdelcerro | public Iterator<Feature> getInsertedFeatures() { |
317 | return new InsertedFeaturesIterator(); |
||
318 | } |
||
319 | 40435 | jjdelcerro | |
320 | 44871 | jjdelcerro | private class InsertedFeaturesIterator implements Iterator<Feature> { |
321 | |||
322 | 43838 | jjdelcerro | private final Iterator addedIter; |
323 | 44871 | jjdelcerro | private Feature feature;
|
324 | 43838 | jjdelcerro | private Boolean hasnext = null; |
325 | 40435 | jjdelcerro | |
326 | 44871 | jjdelcerro | public InsertedFeaturesIterator() {
|
327 | 43838 | jjdelcerro | addedIter = added.values().iterator(); |
328 | } |
||
329 | 40435 | jjdelcerro | |
330 | 43838 | jjdelcerro | @Override
|
331 | public boolean hasNext() { |
||
332 | if (hasnext != null) { |
||
333 | return hasnext;
|
||
334 | } |
||
335 | hasnext = false;
|
||
336 | int pos;
|
||
337 | while (addedIter.hasNext()) {
|
||
338 | pos = ((Integer) addedIter.next());
|
||
339 | 44871 | jjdelcerro | feature = (Feature) expansionAdapter.getObject(pos); |
340 | if (!deleted.contains(feature.getReference())) {
|
||
341 | 43838 | jjdelcerro | hasnext = true;
|
342 | break;
|
||
343 | } |
||
344 | } |
||
345 | return hasnext;
|
||
346 | } |
||
347 | 40435 | jjdelcerro | |
348 | 43838 | jjdelcerro | @Override
|
349 | 44871 | jjdelcerro | public Feature next() {
|
350 | 43838 | jjdelcerro | if (!hasNext()) {
|
351 | throw new NoSuchElementException(); |
||
352 | } |
||
353 | hasnext = null;
|
||
354 | 44871 | jjdelcerro | return feature;
|
355 | 43838 | jjdelcerro | } |
356 | 40435 | jjdelcerro | |
357 | 43838 | jjdelcerro | @Override
|
358 | public void remove() { |
||
359 | addedIter.remove(); |
||
360 | } |
||
361 | 40435 | jjdelcerro | |
362 | 43838 | jjdelcerro | } |
363 | 40435 | jjdelcerro | |
364 | 44871 | jjdelcerro | public Iterator<Feature> getUpdatedFeatures() { |
365 | return new UpdatedFeaturesIterator(); |
||
366 | 43838 | jjdelcerro | } |
367 | 40435 | jjdelcerro | |
368 | 44871 | jjdelcerro | public Iterator<FeatureProvider> getUpdated() { |
369 | Iterator<Feature> it = new UpdatedFeaturesIterator(); |
||
370 | return new Iterator<FeatureProvider>() { |
||
371 | @Override
|
||
372 | public boolean hasNext() { |
||
373 | return it.hasNext();
|
||
374 | } |
||
375 | 40435 | jjdelcerro | |
376 | 44871 | jjdelcerro | @Override
|
377 | public FeatureProvider next() {
|
||
378 | return ((DefaultFeature)it.next()).getData();
|
||
379 | } |
||
380 | }; |
||
381 | } |
||
382 | |||
383 | private class UpdatedFeaturesIterator implements Iterator<Feature> { |
||
384 | |||
385 | 43838 | jjdelcerro | private Boolean hasnext = null; |
386 | private final Iterator iter; |
||
387 | 44871 | jjdelcerro | private Feature feature;
|
388 | 43838 | jjdelcerro | private int pos; |
389 | 40435 | jjdelcerro | |
390 | 44871 | jjdelcerro | public UpdatedFeaturesIterator() {
|
391 | 43838 | jjdelcerro | iter = expansionAdapter.iterator(); |
392 | pos = -1;
|
||
393 | } |
||
394 | 40435 | jjdelcerro | |
395 | 43838 | jjdelcerro | @Override
|
396 | public boolean hasNext() { |
||
397 | if (hasnext != null) { |
||
398 | return hasnext;
|
||
399 | } |
||
400 | hasnext = false;
|
||
401 | while (iter.hasNext()) {
|
||
402 | pos++; |
||
403 | 44871 | jjdelcerro | feature = (Feature) iter.next(); |
404 | 45521 | fdiaz | if ( feature != null && |
405 | !deleted.contains(feature.getReference()) && |
||
406 | 44871 | jjdelcerro | modifiedFromOriginal.containsValue(pos)) { |
407 | 43838 | jjdelcerro | hasnext = true;
|
408 | break;
|
||
409 | } |
||
410 | } |
||
411 | return hasnext;
|
||
412 | } |
||
413 | 40435 | jjdelcerro | |
414 | 43838 | jjdelcerro | @Override
|
415 | 44871 | jjdelcerro | public Feature next() {
|
416 | 43838 | jjdelcerro | if (!hasNext()) {
|
417 | throw new NoSuchElementException(); |
||
418 | } |
||
419 | hasnext = null;
|
||
420 | 44871 | jjdelcerro | return feature;
|
421 | 43838 | jjdelcerro | } |
422 | 40435 | jjdelcerro | |
423 | 43838 | jjdelcerro | @Override
|
424 | public void remove() { |
||
425 | throw new UnsupportedOperationException(); |
||
426 | 40435 | jjdelcerro | |
427 | 43838 | jjdelcerro | } |
428 | } |
||
429 | 40435 | jjdelcerro | |
430 | 43838 | jjdelcerro | public boolean hasNews() { |
431 | return !added.isEmpty();
|
||
432 | } |
||
433 | 42639 | dmartinezizquierdo | |
434 | 43838 | jjdelcerro | public long getDeltaSize() { |
435 | return deltaSize;
|
||
436 | } |
||
437 | |||
438 | 42639 | dmartinezizquierdo | /**
|
439 | * Indicates if any operation has comprimised the selected features.
|
||
440 | 43838 | jjdelcerro | *
|
441 | 42639 | dmartinezizquierdo | * @return
|
442 | */
|
||
443 | public boolean isSelectionCompromised() { |
||
444 | //Only deleted features can change order, as added features are added at the end.
|
||
445 | 43838 | jjdelcerro | return deleted.size() > 0; |
446 | 42639 | dmartinezizquierdo | } |
447 | 45521 | fdiaz | |
448 | public Feature getOriginal(FeatureReference id){
|
||
449 | Integer n = original.get(id);
|
||
450 | if(n == null){ |
||
451 | return null; |
||
452 | } |
||
453 | return (Feature) this.expansionAdapter.getObject(n); |
||
454 | } |
||
455 | |||
456 | public boolean isFeatureModified(FeatureReference id) { |
||
457 | return original.containsKey(id);
|
||
458 | } |
||
459 | |||
460 | 40435 | jjdelcerro | } |