Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.library / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / legend / impl / VectorialUniqueValueLegend.java @ 44910

History | View | Annotate | Download (16.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
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 3
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
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl;
25

    
26
import java.awt.Color;
27
import java.util.ArrayList;
28
import java.util.Comparator;
29
import java.util.Iterator;
30
import java.util.List;
31
import java.util.Map;
32
import java.util.Map.Entry;
33
import java.util.TreeMap;
34
import java.util.logging.Level;
35
import org.apache.commons.lang3.ObjectUtils;
36
import org.apache.commons.lang3.mutable.MutableObject;
37
import org.gvsig.fmap.dal.DataTypeUtils;
38

    
39
import org.slf4j.Logger;
40
import org.slf4j.LoggerFactory;
41

    
42
import org.gvsig.fmap.dal.feature.Feature;
43
import org.gvsig.fmap.mapcontext.MapContextException;
44
import org.gvsig.fmap.mapcontext.MapContextLocator;
45
import org.gvsig.fmap.mapcontext.MapContextManager;
46
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorialUniqueValueLegend;
47
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendClearEvent;
48
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendContentsChangedListener;
49
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
50
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
51
import org.gvsig.tools.ToolsLocator;
52
import org.gvsig.tools.dataTypes.Coercion;
53
import org.gvsig.tools.dataTypes.CoercionException;
54
import org.gvsig.tools.dynobject.DynStruct;
55
import org.gvsig.tools.persistence.PersistenceManager;
56
import org.gvsig.tools.persistence.PersistentState;
57
import org.gvsig.tools.persistence.exception.PersistenceException;
58
import org.gvsig.tools.util.Callable;
59

    
60
/**
61
 * Vectorial legend for unique values
62
 *
63
 * @author Vicente Caballero Navarro
64
 * @author 2009- <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
65
 */
66
public class VectorialUniqueValueLegend extends AbstractClassifiedVectorLegend implements IVectorialUniqueValueLegend {
67
        final static private Logger LOG = LoggerFactory.getLogger(VectorialUniqueValueLegend.class);
68

    
69
        public static final String VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME =
70
                        "VectorialUniqueValueLegend";
71

    
72
        private static final String FIELD_KEYS = "keys";
73
        private static final String FIELD_NULL_VALUE_SYMBOL = "nullValueSymbol";
74
        private static final String FIELD_SELECTED_COLORS = "selectedColors";
75
        private static final String FIELD_SYMBOLS = "symbols";
76
        private static final String FIELD_USE_DEFAULT_SYMBOL = "useDefaultSymbol";
77

    
78
        private Map<Object, ISymbol> symbols = createSymbolMap();
79

    
80
        private List<Object> keys = new ArrayList<Object>();
81

    
82
    private ISymbol defaultSymbol;
83
    private int shapeType;
84
    private boolean useDefaultSymbol = false;
85
    private Color[] selectedColors=null;
86

    
87
    private ISymbol nullValueSymbol = null;
88

    
89
    public VectorialUniqueValueLegend() {
90
                super();
91
        }
92

    
93
    /**
94
     * Constructor method
95
     *
96
     * @param shapeType Type of the shape.
97
     */
98
    public VectorialUniqueValueLegend(int shapeType) {
99
                super();
100
            setShapeType(shapeType);
101
    }
102

    
103
        @Override
104
    public void setShapeType(int shapeType) {
105
            if (this.shapeType != shapeType) {
106
                    if(defaultSymbol==null || defaultSymbol.getSymbolType()!=shapeType){
107
                            ISymbol old = defaultSymbol;
108
                            defaultSymbol = getSymbolManager().createSymbol(shapeType);
109
                            fireDefaultSymbolChangedEvent(new SymbolLegendEvent(old, defaultSymbol));
110
                    }
111
                    this.shapeType = shapeType;
112
            }
113
    }
114

    
115
        @Override
116
    public void setValueSymbolByID(int id, ISymbol symbol) {
117
        ISymbol old = (ISymbol)symbols.put(keys.get(id), symbol);
118
        fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(old, symbol));
119
    }
120

    
121
        @Override
122
    public Object[] getValues() {
123
        return symbols.keySet().toArray(new Object[0]);
124
    }
125

    
126
        @Override
127
    public void addSymbol(Object key, ISymbol symbol) {
128
            ISymbol resul;
129
            if (key == null) {
130
                    resul = nullValueSymbol;
131
                    nullValueSymbol = symbol;
132
            }
133
            else {
134
                        resul = (ISymbol) symbols.put(key, symbol);
135

    
136
                        if (resul != null) {
137
                                LOG.error("Error: la clave " + key + " ya exist?a. Resul = "
138
                                                + resul);
139
                                LOG.warn("symbol nuevo:" + symbol.getDescription()
140
                                                + " Sviejo= " + resul.getDescription());
141
                        } else {
142
                                keys.add(key);
143
                        }
144
            }
145

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

    
149
    public void delAllSymbols() {
150
        keys.clear();
151
        ISymbol[] olds = (ISymbol[])symbols.values().toArray(new ISymbol[0]);
152
        symbols.clear();
153
        fireLegendClearEvent(new LegendClearEvent(olds));
154
    }
155
    
156
        @Override
157
    public void clear() {
158
        keys.clear();
159
        ISymbol[] olds = (ISymbol[])symbols.values().toArray(new ISymbol[0]);
160
        symbols.clear();
161
        removeLegendListener(getZSort());
162
        setZSort(null);
163

    
164
        fireLegendClearEvent(new LegendClearEvent(olds));
165
    }
166

    
167
        @Override
168
    public String[] getDescriptions() {
169
        String[] descriptions = new String[symbols.size()];
170
        ISymbol[] auxSym = getSymbols();
171

    
172
        for (int i = 0; i < descriptions.length; i++) {
173
                        descriptions[i] = auxSym[i].getDescription();
174
                }
175

    
176
        return descriptions;
177
    }
178

    
179
        @Override
180
     public ISymbol[] getSymbols() {
181
                 ISymbol[] symbolList;
182
                if (nullValueSymbol == null) {
183
                        symbolList = new ISymbol[symbols.size()];
184
                        return (ISymbol[]) symbols.values().toArray(symbolList);
185
                }
186
                else {
187
                        symbolList = new ISymbol[symbols.size() + 1];
188
                        symbolList[0] = nullValueSymbol;
189
                        int i = 1;
190
                        for (Iterator<ISymbol> iterator = symbols.values().iterator(); iterator
191
                                        .hasNext();) {
192
                                symbolList[i] = iterator.next();
193
                                i++;
194
                        }
195
                        return symbolList;
196
                }
197
    }
198

    
199
        @Override
200
    public void setClassifyingFieldNames(String[] fNames) {
201
        // TODO: Check if need more process
202
        super.setClassifyingFieldNames(fNames);
203
    }
204

    
205
    /**
206
         * Devuelve un s?mbolo a partir de una IFeature. OJO!! Cuando usamos un
207
         * feature iterator de base de datos el ?nico campo que vendr? rellenado es
208
         * el de fieldID. Los dem?s vendr?n a nulos para ahorra tiempo de creaci?n.
209
         *
210
         * @param feat
211
         *            IFeature
212
         *
213
         * @return S?mbolo.
214
     * @throws MapContextException
215
         */
216
        @Override
217
    public ISymbol getSymbolByFeature(Feature feat) throws MapContextException {
218

    
219
        Object val = null;
220
        String classifyingFieldName = getClassifyingFieldNames()[0];
221
        try {
222
            val = feat.get(classifyingFieldName);
223
        } catch (Exception e) {
224
            LOG.info("Can't get value from field \"" + classifyingFieldName + "\". Return null or defaultSymbol", e);
225
        }
226

    
227
        ISymbol theSymbol = getSymbolByValue(val);
228

    
229
        if (theSymbol != null) {
230
                return theSymbol;
231
        }
232

    
233
        if (isUseDefaultSymbol()) {
234
                        return defaultSymbol;
235
                }
236

    
237
        return null;
238
    }
239

    
240

    
241
        @Override
242
    public ISymbol getDefaultSymbol() {
243

    
244
            if(defaultSymbol==null) {
245
                        defaultSymbol = getSymbolManager().createSymbol(shapeType);
246
                    fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null, defaultSymbol));
247
            }
248
            return defaultSymbol;
249
    }
