Statistics
| Revision:

svn-gvsig-desktop / tags / v2_0_0_Build_2030 / libraries / org.gvsig.symbology / org.gvsig.symbology.lib / org.gvsig.symbology.lib.impl / src / main / java / org / gvsig / symbology / fmap / mapcontext / rendering / symbol / text / impl / SimpleTextSymbol.java @ 35919

History | View | Annotate | Download (13.6 KB)

1
/* 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.symbol.text.impl;
23

    
24
import java.awt.Color;
25
import java.awt.Font;
26
import java.awt.FontMetrics;
27
import java.awt.Graphics2D;
28
import java.awt.Rectangle;
29
import java.awt.RenderingHints;
30
import java.awt.Shape;
31
import java.awt.font.FontRenderContext;
32
import java.awt.font.GlyphVector;
33
import java.awt.geom.AffineTransform;
34
import java.awt.geom.Rectangle2D;
35

    
36
import org.slf4j.Logger;
37
import org.slf4j.LoggerFactory;
38

    
39
import org.gvsig.compat.print.PrintAttributes;
40
import org.gvsig.fmap.dal.feature.Feature;
41
import org.gvsig.fmap.geom.Geometry;
42
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
43
import org.gvsig.fmap.geom.GeometryLocator;
44
import org.gvsig.fmap.geom.GeometryManager;
45
import org.gvsig.fmap.geom.exception.CreateGeometryException;
46
import org.gvsig.fmap.geom.primitive.GeneralPathX;
47
import org.gvsig.fmap.geom.primitive.Point;
48
import org.gvsig.fmap.mapcontext.MapContextLocator;
49
import org.gvsig.fmap.mapcontext.ViewPort;
50
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
51
import org.gvsig.fmap.mapcontext.rendering.symbols.ITextSymbol;
52
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
53
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
54
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolPreferences;
55
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.AbstractSymbol;
56
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.CartographicSupportToolkit;
57
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text.ISimpleTextSymbol;
58
import org.gvsig.tools.ToolsLocator;
59
import org.gvsig.tools.dynobject.DynStruct;
60
import org.gvsig.tools.persistence.PersistenceManager;
61
import org.gvsig.tools.persistence.PersistentState;
62
import org.gvsig.tools.persistence.exception.PersistenceException;
63
import org.gvsig.tools.task.Cancellable;
64
import org.gvsig.tools.util.Callable;
65

    
66
/**
67
 * SimpleTextSymbol is a class used to create symbols composed using a text defined by
68
 * the user.This text can be edited (changing the color, the font of the characters, and
69
 * the rotation of the text).
70
 * @author 2005-2008 jaume dominguez faus - jaume.dominguez@iver.es
71
 * @author 2009-     <a href="cordinyana@gvsig.org">C?sar Ordi?ana</a> - gvSIG team
72
 */
