Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libTopology / src / org / gvsig / topology / Topology.java @ 18995

History | View | Annotate | Download (40.1 KB)

1
/*
2
 * Created on 07-sep-2007
3
 *
4
 * gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
5
 *
6
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
7
 *
8
 * This program is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU General Public License
10
 * as published by the Free Software Foundation; either version 2
11
 * of the License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
21
 *
22
 * For more information, contact:
23
 *
24
 *  Generalitat Valenciana
25
 *   Conselleria d'Infraestructures i Transport
26
 *   Av. Blasco Ib??ez, 50
27
 *   46010 VALENCIA
28
 *   SPAIN
29
 *
30
 *      +34 963862235
31
 *   gvsig@gva.es
32
 *      www.gvsig.gva.es
33
 *
34
 *    or
35
 *
36
 *   IVER T.I. S.A
37
 *   Salamanca 50
38
 *   46005 Valencia
39
 *   Spain
40
 *
41
 *   +34 963163400
42
 *   dac@iver.es
43
 */
44
/* CVS MESSAGES:
45
 *
46
 * $Id: 
47
 * $Log: 
48
 */
49
package org.gvsig.topology;
50

    
51
import java.awt.Image;
52
import java.awt.geom.Rectangle2D;
53
import java.util.ArrayList;
54
import java.util.Collection;
55
import java.util.Collections;
56
import java.util.HashMap;
57
import java.util.Iterator;
58
import java.util.List;
59
import java.util.Map;
60

    
61
import javax.swing.ImageIcon;
62

    
63
import org.apache.log4j.Logger;
64
import org.cresques.cts.IProjection;
65
import org.gvsig.topology.topologyrules.MustBeLargerThanClusterTolerance;
66

    
67
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
68
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
69
import com.iver.cit.gvsig.fmap.MapContext;
70
import com.iver.cit.gvsig.fmap.core.FShape;
71
import com.iver.cit.gvsig.fmap.core.IGeometry;
72
import com.iver.cit.gvsig.fmap.core.IRow;
73
import com.iver.cit.gvsig.fmap.edition.AfterFieldEditEvent;
74
import com.iver.cit.gvsig.fmap.edition.AfterRowEditEvent;
75
import com.iver.cit.gvsig.fmap.edition.BeforeFieldEditEvent;
76
import com.iver.cit.gvsig.fmap.edition.BeforeRowEditEvent;
77
import com.iver.cit.gvsig.fmap.edition.EditionEvent;
78
import com.iver.cit.gvsig.fmap.edition.IEditionListener;
79
import com.iver.cit.gvsig.fmap.edition.VectorialEditableAdapter;
80
import com.iver.cit.gvsig.fmap.layers.CancelationException;
81
import com.iver.cit.gvsig.fmap.layers.FLayer;
82
import com.iver.cit.gvsig.fmap.layers.FLayers;
83
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
84
import com.iver.cit.gvsig.fmap.layers.LayerCollectionEvent;
85
import com.iver.cit.gvsig.fmap.layers.LayerEvent;
86
import com.iver.cit.gvsig.fmap.layers.LayerListener;
87
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
88
import com.iver.cit.gvsig.fmap.layers.XMLException;
89
import com.iver.utiles.IPersistence;
90
import com.iver.utiles.XMLEntity;
91
import com.iver.utiles.swing.threads.CancellableProgressTask;
92

    
93
/**
94
 * 
95
 * This class represents a Topology, as a group of vectorial layers
96
 * and topology rules that checks geometries and their spatial relationships of
97
 * these layers.
98
 * 
99
 * It extends FLayers to reuse all already existent code related with
100
 * groups of layers (TOC related, etc.)
101
 * 
102
 * TODO Study if we must syncronize writing methods (validate, markAsException, addError,
103
 * ruleId++, etc)
104
 *
105
 *
106
 * @author azabala
107
 *
108
 */
