Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / org.gvsig.arcims / src / org / gvsig / remoteclient / arcims / styling / renderers / ArcImsFLegendFactory.java @ 32668

History | View | Annotate | Download (17.5 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2010 Prodevelop S.L. main development
26
 * http://www.prodevelop.es
27
 */
28

    
29
package org.gvsig.remoteclient.arcims.styling.renderers;
30

    
31
import java.text.DecimalFormatSymbols;
32
import java.text.ParseException;
33
import java.util.ArrayList;
34
import java.util.Iterator;
35
import java.util.List;
36

    
37
import org.gvsig.fmap.geom.Geometry;
38
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
39
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
40
import org.gvsig.remoteclient.arcims.ArcXML;
41
import org.gvsig.remoteclient.arcims.exceptions.ArcImsException;
42
import org.gvsig.remoteclient.arcims.styling.symbols.ArcImsFSymbolFactory;
43
import org.gvsig.remoteclient.arcims.styling.symbols.IArcIMSSymbol;
44
import org.gvsig.remoteclient.arcims.utils.ArcImsObjectFactory;
45
import org.gvsig.remoteclient.arcims.utils.FieldInformation;
46
import org.gvsig.remoteclient.arcims.utils.ServiceInfoTags;
47
import org.gvsig.remoteclient.arcims.utils.ServiceInformation;
48
import org.gvsig.remoteclient.arcims.utils.ServiceInformationLayerFeatures;
49
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractClassifiedVectorLegend;
50
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractVectorialLegend;
51
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.FInterval;
52
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.SingleSymbolLegend;
53
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.VectorialIntervalLegend;
54
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.VectorialUniqueValueLegend;
55
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
57

    
58

    
59

    
60
/**
61
 * Factory class to produce FLegend's from ArcIMS Renderers defintions
62
 * 
63
 * @author jsanz
64
 * @author vsanjaime version 2.0
65
 * 
66
 */
67
public class ArcImsFLegendFactory {
68

    
69
        private static Logger logger = LoggerFactory
70
                        .getLogger(ArcImsFLegendFactory.class.getName());
71
        private char ds;
72
        private ServiceInformationLayerFeatures silf;
73
        private ServiceInformation si;
74

    
75
        // We use a class variable to overwrite every label definition
76
        private AbstractVectorialLegend auxLabelsOuter = null;
77

    
78
        // private String PATRON = ArcXML.PATRON;
79
        // DecimalFormat formatter;
80
        private int featType;
81

    
82
        /**
83
         * Constructor
84
         * 
85
         * @param ds
86
         *            Decimal separator char
87
         * @param msilf
88
         *            An object with all the information to build the legend of a
89
         *            vectorial layer
90
         * @see org.gvsig.remoteclient.arcims.utils.ServiceInformationLayerFeatures
91
         */
92
        public ArcImsFLegendFactory(ServiceInformation msi, String layerId) {
93
                si = msi;
94
                ds = msi.getSeparators().getDs();
95
                ArcImsFSymbolFactory.ds = ds;
96

    
97
                silf = (ServiceInformationLayerFeatures) this.si.getLayerById(layerId);
98
                this.featType = getSymbType(silf.getFclasstype());
99

    
100
                DecimalFormatSymbols dfs = new DecimalFormatSymbols();
101
                dfs.setDecimalSeparator(ds);
102
        }
103

    
104
        /**
105
         * Main method on this class. It calls proper getLegend method based on type
106
         * of render.
107
         * 
108
         * @param render
109
         * @return
110
         * @throws ArcImsException
111
         */
112
        public ILegend getMainLegend() throws ArcImsException {
113
                logger.info("======Start creating main layer Legend======");
114

    
115
                Renderer render = silf.getLayerMainRenderer();
116
                ILegend leg = getLegend(render, true);
117
                logger.info("======Getting main Legend ("
118
                                + getClassName(leg.getClass()) + ")======");
119

    
120
                return leg;
121
        }
122

    
123
        /**
124
         * Main method that calls proper getLengend methods according to the type of
125
         * renderer is passed.
126
         * 
127
         * @param render
128
         * @param isMainRender
129
         * @return
130
         * @throws ArcImsException
131
         */
132
        private AbstractVectorialLegend getLegend(Renderer render,
133
                        boolean isMainRender) throws ArcImsException {
134

    
135
                AbstractVectorialLegend leg = null;
136

    
137
                if (render instanceof SimpleRenderer) {
138
                        SimpleRenderer srender = (SimpleRenderer) render;
139
                        leg = getLegend(srender);
140
                } else if (render instanceof ValueMapRenderer) {
141
                        ValueMapRenderer srender = (ValueMapRenderer) render;
142
                        leg = getLegend(srender);
143
                }
144
                // In the main legend, a ScaleDependent and a GroupRenderer can be
145
                // treated in the same way (ScaleDependent inherits from GroupRenderer)
146
                else if (render instanceof GroupRenderer) {
147
                        GroupRenderer groupRender = (GroupRenderer) render;
148
                        leg = getLegend(groupRender);
149
                } else {
150
                        leg = getDefaultLegend();
151
                }
152

    
153
                if (leg != null) {
154
                        logger.info("Getting Render of type: "
155
                                        + getClassName(render.getClass()));
156

    
157
                        return leg;
158
                } else {
159
                        throw new ArcImsException("arcims_legend_error");
160
                }
161
        }
162

    
163
        /**
164
         * Method to generate a valid simple legend.
165
         * 
166
         * @return
167
         */
168
        private AbstractVectorialLegend getDefaultLegend() {
169
                SingleSymbolLegend leg = new SingleSymbolLegend();
170
                leg.setDefaultSymbol(ArcImsFSymbolFactory.getDefaultFSymbol(featType));
171
                leg.setShapeType(featType);
172
                logger.info("Getting default legend");
173

    
174
                return leg;
175
        }
176

    
177
        /**
178
         * Gets a simple Legend with only one symbol
179
         * 
180
         * @see com.iver.cit.gvsig.fmap.rendering.SingleSymbolLegend
181
         * @param renderer
182
         * @return
183
         */
184
        private AbstractVectorialLegend getLegend(SimpleRenderer renderer) {
185
                // Get the ArcIMS Simbol
186
                IArcIMSSymbol imsSimb = renderer.getSymbol();
187

    
188
                // Get the FSymbol of the renderer
189
                ISymbol simb = imsSimb.getFSymbol();
190

    
191
                // Creates the legend
192
                SingleSymbolLegend leg = new SingleSymbolLegend();
193
                leg.setDefaultSymbol(simb);
194
                leg.setShapeType(this.featType);
195
                logger.info("Getting a Simple Renderer");
196

    
197
                return (AbstractVectorialLegend) leg;
198
        }
199

    
200
        /**
201
         * Gets a Legend based on intervals
202
         * 
203
         * @see com.iver.cit.gvsig.fmap.rendering.VectorialIntervalLegend
204
         * @param renderer
205
         * @return
206
         * @throws ArcImsException
207
         */
208
        private AbstractVectorialLegend getLegend(ValueMapRenderer renderer)
209
                        throws ArcImsException {
210
                // Get the proper Field Information object
211
                FieldInformation fi = silf.getFieldInformation(renderer
212
                                .getLookupfield());
213

    
214
                // Gets the array of ranges
215
                List<TypeValueMap> values = renderer.getValues();
216
                Iterator<TypeValueMap> it = values.iterator();
217

    
218
                // Creates the two types of legends
219
                VectorialIntervalLegend viLeg = new VectorialIntervalLegend();
220
                VectorialUniqueValueLegend vuLeg = new VectorialUniqueValueLegend();
221

    
222
                // Initialize counters
223
                int nIntervals = 0;
224
                int nUniques = 0;
225

    
226
                // Create a default simbol
227
                ISymbol defSimb = ArcImsFSymbolFactory.getDefaultFSymbol(this.featType);
228
                defSimb.setDescription("Default");
229

    
230
                boolean hasDefSymbol = false;
231

    
232
                // Fills with intervals and symbols
233
                while (it.hasNext()) {
234
                        // Only RangeValueMaps are allowed
235
                        TypeValueMap tvm = (TypeValueMap) it.next();
236

    
237
                        // Gets the symbol
238
                        IArcIMSSymbol simb = tvm.getSymbol();
239
                        ISymbol fsimb = simb.getFSymbol();
240

    
241
                        // Set the description
242
                        String descr = tvm.getLabel();
243

    
244
                        if (descr == null) {
245
                                descr = "";
246
                        }
247

    
248
                        fsimb.setDescription(descr);
249

    
250
                        if (tvm instanceof RangeValueMap) {
251
                                RangeValueMap rvm = (RangeValueMap) tvm;
252

    
253
                                // Get the bounds of the intverval
254
                                String sFrom = rvm.getLower();
255
                                String sTo = rvm.getUpper();
256
                                double from = Double.parseDouble(sFrom.replace(ds, '.'));
257
                                double to = Double.parseDouble(sTo.replace(ds, '.'));
258

    
259
                                if (descr == null) {
260
                                        fsimb.setDescription(sFrom + "-" + sTo);
261
                                }
262

    
263
                                // Creates the Interval
264
                                FInterval interv = new FInterval(from, to);
265

    
266
                                // Adds the symbol to the legend
267
                                viLeg.addSymbol(interv, fsimb);
268

    
269
                                // viLeg.setIntervalSymbol(interv,fsimb);
270
                                nIntervals++;
271
                        } else if (tvm instanceof ExactValueMap) {
272
                                ExactValueMap evm = (ExactValueMap) tvm;
273

    
274
                                // We have to build a Value object
275
                                String strVal = evm.getValue();
276

    
277
                                try {
278
                                        Object val = ArcImsObjectFactory.createObjectByType(strVal, fi
279
                                                        .getType(), this.ds);
280
                                        vuLeg.addSymbol(val, fsimb);
281
                                } catch (ParseException e) {
282
                                        logger.error(e.getMessage(), e);
283
                                        throw new ArcImsException("arcims_legend_error");
284
                                }
285

    
286
                                nUniques++;
287
                        } else if (tvm instanceof OtherValueMap) {
288
                                hasDefSymbol = true;
289
                                defSimb = fsimb;
290
                        }
291
                }
292

    
293
                /*
294
                 * Determine what type of legend the method will return (Unique or
295
                 * Interval) The condition will be the legend with more classes
296
                 * (intervals, values)
297
                 */
298
                AbstractVectorialLegend leg = null;
299
                AbstractClassifiedVectorLegend cleg = null;
300

    
301
                if (nUniques >= nIntervals) {
302
                        leg = vuLeg;
303
                        cleg = vuLeg;
304
                } else {
305
                        leg = viLeg;
306
                        cleg = viLeg;
307
                }
308

    
309
                /*
310
                 * Finally we can add the field name and default symbol
311
                 */
312

    
313
                // Set the field name
314
                String fieldName = ArcXML.replaceUnwantedCharacters(fi.getName());
315
                cleg.setClassifyingFieldNames(new String[]{fieldName});
316

    
317
                // Set the default symbol, if it is used and asign the symbol to a
318
                // nullvalue
319
                leg.setDefaultSymbol(defSimb);
320
                leg.useDefaultSymbol(hasDefSymbol);
321

    
322
                if (hasDefSymbol) {
323
                        if (leg instanceof VectorialUniqueValueLegend) {
324
                                vuLeg.addSymbol(null, leg.getDefaultSymbol());
325
                        } else {
326
                                viLeg
327
                                                .addSymbol(null, leg
328
                                                                .getDefaultSymbol());
329
                        }
330
                }
331

    
332
                logger.info("Getting a Value Map Renderer");
333

    
334
                return leg;
335
        }
336

    
337
        // /**
338
        // * Gets the most detailed legend from the ScaleDependentRender
339
        // * @param sdrender
340
        // * @return
341
        // */
342
        // private VectorialLegend getLegend(ScaleDependentRenderer sdrender) throws
343
        // ArcImsException {
344
        // VectorialLegend leg = getLegend((GroupRenderer) sdrender);
345
        // logger.info("Getting a ScaleDependent Renderer");
346
        // return leg;
347
        // }
348
        private AbstractVectorialLegend getLegend(GroupRenderer groupRender)
349
                        throws ArcImsException {
350
                List<Renderer> renderers = groupRender.renderers;
351
                List<AbstractVectorialLegend> legends = new ArrayList<AbstractVectorialLegend>();
352
                AbstractVectorialLegend biggerScale = null;
353
                AbstractVectorialLegend leg = null;
354
                double[] limit = { Double.MAX_VALUE, 0 };
355
                Iterator<Renderer> it = renderers.iterator();
356

    
357
                // We use a class variable to overwrite every label definition
358
                AbstractVectorialLegend auxLabelsInner = null;
359

    
360
                while (it.hasNext()) {
361
                        leg = null;
362

    
363
                        Renderer iRender = (Renderer) it.next();
364

    
365
                        // If we don't have a Label renderer use the generic method
366
                        if (!(iRender instanceof ILabelRenderer)) {
367
                                leg = getLegend(iRender, false);
368
                        }
369
                        // Otherwise, use the specific method for labels
370
                        else {
371
                                auxLabelsInner = getLegend((ILabelRenderer) iRender);
372
                        }
373

    
374
                        // If renderer is Scale Dependent, we inspect their scale limits
375
                        if (iRender instanceof ScaleDependentRenderer) {
376
                                ScaleDependentRenderer iSDRender = (ScaleDependentRenderer) iRender;
377
                                String strLow = iSDRender.getLower();
378
                                String strUpp = iSDRender.getUpper();
379
                                double low = 0;
380
                                double upp = Double.MAX_VALUE;
381

    
382
                                if (strLow != null) {
383
                                        low = Double.parseDouble(strLow.replace(ds, '.'));
384
                                }
385

    
386
                                if (strUpp != null) {
387
                                        upp = Double.parseDouble(strUpp.replace(ds, '.'));
388
                                }
389

    
390
                                // First loop
391
                                if (biggerScale == null) {
392
                                        biggerScale = leg;
393
                                        limit[0] = low;
394
                                        limit[1] = upp;
395
                                }
396
                                /*
397
                                 * Next loops we allways get the minimum interval If lower
398
                                 * bounds are equal, we get the lower upper value
399
                                 */
400
                                else if ((low <= limit[0]) && (upp <= limit[1])) {
401
                                        limit[0] = low;
402
                                        limit[1] = upp;
403
                                        biggerScale = leg;
404
                                }
405
                        }
406

    
407
                        if (leg != null) {
408
                                legends.add(leg);
409
                        }
410
                }
411

    
412
                /*
413
                 * TODO At this time we will return the first (bottom) legend of the
414
                 * ArrayList or the most detailed legend if there are any
415
                 * ScaleDependentRenderers Probably I will add more "logic" into this
416
                 * code
417
                 */
418
                AbstractVectorialLegend finalLegend = null;
419
                boolean onlyLabels = false;
420

    
421
                /*
422
                 * Check if auxLabels is equal to the last element of the array Legends
423
                 * and if it's true, merge it with the first one (its label definition)
424
                 */
425
                if (auxLabelsOuter != null && legends.size() > 0) {
426

    
427
                        for (int i = 0; i < legends.size(); i++) {
428
                                // FSymbol simb1 = auxLabelsOuter.getDefaultSymbol();
429
                                // FSymbol simb2 = ((VectorialLegend)
430
                                // legends.get(i)).getDefaultSymbol();
431
                                ISymbol simb1 = (ISymbol) auxLabelsOuter.getDefaultSymbol();
432
                                ISymbol simb2 = (ISymbol) ((AbstractVectorialLegend) legends
433
                                                .get(i)).getDefaultSymbol();
434

    
435
                                if (simb1 == simb2) {
436
                                        // Null the biggerScale to force the next if statement
437
                                        biggerScale = null;
438
                                        // Merge the auxLabels object into the first legend of the
439
                                        // arrayList
440
                                        AbstractVectorialLegend legend = setLabelDefIntoSymbol(
441
                                                        auxLabelsOuter, (AbstractVectorialLegend) legends
442
                                                                        .get(0));
443
                                        legends.set(0, legend);
444
                                        // Null the auxlabelsinner to avoid the last if
445
                                        auxLabelsInner = null;
446
                                        break;
447
                                }
448
                        }
449

    
450
                }
451

    
452
                // We don't have any scaledependent
453
                if (((biggerScale == null) && (legends.size() > 0))) {
454
                        // if (!(groupRender instanceof ScaleDependentRenderer)){
455
                        logger.info("Getting the bottom renderer of the Group Renderer");
456
                        finalLegend = (AbstractVectorialLegend) legends.get(0);
457
                }
458
                // We have any scaledpendent
459
                else if (biggerScale != null) {
460
                        logger
461
                                        .info("Getting the most detailed ScaleDependent renderer of the Group Renderer");
462
                        finalLegend = biggerScale;
463
                }
464
                // We don't have any legend parsed (maybe the layer only have label
465
                // definitions
466
                else {
467
                        //finalLegend = new SingleSymbolLegend(this.featType);
468
                        finalLegend = new SingleSymbolLegend();
469
                        finalLegend.setShapeType(this.featType);
470
                        onlyLabels = true;
471
                }
472

    
473
                /*
474
                 * Finally if some label renderer is found, we have to pass the label
475
                 * properties to the final legend
476
                 */
477
                if (auxLabelsInner != null) {
478
                        finalLegend = setLabelDefIntoSymbol(auxLabelsInner, finalLegend);
479
//FIXME
480
//                        // finalLegend.getDefaultSymbol().setShapeVisible(!onlyLabels);
481
//                        ((ISymbol) finalLegend.getDefaultSymbol())
482
//                                        .setShapeVisible(!onlyLabels);
483

    
484
                        auxLabelsOuter = finalLegend;
485
                }
486
                return finalLegend;
487
        }
488

    
489
        /**
490
         * Method that returns a SingleSymboLegend with Font definition and field to
491
         * retrieve labels. These properties will be transferred to the main layer
492
         * legend.
493
         * 
494
         * @param renderer
495
         * @return
496
         */
497
        private AbstractVectorialLegend getLegend(ILabelRenderer renderer) {
498
                // Get the proper Field Information object
499
                FieldInformation fi = silf.getFieldInformation(renderer.getField());
500

    
501
                // Create a legend
502
                SingleSymbolLegend leg = new SingleSymbolLegend();
503
                leg.setShapeType(this.featType);
504
                IArcIMSSymbol arcSimb = null;
505

    
506
                // Get the ArcIMS Symbol with Font definition
507
                if (renderer instanceof SimpleLabelRenderer) {
508
                        SimpleLabelRenderer slrender = (SimpleLabelRenderer) renderer;
509
                        arcSimb = slrender.getSymbol();
510
                } else if (renderer instanceof ValueMapLabelRenderer) {
511
                        ValueMapLabelRenderer vmlrender = (ValueMapLabelRenderer) renderer;
512
                        arcSimb = vmlrender.getValue(0).getSymbol();
513
                }
514

    
515
                // Asign it (or a default) to the legend
516
                if (arcSimb != null) {
517
                        leg.setDefaultSymbol(arcSimb.getFSymbol());
518
                } else {
519
                        leg.setDefaultSymbol(ArcImsFSymbolFactory
520
                                        .getDefaultFSymbol(this.featType));
521
                }
522

    
523
                // Set the label field
524
        //FIXME        
525
//                String labelField = ArcXML.replaceUnwantedCharacters(fi.getName());
526
//                leg.setLabelField(labelField);
527

    
528
                // Return the legend
529
                return leg;
530
        }
531

    
532
        /**
533
         * @return Returns the featType.
534
         */
535
        public int getFeatType() {
536
                return featType;
537
        }
538

    
539
        /**
540
         * @param featType
541
         *            The featType to set.
542
         */
543
        public void setFeatType(int featType) {
544
                this.featType = featType;
545
        }
546

    
547
        /**
548
         * Gets the simple class name
549
         * 
550
         * @param mclass
551
         * @return
552
         */
553
        private String getClassName(Class mclass) {
554
                String[] classSplitted = mclass.getName().split("\\.");
555

    
556
                return classSplitted[classSplitted.length - 1];
557
        }
558

    
559
        /**
560
         * Private method to set into a legend the label definition of another
561
         * legend
562
         * 
563
         * @param withLabels
564
         * @param finalLegend
565
         * @return
566
         */
567
        private AbstractVectorialLegend setLabelDefIntoSymbol(
568
                        AbstractVectorialLegend withLabels,
569
                        AbstractVectorialLegend finalLegend) {
570
//FIXME
571
//                // Set the label
572
//                finalLegend.setLabelField(withLabels.getLabelField());
573
//                // Get simbol with font definition
574
//
575
//                // FSymbol simbWithFont = withLabels.getDefaultSymbol();
576
//                ISymbol simbWithFont = (ISymbol) withLabels.getDefaultSymbol();
577
//
578
//                // Get simbol to insert font definition
579
//                // FSymbol simb = finalLegend.getDefaultSymbol();
580
//                ISymbol simb = (ISymbol) finalLegend.getDefaultSymbol();
581
//
582
//                // Insert into simb the font properties
583
//                simb.setFont(simbWithFont.getFont());
584
//                simb.setFontColor(simbWithFont.getFontColor());
585
//                simb.setFontSize(simbWithFont.getFontSize());
586
//                simb.setFontSizeInPixels(true);
587
//                // Set simbol modified into final legend to return
588
//                finalLegend.setDefaultSymbol(simb);
589

    
590
                return finalLegend;
591
        }
592

    
593
        /**
594
         * Converts ArcIMS feature type to a constant value
595
         * 
596
         * @param fclasstype
597
         * @return
598
         */
599
        private int getSymbType(String fclasstype) {
600
                
601
                if (fclasstype.equals(ServiceInfoTags.aPOLYGON)) {
602

    
603
                        return Geometry.TYPES.SURFACE;
604
                }
605

    
606
                if (fclasstype.equals(ServiceInfoTags.aPOLYLINE)) {
607
                        return Geometry.TYPES.CURVE;
608
                }
609

    
610
                if (fclasstype.equals(ServiceInfoTags.aMULTIPOINT)) {
611
                        return Geometry.TYPES.MULTIPOINT;
612
                }
613

    
614
                return Geometry.TYPES.NULL;
615
        }
616
}