Statistics
| Revision:

root / org.gvsig.legend.vectorfilterexpression.app.mainplugin / trunk / org.gvsig.legend.vectorfilterexpression.app.mainplugin / src / main / java / org / gvsig / symbology / fmap / rendering / VectorFilterExpressionLegend.java @ 1856

History | View | Annotate | Download (16.1 KB)

1 36 jldominguez
/* gvSIG. Sistema de Informaci�n Geogr�fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib��ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.symbology.fmap.rendering;
42
43
44
import java.util.ArrayList;
45
46 39 jldominguez
import org.slf4j.Logger;
47
import org.slf4j.LoggerFactory;
48 36 jldominguez
49
import org.gvsig.fmap.dal.feature.Feature;
50 39 jldominguez
import org.gvsig.fmap.geom.Geometry;
51 1856 jjdelcerro
import org.gvsig.fmap.geom.GeometryLocator;
52
import org.gvsig.fmap.geom.GeometryManager;
53 36 jldominguez
import org.gvsig.fmap.mapcontext.MapContextLocator;
54 39 jldominguez
import org.gvsig.fmap.mapcontext.MapContextManager;
55 36 jldominguez
import org.gvsig.fmap.mapcontext.rendering.legend.events.SymbolLegendEvent;
56
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
57 40 jldominguez
import org.gvsig.i18n.Messages;
58 36 jldominguez
import org.gvsig.symbology.fmap.mapcontext.rendering.legend.impl.AbstractClassifiedVectorLegend;
59 40 jldominguez
import org.gvsig.symbology.fmap.rendering.filterexpression.EvaluatorCreator;
60 39 jldominguez
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.dynobject.DynStruct;
62
import org.gvsig.tools.evaluator.Evaluator;
63
import org.gvsig.tools.evaluator.EvaluatorData;
64 40 jldominguez
import org.gvsig.tools.evaluator.EvaluatorWithDescriptions;
65 39 jldominguez
import org.gvsig.tools.persistence.PersistenceManager;
66
import org.gvsig.tools.persistence.PersistentState;
67
import org.gvsig.tools.persistence.exception.PersistenceException;
68
import org.gvsig.tools.util.Callable;
69 36 jldominguez
70
71
/**
72
 *
73 40 jldominguez
 * Implements a vector legend which represents the elements of a layer
74 36 jldominguez
 * depending on the value of an expression. That is, if the expression is
75
 * evaluated to true, then the symbol associated to the expression is painted.
76
 * In other case it is not showed.
77 107 fdiaz
 *
78 40 jldominguez
 * If the expression result is a string, it is considered false if
79
 * it is the empty string "", true otherwise.
80 107 fdiaz
 *
81 40 jldominguez
 * If the expression result is numeric, it is considered false
82
 * if it is zero, and true otherwise.
83 107 fdiaz
 *
84 40 jldominguez
 * In other cases, it is considered false if the result is null and true
85
 * otherwise.
86 36 jldominguez
 *
87
 * @author Pepe Vidal Salvador - jose.vidal.salvador@iver.es
88 40 jldominguez
 * @author jldominguez
89 36 jldominguez
 */