109
public class Topology extends FLayers implements ITopologyStatus, ITopologyErrorContainer, Cloneable {
110

    
111
        private static Logger logger = Logger.getLogger(Topology.class.getName());
112
                
113
        private final static ImageIcon NOT_VALIDATED_TOC_ICON = 
114
                new ImageIcon(Topology.class.getResource("images/topoicon.png"));
115
        
116
        private final static ImageIcon VALIDATED_TOC_ICON = 
117
                new ImageIcon(Topology.class.getResource("images/topoicon_validated.png"));
118
        
119
        private final static ImageIcon VALIDATED_WITH_ERRORS_TOC_ICON = 
120
                new ImageIcon(Topology.class.getResource("images/topoicon_validated_with_errors.png"));
121
         
122
        private final static ImageIcon EMPTY_TOC_ICON = 
123
                new ImageIcon(Topology.class.getResource("images/topoicon_empty.png"));
124

    
125
        private final static ImageIcon VALIDATED_WITH_DIRTY_ZONES_TOC_ICON = 
126
                new ImageIcon(Topology.class.getResource("images/topoicon_validated_with_dirty_zones.png"));
127
        
128
        private final static ImageIcon VALIDATING_TOC_ICON = 
129
                new ImageIcon(Topology.class.getResource("images/topoicon_validating.png"));
130
        
131
        private ImageIcon statusIcon = EMPTY_TOC_ICON;
132
        
133
        /**
134
         * topology name
135
         */
136
        private String name;
137
        /**
138
         * cluster tolerance of the topology
139
         */
140
        
141
        private double clusterTolerance;
142

    
143
        /**
144
         * validation status of the topology
145
         */
146
        private byte status = EMPTY;
147

    
148
        
149
        /**
150
         * If during validation process a topoly exceeds this parameters, validation
151
         * will be stopped.
152
         * 
153
         */
154
        private int maxNumberOfErrors = -1;
155

    
156
        
157
        /**
158
         * topology rules of the topology
159
         */
160
        private List<ITopologyRule> rules;
161

    
162
        
163
        /**
164
         * Each layer of a topology must have a cluster tolerance rule
165
         */
166
        private List<MustBeLargerThanClusterTolerance> clusterToleranceRules;
167

    
168
        
169
        /**
170
         * Regions of the topology to be validated
171
         */
172
        private List<Rectangle2D> dirtyZones;
173

    
174
        /**
175
         * Error container in which topology delegates error container
176
         * responsability.
177
         */
178
        private ITopologyErrorContainer errorContainer;
179
        
180
        /**
181
         * Collection of error layers created from topology errors in topology
182
         * error container.
183
         */
184
        private FLayer errorLayer;
185
        
186
        /**
187
         * Registered class to listen for change status events.
188
         */
189
        private List<ITopologyStatusListener> statusListeners;
190
        
191
        
192
        /**
193
         * Map that relates a FLyrVect of the Topology with its rank (weight when we
194
         * are going to snap many coordinates)
195
         */
196
        private Map<FLyrVect, XYZLayerRank> layerRanks;
197
        
198
        /**
199
         * Numerical identifier for rules of a topology
200
         */
201
        private int ruleId = 0;
202
        
203
        /**
204
         * Interface for all of these classes interested in listening topology change status
205
         * events.
206
         * @author Alvaro Zabala
207
         *
208
         */
209
        public interface ITopologyStatusListener{
210
                public void statusChange(TopologyStatusEvent event);
211
        }
212
        
213
        /**
214
         * Topology change status event. It contains old and new topology status.
215
         * @author Alvaro Zabala
216
         *
217
         */
218
        public class TopologyStatusEvent{
219
                int newStatus;
220
                int prevStatus;
221
        }
222
        
223
        /**
224
         * Default constructor for a topology as a FLayers
225
         * 
226
         * @param fmap
227
         * @param parent
228
         */
229
        public Topology(MapContext fmap, 
230
                                        FLayers parent, 
231
                                        double clusterTolerance, 
232
                                        int numberOfErrors,
233
                                        ITopologyErrorContainer errorContainer) {
234
                super(fmap, parent);
235
                this.clusterTolerance = clusterTolerance;
236
                this.maxNumberOfErrors = numberOfErrors;
237
                this.errorContainer = errorContainer;
238
                this.errorContainer.setTopology(this);
239
                
240
                rules = new ArrayList<ITopologyRule>();
241
                clusterToleranceRules = new ArrayList<MustBeLargerThanClusterTolerance>();
242
                dirtyZones = new ArrayList<Rectangle2D>();
243
                layerRanks = new HashMap<FLyrVect, XYZLayerRank>();
244
                
245
                statusListeners = new ArrayList<ITopologyStatusListener>();
246
                //This listener updates the icon status returneb by this kind of layer
247
                statusListeners.add(new ITopologyStatusListener(){
248
                        public void statusChange(TopologyStatusEvent event) {
249
                                switch(event.newStatus){
250
                                case ITopologyStatus.VALIDATED:
251
                                        statusIcon = VALIDATED_TOC_ICON;
252
                                        break;
253
                                        
254
                                case ITopologyStatus.NOT_VALIDATED:
255
                                        statusIcon = NOT_VALIDATED_TOC_ICON;
256
                                        break;
257
                                        
258
                                case ITopologyStatus.VALIDATED_WITH_DIRTY_ZONES:
259
                                        statusIcon = VALIDATED_WITH_DIRTY_ZONES_TOC_ICON;
260
                                        break;
261
                                        
262
                                case ITopologyStatus.VALIDATED_WITH_ERRORS:
263
                                        statusIcon = VALIDATED_WITH_ERRORS_TOC_ICON;
264
                                        break;
265
                                        
266
                                case ITopologyStatus.VALIDATING:
267
                                        statusIcon = VALIDATING_TOC_ICON;
268
                                        break;
269
                                }
270
                        }});
271
        }
272
        
273
        public Topology(MapContext mapContext, FLayers layers){
274
                this(mapContext, layers, 0d, 1000, new SimpleTopologyErrorContainer());
275
        }
276
        
277
        
278
        public void addStatusListener(ITopologyStatusListener statusListener){
279
                this.statusListeners.add(statusListener);
280
        }
281
        
282
        /**
283
         * Creates a topology from its XML representation
284
         * @param xmlEntity
285
         * @return
286
         */
287
        public static Topology createFromXML(MapContext mapContext, XMLEntity xmlEntity){
288
                FLayers rootLyr = mapContext.getLayers();
289
                Topology solution = new Topology(mapContext, rootLyr);
290
                
291
                try {
292
                        solution.setXMLEntity(xmlEntity);
293
                        if(solution.getErrorContainer() == null){
294
                                solution.setErrorContainer(new SimpleTopologyErrorContainer());
295
                        }
296
                } catch (XMLException e) {
297
                        logger.error("Error al reconstruir la topologia desde fichero xml", e);
298
                }
299
                return solution;
300
        }
301
        
302
        public ImageIcon getTocImageIcon() {
303
                return statusIcon;
304
        }
305
        
306
        public Image getTocStatusImage() {
307
                return statusIcon.getImage();
308
        }
309

    
310
        /**
311
         * Changes the cluster tolerance of the topology
312
         * 
313
         * 
314
         * This operation resets the status of the topology (it clears
315
         * errors and dirty zones)
316
         * 
317
         * @param clusterTolerance
318
         */
319
        public void setClusterTolerance(double clusterTolerance) {
320
                if(status == VALIDATING)
321
                        return;//maybe we could launch an exception??
322
                this.clusterTolerance = clusterTolerance;
323
                resetStatus();
324
                Iterator<MustBeLargerThanClusterTolerance> rulesIt = this.clusterToleranceRules.iterator();
325
                while(rulesIt.hasNext()){
326
                        MustBeLargerThanClusterTolerance rule = rulesIt.next();
327
                        rule.setClusterTolerance(clusterTolerance);
328
                }
329
                
330
        }
331

    
332
        public double getClusterTolerance() {
333
                return clusterTolerance;
334
        }
335
        
336
        public void resetStatus(){
337
                setStatus(NOT_VALIDATED);
338
                this.clear();
339
                this.dirtyZones.clear();
340
                
341
        }
342

    
343
        /**
344
         * Adds a new topology rule to the topology.
345
         * 
346
         * The layers referenced by the rule must exist in the topology.
347
         * 
348
         * The state of the topology changes to "NON_VALIDATED", and a new dirty zone
349
         * is added for the scope of the new rule (envelope of one or two layers).
350
         * 
351
         * 
352
         * @throws TopologyRuleDefinitionException
353
         */
354
        public void addRule(ITopologyRule rule) throws RuleNotAllowedException,
355
                        TopologyRuleDefinitionException {
356

    
357
                if(status == VALIDATING)
358
                        throw new RuleNotAllowedException("No se puede a?adir una regla si la topologia est? siendo validada");
359
                
360
                
361
                Rectangle2D ruleScope = null;
362
                try {
363
                        if (rule instanceof IOneLyrRule) {
364
                                FLyrVect originLyr = ((IOneLyrRule) rule).getOriginLyr();
365
                                if (getLayer(originLyr.getName()) == null) {
366
                                        throw new RuleNotAllowedException(
367
                                                        "Regla con capa  que no forma parte de la topologia");
368
                                }
369
                                ruleScope = originLyr.getFullExtent();
370
                        }
371
                        if (rule instanceof ITwoLyrRule) {
372
                                FLyrVect destLyr = ((ITwoLyrRule) rule).getDestinationLyr();
373
                                if (getLayer(destLyr.getName()) == null) {
374
                                        throw new RuleNotAllowedException(
375
                                                        "Regla con capa  que no forma parte de la topologia");
376
                                }
377
                                if (ruleScope != null)
378
                                        ruleScope.add(destLyr.getFullExtent());
379
                        }
380
                } catch (ExpansionFileReadException e) {
381
                        e.printStackTrace();
382
                        throw new TopologyRuleDefinitionException(e);
383
                } catch (ReadDriverException e) {
384
                        e.printStackTrace();
385
                        throw new TopologyRuleDefinitionException(e);
386
                }
387
                
388
                // before to add the rule we check if it verifies preconditions
389
                rule.checkPreconditions();
390
                rule.setTopology(this);
391
                rules.add(rule);
392
                
393
//   Si se a?ade una nueva regla, no es posible conservar los errores
394
//   y las zonas sucias previas
395
//                if(status == EMPTY)
396
//                        status = NOT_VALIDATED;
397
//                else if(status == VALIDATED ){
398
//                        status = VALIDATED_WITH_DIRTY_ZONES;
399
//                        addDirtyZone(ruleScope);
400
//                }else if(status == VALIDATED_WITH_ERRORS){
401
//                        //we dont change the status, but add a new dirty zone
402
//                        addDirtyZone(ruleScope);
403
//                }
404
                resetStatus();
405
                rule.setTopologyErrorContainer(this);
406
                rule.setId(this.ruleId++);
407
        }
408
        
409
        
410
        
411

    
412
        /*
413
         * Overwrited implementations of FLayers methods
414
         */
415
        
416
        public void addLayer(FLayer layer) {
417
                addLayer(layers.size(), layer);
418
        }
419

    
420
        public void addLayer(int pos, FLayer layer)  {
421
                if (!(layer instanceof FLyrVect))
422
                        throw new WrongLyrForTopologyException(
423
                                        "Intentando a?adir capa no vectorial a una topologia");
424
                super.addLayer(pos, layer);
425
                setRank((FLyrVect) layer, 1, 1);
426
                
427
                int shapeType = -1;
428
                try {
429
                        shapeType = ((FLyrVect)layer).getShapeType();
430
                        if( (shapeType == FShape.POINT) || (shapeType == FShape.MULTIPOINT) || (shapeType == FShape.TEXT))
431
                                return;
432
                } catch (ReadDriverException e) {
433
                        e.printStackTrace();
434
                        throw new WrongLyrForTopologyException("Error al intentar verificar el tipo de geometria de la capa", e);
435
                }
436
                
437
                
438
                MustBeLargerThanClusterTolerance rule = new 
439
                        MustBeLargerThanClusterTolerance(this, (FLyrVect) layer, clusterTolerance);
440
                rule.setId(this.ruleId++);
441
                Rectangle2D ruleScope;
442
                try {
443
                        ruleScope = layer.getFullExtent();
444
//                 before to add the rule we check if it verifies preconditions
445
                        rule.checkPreconditions();
446
                        
447
                        if(status == EMPTY)
448
                                setStatus(NOT_VALIDATED);
449
                        else if(status == VALIDATED ){
450
                                setStatus(VALIDATED_WITH_DIRTY_ZONES);
451
                                addDirtyZone(ruleScope);
452
                        }else if(status == VALIDATED_WITH_ERRORS){
453
                                //we dont change the status, but add a new dirty zone
454
//                                addDirtyZone(ruleScope);
455
                                //si habia errores, la reevaluacion haria que se repitiesen
456
                                resetStatus();
457
                        }
458
                        rule.setTopologyErrorContainer(this);
459
                        clusterToleranceRules.add(rule);
460
                        
461
                        //finally, we connect edition with topology
462
                        layer.addLayerListener(new LayerListener(){
463

    
464
                                public void activationChanged(LayerEvent e) {
465
                                }
466

    
467
                                public void editionChanged(LayerEvent e) {
468
                                        FLayer editionLyr = e.getSource();
469
                                        
470
                                        if (editionLyr instanceof FLyrVect){
471
                                                
472
                                                final ArrayList<Rectangle2D> dirtyZones = new ArrayList<Rectangle2D>();
473
                                                
474
                                                FLyrVect fLyrVect = (FLyrVect)editionLyr;
475
                                                
476
                                                ReadableVectorial rv = fLyrVect.getSource();
477
                                                if(! (rv instanceof VectorialEditableAdapter))
478
                                                        return;
479
                                                final VectorialEditableAdapter vea =
480
                                                        (VectorialEditableAdapter)rv;
481
                                                
482
                                                vea.addEditionListener(new IEditionListener(){
483

    
484
                                                        public void afterFieldEditEvent(
485
                                                                        AfterFieldEditEvent e) {
486
                                                        }
487

    
488
                                                        public void afterRowEditEvent(IRow row,
489
                                                                        AfterRowEditEvent e) {
490
                                                                //If we include alphanumeric rules to a topology as a
491
                                                                //integrity rule, we'll add a new dirty zone for this too
492
                                                                if(e.getChangeType() == EditionEvent.ALPHANUMERIC)
493
                                                                        return;
494
                                                                int numRow = (int) e.getNumRow();
495
                                                                
496
                                                                IGeometry geom;
497
                                                                try {
498
                                                                        geom = vea.getShape(numRow);
499
                                                                        dirtyZones.add(geom.getBounds2D());
500
                                                                } catch (ExpansionFileReadException e1) {
501
                                                                        e1.printStackTrace();
502
                                                                } catch (ReadDriverException e1) {
503
                                                                        e1.printStackTrace();
504
                                                                }
505
                                                        }
506

    
507
                                                        public void beforeFieldEditEvent(
508
                                                                        BeforeFieldEditEvent e) {
509
                                                        }
510

    
511
                                                        public void beforeRowEditEvent(IRow feat,
512
                                                                        BeforeRowEditEvent e) {
513
                                                        }
514

    
515
                                                        public void processEvent(EditionEvent e) {
516
                                                                if(e.getChangeType() == EditionEvent.STOP_EDITION){
517
                                                                        for(int i = 0; i < dirtyZones.size(); i++){
518
                                                                                Rectangle2D dirtyZone = dirtyZones.get(i);
519
                                                                                Topology.this.addDirtyZone(dirtyZone);
520
                                                                        }//for
521
                                                                }//if
522
                                                        }});
523
                                        }
524
                                }
525

    
526
                                public void nameChanged(LayerEvent e) {
527
                                }
528

    
529
                                public void visibilityChanged(LayerEvent e) {
530
                                }});
531
                        
532
                        
533
                } catch (ExpansionFileReadException e) {
534
                        e.printStackTrace();
535
                        throw new WrongLyrForTopologyException("No es posible acceder all FullExtent de la capa", e);
536
                } catch (ReadDriverException e) {
537
                        e.printStackTrace();
538
                        throw new WrongLyrForTopologyException("No es posible acceder all FullExtent de la capa", e);
539
                } catch (TopologyRuleDefinitionException e) {
540
                        e.printStackTrace();
541
                        throw new WrongLyrForTopologyException("Regla topologica mal definida", e);
542
                }
543
        }
544

    
545
        /**
546
         * Sets the rank/importance of a layer in xy and z planes.
547
         * 
548
         * @param lyr layer
549
         * 
550
         * @param xyRank importance of this layer coordinates in xy plane
551
         * 
552
         * @param zRank importante of this layer coordinates in z plane
553
         */
554
        public void setRank(FLyrVect lyr, int xyRank, int zRank) {
555
                XYZLayerRank rank = new XYZLayerRank(lyr.getName(), xyRank, zRank);
556
                layerRanks.put(lyr, rank);
557
        }
558
        
559
        
560
        public XYZLayerRank getRank(FLyrVect lyr){
561
                return layerRanks.get(lyr);
562
        }
563

    
564
        /**
565
         * Adds a layer to the topology. If the topology has been validated, changes
566
         * topology status to NON-VALIDATED and adds a dirty zone equals to the
567
         * layer extent.
568
         */
569
        public void addLayer(FLyrVect layer, int xyRank, int zRank) {
570
                this.addLayer(layer);
571
                setRank(layer, xyRank, zRank);
572
        }
573
        
574
        
575
        /**
576
         * Remove a layer from a topology.
577
         * 
578
         * This task is more complex than removing a layer from a LayerCollection:
579
         * -must remove all rules which references to this layer.
580
         * -must recompute status and dirty zones.
581
         * etc.
582
         * 
583
         * TODO Implement remove layer as a geoprocess.
584
         * 
585
         */
586
        public void removeLayer(FLayer lyr) throws CancelationException {
587
                callLayerRemoving(LayerCollectionEvent.createLayerRemovingEvent(lyr));
588
                
589
                //remove cluster rules related with the layer
590
                Iterator<MustBeLargerThanClusterTolerance> clusterRulesIt = clusterToleranceRules.iterator();
591
                while(clusterRulesIt.hasNext()){
592
                        MustBeLargerThanClusterTolerance rule = clusterRulesIt.next();
593
                        if(rule.getOriginLyr().equals(lyr)){
594
                                clusterRulesIt.remove();
595
                        }
596
                }//while
597
                
598
                //Remove normal rules related with the layer
599
                Iterator<ITopologyRule> rulesIt = this.rules.iterator();
600
                while(rulesIt.hasNext()){
601
                        ITopologyRule rule =  rulesIt.next();
602
                        if(rule instanceof IOneLyrRule){
603
                                IOneLyrRule oneLyrRule = (IOneLyrRule) rule;
604
                                if(oneLyrRule.getOriginLyr().equals(lyr)){
605
                                        rulesIt.remove();
606
                                        continue;
607
                                }
608
                        }
609
                        
610
                        if(rule instanceof ITwoLyrRule){
611
                                ITwoLyrRule twoLyrRule = (ITwoLyrRule) rule;
612
                                if(twoLyrRule.getOriginLyr().equals(lyr)){
613
                                        rulesIt.remove();
614
                                }
615
                        }
616
                }//while
617
                
618
                this.errorContainer.removeErrorsByLayer((FLyrVect) lyr);
619
                this.layerRanks.remove(lyr);                
620
                this.updateDirtyZones();
621
                callLayerRemoved(LayerCollectionEvent.createLayerRemovedEvent(lyr));
622
        }
623
        
624
        public void removeLayer(int idLyr){
625
                FLayer lyr = (FLayer) layers.get(idLyr);
626
                removeLayer(lyr);
627
        }
628
        
629
        public void removeRule(ITopologyRule rule){
630
                if(rules.contains(rule)){
631
                        rules.remove(rule);
632
                }else if(clusterToleranceRules.contains(rule)){
633
                        clusterToleranceRules.remove(rule);
634
                }
635
                this.errorContainer.removeErrorsByRule(rule.getName());
636
                
637
                this.updateDirtyZones();
638
        }
639
        
640
        
641
        
642
        private void updateDirtyZones() {
643
//                this.dirtyZones.clear(); //FIXME REVISAR SI ES NECESARIO BORRAR LAS ZONAS SUCIAS
644
                int errorNum = errorContainer.getNumberOfErrors();
645
                for(int i = 0; i < errorNum; i++){
646
                        TopologyError topologyError = errorContainer.getTopologyError(i);
647
                        Rectangle2D rect = topologyError.getGeometry().getBounds2D();
648
                        addDirtyZone(rect);
649
                }
650
        }
651

    
652
        /**
653
         * Ranks (in xy plane and z plane) for layers of the topology.
654
         * 
655
         * The rank of layer marks its weight for computing weihgted average
656
         * coordinates.
657
         * 
658
         * @author azabala
659
         * 
660
         */
661
        class XYZLayerRank implements IPersistence {
662
                int xyRank;
663
                int zRank;
664
                String layerName;
665

    
666
                XYZLayerRank(String layerName, int xyRank, int zRank) {
667
                        this.layerName = layerName;
668
                        this.xyRank = xyRank;
669
                        this.zRank = zRank;
670
                }
671
                
672
                XYZLayerRank(){}
673

    
674
                public String getClassName() {
675
                        return this.getClass().getName();
676
                }
677

    
678
                public XMLEntity getXMLEntity() {
679
                        XMLEntity solution = new XMLEntity();
680
                        solution.putProperty("layerName", layerName);
681
                        solution.putProperty("xyRank", xyRank);
682
                        solution.putProperty("zRank", zRank);
683
                        return solution;
684
                }
685

    
686
                public void setXMLEntity(XMLEntity xml) {
687
                        if(xml.contains("layerName"))
688
                                layerName = xml.getStringProperty("layerName");
689
                        
690
                        if(xml.contains("xyRank"))
691
                                xyRank = xml.getIntProperty("xyRank");
692
                        
693
                        if(xml.contains("zRank"))
694
                                zRank = xml.getIntProperty("zRank");
695
                        
696
                }
697
        }
698

    
699
        public void setStatus(byte newStatus) {
700
                TopologyStatusEvent newStatusEvent = new TopologyStatusEvent();
701
                newStatusEvent.prevStatus = this.status;
702
                newStatusEvent.newStatus = newStatus;
703
                this.status = newStatus;
704
                
705
                fireStatusChange(newStatusEvent);
706
        }
707

    
708
        public byte getStatus() {
709
                return status;
710
        }
711
        
712
        public List<ITopologyRule> getAllRules(){
713
                List<ITopologyRule> solution = new ArrayList<ITopologyRule>();
714
                solution.addAll(this.rules);
715
                solution.addAll(this.clusterToleranceRules);
716
                return solution;
717
        }
718

    
719
        /**
720
         * Adds a dirty zone to the topology (usually when a feature of a layer of
721
         * the topology has been edited)
722
         */
723
        public void addDirtyZone(Rectangle2D newDirtyZone) {
724
                if(status == NOT_VALIDATED)
725
                        return;
726
                Iterator<Rectangle2D> zonesIt = dirtyZones.iterator();
727
                while (zonesIt.hasNext()) {
728
                        Rectangle2D dirtyZone = zonesIt.next();
729
                        if (dirtyZone.contains(newDirtyZone)) {
730
                                return;// we dont add this dirty zone. Its redundant
731
                        }
732
                        if (newDirtyZone.contains(dirtyZone)) {
733
                                zonesIt.remove();
734
                                dirtyZones.add(newDirtyZone);
735
                                return;
736
                        }
737

    
738
                        if (dirtyZone.intersects(newDirtyZone)) {
739
                                dirtyZone.add(newDirtyZone);
740
                                return;
741
                        }
742
                }// while
743
                
744
                if(status == VALIDATED)
745
                        setStatus(VALIDATED_WITH_DIRTY_ZONES);
746
                
747
                // at this point, we add the new dirty zone
748
                dirtyZones.add(newDirtyZone);
749
        }
750
        
751
        
752
        public void removeDirtyZone(Rectangle2D newDirtyZone) {
753
                if(status == NOT_VALIDATED)
754
                        return;//maybe we must launch an inconsistent status exception
755
                Iterator<Rectangle2D> zonesIt = dirtyZones.iterator();
756
                while (zonesIt.hasNext()) {
757
                        Rectangle2D dirtyZone = zonesIt.next();
758
                        if (newDirtyZone.contains(dirtyZone)) {
759
                                zonesIt.remove();
760
                                continue;
761
                        }
762
                }// while
763

    
764
                // at this point, we add the new dirty zone
765
                dirtyZones.remove(newDirtyZone);
766
        }
767
        
768

    
769
        public Rectangle2D getDirtyZone(int i) {
770
                return dirtyZones.get(i);
771
        }
772
        
773
        public int getNumberOfDirtyZones(){
774
                return dirtyZones.size();
775
        }
776
        
777
        
778
        public void validate(){
779
                validate(null);
780
        }
781
        
782
        /**
783
         * Validates the topology: it validates each topology rule for the given
784
         * dirty zones. After the end of the process,
785
         */
786
        public void validate(CancellableProgressTask progressMonitor) {
787
                
788
                if(progressMonitor != null){
789
                        progressMonitor.setInitialStep(0);
790
                        int numOfSteps = rules.size() + clusterToleranceRules.size();
791
                        progressMonitor.setFinalStep(numOfSteps);
792
                        progressMonitor.setDeterminatedProcess(true);
793
                        progressMonitor.setNote(Messages.getText("Validating_a_topology"));
794
                        progressMonitor.setStatusMessage(Messages.getText(rules.get(0).getName()));
795
                }
796
                
797
                
798
                if (this.status == EMPTY) {
799
                        //TODO Maybe we must do progressMonitor.setFinished(true)
800
                        //or throw an exception
801
                        return;
802
                } else if (this.status == VALIDATED) {
803
                        return;
804
                } 
805
                
806
                else if (this.status == NOT_VALIDATED){
807
                        setStatus(VALIDATING);
808
                        
809
                        
810
                        //we make a local copy of dirty zones to avoid to use dirty zones created in 
811
                        //the current validation.
812
                        ArrayList<Rectangle2D> dirtyZonesCopy = new ArrayList<Rectangle2D>();
813
                        Collections.copy(dirtyZonesCopy, this.dirtyZones);
814
                        Iterator<MustBeLargerThanClusterTolerance> it = 
815
                                clusterToleranceRules.iterator();
816
                        while(it.hasNext()){
817
                                MustBeLargerThanClusterTolerance rule = it.next();
818
                                if(progressMonitor != null){
819
                                        if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
820
                                                resetStatus();
821
                                                return;
822
                                        }
823
                                        progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
824
                                                   Messages.getText(rule.getName()));
825
                                        progressMonitor.reportStep();
826
                                   }
827
                                
828
                                if(getNumberOfErrors() >= this.maxNumberOfErrors){
829
                                        if(progressMonitor != null)
830
                                                progressMonitor.setCanceled(true);
831
                                        return;
832
                                }
833
                                
834
                                rule.checkRule(progressMonitor);
835
                        }
836
                        
837
                        Iterator<ITopologyRule> rulesIt = this.rules.iterator();
838
                        while (rulesIt.hasNext()) {
839
                                ITopologyRule rule = rulesIt.next();
840
                                
841
                                if(progressMonitor != null){
842
                                        if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
843
                                                resetStatus();
844
                                                return;
845
                                        }
846
                                        progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
847
                                                   Messages.getText(rule.getName()));
848
                                        progressMonitor.reportStep();
849
                                   }