250

    
251
        @Override
252
        public void setDefaultSymbol(ISymbol s) {
253
            ISymbol mySymbol = defaultSymbol;
254

    
255
            if (s == null) {
256
                        throw new NullPointerException("Default symbol cannot be null");
257
                }
258

    
259
            ISymbol old = mySymbol;
260
            defaultSymbol = s;
261
            fireDefaultSymbolChangedEvent(new SymbolLegendEvent(old, s));
262
    }
263

    
264

    
265
    /*
266
     * (non-Javadoc)
267
     *
268
     * @see com.iver.cit.gvsig.fmap.rendering.UniqueValueLegend#getSymbolByValue(com.hardcode.gdbms.engine.values.Value)
269
     */
270
        @Override
271
    public ISymbol getSymbolByValue(Object key) {
272
            ISymbol symbol = null;
273
            if (key == null) {
274
                    symbol = nullValueSymbol;
275
            }
276
            else {
277
                    symbol = (ISymbol)symbols.get(key);
278
            }
279
            if (symbol == null && useDefaultSymbol) {
280
                    symbol = getDefaultSymbol();
281
            }
282
            return symbol;
283

    
284
    }
285

    
286
        @Override
287
        public Object getSymbolKey(ISymbol symbol) {
288
                if (symbol != null) {
289
                        for (Iterator<Entry<Object, ISymbol>> iterator = symbols.entrySet()
290
                                        .iterator(); iterator.hasNext();) {
291
                                Entry<Object, ISymbol> entry = iterator.next();
292
                                if (symbol.equals(entry.getValue())) {
293
                                        return entry.getKey();
294
                                }
295
                        }
296
                }
297
                return null;
298
        }