90
public class VectorFilterExpressionLegend
91
extends AbstractClassifiedVectorLegend  {
92
93 39 jldominguez
    private static final Logger logger = LoggerFactory.getLogger(
94
        VectorFilterExpressionLegend.class);
95 107 fdiaz
96 39 jldominguez
    public static final String
97
    FILTER_EXPRESSION_LEGEND_PERSISTENCE_DEFINITION_NAME =
98
    "FILTER_EXPRESSION_LEGEND_PERSISTENCE_DEFINITION_NAME";
99 107 fdiaz
100 39 jldominguez
    public static final String
101
    FILTER_EXPRESSION_LEGEND_NAME = "FILTER_EXPRESSION_LEGEND_NAME";
102
103 40 jldominguez
    public static final String I18N_DEFAULT = Messages.getText("default_value");
104
    public static final String NON_I18N_DEFAULT = Messages.getText("Default");
105 107 fdiaz
106 36 jldominguez
        private int shapeType;
107
        private ISymbol defaultSymbol;
108 107 fdiaz
109 36 jldominguez
        private boolean useDefaultSymbol = false;
110 40 jldominguez
111
        private long error_msg_count = 0;
112 107 fdiaz
113 36 jldominguez
        private ArrayList<Item> newSymbols = new ArrayList<Item>() {
114
                private static final long serialVersionUID = 1L;
115
116
                public int indexOf(String expr) {
117
                        return super.indexOf(new Item(expr, null));
118
                }
119
        };
120
121
122 40 jldominguez
        private class Item implements Cloneable {
123 107 fdiaz
124 36 jldominguez
                private ISymbol sym;
125 39 jldominguez
                // get it with getSql()
126
                // private String expression;
127 40 jldominguez
                private EvaluatorWithDescriptions evaluator;
128 36 jldominguez
129
                public Item(String expression, ISymbol sym) {
130
                        this.sym = sym;
131 40 jldominguez
                        evaluator = EvaluatorCreator.getEvaluator(expression);
132 36 jldominguez
                }
133
134
                public boolean equals(Object obj) {
135
                        if (obj == null) return false;
136
                        if (!obj.getClass().equals(Item.class)) return false;
137 40 jldominguez
                        return this.evaluator.getSQL().equals(
138
                            ((Item) obj).evaluator.getSQL()
139
                            );
140 36 jldominguez
                }
141
142
                public String getStringExpression() {
143 39 jldominguez
                        return evaluator.getSQL();
144 36 jldominguez
                }
145
146 39 jldominguez
                public Evaluator getEvaluator() {
147
                        return evaluator;
148 36 jldominguez
                }
149 107 fdiaz
150 40 jldominguez
                public Object clone() {
151 107 fdiaz
152 40 jldominguez
                    ISymbol clonesym = null;
153
                    try {
154
                clonesym = (ISymbol) this.sym.clone();
155
            } catch (CloneNotSupportedException e) {
156
                logger.info("Error: unable to clone symbol.", e);
157
                clonesym = this.sym;
158
            }
159
                    return new Item(getStringExpression(), clonesym);
160
                }
161 36 jldominguez
        }
162
163 40 jldominguez
    public VectorFilterExpressionLegend() {
164
        this.setClassifyingFieldNames(new String[0]);
165
        this.setClassifyingFieldTypes(new int[0]);
166
    }
167
168 39 jldominguez
        public ISymbol getSymbolByFeature(Feature featu) {
169 107 fdiaz
170 40 jldominguez
            EvaluatorData evda = featu.getEvaluatorData();
171 107 fdiaz
172 36 jldominguez
                ISymbol returnSymbol = null;
173
                Object result = null;
174 40 jldominguez
                String expr = null;
175 107 fdiaz
176 36 jldominguez
                try {
177
178
                        for (int i = 0; i < newSymbols.size(); i++) {
179 107 fdiaz
180 39 jldominguez
                                Evaluator eval = newSymbols.get(i).getEvaluator();
181 40 jldominguez
                                expr = eval.getSQL();
182 107 fdiaz
183 40 jldominguez
                if (expr.equalsIgnoreCase(VectorFilterExpressionLegend.I18N_DEFAULT)){
184
                    /*
185
                     * Skip default item
186
                     */
187
                    continue;
188
                }
189 107 fdiaz
190 39 jldominguez
                                result = eval.evaluate(evda);
191 40 jldominguez
                                if (isConsideredTrue(result)) {
192
                    returnSymbol = newSymbols.get(i).sym;
193
                    if (returnSymbol != null) {
194
                        return returnSymbol;
195
                    }
196 36 jldominguez
                                }
197
                        }
198 39 jldominguez
                } catch (Exception e) {
199 107 fdiaz
200 40 jldominguez
                    if (error_msg_count % 1000 == 0) {
201
                        logger.info("Error (msg every 1000 occurrences) while getting symbol in VectorFilterExpressionLegend", e);
202
                        error_msg_count = 0;
203
                    }
204
                    error_msg_count++;
205 36 jldominguez
                }
206
207 39 jldominguez
                if (useDefaultSymbol)
208 36 jldominguez
                        return getDefaultSymbol();
209
210
                return null;
211
        }
212 107 fdiaz
213 36 jldominguez
        /**
214 40 jldominguez
         * Tells whether the input object is considered true.
215
         * Basically, it is false if it has an empty value
216
         * (FALSE, null, 0, "")
217 107 fdiaz
         *
218 40 jldominguez
     * @param result
219
     * @return
220
     */
221
    private boolean isConsideredTrue(Object res) {
222 107 fdiaz
223 40 jldominguez
        if (res == null) {
224
            return false;
225
        }
226 107 fdiaz
227 40 jldominguez
        if (res instanceof Boolean) {
228
            return ((Boolean) res).booleanValue();
229
        }
230 107 fdiaz
231 40 jldominguez
        if (res instanceof Number) {
232
            return ((Number) res).doubleValue() != 0d;
233
        }
234 107 fdiaz
235 40 jldominguez
        if (res instanceof String) {
236
            return ((String) res).length() > 0;
237
        }
238 107 fdiaz
239 40 jldominguez
        // Because it is not null
240
        return true;
241
    }
242
243 36 jldominguez
        public void addSymbol(Object key, ISymbol symbol) {
244
                newSymbols.add(new Item((String)key.toString(),
245
                                symbol));
246
        }
247
248
        public void clear() {
249
                newSymbols.clear();
250
        }
251 107 fdiaz
252 40 jldominguez
        public void resetItems() {
253
            newSymbols = new ArrayList<Item>() {
254
            private static final long serialVersionUID = 1L;
255 36 jldominguez
256 40 jldominguez
            public int indexOf(String expr) {
257
                return super.indexOf(new Item(expr, null));
258
            }
259
            };
260
        }
261
262 36 jldominguez
        public void delSymbol(Object key) {
263
                ISymbol mySymbol = null;
264
                for (int i = 0; i < newSymbols.size(); i++) {
265 40 jldominguez
                        if (newSymbols.get(i).evaluator.getSQL().equals(key))
266 36 jldominguez
                                newSymbols.remove(i);
267
                }
268
                fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(mySymbol,null));
269
        }