850
                                
851
                                if(getNumberOfErrors() >= this.maxNumberOfErrors){
852
                                        if(progressMonitor != null)
853
                                                progressMonitor.setCanceled(true);
854
                                        return;
855
                                }
856
                                
857
                                if(dirtyZonesCopy.size() == 0){
858
                                        rule.checkRule(progressMonitor);
859
                                }else{
860
                                        //A topology is NON_VALIDATED with dirty zones when
861
                                        //it has VALIDATED status and we add a new rule.
862
                                        
863
                                        //TODO Check to add a new rule to a topology
864
                                        //with VALIDATED_WITH_ERROR status
865
                                        Iterator<Rectangle2D> dirtyZonesIt = dirtyZonesCopy.iterator();
866
                                        while(dirtyZonesIt.hasNext()){
867
                                                Rectangle2D rect = dirtyZonesIt.next();
868
                                                rule.checkRule(progressMonitor,rect);
869
                                        }//while
870
                                }//else
871
                        }//while
872
                        if(this.errorContainer.getNumberOfErrors() > 0){
873
                                setStatus(VALIDATED_WITH_ERRORS);
874
                                addErrorLyr();
875
                        }else
876
                                setStatus(VALIDATED);        
877
                }
878
                else if (this.status == VALIDATED_WITH_ERRORS || 
879
                                this.status == ITopologyStatus.VALIDATED_WITH_DIRTY_ZONES) {
880
                        setStatus(VALIDATING);
881
                        // this topology must have at least one dirty zone
882
                        if (this.dirtyZones.size() < 1){
883
//                                 FIXME Deberiamos lanzar una
884
                                // InconsistentStatusException ??
885
                                return;
886
                        }
887

    
888
                        Iterator<Rectangle2D> dirtyZonesIt = this.dirtyZones.iterator();
889
                        while (dirtyZonesIt.hasNext()) {
890
                                Rectangle2D dirtyZone = dirtyZonesIt.next();
891
                                
892
                                Iterator<MustBeLargerThanClusterTolerance> it = this.clusterToleranceRules.iterator();
893
                                while(it.hasNext()){
894
                                        MustBeLargerThanClusterTolerance rule = it.next();
895
                                        if(progressMonitor != null){
896
                                                if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
897
                                                        resetStatus();
898
                                                        return;
899
                                                }
900
                                                progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
901
                                                           Messages.getText(rule.getName()));
902
                                                progressMonitor.reportStep();
903
                                           }
904
                                        
905
                                        if(getNumberOfErrors() >= this.maxNumberOfErrors){
906
                                                if(progressMonitor != null)
907
                                                        progressMonitor.setCanceled(true);
908
                                                return;
909
                                        }
910
                                        
911
                                        rule.checkRule(dirtyZone);
912
                                }