73
public class SimpleTextSymbol extends AbstractSymbol implements ITextSymbol, ISimpleTextSymbol {
74
        final static private Logger LOG = LoggerFactory.getLogger(SimpleTextSymbol.class);
75

    
76
        public static final String SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME = "SimpleTextSymbol";
77
        
78
        private static final String FIELD_TEXT = "text";
79
        private static final String FIELD_FONT = "font";
80
        private static final String FIELD_TEXT_COLOR = "textColor";
81
        private static final String FIELD_ROTATION = "rotation";
82
        private static final String FIELD_AUTO_RESIZE = "autoResize";
83

    
84
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
85
        private String text = "";
86

    
87
        private Font font;
88

    
89
        private Color textColor;
90
        private double rotation;
91
        private FontRenderContext frc = new FontRenderContext(
92
                        new AffineTransform(), false, true);
93
        private boolean autoresize;
94

    
95
        public SimpleTextSymbol() {
96
                super();
97
                SymbolPreferences preferences =
98
                                MapContextLocator.getSymbolManager().getSymbolPreferences();
99
                font = preferences.getDefaultSymbolFont();
100
                textColor = preferences.getDefaultSymbolColor();
101
        }
102

    
103
        public void draw(Graphics2D g, AffineTransform affineTransform,
104
                        Geometry geom, Feature feature, Cancellable cancel) {
105
                if (!isShapeVisible()) {
106
                        return;
107
                }
108
                
109
                Point point = (Point)geom;
110
            point.transform(affineTransform);
111
          
112
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
113
                g.setColor(textColor);
114
                g.setFont(font);
115
                g.translate(point.getX(), point.getY());
116

    
117
                g.rotate(rotation);
118
                Rectangle2D bounds = getBounds();
119
//                 getBounds devuelve el bounds de un texto dibujado de manera que
120
                // la linea base de la primera letra est? en el punto (0,0).
121
                // Por eso, si queremos alinear el texto de manera que la parte superior
122
                // izquierda de la primera letra est? en (0,0) debemos moverlo seg?n
123
                // el valor de la ordenada, en lugar de seg?n su altura.
124
                g.drawString(getText(), 0, (int)-bounds.getY());//(int) bounds.getHeight());
125
                g.rotate(-rotation);
126
                g.translate(-point.getX(), -point.getY());
127
        }
128

    
129
        public void drawInsideRectangle(Graphics2D g,
130
                        AffineTransform scaleInstance, Rectangle r, PrintAttributes properties) throws SymbolDrawingException {
131
                int s = getFont().getSize();
132
                if (autoresize) {
133
                        if (s==0) {
134
                                s =1;
135
                                setFontSize(s);
136
                        }
137
                        g.setFont(getFont());
138
                    FontMetrics fm = g.getFontMetrics();
139
                    Rectangle2D rect = fm.getStringBounds(text, g);
140
                    double width = rect.getWidth();
141
                    double height = rect.getHeight();
142
                    double rWidth = r.getWidth();
143
                    double rHeight = r.getHeight();
144
                    double ratioText = width/height;
145
                    double ratioRect = rWidth/rHeight;
146

    
147
                    if (ratioText>ratioRect) {
148
                            s = (int) (s*(rWidth/width));
149
                    } else {
150
                            s = (int) (s*(rHeight/height));
151
                    }
152
//                    r.setLocation(r.x, (int) Math.round(r.getY()+r.getHeight()));
153
                }
154
                setFontSize(s);
155
//                g.setColor(Color.red);
156
//                g.draw(r);
157
                try {
158
                        if (properties==null)
159
                                draw(g, null, geomManager.createPoint(r.getX(), r.getY(),
160
                                                SUBTYPES.GEOM2D), null, null);
161
                        else
162
                                print(g, new AffineTransform(), geomManager.createPoint(r.getX(), r.getY(), SUBTYPES.GEOM2D), properties);
163
                } catch (CreateGeometryException e) {
164
                        LOG.error("Error creatint a point", e);
165
                        e.printStackTrace();
166
                }
167

    
168

    
169
        }
170

    
171
        public int getOnePointRgb() {
172
                return textColor.getRGB();
173
        }
174

    
175
        public void getPixExtentPlus(org.gvsig.fmap.geom.Geometry geom, float[] distances,
176
                        ViewPort viewPort, int dpi) {
177
                throw new Error("Not yet implemented!");
178

    
179
        }
180

    
181
        public ISymbol getSymbolForSelection() {
182
                return this; // a text is not selectable
183
        }
184

    
185
        public int getSymbolType() {
186
                //This method returned the deleted type Geometry.TYPES.TEXT. I suppose that now
187
            //it has to retrun geometry
188
            return Geometry.TYPES.GEOMETRY;
189
        }
190

    
191
        public boolean isSuitableFor(Geometry geom) {
192
                return true;
193
        }
194

    
195
        public String getClassName() {
196
                return getClass().getName();
197
        }
198

    
199
        public void print(Graphics2D g, AffineTransform at, org.gvsig.fmap.geom.Geometry geom, PrintAttributes properties){
200
                float originalSize = getFont().getSize2D();
201
                float size=originalSize;
202
                // scale it to size
203
                int pq = properties.getPrintQuality();
204
                if (pq == PrintAttributes.PRINT_QUALITY_NORMAL){
205
                        size *= (double) 300/72;
206
                }else if (pq == PrintAttributes.PRINT_QUALITY_HIGH){
207
                        size *= (double) 600/72;
208
                }else if (pq == PrintAttributes.PRINT_QUALITY_DRAFT){
209
                        // d *= 72/72; // (which is the same than doing nothing)
210
                }
211
                setFont(getFont().deriveFont(size));
212
                draw(g,at,geom, null, null);
213
                setFont(getFont().deriveFont(originalSize));
214
        }
215

    
216
        public String getText() {
217
                return text;
218
        }
219

    
220
        public Font getFont() {
221
                return font;
222
        }
223

    
224
        public Color getTextColor() {
225
                return textColor;
226
        }
227

    
228
        public void setText(String text) {
229
                this.text = text;
230
        }
231

    
232
        public void setFont(Font font) {
233
                if (font == null) {
234
                        LOG.warn("font <-- null");
235

    
236
                        return;
237
                }
238
                this.font = font;
239
        }
240

    
241
        public void setTextColor(Color color) {
242
                this.textColor = color;
243
        }
244
        
245
        public Color getColor() {
246
                return getTextColor();
247
        }
248
        
249
        public void setColor(Color color) {
250
                setTextColor(color);
251
        }
252

    
253
        public void setFontSize(double size) {
254
                Font newFont = new Font(font.getName(), font.getStyle(), (int) size);
255
//                if (newFont == null) {
256
//                        logger.warn(
257
//                                        "Font(" + font.getName() + ", "
258
//                                        + font.getStyle() + ", " + (int) size + " --> null");
259
//                } else {
260
                        this.font = newFont;
261
//                }
262
        }
263

    
264
        public double getRotation() {
265
                return rotation;
266
        }
267

    
268
        /**
269
         * Defines the angle of rotation for the text that composes the symbol
270
         *
271
         * @param rotation
272
         */
273
        public void setRotation(double rotation) {
274
                this.rotation = rotation;
275
        }
276

    
277
        /**
278
         * Returns an Geometry which represents a rectangle containing the text in
279
         * <b>screen</b> units.
280
         */
281
        public Geometry getTextWrappingShape(org.gvsig.fmap.geom.primitive.Point p) {
282
                Font font = getFont();
283
                GlyphVector gv = font.createGlyphVector(frc, text);
284

    
285
                Shape shape = gv.getOutline((float) p.getX(), (float) p.getY());
286
                Geometry myFShape;
287
                try {
288
                        myFShape = geomManager.createSurface(new GeneralPathX(shape
289
                                        .getBounds2D().getPathIterator(null)), SUBTYPES.GEOM2D);
290
                        myFShape.transform(AffineTransform.getTranslateInstance(p.getX(), p.getY()));
291

    
292
                        if (rotation != 0) {
293
                                myFShape.transform(AffineTransform.getRotateInstance(rotation));
294
                        }
295
                        return myFShape;
296
                } catch (CreateGeometryException e) {
297
                        LOG.error("Error creating a surface", e);
298
                        e.printStackTrace();
299
                }
300
                return null;
301
        }
302

    
303
        public Rectangle getBounds() {
304
//                FontMetrics fm = g.getFontMetrics();
305
//                Rectangle2D rect = fm.getStringBounds("graphics", g);
306

    
307
                Rectangle bounds = null;
308
                try {
309
                        bounds = getTextWrappingShape(geomManager.createPoint(0,0, SUBTYPES.GEOM2D)).getShape().getBounds();
310
                } catch (CreateGeometryException e) {
311
                        LOG.error("Error creating a point", e);
312
                }
313
                return bounds;
314
        }
315

    
316
        public void setCartographicSize(double cartographicSize, Geometry geom) {
317
                setFontSize(cartographicSize);
318
        }
319

    
320
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
321
                double oldSize = getFont().getSize();
322
                setCartographicSize(getCartographicSize(
323
                                                                viewPort,
324
                                                                dpi,
325
                                                                geom),
326
                                                        geom);
327
                return oldSize;
328
        }