270
271
272
        public void replace(ISymbol oldSymbol, ISymbol newSymbol) {
273
274
                for (int i = 0; i < newSymbols.size(); i++) {
275
                        if (newSymbols.get(i).sym.equals(oldSymbol))
276
                                newSymbols.get(i).sym = newSymbol;
277
                }
278
279
                fireClassifiedSymbolChangeEvent(new SymbolLegendEvent(oldSymbol,newSymbol));
280
        }
281
282
283
        public String[] getDescriptions() {
284
                String[] descriptions = new String[newSymbols.size()];
285
                ISymbol[] auxSym = getSymbols();
286
287
                for (int i = 0; i < descriptions.length; i++)
288
                        descriptions[i] = auxSym[i].getDescription();
289
290
                return descriptions;
291
        }
292
293
        public ISymbol[] getSymbols() {
294
295
                if (newSymbols != null) {
296
                        ISymbol[] mySymbols = new ISymbol[newSymbols.size()];
297
                        for (int i = 0; i < newSymbols.size(); i++) {
298
                                mySymbols[i] = newSymbols.get(i).sym;
299
                        }
300
                        return mySymbols;
301
                }
302
                return null;
303
        }
304
305
306
307
        public ISymbol getDefaultSymbol() {
308
                if(defaultSymbol==null) {
309 39 jldominguez
310
                    defaultSymbol = MapContextLocator.getSymbolManager(
311
                        ).createSymbol(shapeType);
312 36 jldominguez
                        fireDefaultSymbolChangedEvent(new SymbolLegendEvent(null, defaultSymbol));
313
                }
314
                return defaultSymbol;
315
        }
316
317
318
        public String getClassName() {
319
                return getClass().getName();
320
        }
321
322
323
        public int getShapeType() {
324
                return shapeType;
325
        }
326
327
        public boolean isUseDefaultSymbol() {
328
                return useDefaultSymbol;
329
        }
330
331
        public void setDefaultSymbol(ISymbol s) throws IllegalArgumentException {
332
                if (s == null) throw new NullPointerException("Default symbol cannot be null");
333
                ISymbol old = defaultSymbol;
334
                defaultSymbol = s;
335
                fireDefaultSymbolChangedEvent(new SymbolLegendEvent(old, defaultSymbol));
336
        }
337
338
        public void setShapeType(int shapeType) {
339
                if (this.shapeType != shapeType) {
340 107 fdiaz
341 39 jldominguez
                    ISymbol sym = MapContextLocator.getSymbolManager(
342
                        ).createSymbol(shapeType);
343
                        setDefaultSymbol(sym);
344 36 jldominguez
                        this.shapeType = shapeType;
345
                }
346
        }