913
                                
914
                                Iterator<ITopologyRule> rulesIt = this.rules.iterator();
915
                                while (rulesIt.hasNext()) {
916
                                        ITopologyRule rule = rulesIt.next();
917
                                        if(progressMonitor != null){
918
                                                if(progressMonitor.isCanceled()/*|| progressMonitor.isFinished()*/){
919
                                                        resetStatus();
920
                                                        return;
921
                                                }
922
                                                progressMonitor.setNote(Messages.getText("VALIDANDO_REGLA")+" "+
923
                                                           Messages.getText(rule.getName()));
924
                                                progressMonitor.reportStep();
925
                                           }
926
                                        
927
                                        if(getNumberOfErrors() >= this.maxNumberOfErrors){
928
                                                if(progressMonitor != null)
929
                                                        progressMonitor.setCanceled(true);
930
                                                return;
931
                                        }
932
                                        rule.checkRule(dirtyZone);
933
                                }//while
934
                                
935
                                
936
                        }//while
937
                        if(this.errorContainer.getNumberOfErrors() > 0){
938
                                setStatus(VALIDATED_WITH_ERRORS);
939
                                addErrorLyr();
940
                        }else
941
                                setStatus(VALIDATED);
942
                }//if
943
        }
944

    
945
        private void addErrorLyr() {        
946
                IProjection proj = this.getProjection();
947
                int idx = 0;
948
                while(proj == null && idx < this.getLayerCount()){
949
                        proj = this.getLayer(idx).getProjection();
950
                        idx++;
951
                }
952
                errorLayer = this.errorContainer.getAsFMapLayer(this.name+"_error",                                                                                                                 proj);
953
        }