329

    
330
        public double getCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
331
                return CartographicSupportToolkit.
332
                                        getCartographicLength(this,
333
                                                                                  getFont().getSize(),
334
                                                                                  viewPort,
335
                                                                                  dpi);
336
        }
337
        public boolean isAutoresizeEnabled() {
338
                return autoresize;
339
        }
340

    
341
        public void setAutoresizeEnabled(boolean autoresizeFlag) {
342
                this.autoresize = autoresizeFlag;
343
        }
344

    
345
        
346
        public Object clone() throws CloneNotSupportedException {
347
                SimpleTextSymbol copy = (SimpleTextSymbol) super.clone();
348

    
349
                return copy;
350
        }
351

    
352
        public void loadFromState(PersistentState state)
353
        
354
                        throws PersistenceException {
355
                // Set parent fill symbol properties
356
                super.loadFromState(state);
357

    
358
                // Set own properties
359
                setAutoresizeEnabled(state.getBoolean(FIELD_AUTO_RESIZE));
360
                setFont((Font) state.get(FIELD_FONT));
361
                setRotation(state.getDouble(FIELD_ROTATION));
362
                setText(state.getString(FIELD_TEXT));
363
                setTextColor((Color) state.get(FIELD_TEXT_COLOR));
364
        }
365

    
366
        public void saveToState(PersistentState state) throws PersistenceException {
367
                // Save parent fill symbol properties
368
                super.saveToState(state);
369

    
370
                // Save own properties
371
                state.set(FIELD_AUTO_RESIZE, isAutoresizeEnabled());
372
                state.set(FIELD_FONT, getFont());
373
                state.set(FIELD_ROTATION, getRotation());
374
                state.set(FIELD_TEXT, getText());
375
                state.set(FIELD_TEXT_COLOR, getTextColor());
376
        }