347
348
        public void useDefaultSymbol(boolean b) {
349
                useDefaultSymbol = b;
350
        }
351
352
        public Object[] getValues() {
353
                if (newSymbols != null) {
354
                        Object[] myObjects = new Object[newSymbols.size()];
355
                        for (int i = 0; i < newSymbols.size(); i++) {
356 39 jldominguez
                                myObjects[i] = newSymbols.get(i).getStringExpression();
357 36 jldominguez
                        }
358
                        return myObjects;
359
                }
360
                return null;
361
        }
362 107 fdiaz
363 39 jldominguez
    public static boolean isPolygonal(int ty) {
364 1856 jjdelcerro
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
365
        return geomManager.isSubtype(Geometry.TYPES.MULTISURFACE, ty) ||
366
            geomManager.isSubtype(Geometry.TYPES.SURFACE, ty);
367 39 jldominguez
    }
368 36 jldominguez
369
370 39 jldominguez
    public static boolean isLinear(int ty) {
371 1856 jjdelcerro
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
372
        return geomManager.isSubtype(Geometry.TYPES.MULTICURVE, ty) ||
373
            geomManager.isSubtype(Geometry.TYPES.CURVE, ty);
374 39 jldominguez
    }
375 1856 jjdelcerro
376 39 jldominguez
    public static boolean isPoint(int ty) {
377 1856 jjdelcerro
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
378
        return geomManager.isSubtype(Geometry.TYPES.MULTIPOINT, ty) ||
379
            geomManager.isSubtype(Geometry.TYPES.POINT, ty);
380 39 jldominguez
    }
381 1856 jjdelcerro
382 40 jldominguez
    public void removeDefaultSymbol() {
383 107 fdiaz
384 40 jldominguez
    }
385 107 fdiaz
386 39 jldominguez
    // =============================
387 107 fdiaz
388 39 jldominguez
    public static class RegisterPersistence implements Callable {
389 36 jldominguez
390 39 jldominguez
        public Object call() throws Exception {
391 107 fdiaz
392 39 jldominguez
            PersistenceManager manager = ToolsLocator.getPersistenceManager();
393
            if (manager.getDefinition(
394
                FILTER_EXPRESSION_LEGEND_PERSISTENCE_DEFINITION_NAME) == null) {
395
                DynStruct definition = manager
396
                    .addDefinition(VectorFilterExpressionLegend.class,
397
                        FILTER_EXPRESSION_LEGEND_PERSISTENCE_DEFINITION_NAME,
398
                        FILTER_EXPRESSION_LEGEND_PERSISTENCE_DEFINITION_NAME
399
                        + " Persistence definition", null, null);
400 107 fdiaz
401 39 jldominguez
                definition.extend(manager.getDefinition(
402
                    AbstractClassifiedVectorLegend
403
                    .CLASSIFIED_VECTOR_LEGEND_PERSISTENCE_DEFINITION_NAME));
404 107 fdiaz
405 39 jldominguez
                definition.addDynFieldBoolean("useDefaultSymbol")
406
                .setMandatory(true);
407
                definition.addDynFieldObject("defaultSymbol")
408
                .setClassOfValue(ISymbol.class).setMandatory(true);
409
                definition.addDynFieldInt("shapeType")
410
                .setMandatory(true);
411 107 fdiaz
412 39 jldominguez
                definition.addDynFieldArray("itemSymbolArray")
413
                .setClassOfItems(ISymbol.class);
414
                definition.addDynFieldArray("itemStringArray")
415
                .setClassOfItems(String.class);
416
417
            }
418
            return Boolean.TRUE;
419
        }
420
421
    }
422
423
    public static class RegisterLegend implements Callable {
424
425
        public Object call() throws Exception {
426
            MapContextManager manager =
427
                MapContextLocator.getMapContextManager();
428
429
            manager.registerLegend(
430
                FILTER_EXPRESSION_LEGEND_NAME,
431
                VectorFilterExpressionLegend.class);
432
433
            return Boolean.TRUE;
434
        }
435
436
    }