954

    
955
        public int getLayerCount() {
956
                return super.getLayersCount();
957
        }
958
        
959
        public List getLayers(){
960
                return this.layers;
961
        }
962

    
963
        public int getRuleCount() {
964
                return rules.size();
965
        }
966

    
967
        public FLyrVect getLyr(int lyrIndex) {
968
                return (FLyrVect) super.getLayer(lyrIndex);
969
        }
970

    
971
        public ITopologyRule getRule(int ruleIndex) {
972
                return rules.get(ruleIndex);
973
        }
974
        
975
        public ITopologyRule getRuleById(int ruleId){
976
                for(int i = 0; i < rules.size(); i++){
977
                        ITopologyRule rule = rules.get(i);
978
                        if(rule.getId() == ruleId){
979
                                return rule;
980
                        }//if
981
                }//for
982
                
983
                for(int i = 0; i < clusterToleranceRules.size(); i++){
984
                        MustBeLargerThanClusterTolerance rule = clusterToleranceRules.get(i);
985
                        if(rule.getId() == ruleId){
986
                                return rule;
987
                        }//if
988
                }
989
                return null;
990
        }
991
        
992
        /**
993
         * Looks for all rules which has at least one reference to the given layer
994
         * (as origin or destination layer in the rule)
995
         * 
996
         * @param lyr
997
         * @return
998
         */