377

    
378
        public static class RegisterPersistence implements Callable {
379

    
380
                public Object call() throws Exception {
381
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
382
                        if( manager.getDefinition(SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
383
                                DynStruct definition = manager.addDefinition(
384
                                                SimpleTextSymbol.class,
385
                                                SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME,
386
                                                SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
387
                                                null, 
388
                                                null
389
                                );
390
                                // Extend the Symbol base definition
391
                                definition.extend(manager.getDefinition(SYMBOL_PERSISTENCE_DEFINITION_NAME));
392

    
393
                                // Auto resize?
394
                                definition.addDynFieldBoolean(FIELD_AUTO_RESIZE)
395
                                        .setMandatory(true);
396
                                
397
                                // Font
398
                                definition.addDynFieldObject(FIELD_FONT)
399
                                        .setClassOfValue(Font.class)
400
                                        .setMandatory(true);
401
                                
402
                                // Rotation
403
                                definition.addDynFieldDouble(FIELD_ROTATION)
404
                                        .setMandatory(true);
405
                                
406
                                // Text
407
                                definition.addDynFieldString(FIELD_TEXT);
408
                                
409
                                // Text color
410
                                definition.addDynFieldObject(FIELD_TEXT_COLOR)
411
                                        .setClassOfValue(Color.class)
412
                                        .setMandatory(true);
413
                        }
414
                        return Boolean.TRUE;
415
                }
416
                
417
        }
418

    
419
        public static class RegisterSymbol implements Callable {
420

    
421
                public Object call() throws Exception {
422
                        int[] shapeTypes;
423
                        SymbolManager manager = MapContextLocator.getSymbolManager();
424
                
425
                        //This method registered the deleted type Geometry.TYPES.TEXT. I suppose that now
426
                //it has to register geometry
427
                shapeTypes = new int[] { Geometry.TYPES.GEOMETRY };
428
                manager.registerSymbol(ITextSymbol.SYMBOL_NAME,
429
                    shapeTypes,
430
                    SimpleTextSymbol.class);
431

    
432
                        return Boolean.TRUE;
433
                }
434
                
435
        }
436

    
437
}