437 107 fdiaz
438 39 jldominguez
    public void saveToState(PersistentState state) throws PersistenceException {
439
440
        super.saveToState(state);
441
        state.set("useDefaultSymbol", this.isUseDefaultSymbol());
442
        state.set("defaultSymbol", this.getDefaultSymbol());
443
        state.set("shapeType", this.getShapeType());
444 107 fdiaz
445 39 jldominguez
        ISymbol[] syms = this.getSymbols();
446
        if (syms == null) {
447
            syms = new ISymbol[0];
448
        }
449
        Object[] vals = this.getValues();
450
        String[] vals_str = null;
451
        if (vals == null) {
452
            vals_str = new String[0];
453
        } else {
454
            vals_str = new String[vals.length];
455
            for (int i=0; i<vals.length; i++) {
456 40 jldominguez
                String aux = ((vals[i] == null) ? null : vals[i].toString());
457
                // Prevents saving localized version of 'Default'
458
                aux = translateDefault(aux, false);
459
                vals_str[i] = aux;
460 39 jldominguez
            }
461
        }
462 107 fdiaz
463 39 jldominguez
        state.set("itemSymbolArray", syms);
464
        state.set("itemStringArray", vals_str);
465 107 fdiaz
466 39 jldominguez
    }
467
468
    public void loadFromState(PersistentState state)
469
        throws PersistenceException {
470 107 fdiaz
471 39 jldominguez
        super.loadFromState(state);
472 107 fdiaz
473 39 jldominguez
        this.setShapeType(state.getInt("shapeType"));
474
        Boolean b = state.getBoolean("useDefaultSymbol");
475
        this.useDefaultSymbol(b);
476
        ISymbol defsym = (ISymbol) state.get("defaultSymbol");
477
        this.setDefaultSymbol(defsym);
478 107 fdiaz
479 39 jldominguez
        String[] strs = state.getStringArray("itemStringArray");
480
        ISymbol[] syms = (ISymbol[]) state.getArray("itemSymbolArray",
481
            ISymbol.class);
482 107 fdiaz
483 39 jldominguez
        if (strs.length != syms.length) {
484
            logger.info("VectorFilterExpressionLegend - load state - Different size in arrays: " + strs.length + ", " + syms.length);
485
        }
486
        int nmin = Math.min(strs.length, syms.length);
487
        for (int i=0; i<nmin; i++) {
488 40 jldominguez
            String aux = strs[i];
489
            aux = translateDefault(aux, true);
490
            this.addSymbol(aux, syms[i]);
491 39 jldominguez
        }
492 40 jldominguez
    }
493 107 fdiaz
494 40 jldominguez
    /**
495
     * Utility method to (un)translate the word 'Default'
496
     * @param aux
497
     * @param forward
498
     * If TRUE, then translate (Default -> Por defecto)
499
     * If FALSE then untranslate (Por defecto -> Default)
500
     * @return
501
     */
502
    private String translateDefault(String aux, boolean forward) {
503 107 fdiaz
504 40 jldominguez
        if (aux == null) {
505
            return null;
506
        }
507
        if (forward && aux.compareTo(NON_I18N_DEFAULT) == 0) {
508
            return I18N_DEFAULT;
509
        }
510
        if (!forward && aux.compareTo(I18N_DEFAULT) == 0) {
511
            return NON_I18N_DEFAULT;
512
        }
513
        return aux;
514 39 jldominguez
    }
515
516
517 40 jldominguez
    public Object clone() throws CloneNotSupportedException {
518 107 fdiaz
519 40 jldominguez
        VectorFilterExpressionLegend resp =
520
            (VectorFilterExpressionLegend) super.clone();
521 107 fdiaz
522 40 jldominguez
        Object[] vals = this.getValues();
523
        ISymbol[] syms = this.getSymbols();
524
        if (vals != null && syms != null) {
525 107 fdiaz
526 40 jldominguez
            resp.resetItems();
527 107 fdiaz
528 40 jldominguez
            int n = Math.min(vals.length, syms.length);
529
            for (int i=0; i<n; i++) {
530
                resp.addSymbol(
531
                    vals[i],
532
                    (ISymbol) syms[i].clone());
533
            }
534
        }
535
        ISymbol sym = this.getDefaultSymbol();
536
        sym = (ISymbol) sym.clone();
537
        resp.setDefaultSymbol(sym);
538
        return resp;
539
    }
540 39 jldominguez
541
542 107 fdiaz
543 36 jldominguez
}