999
        public List<ITopologyRule> getRulesByLyr(FLyrVect lyr){
1000
                List<ITopologyRule> solution = new ArrayList<ITopologyRule>();
1001
                Iterator<ITopologyRule> ruleIt = this.rules.iterator();
1002
                while(ruleIt.hasNext()){
1003
                        ITopologyRule rule = ruleIt.next();
1004
                        if(rule instanceof IOneLyrRule){
1005
                                IOneLyrRule oneLyrRule = (IOneLyrRule) rule;
1006
                                FLyrVect originLyr = oneLyrRule.getOriginLyr();
1007
                                if(originLyr.equals(lyr))
1008
                                {
1009
                                        solution.add(rule);
1010
                                        continue;//dont need to check for destination layer
1011
                                }
1012
                        }//if
1013
                        
1014
                        if(rule instanceof ITwoLyrRule){
1015
                                ITwoLyrRule twoLyrRule = (ITwoLyrRule) rule;
1016
                                FLyrVect destinationLyr = twoLyrRule.getDestinationLyr();
1017
                                if(destinationLyr.equals(lyr)){
1018
                                        solution.add(rule);
1019
                                }
1020
                        }
1021
                        
1022
                }//while
1023
                
1024
                Iterator<MustBeLargerThanClusterTolerance> clusterIt = clusterToleranceRules.iterator();
1025
                while(clusterIt.hasNext()){
1026
                        MustBeLargerThanClusterTolerance rule = clusterIt.next();
1027
                        FLyrVect originLyr = rule.getOriginLyr();
1028
                        if(originLyr.equals(lyr))
1029
                        {
1030
                                solution.add(rule);
1031
                                continue;//dont need to check for destination layer
1032
                        }
1033
                }
1034
                return solution;
1035
        }
1036
        
1037
        /**
1038
         * Returns if a specified rectangle touch one of the existing dirty zones.
1039
         * If not, probably is needed to add to the dirty zones collection. If true,
1040
         * maybe it could modify the dirty zone.
1041
         */
1042
        public boolean isInDirtyZone(Rectangle2D envelope) {
1043
                Iterator<Rectangle2D> zonesIt = dirtyZones.iterator();
1044
                while (zonesIt.hasNext()) {
1045
                        Rectangle2D rect = zonesIt.next();
1046
                        if (rect.contains(envelope))
1047
                                return true;
1048
                }
1049
                return false;
1050
        }
1051

    
1052
        /**
1053
         * Modify the dirty zone of the specified index
1054
         * 
1055
         * TODO Make thread safe ?
1056
         */
1057
        public void updateDirtyZone(int dirtyZoneIndex, Rectangle2D dirtyZone) {
1058
                dirtyZones.remove(dirtyZoneIndex);
1059
                dirtyZones.add(dirtyZoneIndex, dirtyZone);
1060
        }
1061

    
1062
        public void setMaxNumberOfErrors(int maxNumberOfErrors) {
1063
                this.maxNumberOfErrors = maxNumberOfErrors;
1064
        }
1065

    
1066
        public int getMaxNumberOfErrors() {
1067
                return maxNumberOfErrors;
1068
        }
1069

    
1070
        /*
1071
         * @see org.gvsig.topology.ITopologyErrorContainer#addTopologyError(org.gvsig.topology.TopologyError)
1072
         */
1073

    
1074
        public void addTopologyError(TopologyError topologyError) {
1075
                errorContainer.addTopologyError(topologyError);
1076
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
1077
                addDirtyZone(rect);
1078
        }
1079

    
1080
        /**
1081
         * marks topologyErrors as an exception (and removes its bounds of the 
1082
         * dirty zones list)
1083
         * @param topologyError error to mark as exceptions
1084
         */
1085
        public void markAsTopologyException(TopologyError topologyError) {
1086
                errorContainer.markAsTopologyException(topologyError);
1087
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
1088
                removeDirtyZone(rect);
1089
                
1090
                if(status == VALIDATED_WITH_DIRTY_ZONES){
1091
                        if(dirtyZones.size() == 0)
1092
                                setStatus(VALIDATED);
1093
                }else if(status == VALIDATED_WITH_ERRORS){
1094
                        if(getNumberOfErrors() == getNumberOfExceptions())
1095
                                setStatus(VALIDATED);
1096
                }
1097
        }
1098
        
1099
        public void demoteToError(TopologyError topologyError) {
1100
                errorContainer.demoteToError(topologyError);
1101
                Rectangle2D rect = topologyError.getGeometry().getBounds2D();
1102
                addDirtyZone(rect);
1103
                if(getNumberOfErrors() > getNumberOfExceptions() )
1104
                        setStatus(VALIDATED_WITH_ERRORS);
1105
        }
