Statistics
| Revision:

root / org.gvsig.legend.quantitybycategory.app.mainplugin / trunk / org.gvsig.legend.quantitybycategory.app.mainplugin / src / main / java / org / gvsig / symbology / fmap / rendering / QuantityByCategoryLegend.java @ 1857

History | View | Annotate | Download (16.5 KB)

1
package org.gvsig.symbology.fmap.rendering;
2

    
3
import java.util.ArrayList;
4
import java.util.List;
5

    
6
import org.slf4j.Logger;
7
import org.slf4j.LoggerFactory;
8

    
9
import org.gvsig.fmap.dal.feature.Feature;
10
import org.gvsig.fmap.geom.Geometry;
11
import org.gvsig.fmap.geom.GeometryLocator;
12
import org.gvsig.fmap.geom.GeometryManager;
13
import org.gvsig.fmap.mapcontext.MapContextException;
14
import org.gvsig.fmap.mapcontext.MapContextLocator;
15
import org.gvsig.fmap.mapcontext.MapContextManager;
16
import org.gvsig.fmap.mapcontext.rendering.legend.IInterval;
17
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
18
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
19
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
20
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
21
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractClassifiedVectorLegend;
22
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.VectorialIntervalLegend;
23
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IFillSymbol;
24
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
25
import org.gvsig.tools.ToolsLocator;
26
import org.gvsig.tools.dynobject.DynStruct;
27
import org.gvsig.tools.persistence.PersistenceManager;
28
import org.gvsig.tools.persistence.PersistentState;
29
import org.gvsig.tools.persistence.exception.PersistenceException;
30
import org.gvsig.tools.util.Callable;
31

    
32
/**
33
 * Implements a legend where the user can compare two different characteristics
34
 * of a region in the map. These two "fields" will be compared, on one side,
35
 * using a color for the region and , on the other side, using a graduated symbol.
36
 * Both methods will change (the color or the size of the symbol) depending on
37
 * the value of the fields.
38
 *
39
 * @author jaume dominguez faus - jaume.dominguez@iver.es
40
 */