299

    
300
        @Override
301
    public int getShapeType() {
302
        return shapeType;
303
    }
304

    
305
        @Override
306
    public void useDefaultSymbol(boolean b) {
307
        useDefaultSymbol = b;
308
    }
309

    
310
    /**
311
         * Devuelve si se utiliza o no el resto de valores para representarse.
312
         * @return  True si se utiliza el resto de valores.
313
         */
314
        @Override
315
    public boolean isUseDefaultSymbol() {
316
        return useDefaultSymbol;
317
    }
318

    
319
        @Override
320
    public void delSymbol(Object key) {
321
        keys.remove(key);
322

    
323
                ISymbol removedSymbol = (ISymbol) symbols.remove(key);
324
                if (removedSymbol != null){
325
                        fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(removedSymbol, null));
326
                }
327
    }
328

    
329
        public String getClassName() {
330
                return getClass().getName();
331
        }
332

    
333
        @Override
334
        public void replace(ISymbol oldSymbol, ISymbol newSymbol) {
335
                if (symbols.containsValue(oldSymbol)) {
336
                        Iterator<Object> it = symbols.keySet().iterator();
337
                        while (it.hasNext()) {
338
                                Object key = it.next();
339
                                if (symbols.get(key).equals(oldSymbol)) {
340
                                        fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(
341
                                                        (ISymbol)symbols.put(key, newSymbol), newSymbol));
342
                                }
343

    
344
                        }
345
                }
346
        }
347
        @Override
348
        public Color[] getColorScheme() {
349
                return selectedColors;
350
        }
351

    
352
        @Override
353
        public void setColorScheme(Color[] cc) {
354
                 this.selectedColors = cc;
355
        }
356

    
357
        @Override
358
        public Object clone() throws CloneNotSupportedException {
359
                VectorialUniqueValueLegend clone =
360
                                (VectorialUniqueValueLegend) super.clone();
361

    
362
                // Clone default symbol
363
                if (defaultSymbol != null) {
364
                        clone.defaultSymbol = (ISymbol) defaultSymbol.clone();
365
                }
366
                // Clone keys
367
                clone.keys = new ArrayList<Object>();
368

    
369
        // ====================================================
370
                // Temporarily remove listeners to prevent
371
                // cascade of notifications
372
                LegendContentsChangedListener[] list = this.getListeners();
373
                removeListeners(list);
374
        // ====================================================
375

    
376
                // Clone symbols
377
                if (symbols != null) {
378
                        clone.symbols = createSymbolMap();
379
                        for (Iterator<Entry<Object, ISymbol>> iterator =
380
                                        symbols.entrySet().iterator(); iterator.hasNext();) {
381
                                Entry<Object, ISymbol> entry = iterator.next();
382
                                ISymbol symbolClone =
383
                                                (ISymbol) ((ISymbol) entry.getValue()).clone();
384
                                // Map keys are of type Number or String, so being
385
                                // immutable objects, don't clone them
386
                                clone.addSymbol(entry.getKey(), symbolClone);
387
                        }
388
                }
389

    
390
        // ====================================================
391
        // Restore listeners
392
        addListeners(list);
393
        // ====================================================
394
                return clone;
395
        }
396

    
397

    
398
    private void addListeners(LegendContentsChangedListener[] list) {
399
        int len = list.length;
400
        for (int i=0; i<len; i++) {
401
            addLegendListener(list[i]);
402
        }
403
    }
404

    
405
    private void removeListeners(LegendContentsChangedListener[] list) {
406
        int len = list.length;
407
        for (int i=0; i<len; i++) {
408
            removeLegendListener(list[i]);
409
        }
410
    }