1106

    
1107
        
1108
        
1109
        public List<TopologyError> getTopologyErrorsByLyr(FLyrVect layer,
1110
                                                                                                        IProjection desiredProjection, 
1111
                                                                                                        boolean includeExceptions) {
1112
                
1113
                return errorContainer.getTopologyErrorsByLyr(layer, 
1114
                                                                                 desiredProjection,  
1115
                                                                                 includeExceptions);
1116
        }
1117

    
1118
        public List<TopologyError> getTopologyErrorsByRule(String ruleName,
1119
                        IProjection desiredProjection, boolean includeExceptions) {
1120
                
1121
                return errorContainer.getTopologyErrorsByRule(ruleName, 
1122
                                                                                                desiredProjection, 
1123
                                                                                                includeExceptions);
1124
        }
1125
        
1126

    
1127
        public List<TopologyError> getTopologyErrorsByShapeType(int shapeType,
1128
                        IProjection desiredProjection, boolean includeExceptions) {
1129
                return errorContainer.getTopologyErrorsByShapeType(shapeType, 
1130
                                                                                                        desiredProjection, 
1131
                                                                                                        includeExceptions);        
1132
        }
1133

    
1134
        
1135
        /**
1136
         * Get TopologyError filtered byte shapeType, sourte layer of the rule which
1137
         * was violtated by this error.
1138
         */
1139
        public List<TopologyError> getTopologyErrors(String ruleName,
1140
                        int shapeType, FLyrVect sourceLayer, IProjection desiredProjection,
1141
                        boolean includeExceptions) {
1142

    
1143
                return errorContainer.getTopologyErrors(ruleName,
1144
                                                                                                shapeType, 
1145
                                                                                                sourceLayer, 
1146
                                                                                                desiredProjection, 
1147
                                                                                                includeExceptions);
1148
        }
1149

    
1150
        /**
1151
         * Return an unique identifier for the error saved in this
1152
         * TopologyErrorContainer.
1153
         * 
1154
         * Until a new error would be added to this error container, it will
1155
         * return always the same error fid.
1156
         */
1157
        public synchronized String getErrorFid() {
1158
                return errorContainer.getErrorFid();
1159
        }
1160

    
1161
        public int getNumberOfErrors() {
1162
                return errorContainer.getNumberOfErrors();
1163
        }
1164

    
1165
        public TopologyError getTopologyError(int index) {
1166
                return errorContainer.getTopologyError(index);
1167
        }
1168
        
1169
        public void clear() {
1170
                errorContainer.clear();
1171
        }
1172

    
1173
        public XMLEntity getXMLEntity() throws XMLException{
1174
                
1175
                //Topology is a subclass of FLayers, so the call to super
1176
                //allows to persist layer status, toc information and layers
1177
                XMLEntity xml = super.getXMLEntity();
1178
                
1179
                //Si no ponemos esto className ser? FLayerDefault, no??
1180
                xml.putProperty("className", this.getClass().getName());
1181
                xml.putProperty("name", name);
1182
                xml.putProperty("clusterTolerance", clusterTolerance);
1183
                xml.putProperty("status", status);
1184
                xml.putProperty("maxNumberOfErrors", maxNumberOfErrors);
1185
                
1186
                int numberOfTopologyRules = rules.size();
1187
                xml.putProperty("numberOfTopologyRules", numberOfTopologyRules);
1188
                for(int i = 0; i < numberOfTopologyRules; i++){
1189
                        ITopologyRule rule = rules.get(i);
1190
                        xml.addChild(rule.getXMLEntity());
1191
                }
1192
                
1193
                
1194
                int numberOfClusterRules = clusterToleranceRules.size();
1195
                xml.putProperty("numberOfClusterRules", numberOfClusterRules);
1196
                for(int i = 0; i < numberOfClusterRules; i++){
1197
                        MustBeLargerThanClusterTolerance rule = clusterToleranceRules.get(i);
1198
                        xml.addChild(rule.getXMLEntity());
1199
                }
1200
                
1201
                int numberOfDirtyZones = dirtyZones.size();
1202
                xml.putProperty("numberOfDirtyZones", numberOfDirtyZones);
1203
                for(int i = 0; i < numberOfDirtyZones; i++){
1204
                        Rectangle2D rect = dirtyZones.get(i);
1205
                        if(rect != null){
1206
                                XMLEntity dirtyZoneXML = new XMLEntity();
1207
                                dirtyZoneXML.putProperty("extent" + i + "X", rect.getX());
1208
                                dirtyZoneXML.putProperty("extent" + i + "Y", rect.getY());
1209
                                dirtyZoneXML.putProperty("extent" + i + "W", rect.getWidth());
1210
                                dirtyZoneXML.putProperty("extent" + i + "H", rect.getHeight());        
1211
                                
1212
                                xml.addChild(dirtyZoneXML);
1213
                        }//if
1214
                        
1215
                }//for
1216
                
1217
                XMLEntity errorContainerXML = errorContainer.getXMLEntity();
1218
                xml.addChild(errorContainerXML);
1219
                
1220
                Collection<XYZLayerRank> ranksVal = layerRanks.values();
1221
                int numberOfRanks = ranksVal.size();
1222
                xml.putProperty("numberOfRanks", numberOfRanks);
1223
                Iterator<XYZLayerRank> xyzRankIterator = layerRanks.values().iterator();
1224
                while(xyzRankIterator.hasNext()){
1225
                        XYZLayerRank layerRank = xyzRankIterator.next();
1226
                        XMLEntity entity = layerRank.getXMLEntity();
1227
                        xml.addChild(entity);
1228
                }
1229
                return xml;
1230
        }
1231
        