41
public class QuantityByCategoryLegend extends AbstractClassifiedVectorLegend {
42

    
43
    private static final Logger logger =
44
        LoggerFactory.getLogger(QuantityByCategoryLegend.class);
45

    
46
    public static final String
47
    QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME =
48
    "QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME";
49

    
50
    public static final String
51
    QUANTITY_BY_CATEGORY_LEGEND_NAME = "QUANTITY_BY_CATEGORY_LEGEND_NAME";
52

    
53
        private GraduatedSymbolsLegend graduatedSymbol;
54
        private VectorialIntervalLegend colorRamp;
55

    
56
        private ISymbol defaultSymbol = null;
57
        private int shapeType = Geometry.TYPES.SURFACE;
58

    
59
        private boolean isUseDefaultSymbol;
60
        // private DataSource ds;
61

    
62
        public QuantityByCategoryLegend() {
63
                graduatedSymbol = new GraduatedSymbolsLegend();
64
                colorRamp = new VectorialIntervalLegend(getShapeType());
65
                this.setShapeType(Geometry.TYPES.SURFACE);
66

    
67
                ISymbol def = MapContextLocator.getSymbolManager().
68
            createSymbol(getShapeType());
69
                this.setDefaultSymbol(def);
70
        }
71

    
72

    
73
        public void clear() {
74
                colorRamp.clear();
75
                graduatedSymbol.clear();
76
        }
77

    
78
        public String[] getClassifyingFieldNames() {
79
                ArrayList<String> l = new ArrayList<String>();
80
                for (int i = 0; i < graduatedSymbol.getClassifyingFieldNames().length; i++) {
81
                        l.add(graduatedSymbol.getClassifyingFieldNames()[i]);
82
                }
83

    
84
                for (int i = 0; i < colorRamp.getClassifyingFieldNames().length; i++) {
85
                        l.add(colorRamp.getClassifyingFieldNames()[i]);
86
                }
87
                return l.toArray(new String[l.size()]);
88
        }
89

    
90

    
91
        @Override
92
        public int[] getClassifyingFieldTypes() {
93
        ArrayList<Integer> l = new ArrayList<Integer>();
94
        for (int i = 0; i < graduatedSymbol.getClassifyingFieldTypes().length; i++) {
95
            l.add(graduatedSymbol.getClassifyingFieldTypes()[i]);
96
        }
97

    
98
        for (int i = 0; i < colorRamp.getClassifyingFieldTypes().length; i++) {
99
            l.add(colorRamp.getClassifyingFieldTypes()[i]);
100
        }
101

    
102
        int len = l.size();
103
        int[] resp = new int[len];
104
        for (int i=0; i<len; i++) {
105
            resp[i] = l.get(i).intValue();
106
        }
107
        return resp;
108
        }
109

    
110
        public void setClassifyingFieldTypes(int[] fieldTypes) {
111
                if (fieldTypes.length == 2) {
112
                colorRamp.setClassifyingFieldTypes(new int[] {fieldTypes[1]});
113
                graduatedSymbol.setClassifyingFieldTypes(new int[] {fieldTypes[0]});
114
                } else {
115
                    logger.info("Error: Unexpected array size (should be 2)");
116
                }
117
                super.setClassifyingFieldTypes(fieldTypes);
118
        }
119

    
120

    
121
        /**
122
         * Sets the field names required to build this legend. In this case
123
         * fieldNames is an array of length 2 where the first element is
124
         * the field name for the embedded GraduatedSymbolLegend, and the
125
         * second is the field name for the embedded colorRamp (VectorialIntervalLegend)
126
         * legend.
127
         */
128
        public void setClassifyingFieldNames(String[] fieldNames) {
129

    
130
                if (fieldNames.length == 2) {
131
                colorRamp.setClassifyingFieldNames(new String[] {fieldNames[1]});
132
                graduatedSymbol.setClassifyingFieldNames(new String[] {fieldNames[0]});
133
                } else {
134
            logger.info("Error: Unexpected array size (should be 2)");
135
                }
136
                super.setClassifyingFieldNames(fieldNames);
137
        }
138

    
139
        public void addSymbol(Object key, ISymbol symbol) {
140
//                System.out.println("adding "+key+"["+symbol+"]");
141

    
142
                if(symbol instanceof IFillSymbol)
143
                        colorRamp.addSymbol(key, symbol);
144
                else if(symbol instanceof IMarkerSymbol)
145
                        graduatedSymbol.addSymbol(key, symbol);
146

    
147
                fireClassifiedSymbolChangeEvent(
148
                    new SymbolLegendEvent(null, symbol));
149
        }
150

    
151
        public void delSymbol(Object key) {
152
                colorRamp.delSymbol(key);
153
                graduatedSymbol.delSymbol(key);
154
                fireClassifiedSymbolChangeEvent(
155
                                new SymbolLegendEvent(
156
                                                null,
157
                                                null));
158
        }
159

    
160
        public String[] getDescriptions() {
161
                String[] desc1 = colorRamp.getDescriptions();
162
                String[] desc2 = graduatedSymbol.getDescriptions();
163
        Object[] objects1 = colorRamp.getValues();
164
        Object[] objects2 = graduatedSymbol.getValues();
165

    
166
        List descriptionsList = new ArrayList<String>();
167
        for (int i = 0; i < objects1.length; i++) {
168
            //Pretend?a saltar el valor por defecto pero no es necesario si en getValues se pone como clave null
169
//            if(objects1[i] instanceof IInterval){
170
                descriptionsList.add(desc1[i]);
171
//            }
172
        }
173
        for (int i = 0; i < objects2.length; i++) {
174
            //Pretend?a saltar el valor por defecto pero no es necesario si en getValues se pone como clave null
175
//            if(objects2[i] instanceof IInterval){
176
                descriptionsList.add(desc2[i]);
177
//            }
178
        }
179

    
180
        String[] descriptions = new String[descriptionsList.size()];
181
        descriptions = (String[]) descriptionsList.toArray(descriptions);
182
        return descriptions;
183

    
184
        }
185

    
186
        public ISymbol[] getSymbols() {
187
                ISymbol[] symbols1 = colorRamp.getSymbols();
188
                ISymbol[] symbols2 = graduatedSymbol.getSymbols();
189
            Object[] objects1 = colorRamp.getValues();
190
            Object[] objects2 = graduatedSymbol.getValues();
191

    
192

    
193
        List symbolsList = new ArrayList<ISymbol>();
194
        for (int i = 0; i < objects1.length; i++) {
195
            //Pretend?a saltar el valor por defecto pero no es necesario si en getValues se pone como clave null
196
//            if(objects1[i] instanceof IInterval){
197
                symbolsList.add(symbols1[i]);
198
//            }
199
        }
200
        for (int i = 0; i < objects2.length; i++) {
201
            //Pretend?a saltar el valor por defecto pero no es necesario si en getValues se pone como clave null
202
//            if(objects2[i] instanceof IInterval){
203
                symbolsList.add(symbols2[i]);
204
//            }
205
        }
206

    
207
        ISymbol[] symbols = new ISymbol[symbolsList.size()];
208
        symbols = (ISymbol[]) symbolsList.toArray(symbols);
209
        return symbols;
210
        }
211

    
212
        public Object[] getValues() {
213
                Object[] objects1 = colorRamp.getValues();
214
                Object[] objects2 = graduatedSymbol.getValues();
215

    
216
                List objectsList = new ArrayList<IInterval>();
217
                for (int i = 0; i < objects1.length; i++) {
218
            if(objects1[i] instanceof IInterval){
219
                objectsList.add(objects1[i]);
220
            } else {
221
                objectsList.add(null); //Si no es un IInterval es el valor por defecto
222
            }
223
        }
224
        for (int i = 0; i < objects2.length; i++) {
225
            if(objects2[i] instanceof IInterval){
226
                objectsList.add(objects2[i]);
227
            } else {
228
                objectsList.add(null); //Si no es un IInterval es el valor por defecto
229
            }
230
        }
231
        Object[] objects = new IInterval[objectsList.size()];
232
        objects = objectsList.toArray(objects);
233
                return objects;
234

    
235
        }
236

    
237

    
238
        public Object clone() throws CloneNotSupportedException {
239

    
240
            QuantityByCategoryLegend resp =
241
                (QuantityByCategoryLegend) super.clone();
242

    
243
        resp.setShapeType(this.getShapeType());
244

    
245
            resp.useDefaultSymbol(this.isUseDefaultSymbol());
246
            ISymbol defsym = this.getDefaultSymbol();
247
            defsym = (ISymbol) defsym.clone();
248
            resp.setDefaultSymbol(defsym);
249

    
250
            GraduatedSymbolsLegend gleg = this.getGraduatedSymbolsLegend();
251
            gleg = (GraduatedSymbolsLegend) gleg.cloneLegend();
252
            resp.setGraduateSymbolLegend(gleg);
253

    
254
            VectorialIntervalLegend interleg = this.getColorRampLegend();
255
            interleg = (VectorialIntervalLegend) interleg.cloneLegend();
256
            resp.setColorRampLegend(interleg);
257
                return resp;
258
        }
259
        /**
260
         * Obtains the GraduatedSymbolLegend
261
         *
262
         * @return GraduatedSymbolLegend
263
         */
264
        public GraduatedSymbolsLegend getGraduatedSymbolsLegend() {
265
                return graduatedSymbol;
266
        }
267
        /**
268
         * Obtains the VectorialIntervalLegend
269
         *
270
         * @return VectorialIntervalLegend
271
         */
272
        public VectorialIntervalLegend getColorRampLegend() {
273
                return colorRamp;
274
        }
275

    
276
        /*
277
        public void setDataSource(DataSource ds) throws FieldNotFoundException, ReadDriverException {
278
                // TODO remove it when FLyrVect.forTestOnlyVariableUseIterators_REMOVE_THIS_FIELD is removed
279
//                if (FLyrVect.forTestOnlyVariableUseIterators_REMOVE_THIS_FIELD) {
280
                        this.ds = ds;
281
//                }
282
                graduatedSymbol.setDataSource(ds);
283
                colorRamp.setDataSource(ds);
284
        }
285
        */
286

    
287
        /*
288
        public ISymbol getSymbol(int i) {
289

290
                IMarkerSymbol sym1 = (IMarkerSymbol) graduatedSymbol.getSymbol(i);
291
                ISymbol sym2 =  colorRamp.getSymbol(i);
292

293
                IMultiLayerSymbol multiSym = null;
294
                int shpt = this.getShapeType();
295

296
                if (isPolygonal(shpt)) {
297
            // symbol from the GraduatedSymbolLegend is a marker, but
298
            // what we need is a fill symbol. Will use a MarkerFillSymbol
299
            // to enable support for Polygons
300
            MarkerFillSymbol aux = new MarkerFillSymbol();
301
            // tell the fill style to draw the IMarkerSymbol
302
            // as a IFillSymbol centering it in the shape polygon
303
            // centroid and applying offset (if any).
304
            aux.setMarker(sym1);
305
            SimpleMarkerFillPropertiesStyle p =
306
                new SimpleMarkerFillPropertiesStyle();
307
            p.setFillStyle(SimpleMarkerFillPropertiesStyle.SINGLE_CENTERED_SYMBOL);
308
            aux.setMarkerFillProperties(p);
309

310
            multiSym = MapContextLocator.getSymbolManager().
311
                createMultiLayerSymbol(Geometry.TYPES.SURFACE);
312

313
            multiSym.addLayer(sym2);
314
            multiSym.addLayer(aux);
315
            break;
316

317
                } else {
318
                    logger.info("Error: unexpected shape type (should be surface): " + shpt);
319
                }
320

321
                return multiSym;
322
        }
323
        */
324

    
325
        public ISymbol getSymbolByFeature(Feature feat) throws MapContextException {
326

    
327
                ISymbol sym1 = null, sym2 = null;
328
                sym1 = graduatedSymbol.getSymbolByFeature(feat);
329
                // Ensure fill symbol
330
                sym1 = GraduatedSymbolsLegend.toFillSymbol(sym1);
331

    
332
                sym2 = colorRamp.getSymbolByFeature(feat);
333

    
334
                IMultiLayerSymbol multiSym = null;
335
                int shpt = this.getShapeType();
336

    
337
                if (isPolygonal(shpt)) {
338

    
339
            multiSym = MapContextLocator.getSymbolManager().
340
                createMultiLayerSymbol(Geometry.TYPES.SURFACE);
341

    
342
            if (sym2 != null) multiSym.addLayer(sym2);
343
            if (sym1 != null) multiSym.addLayer(sym1);
344
                } else {
345
                    logger.info("Error: unexpected shape type (should be surface): " + shpt);
346
                }
347

    
348
                return multiSym;
349
        }
350

    
351
        public void setShapeType(int shpt) {
352

    
353
            this.shapeType = shpt;
354
            ISymbol sym = null;
355

    
356
                graduatedSymbol.setShapeType(Geometry.TYPES.POINT);
357
                sym = MapContextLocator.getSymbolManager().createSymbol(
358
                    Geometry.TYPES.POINT);
359
                graduatedSymbol.setDefaultSymbol(sym);
360

    
361
                colorRamp.setShapeType(shpt);
362
                sym = MapContextLocator.getSymbolManager().createSymbol(shpt);
363
                colorRamp.setDefaultSymbol(sym);
364
        }
365

    
366

    
367

    
368
        public boolean isUseDefaultSymbol() {
369
                return isUseDefaultSymbol;
370
        }
371

    
372
        public void useDefaultSymbol(boolean b) {
373
                this.isUseDefaultSymbol = b;
374
        }
375

    
376
        public void setGraduateSymbolLegend(GraduatedSymbolsLegend legend) {
377
                this.graduatedSymbol = legend;
378
        }
379

    
380
        public void setColorRampLegend(VectorialIntervalLegend legend) {
381
                this.colorRamp = legend;
382
        }
383

    
384
        public String getClassName() {
385
                return getClass().getName();
386
        }
387

    
388
        public void replace(ISymbol oldSymbol, ISymbol newSymbol) {
389
                ISymbol[] symbols;
390
                // look first in the graduated symbol legend
391
                symbols = graduatedSymbol.getSymbols();
392

    
393
                for (int i = 0; i < symbols.length; i++) {
394
                        if (symbols[i].equals(oldSymbol)) {
395
                                graduatedSymbol.replace(oldSymbol, newSymbol);
396
                                return;
397
                        }
398
                }
399

    
400
                // if the symbol wasn't found yet, proceed with color ramp
401
                symbols = colorRamp.getSymbols();
402

    
403
                for (int i = 0; i < symbols.length; i++) {
404
                        if (symbols[i].equals(oldSymbol)) {
405
                                colorRamp.replace(oldSymbol, newSymbol);
406
                                return;
407
                        }
408
                }
409

    
410
        }
411

    
412
    public static boolean isPolygonal(int ty) {
413
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
414
        return geomManager.isSubtype(Geometry.TYPES.MULTISURFACE, ty) || 
415
            geomManager.isSubtype(Geometry.TYPES.SURFACE, ty);
416
    }
417

    
418
    public ISymbol getDefaultSymbol() {
419
        return this.defaultSymbol;
420
    }
421

    
422

    
423
    public int getShapeType() {
424
        return this.shapeType;
425
    }
426

    
427

    
428
    public void setDefaultSymbol(ISymbol s) {
429
        this.defaultSymbol = s;
430
    }
431

    
432

    
433
    // =============================
434

    
435
    public static class RegisterPersistence implements Callable {
436

    
437
        public Object call() throws Exception {
438

    
439
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
440
            if (manager.getDefinition(
441
                QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME) == null) {
442
                DynStruct definition = manager
443
                    .addDefinition(QuantityByCategoryLegend.class,
444
                        QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME,
445
                        QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME
446
                        + " Persistence definition", null, null);
447

    
448
                definition.extend(manager.getDefinition(
449
                    AbstractClassifiedVectorLegend
450
                    .CLASSIFIED_VECTOR_LEGEND_PERSISTENCE_DEFINITION_NAME));
451

    
452
                definition.addDynFieldBoolean("useDefaultSymbol")
453
                .setMandatory(true);
454

    
455
                definition.addDynFieldObject("graduatedLegend")
456
                .setClassOfValue(ILegend.class).setMandatory(true);
457
                definition.addDynFieldObject("rampLegend")
458
                .setClassOfValue(ILegend.class).setMandatory(true);
459
            }
460
            return Boolean.TRUE;
461
        }
462

    
463
    }
464

    
465
    public static class RegisterLegend implements Callable {
466

    
467
        public Object call() throws Exception {
468
            MapContextManager manager =
469
                MapContextLocator.getMapContextManager();
470

    
471
            manager.registerLegend(
472
                QUANTITY_BY_CATEGORY_LEGEND_NAME,
473
                QuantityByCategoryLegend.class);
474

    
475
            return Boolean.TRUE;
476
        }
477

    
478
    }
479

    
480
    public void saveToState(PersistentState state) throws PersistenceException {
481

    
482
        super.saveToState(state);
483
        state.set("useDefaultSymbol", this.isUseDefaultSymbol());
484
        state.set("graduatedLegend", this.getGraduatedSymbolsLegend());
485
        state.set("rampLegend", this.getColorRampLegend());
486
    }
487

    
488
    public void loadFromState(PersistentState state)
489
        throws PersistenceException {
490

    
491
        super.loadFromState(state);
492

    
493
        Boolean b = state.getBoolean("useDefaultSymbol");
494
        this.useDefaultSymbol(b);
495

    
496
        ILegend leg = (ILegend) state.get("graduatedLegend");
497
        if (leg instanceof GraduatedSymbolsLegend) {
498
            this.setGraduateSymbolLegend((GraduatedSymbolsLegend) leg);
499
        } else {
500
            throw new PersistenceException(new ClassCastException(
501
                "Unexpected legend type (" + leg + "). Should be GraduatedSymbolsLegend"));
502
        }
503

    
504
        leg = (ILegend) state.get("rampLegend");
505
        if (leg instanceof VectorialIntervalLegend) {
506
            this.setColorRampLegend((VectorialIntervalLegend) leg);
507
        } else {
508
            throw new PersistenceException(new ClassCastException(
509
                "Unexpected legend type (" + leg + "). Should be VectorialIntervalLegend"));
510
        }
511
    }
512

    
513

    
514

    
515
}