411
    
412
    public void setClassifyingFieldTypes(int[] fieldTypes) {
413
        
414
        Class fieldClass = ToolsLocator.getDataTypesManager().getDefaultClass(fieldTypes[0]);
415
        if (!Comparable.class.isAssignableFrom(fieldClass)) {
416
             throw new IllegalArgumentException("Should be comparable");   
417
        }
418
        super.setClassifyingFieldTypes(fieldTypes);
419
    }
420
        
421
    private Map<Object, ISymbol> createSymbolMap() {
422
        final MutableObject<Coercion> convert = new MutableObject<>();
423

    
424
        return new TreeMap<Object, ISymbol>(
425
                new Comparator<Object>() {
426
            public int compare(Object o1, Object o2) {
427
                if (convert.getValue() == null) {
428
                    convert.setValue(ToolsLocator.getDataTypesManager().getCoercion(getClassifyingFieldTypes()[0]));
429
                }
430
                try {
431
                    return ObjectUtils.compare((Comparable) (convert.getValue().coerce(o1)), (Comparable) (convert.getValue().coerce(o2)));
432
                } catch (CoercionException ex) {
433
                    throw new RuntimeException("Not able to coerce values in symbol map");
434
                }
435
            }
436
        });
437
    }
438

    
439
        @SuppressWarnings({ "unchecked", "rawtypes" })
440
        public void loadFromState(PersistentState state)
441
                        throws PersistenceException {
442
                // Set parent properties
443
                super.loadFromState(state);
444
                // Set own properties
445
                keys = new ArrayList<Object>((List) state.get(FIELD_KEYS));
446
                nullValueSymbol = (ISymbol) state.get(FIELD_NULL_VALUE_SYMBOL);
447
                selectedColors =
448
                                (Color[]) state.getArray(FIELD_SELECTED_COLORS, Color.class);
449
                Map persistedSymbolMap = (Map) state.get(FIELD_SYMBOLS);
450
                if (persistedSymbolMap != null) {
451
                        symbols.putAll(persistedSymbolMap);
452
                }
453
                useDefaultSymbol(state.getBoolean(FIELD_USE_DEFAULT_SYMBOL));
454
        }
455

    
456
        public void saveToState(PersistentState state) throws PersistenceException {
457
                // Save parent properties
458
                super.saveToState(state);
459
                // Save own properties
460
                state.set(FIELD_KEYS, keys);
461
                state.set(FIELD_NULL_VALUE_SYMBOL, nullValueSymbol);
462
                state.set(FIELD_SELECTED_COLORS, selectedColors);
463
                state.set(FIELD_USE_DEFAULT_SYMBOL, isUseDefaultSymbol());
464
                state.set(FIELD_SYMBOLS, symbols);
465
        }
466

    
467
        public static class RegisterPersistence implements Callable {
468

    
469
                public Object call() throws Exception {
470
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
471
                        if( manager.getDefinition(VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME)==null ) {
472
                                DynStruct definition = manager.addDefinition(
473
                                                VectorialUniqueValueLegend.class,
474
                                                VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME,
475
                                                VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
476
                                                null,
477
                                                null
478
                                );
479
                                // Extend the Classified Vector Legend base definition
480
                                definition.extend(manager.getDefinition(CLASSIFIED_VECTOR_LEGEND_PERSISTENCE_DEFINITION_NAME));
481

    
482
                                // Keys
483
                                definition.addDynFieldList(FIELD_KEYS).setClassOfItems(Object.class);
484
                                // Null interval symbol
485
                                definition.addDynFieldObject(FIELD_NULL_VALUE_SYMBOL).setClassOfValue(ISymbol.class);
486
                                // Selected colors
487
                                definition.addDynFieldList(FIELD_SELECTED_COLORS).setClassOfItems(Color.class);
488
                                // Symbols
489
                                definition.addDynFieldMap(FIELD_SYMBOLS).setClassOfItems(ISymbol.class);
490
                                // Use default symbol?
491
                                definition.addDynFieldBoolean(FIELD_USE_DEFAULT_SYMBOL);
492
                        }
493
                        return Boolean.TRUE;
494
                }
495

    
496
        }
497

    
498
        public static class RegisterLegend implements Callable {
499

    
500
                public Object call() throws Exception {
501
                MapContextManager manager = MapContextLocator.getMapContextManager();
502

    
503
            manager.registerLegend(IVectorialUniqueValueLegend.LEGEND_NAME,
504
                    VectorialUniqueValueLegend.class);
505

    
506
                        return Boolean.TRUE;
507
                }
508

    
509
        }
510
}