1232

    
1233
        public void setXMLEntity(XMLEntity xml) throws XMLException {
1234
                super.setXMLEntity(xml);
1235
                
1236
                //FIXME Cambiar el uso de childrenCount por el empleo de propiedades
1237
                int numLayers = this.getLayersCount();
1238
                int numProperties = this.getExtendedProperties().size();
1239
                
1240
                int childrenCount = numLayers + numProperties;
1241
                
1242
                if(xml.contains("clusterTolerance"))
1243
                {
1244
                        this.clusterTolerance = xml.getDoubleProperty("clusterTolerance");
1245
                }
1246
                
1247
                if(xml.contains("name"))
1248
                {
1249
                        this.name = xml.getStringProperty("name");
1250
                }
1251
                
1252
                if(xml.contains("status"))
1253
                {
1254
                        this.status = (byte) xml.getIntProperty("status");
1255
                }
1256
                
1257
                if(xml.contains("maxNumberOfErrors"))
1258
                {
1259
                        this.maxNumberOfErrors =  xml.getIntProperty("maxNumberOfErrors");
1260
                }
1261
                
1262
                if(xml.contains("numberOfTopologyRules"))
1263
                {
1264
                        int numberOfTopologyRules =   xml.getIntProperty("numberOfTopologyRules");
1265
                        for(int i = 0; i < numberOfTopologyRules; i++){
1266
                                XMLEntity ruleXML = xml.getChild(childrenCount++);
1267
                                ITopologyRule rule = TopologyRuleFactory.createFromXML(this, ruleXML);
1268
                                this.rules.add(rule);
1269
                        }
1270
                }
1271
                
1272
                
1273
                if(xml.contains("numberOfClusterRules")){
1274
                        int numberOfClusterRules = xml.getIntProperty("numberOfClusterRules");
1275
                        for(int i = 0; i < numberOfClusterRules; i++){
1276
                                XMLEntity ruleXML = xml.getChild(childrenCount++);
1277
                                MustBeLargerThanClusterTolerance rule = (MustBeLargerThanClusterTolerance)TopologyRuleFactory.createFromXML(this, ruleXML);
1278
                                this.clusterToleranceRules.add(rule);
1279
                        }
1280
                }
1281
                
1282
                if(xml.contains("numberOfDirtyZones")){
1283
                        int numberOfDirtyZones = xml.getIntProperty("numberOfDirtyZones");
1284
                        for(int i = 0; i < numberOfDirtyZones; i++){
1285
                                XMLEntity dirtyZoneXml = xml.getChild(childrenCount++);
1286
                                double x = dirtyZoneXml.getDoubleProperty("extent"+i+"X");
1287
                                double y = dirtyZoneXml.getDoubleProperty("extent"+i+"Y");
1288
                                double w = dirtyZoneXml.getDoubleProperty("extent"+i+"W");
1289
                                double h = dirtyZoneXml.getDoubleProperty("extent"+i+"H");
1290
                                
1291
                                Rectangle2D.Double rect = new Rectangle2D.Double(x, y, w, h);
1292
                                dirtyZones.add(rect);
1293
                        }
1294
                }
1295
                
1296
                
1297
                
1298
                XMLEntity errorContainerXML = xml.getChild(childrenCount++);
1299
                if(errorContainerXML != null)
1300
                {
1301
                        this.errorContainer = TopologyPersister.createErrorContainerFromXML(errorContainerXML);
1302
                }
1303
                
1304
                if(xml.contains("numberOfRanks")){
1305
                        int numberOfRanks = xml.getIntProperty("numberOfRanks");
1306
                        for(int i = 0; i < numberOfRanks; i++){
1307
                                XMLEntity xmlRank = xml.getChild(childrenCount++);
1308
                                XYZLayerRank rank = new XYZLayerRank();
1309
                                rank.setXMLEntity(xmlRank);
1310
                        }
1311
                }                
1312
        }
1313

    
1314
        public int getNumberOfExceptions() {
1315
                return this.errorContainer.getNumberOfExceptions();
1316
        }
1317

    
1318

    
1319

    
1320
        public String getName() {
1321
                return name;
1322
        }
1323

    
1324

    
1325

    
1326
        public void setName(String name) {
1327
                this.name = name;
1328
        }
1329
        
1330
        public ITopologyErrorContainer getErrorContainer(){
1331
                return this.errorContainer;
1332
        }
1333
        
1334
        
1335
        public FLayer getErrorLayer(){
1336
                return this.errorLayer;
1337
        }
1338
        
1339
        public void setErrorContainer(ITopologyErrorContainer errorContainer){
1340
                this.errorContainer = errorContainer;
1341
                this.errorContainer.setTopology(this);
1342
        }
1343
        
1344
        private void fireStatusChange(TopologyStatusEvent event){
1345
                Iterator<ITopologyStatusListener> it = 
1346
                        this.statusListeners.iterator();
1347
                while(it.hasNext()){
1348
                        ITopologyStatusListener listener = it.next();
1349
                        listener.statusChange(event);
1350
                }
1351
        }
1352

    
1353
        public void removeErrorsByLayer(FLyrVect layer) {
1354
                this.errorContainer.removeErrorsByLayer(layer);
1355
        }
1356

    
1357
        public void removeErrorsByRule(String ruleName) {
1358
                this.errorContainer.removeErrorsByRule(ruleName);
1359
        }
1360
        
1361
        public void setRules(List<ITopologyRule> rules){
1362
                this.rules = rules;
1363
        }
1364
        
1365
        public void setDirtyZones(List<Rectangle2D> dirtyZones){
1366
                this.dirtyZones = dirtyZones;
1367
        }
1368
        
1369
        public void setStatusListeners(List<ITopologyStatusListener> statusListeners){
1370
                this.statusListeners = statusListeners;
1371
        }
1372
        
1373
        public void setLayerRanks(Map<FLyrVect, XYZLayerRank> layerRanks){
1374
                this.layerRanks = layerRanks;
1375
        }
1376
        
1377
        public Object clone(){
1378
                Topology newTopology = new Topology(super.getMapContext(), super.getParentLayer());
1379
                newTopology.setName(this.name);
1380
                newTopology.setClusterTolerance(this.clusterTolerance);
1381
                newTopology.ruleId = ruleId;
1382
                newTopology.setMaxNumberOfErrors(maxNumberOfErrors);
1383
                newTopology.setRules(rules)        ;
1384
                newTopology.setDirtyZones(dirtyZones);
1385
                newTopology.setStatusListeners(statusListeners);
1386
                newTopology.setLayerRanks(layerRanks);
1387
                newTopology.layers = new ArrayList();
1388
                for(int i = 0; i < layers.size(); i++){
1389
                        newTopology.addLayer((FLayer) layers.get(i));
1390
                }
1391
                newTopology.setStatus(status);
1392
                newTopology.setErrorContainer((ITopologyErrorContainer) errorContainer.clone());
1393
                return newTopology;
1394
        }
1395
        
1396
        public static void copyProperties(Topology from, Topology to){
1397
                to.setName(from.name);
1398
                to.ruleId = from.ruleId;
1399
                to.setStatus(from.status);
1400
                to.setMaxNumberOfErrors(from.maxNumberOfErrors);
1401
                to.setRules(from.rules)        ;
1402
                to.setDirtyZones(from.dirtyZones);
1403
                to.setErrorContainer(from.errorContainer);
1404
                to.setStatusListeners(from.statusListeners);
1405
                to.setLayerRanks(from.layerRanks);
1406
                
1407
                List layers = from.layers;
1408
                to.layers = new ArrayList();
1409
                for(int i = 0; i < layers.size(); i++){
1410
                        to.addLayer((FLayer) layers.get(i));
1411
                }
1412
                
1413
//                to.layers = from.layers;
1414
        }
1415

    
1416
        public FLyrVect getAsFMapLayer(String name, IProjection proj) {
1417
                return errorContainer.getAsFMapLayer(name, proj);
1418
        }
1419

    
1420
        /*
1421
         * Implementation of ITopologyErrorContanier
1422
         * 
1423
         */
1424
        public Topology getTopology() {
1425
                return this;
1426
        }
1427

    
1428
        //FIXME See if Topology must implement ITopologyErrorContainer
1429
        public void setTopology(Topology topology) {
1430
        }
1431

    
1432
}