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

History | View | Annotate | Download (16.4 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.mapcontext.MapContextException;
12
import org.gvsig.fmap.mapcontext.MapContextLocator;
13
import org.gvsig.fmap.mapcontext.MapContextManager;
14
import org.gvsig.fmap.mapcontext.rendering.legend.IInterval;
15
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
16
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
17
import org.gvsig.fmap.mapcontext.rendering.symbols.IMultiLayerSymbol;
18
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
19
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractClassifiedVectorLegend;
20
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.VectorialIntervalLegend;
21
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.fill.IFillSymbol;
22
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.marker.IMarkerSymbol;
23
import org.gvsig.tools.ToolsLocator;
24
import org.gvsig.tools.dynobject.DynStruct;
25
import org.gvsig.tools.persistence.PersistenceManager;
26
import org.gvsig.tools.persistence.PersistentState;
27
import org.gvsig.tools.persistence.exception.PersistenceException;
28
import org.gvsig.tools.util.Callable;
29

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

    
41
    private static final Logger logger =
42
        LoggerFactory.getLogger(QuantityByCategoryLegend.class);
43

    
44
    public static final String
45
    QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME =
46
    "QUANTITY_BY_CATEGORY_LEGEND_PERSISTENCE_DEFINITION_NAME";
47

    
48
    public static final String
49
    QUANTITY_BY_CATEGORY_LEGEND_NAME = "QUANTITY_BY_CATEGORY_LEGEND_NAME";
50

    
51
        private GraduatedSymbolsLegend graduatedSymbol;
52
        private VectorialIntervalLegend colorRamp;
53

    
54
        private ISymbol defaultSymbol = null;
55
        private int shapeType = Geometry.TYPES.SURFACE;
56

    
57
        private boolean isUseDefaultSymbol;
58
        // private DataSource ds;
59

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

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

    
70

    
71
        public void clear() {
72
                colorRamp.clear();
73
                graduatedSymbol.clear();
74
        }
75

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

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

    
88

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

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

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

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

    
118

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

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

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

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

    
145
                fireClassifiedSymbolChangeEvent(
146
                    new SymbolLegendEvent(null, symbol));
147
        }
148

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

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

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

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

    
182
        }
183

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

    
190

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

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

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

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

    
233
        }
234

    
235

    
236
        public Object clone() throws CloneNotSupportedException {
237

    
238
            QuantityByCategoryLegend resp =
239
                (QuantityByCategoryLegend) super.clone();
240

    
241
        resp.setShapeType(this.getShapeType());
242

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

    
248
            GraduatedSymbolsLegend gleg = this.getGraduatedSymbolsLegend();
249
            gleg = (GraduatedSymbolsLegend) gleg.cloneLegend();
250
            resp.setGraduateSymbolLegend(gleg);
251

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

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

    
285
        /*
286
        public ISymbol getSymbol(int i) {
287

288
                IMarkerSymbol sym1 = (IMarkerSymbol) graduatedSymbol.getSymbol(i);
289
                ISymbol sym2 =  colorRamp.getSymbol(i);
290

291
                IMultiLayerSymbol multiSym = null;
292
                int shpt = this.getShapeType();
293

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

308
            multiSym = MapContextLocator.getSymbolManager().
309
                createMultiLayerSymbol(Geometry.TYPES.SURFACE);
310

311
            multiSym.addLayer(sym2);
312
            multiSym.addLayer(aux);
313
            break;
314

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

319
                return multiSym;
320
        }
321
        */
322

    
323
        public ISymbol getSymbolByFeature(Feature feat) throws MapContextException {
324

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

    
330
                sym2 = colorRamp.getSymbolByFeature(feat);
331

    
332
                IMultiLayerSymbol multiSym = null;
333
                int shpt = this.getShapeType();
334

    
335
                if (isPolygonal(shpt)) {
336

    
337
            multiSym = MapContextLocator.getSymbolManager().
338
                createMultiLayerSymbol(Geometry.TYPES.SURFACE);
339

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

    
346
                return multiSym;
347
        }
348

    
349
        public void setShapeType(int shpt) {
350

    
351
            this.shapeType = shpt;
352
            ISymbol sym = null;
353

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

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

    
364

    
365

    
366
        public boolean isUseDefaultSymbol() {
367
                return isUseDefaultSymbol;
368
        }
369

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

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

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

    
382
        public String getClassName() {
383
                return getClass().getName();
384
        }
385

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

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

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

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

    
408
        }
409

    
410
    public static boolean isPolygonal(int ty) {
411
        if (ty == Geometry.TYPES.MULTISURFACE
412
            || ty == Geometry.TYPES.SURFACE
413
            ) {
414
            return true;
415
        } else {
416
            return false;
417
        }
418
    }
419

    
420

    
421
    public ISymbol getDefaultSymbol() {
422
        return this.defaultSymbol;
423
    }
424

    
425

    
426
    public int getShapeType() {
427
        return this.shapeType;
428
    }
429

    
430

    
431
    public void setDefaultSymbol(ISymbol s) {
432
        this.defaultSymbol = s;
433
    }
434

    
435

    
436
    // =============================
437

    
438
    public static class RegisterPersistence implements Callable {
439

    
440
        public Object call() throws Exception {
441

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

    
451
                definition.extend(manager.getDefinition(
452
                    AbstractClassifiedVectorLegend
453
                    .CLASSIFIED_VECTOR_LEGEND_PERSISTENCE_DEFINITION_NAME));
454

    
455
                definition.addDynFieldBoolean("useDefaultSymbol")
456
                .setMandatory(true);
457

    
458
                definition.addDynFieldObject("graduatedLegend")
459
                .setClassOfValue(ILegend.class).setMandatory(true);
460
                definition.addDynFieldObject("rampLegend")
461
                .setClassOfValue(ILegend.class).setMandatory(true);
462
            }
463
            return Boolean.TRUE;
464
        }
465

    
466
    }
467

    
468
    public static class RegisterLegend implements Callable {
469

    
470
        public Object call() throws Exception {
471
            MapContextManager manager =
472
                MapContextLocator.getMapContextManager();
473

    
474
            manager.registerLegend(
475
                QUANTITY_BY_CATEGORY_LEGEND_NAME,
476
                QuantityByCategoryLegend.class);
477

    
478
            return Boolean.TRUE;
479
        }
480

    
481
    }
482

    
483
    public void saveToState(PersistentState state) throws PersistenceException {
484

    
485
        super.saveToState(state);
486
        state.set("useDefaultSymbol", this.isUseDefaultSymbol());
487
        state.set("graduatedLegend", this.getGraduatedSymbolsLegend());
488
        state.set("rampLegend", this.getColorRampLegend());
489
    }
490

    
491
    public void loadFromState(PersistentState state)
492
        throws PersistenceException {
493

    
494
        super.loadFromState(state);
495

    
496
        Boolean b = state.getBoolean("useDefaultSymbol");
497
        this.useDefaultSymbol(b);
498

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

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

    
516

    
517

    
518
}