root / tags / v2_0_0_Build_2050 / libraries / 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 @ 38699
History | View | Annotate | Download (14.4 KB)
1 | 34294 | fdiaz | /* 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 | package org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl; |
||
23 | |||
24 | import java.awt.Color; |
||
25 | import java.util.ArrayList; |
||
26 | import java.util.Comparator; |
||
27 | import java.util.Iterator; |
||
28 | import java.util.List; |
||
29 | import java.util.Map; |
||
30 | import java.util.Map.Entry; |
||
31 | import java.util.TreeMap; |
||
32 | |||
33 | 36726 | cordinyana | import org.slf4j.Logger; |
34 | import org.slf4j.LoggerFactory; |
||
35 | |||
36 | 34294 | fdiaz | import org.gvsig.fmap.dal.feature.Feature; |
37 | import org.gvsig.fmap.mapcontext.MapContextException; |
||
38 | import org.gvsig.fmap.mapcontext.MapContextLocator; |
||
39 | import org.gvsig.fmap.mapcontext.MapContextManager; |
||
40 | import org.gvsig.fmap.mapcontext.rendering.legend.IVectorialUniqueValueLegend; |
||
41 | import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendClearEvent; |
||
42 | 38639 | jldominguez | import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendContentsChangedListener; |
43 | 34294 | fdiaz | import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent; |
44 | import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol; |
||
45 | import org.gvsig.tools.ToolsLocator; |
||
46 | import org.gvsig.tools.dynobject.DynStruct; |
||
47 | import org.gvsig.tools.persistence.PersistenceManager; |
||
48 | import org.gvsig.tools.persistence.PersistentState; |
||
49 | import org.gvsig.tools.persistence.exception.PersistenceException; |
||
50 | import org.gvsig.tools.util.Callable; |
||
51 | |||
52 | /**
|
||
53 | * Vectorial legend for unique values
|
||
54 | *
|
||
55 | * @author Vicente Caballero Navarro
|
||
56 | * @author 2009- <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
|
||
57 | */
|
||
58 | public class VectorialUniqueValueLegend extends AbstractClassifiedVectorLegend implements IVectorialUniqueValueLegend { |
||
59 | final static private Logger LOG = LoggerFactory.getLogger(VectorialUniqueValueLegend.class); |
||
60 | |||
61 | public static final String VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME = |
||
62 | "VectorialUniqueValueLegend";
|
||
63 | |||
64 | private static final String FIELD_KEYS = "keys"; |
||
65 | private static final String FIELD_NULL_VALUE_SYMBOL = "nullValueSymbol"; |
||
66 | private static final String FIELD_SELECTED_COLORS = "selectedColors"; |
||
67 | private static final String FIELD_SYMBOLS = "symbols"; |
||
68 | private static final String FIELD_USE_DEFAULT_SYMBOL = "useDefaultSymbol"; |
||
69 | |||
70 | private Map<Object, ISymbol> symbols = createSymbolMap(); |
||
71 | |||
72 | private List<Object> keys = new ArrayList<Object>(); |
||
73 | |||
74 | private ISymbol defaultSymbol;
|
||
75 | private int shapeType; |
||
76 | private boolean useDefaultSymbol = false; |
||
77 | private Color[] selectedColors=null; |
||
78 | |||
79 | private ISymbol nullValueSymbol = null; |
||
80 | |||
81 | public VectorialUniqueValueLegend() {
|
||
82 | super();
|
||
83 | } |
||
84 | |||
85 | /**
|
||
86 | * Constructor method
|
||
87 | *
|
||
88 | * @param shapeType Type of the shape.
|
||
89 | */
|
||
90 | public VectorialUniqueValueLegend(int shapeType) { |
||
91 | super();
|
||
92 | setShapeType(shapeType); |
||
93 | } |
||
94 | |||
95 | 35112 | fdiaz | public void setShapeType(int shapeType) { |
96 | 34294 | fdiaz | if (this.shapeType != shapeType) { |
97 | 35112 | fdiaz | if(defaultSymbol==null || defaultSymbol.getSymbolType()!=shapeType){ |
98 | ISymbol old = defaultSymbol; |
||
99 | defaultSymbol = getSymbolManager().createSymbol(shapeType); |
||
100 | fireDefaultSymbolChangedEvent(new SymbolLegendEvent(old, defaultSymbol));
|
||
101 | } |
||
102 | 34294 | fdiaz | this.shapeType = shapeType;
|
103 | } |
||
104 | } |
||
105 | |||
106 | public void setValueSymbolByID(int id, ISymbol symbol) { |
||
107 | ISymbol old = (ISymbol)symbols.put(keys.get(id), symbol); |
||
108 | fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(old, symbol));
|
||
109 | } |
||
110 | |||
111 | public Object[] getValues() { |
||
112 | return symbols.keySet().toArray(new Object[0]); |
||
113 | } |
||
114 | |||
115 | public void addSymbol(Object key, ISymbol symbol) { |
||
116 | ISymbol resul; |
||
117 | if (key == null) { |
||
118 | resul = nullValueSymbol; |
||
119 | nullValueSymbol = symbol; |
||
120 | } |
||
121 | else {
|
||
122 | resul = (ISymbol) symbols.put(key, symbol); |
||
123 | |||
124 | if (resul != null) { |
||
125 | LOG.error("Error: la clave " + key + " ya exist?a. Resul = " |
||
126 | + resul); |
||
127 | LOG.warn("symbol nuevo:" + symbol.getDescription()
|
||
128 | + " Sviejo= " + resul.getDescription());
|
||
129 | } else {
|
||
130 | keys.add(key); |
||
131 | } |
||
132 | } |
||
133 | |||
134 | fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(resul, symbol));
|
||
135 | } |
||
136 | |||
137 | public void clear() { |
||
138 | keys.clear(); |
||
139 | ISymbol[] olds = (ISymbol[])symbols.values().toArray(new ISymbol[0]); |
||
140 | symbols.clear(); |
||
141 | removeLegendListener(getZSort()); |
||
142 | setZSort(null);
|
||
143 | |||
144 | fireLegendClearEvent(new LegendClearEvent(olds));
|
||
145 | } |
||
146 | |||
147 | public String[] getDescriptions() { |
||
148 | String[] descriptions = new String[symbols.size()]; |
||
149 | ISymbol[] auxSym = getSymbols();
|
||
150 | |||
151 | for (int i = 0; i < descriptions.length; i++) { |
||
152 | descriptions[i] = auxSym[i].getDescription(); |
||
153 | } |
||
154 | |||
155 | return descriptions;
|
||
156 | } |
||
157 | |||
158 | public ISymbol[] getSymbols() { |
||
159 | ISymbol[] symbolList;
|
||
160 | if (nullValueSymbol == null) { |
||
161 | symbolList = new ISymbol[symbols.size()];
|
||
162 | return (ISymbol[]) symbols.values().toArray(symbolList); |
||
163 | } |
||
164 | else {
|
||
165 | symbolList = new ISymbol[symbols.size() + 1]; |
||
166 | symbolList[0] = nullValueSymbol;
|
||
167 | int i = 1; |
||
168 | for (Iterator<ISymbol> iterator = symbols.values().iterator(); iterator |
||
169 | .hasNext();) { |
||
170 | symbolList[i] = iterator.next(); |
||
171 | i++; |
||
172 | } |
||
173 | return symbolList;
|
||
174 | } |
||
175 | } |
||
176 | |||
177 | public void setClassifyingFieldNames(String[] fNames) { |
||
178 | 36726 | cordinyana | // TODO: Check if need more process
|
179 | super.setClassifyingFieldNames(fNames);
|
||
180 | } |
||
181 | 34294 | fdiaz | |
182 | /**
|
||
183 | * Devuelve un s?mbolo a partir de una IFeature. OJO!! Cuando usamos un
|
||
184 | * feature iterator de base de datos el ?nico campo que vendr? rellenado es
|
||
185 | * el de fieldID. Los dem?s vendr?n a nulos para ahorra tiempo de creaci?n.
|
||
186 | *
|
||
187 | * @param feat
|
||
188 | * IFeature
|
||
189 | *
|
||
190 | * @return S?mbolo.
|
||
191 | * @throws MapContextException
|
||
192 | */
|
||
193 | public ISymbol getSymbolByFeature(Feature feat) throws MapContextException { |
||
194 | |||
195 | Object val = feat.get(getClassifyingFieldNames()[0]); |
||
196 | // Object val = feat.get(fieldId);
|
||
197 | ISymbol theSymbol = getSymbolByValue(val); |
||
198 | |||
199 | if (theSymbol != null) { |
||
200 | return theSymbol;
|
||
201 | |||
202 | } |
||
203 | |||
204 | if (isUseDefaultSymbol()) {
|
||
205 | return defaultSymbol;
|
||
206 | } |
||
207 | |||
208 | return null; |
||
209 | } |
||
210 | |||
211 | |||
212 | public ISymbol getDefaultSymbol() {
|
||
213 | |||
214 | if(defaultSymbol==null) { |
||
215 | defaultSymbol = getSymbolManager().createSymbol(shapeType); |
||
216 | fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null, defaultSymbol)); |
||
217 | } |
||
218 | return defaultSymbol;
|
||
219 | } |
||
220 | |||
221 | public void setDefaultSymbol(ISymbol s) { |
||
222 | ISymbol mySymbol = defaultSymbol; |
||
223 | |||
224 | if (s == null) { |
||
225 | throw new NullPointerException("Default symbol cannot be null"); |
||
226 | } |
||
227 | |||
228 | ISymbol old = mySymbol; |
||
229 | defaultSymbol = s; |
||
230 | fireDefaultSymbolChangedEvent(new SymbolLegendEvent(old, s));
|
||
231 | } |
||
232 | |||
233 | |||
234 | /*
|
||
235 | * (non-Javadoc)
|
||
236 | *
|
||
237 | * @see com.iver.cit.gvsig.fmap.rendering.UniqueValueLegend#getSymbolByValue(com.hardcode.gdbms.engine.values.Value)
|
||
238 | */
|
||
239 | public ISymbol getSymbolByValue(Object key) { |
||
240 | ISymbol symbol = null;
|
||
241 | if (key == null) { |
||
242 | symbol = nullValueSymbol; |
||
243 | } |
||
244 | else {
|
||
245 | symbol = (ISymbol)symbols.get(key); |
||
246 | } |
||
247 | if (symbol == null && useDefaultSymbol) { |
||
248 | symbol = getDefaultSymbol(); |
||
249 | } |
||
250 | return symbol;
|
||
251 | |||
252 | } |
||
253 | |||
254 | public Object getSymbolKey(ISymbol symbol) { |
||
255 | if (symbol != null) { |
||
256 | for (Iterator<Entry<Object, ISymbol>> iterator = symbols.entrySet() |
||
257 | .iterator(); iterator.hasNext();) { |
||
258 | Entry<Object, ISymbol> entry = iterator.next();
|
||
259 | if (symbol.equals(entry.getValue())) {
|
||
260 | return entry.getKey();
|
||
261 | } |
||
262 | } |
||
263 | } |
||
264 | return null; |
||
265 | } |
||
266 | |||
267 | public int getShapeType() { |
||
268 | return shapeType;
|
||
269 | } |
||
270 | |||
271 | public void useDefaultSymbol(boolean b) { |
||
272 | useDefaultSymbol = b; |
||
273 | } |
||
274 | |||
275 | /**
|
||
276 | * Devuelve si se utiliza o no el resto de valores para representarse.
|
||
277 | * @return True si se utiliza el resto de valores.
|
||
278 | */
|
||
279 | public boolean isUseDefaultSymbol() { |
||
280 | return useDefaultSymbol;
|
||
281 | } |
||
282 | |||
283 | public void delSymbol(Object key) { |
||
284 | keys.remove(key); |
||
285 | |||
286 | ISymbol removedSymbol = (ISymbol) symbols.remove(key); |
||
287 | if (removedSymbol != null){ |
||
288 | fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(removedSymbol, null)); |
||
289 | } |
||
290 | } |
||
291 | |||
292 | public String getClassName() { |
||
293 | return getClass().getName();
|
||
294 | } |
||
295 | |||
296 | public void replace(ISymbol oldSymbol, ISymbol newSymbol) { |
||
297 | if (symbols.containsValue(oldSymbol)) {
|
||
298 | Iterator<Object> it = symbols.keySet().iterator(); |
||
299 | while (it.hasNext()) {
|
||
300 | Object key = it.next();
|
||
301 | if (symbols.get(key).equals(oldSymbol)) {
|
||
302 | fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(
|
||
303 | (ISymbol)symbols.put(key, newSymbol), newSymbol)); |
||
304 | } |
||
305 | |||
306 | } |
||
307 | } |
||
308 | } |
||
309 | public Color[] getColorScheme() { |
||
310 | return selectedColors;
|
||
311 | } |
||
312 | |||
313 | public void setColorScheme(Color[] cc) { |
||
314 | this.selectedColors = cc;
|
||
315 | } |
||
316 | |||
317 | public Object clone() throws CloneNotSupportedException { |
||
318 | VectorialUniqueValueLegend clone = |
||
319 | (VectorialUniqueValueLegend) super.clone();
|
||
320 | |||
321 | // Clone default symbol
|
||
322 | if (defaultSymbol != null) { |
||
323 | clone.defaultSymbol = (ISymbol) defaultSymbol.clone(); |
||
324 | } |
||
325 | // Clone keys
|
||
326 | clone.keys = new ArrayList<Object>(); |
||
327 | 38639 | jldominguez | |
328 | // ====================================================
|
||
329 | // Temporarily remove listeners to prevent
|
||
330 | // cascade of notifications
|
||
331 | LegendContentsChangedListener[] list = this.getListeners(); |
||
332 | removeListeners(list); |
||
333 | // ====================================================
|
||
334 | 34294 | fdiaz | |
335 | // Clone symbols
|
||
336 | if (symbols != null) { |
||
337 | clone.symbols = createSymbolMap(); |
||
338 | for (Iterator<Entry<Object, ISymbol>> iterator = |
||
339 | symbols.entrySet().iterator(); iterator.hasNext();) { |
||
340 | Entry<Object, ISymbol> entry = iterator.next();
|
||
341 | ISymbol symbolClone = |
||
342 | (ISymbol) ((ISymbol) entry.getValue()).clone(); |
||
343 | // Map keys are of type Number or String, so being
|
||
344 | // immutable objects, don't clone them
|
||
345 | clone.addSymbol(entry.getKey(), symbolClone); |
||
346 | } |
||
347 | } |
||
348 | 38639 | jldominguez | |
349 | // ====================================================
|
||
350 | // Restore listeners
|
||
351 | addListeners(list); |
||
352 | // ====================================================
|
||
353 | 34294 | fdiaz | return clone;
|
354 | } |
||
355 | |||
356 | |||
357 | 38639 | jldominguez | private void addListeners(LegendContentsChangedListener[] list) { |
358 | int len = list.length;
|
||
359 | for (int i=0; i<len; i++) { |
||
360 | addLegendListener(list[i]); |
||
361 | } |
||
362 | } |
||
363 | |||
364 | private void removeListeners(LegendContentsChangedListener[] list) { |
||
365 | int len = list.length;
|
||
366 | for (int i=0; i<len; i++) { |
||
367 | removeLegendListener(list[i]); |
||
368 | } |
||
369 | } |
||
370 | |||
371 | private Map<Object, ISymbol> createSymbolMap() { |
||
372 | 34294 | fdiaz | return new TreeMap<Object, ISymbol>( |
373 | new Comparator<Object>() { |
||
374 | public int compare(Object o1, Object o2) { |
||
375 | if ((o1 != null) && (o2 != null)) { |
||
376 | Object v2 = o2;
|
||
377 | Object v1 = o1;
|
||
378 | if (v1 instanceof Number && v2 instanceof Number) { |
||
379 | return ((Number) v1).intValue() |
||
380 | - ((Number) v2).intValue();
|
||
381 | } |
||
382 | if (v1 instanceof String && v2 instanceof String) { |
||
383 | return ((String) v1).compareTo(((String) v2)); |
||
384 | } |
||
385 | } |
||
386 | |||
387 | return 0; |
||
388 | } |
||
389 | }); |
||
390 | |||
391 | } |
||
392 | |||
393 | @SuppressWarnings({ "unchecked", "rawtypes" }) |
||
394 | public void loadFromState(PersistentState state) |
||
395 | throws PersistenceException {
|
||
396 | // Set parent properties
|
||
397 | super.loadFromState(state);
|
||
398 | // Set own properties
|
||
399 | keys = new ArrayList<Object>((List) state.get(FIELD_KEYS)); |
||
400 | nullValueSymbol = (ISymbol) state.get(FIELD_NULL_VALUE_SYMBOL); |
||
401 | selectedColors = |
||
402 | (Color[]) state.getArray(FIELD_SELECTED_COLORS, Color.class); |
||
403 | Map persistedSymbolMap = (Map) state.get(FIELD_SYMBOLS); |
||
404 | if (persistedSymbolMap != null) { |
||
405 | symbols.putAll(persistedSymbolMap); |
||
406 | } |
||
407 | useDefaultSymbol(state.getBoolean(FIELD_USE_DEFAULT_SYMBOL)); |
||
408 | } |
||
409 | |||
410 | public void saveToState(PersistentState state) throws PersistenceException { |
||
411 | // Save parent properties
|
||
412 | super.saveToState(state);
|
||
413 | // Save own properties
|
||
414 | state.set(FIELD_KEYS, keys); |
||
415 | state.set(FIELD_NULL_VALUE_SYMBOL, nullValueSymbol); |
||
416 | state.set(FIELD_SELECTED_COLORS, selectedColors); |
||
417 | state.set(FIELD_USE_DEFAULT_SYMBOL, isUseDefaultSymbol()); |
||
418 | state.set(FIELD_SYMBOLS, symbols); |
||
419 | } |
||
420 | |||
421 | public static class RegisterPersistence implements Callable { |
||
422 | |||
423 | public Object call() throws Exception { |
||
424 | PersistenceManager manager = ToolsLocator.getPersistenceManager(); |
||
425 | if( manager.getDefinition(VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME)==null ) { |
||
426 | DynStruct definition = manager.addDefinition( |
||
427 | VectorialUniqueValueLegend.class, |
||
428 | VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME, |
||
429 | VECTORIAL_UNIQUE_VALUE_LEGEND_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
|
||
430 | null,
|
||
431 | null
|
||
432 | ); |
||
433 | // Extend the Classified Vector Legend base definition
|
||
434 | definition.extend(manager.getDefinition(CLASSIFIED_VECTOR_LEGEND_PERSISTENCE_DEFINITION_NAME)); |
||
435 | |||
436 | // Keys
|
||
437 | definition.addDynFieldList(FIELD_KEYS).setClassOfItems(Object.class);
|
||
438 | // Null interval symbol
|
||
439 | definition.addDynFieldObject(FIELD_NULL_VALUE_SYMBOL).setClassOfValue(ISymbol.class); |
||
440 | // Selected colors
|
||
441 | definition.addDynFieldList(FIELD_SELECTED_COLORS).setClassOfItems(Color.class);
|
||
442 | // Symbols
|
||
443 | definition.addDynFieldMap(FIELD_SYMBOLS).setClassOfItems(ISymbol.class); |
||
444 | // Use default symbol?
|
||
445 | definition.addDynFieldBoolean(FIELD_USE_DEFAULT_SYMBOL); |
||
446 | } |
||
447 | return Boolean.TRUE; |
||
448 | } |
||
449 | |||
450 | } |
||
451 | |||
452 | public static class RegisterLegend implements Callable { |
||
453 | |||
454 | public Object call() throws Exception { |
||
455 | MapContextManager manager = MapContextLocator.getMapContextManager(); |
||
456 | |||
457 | manager.registerLegend(IVectorialUniqueValueLegend.LEGEND_NAME, |
||
458 | VectorialUniqueValueLegend.class); |
||
459 | |||
460 | return Boolean.TRUE; |
||
461 | } |
||
462 | |||
463 | } |
||
464 | } |