Statistics
| Revision:

root / branches / v2_0_0_prep / 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 @ 34294

History | View | Annotate | Download (13.4 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.gvsig.compat.print.PrintAttributes;
37
import org.gvsig.fmap.dal.feature.Feature;
38
import org.gvsig.fmap.geom.Geometry;
39
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
40
import org.gvsig.fmap.geom.GeometryLocator;
41
import org.gvsig.fmap.geom.GeometryManager;
42
import org.gvsig.fmap.geom.exception.CreateGeometryException;
43
import org.gvsig.fmap.geom.primitive.GeneralPathX;
44
import org.gvsig.fmap.mapcontext.MapContextLocator;
45
import org.gvsig.fmap.mapcontext.ViewPort;
46
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
47
import org.gvsig.fmap.mapcontext.rendering.symbols.ITextSymbol;
48
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolDrawingException;
49
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolManager;
50
import org.gvsig.fmap.mapcontext.rendering.symbols.SymbolPreferences;
51
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.AbstractSymbol;
52
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.impl.CartographicSupportToolkit;
53
import org.gvsig.symbology.fmap.mapcontext.rendering.symbol.text.ISimpleTextSymbol;
54
import org.gvsig.tools.ToolsLocator;
55
import org.gvsig.tools.dynobject.DynStruct;
56
import org.gvsig.tools.persistence.PersistenceManager;
57
import org.gvsig.tools.persistence.PersistentState;
58
import org.gvsig.tools.persistence.exception.PersistenceException;
59
import org.gvsig.tools.task.Cancellable;
60
import org.gvsig.tools.util.Callable;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

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

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

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

    
85
        private Font font;
86

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

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

    
101
        public void draw(Graphics2D g, AffineTransform affineTransform,
102
                        Geometry geom, Feature feature, Cancellable cancel) {
103
                if (!isShapeVisible()) {
104
                        return;
105
                }
106
                g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
107
                g.setColor(textColor);
108
                g.setFont(font);
109
                g.translate(((org.gvsig.fmap.geom.primitive.Point) geom).getX(), ((org.gvsig.fmap.geom.primitive.Point) geom).getY());
110

    
111
                g.rotate(rotation);
112
                Rectangle2D bounds = getBounds();
113
//                 getBounds devuelve el bounds de un texto dibujado de manera que
114
                // la linea base de la primera letra est? en el punto (0,0).
115
                // Por eso, si queremos alinear el texto de manera que la parte superior
116
                // izquierda de la primera letra est? en (0,0) debemos moverlo seg?n
117
                // el valor de la ordenada, en lugar de seg?n su altura.
118
                g.drawString(getText(), 0, (int)-bounds.getY());//(int) bounds.getHeight());
119
                g.rotate(-rotation);
120
                g.translate(-((org.gvsig.fmap.geom.primitive.Point) geom).getX(), -((org.gvsig.fmap.geom.primitive.Point) geom).getY());
121
        }
122

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

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

    
162

    
163
        }
164

    
165
        public int getOnePointRgb() {
166
                return textColor.getRGB();
167
        }
168

    
169
        public void getPixExtentPlus(org.gvsig.fmap.geom.Geometry geom, float[] distances,
170
                        ViewPort viewPort, int dpi) {
171
                throw new Error("Not yet implemented!");
172

    
173
        }
174

    
175
        public ISymbol getSymbolForSelection() {
176
                return this; // a text is not selectable
177
        }
178

    
179
        public int getSymbolType() {
180
                return Geometry.TYPES.TEXT;
181
        }
182

    
183
        public boolean isSuitableFor(Geometry geom) {
184
                return true;
185
        }
186

    
187
        public String getClassName() {
188
                return getClass().getName();
189
        }
190

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

    
208
        public String getText() {
209
                return text;
210
        }
211

    
212
        public Font getFont() {
213
                return font;
214
        }
215

    
216
        public Color getTextColor() {
217
                return textColor;
218
        }
219

    
220
        public void setText(String text) {
221
                this.text = text;
222
        }
223

    
224
        public void setFont(Font font) {
225
                if (font == null) {
226
                        LOG.warn("font <-- null");
227

    
228
                        return;
229
                }
230
                this.font = font;
231
        }
232

    
233
        public void setTextColor(Color color) {
234
                this.textColor = color;
235
        }
236
        
237
        public Color getColor() {
238
                return getTextColor();
239
        }
240
        
241
        public void setColor(Color color) {
242
                setTextColor(color);
243
        }
244

    
245
        public void setFontSize(double size) {
246
                Font newFont = new Font(font.getName(), font.getStyle(), (int) size);
247
//                if (newFont == null) {
248
//                        logger.warn(
249
//                                        "Font(" + font.getName() + ", "
250
//                                        + font.getStyle() + ", " + (int) size + " --> null");
251
//                } else {
252
                        this.font = newFont;
253
//                }
254
        }
255

    
256
        public double getRotation() {
257
                return rotation;
258
        }
259

    
260
        /**
261
         * Defines the angle of rotation for the text that composes the symbol
262
         *
263
         * @param rotation
264
         */
265
        public void setRotation(double rotation) {
266
                this.rotation = rotation;
267
        }
268

    
269
        /**
270
         * Returns an Geometry which represents a rectangle containing the text in
271
         * <b>screen</b> units.
272
         */
273
        public Geometry getTextWrappingShape(org.gvsig.fmap.geom.primitive.Point p) {
274
                Font font = getFont();
275
                GlyphVector gv = font.createGlyphVector(frc, text);
276

    
277
                Shape shape = gv.getOutline((float) p.getX(), (float) p.getY());
278
                Geometry myFShape;
279
                try {
280
                        myFShape = geomManager.createSurface(new GeneralPathX(shape
281
                                        .getBounds2D().getPathIterator(null)), SUBTYPES.GEOM2D);
282
                        myFShape.transform(AffineTransform.getTranslateInstance(p.getX(), p.getY()));
283

    
284
                        if (rotation != 0) {
285
                                myFShape.transform(AffineTransform.getRotateInstance(rotation));
286
                        }
287
                        return myFShape;
288
                } catch (CreateGeometryException e) {
289
                        LOG.error("Error creating a surface", e);
290
                        e.printStackTrace();
291
                }
292
                return null;
293
        }
294

    
295
        public Rectangle getBounds() {
296
//                FontMetrics fm = g.getFontMetrics();
297
//                Rectangle2D rect = fm.getStringBounds("graphics", g);
298

    
299
                Rectangle bounds = null;
300
                try {
301
                        bounds = getTextWrappingShape(geomManager.createPoint(0,0, SUBTYPES.GEOM2D)).getBounds();
302
                } catch (CreateGeometryException e) {
303
                        LOG.error("Error creating a point", e);
304
                }
305
                return bounds;
306
        }
307

    
308
        public void setCartographicSize(double cartographicSize, Geometry geom) {
309
                setFontSize(cartographicSize);
310
        }
311

    
312
        public double toCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
313
                double oldSize = getFont().getSize();
314
                setCartographicSize(getCartographicSize(
315
                                                                viewPort,
316
                                                                dpi,
317
                                                                geom),
318
                                                        geom);
319
                return oldSize;
320
        }
321

    
322
        public double getCartographicSize(ViewPort viewPort, double dpi, Geometry geom) {
323
                return CartographicSupportToolkit.
324
                                        getCartographicLength(this,
325
                                                                                  getFont().getSize(),
326
                                                                                  viewPort,
327
                                                                                  dpi);
328
        }
329
        public boolean isAutoresizeEnabled() {
330
                return autoresize;
331
        }
332

    
333
        public void setAutoresizeEnabled(boolean autoresizeFlag) {
334
                this.autoresize = autoresizeFlag;
335
        }
336

    
337
        
338
        public Object clone() throws CloneNotSupportedException {
339
                SimpleTextSymbol copy = (SimpleTextSymbol) super.clone();
340

    
341
                return copy;
342
        }
343

    
344
        public void loadFromState(PersistentState state)
345
        
346
                        throws PersistenceException {
347
                // Set parent fill symbol properties
348
                super.loadFromState(state);
349

    
350
                // Set own properties
351
                setAutoresizeEnabled(state.getBoolean(FIELD_AUTO_RESIZE));
352
                setFont((Font) state.get(FIELD_FONT));
353
                setRotation(state.getDouble(FIELD_ROTATION));
354
                setText(state.getString(FIELD_TEXT));
355
                setTextColor((Color) state.get(FIELD_TEXT_COLOR));
356
        }
357

    
358
        public void saveToState(PersistentState state) throws PersistenceException {
359
                // Save parent fill symbol properties
360
                super.saveToState(state);
361

    
362
                // Save own properties
363
                state.set(FIELD_AUTO_RESIZE, isAutoresizeEnabled());
364
                state.set(FIELD_FONT, getFont());
365
                state.set(FIELD_ROTATION, getRotation());
366
                state.set(FIELD_TEXT, getText());
367
                state.set(FIELD_TEXT_COLOR, getTextColor());
368
        }
369

    
370
        public static class RegisterPersistence implements Callable {
371

    
372
                public Object call() throws Exception {
373
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
374
                        if( manager.getDefinition(SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME)==null ) {
375
                                DynStruct definition = manager.addDefinition(
376
                                                SimpleTextSymbol.class,
377
                                                SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME,
378
                                                SIMPLE_TEXT_SYMBOL_PERSISTENCE_DEFINITION_NAME+" Persistence definition",
379
                                                null, 
380
                                                null
381
                                );
382
                                // Extend the Symbol base definition
383
                                definition.extend(manager.getDefinition(SYMBOL_PERSISTENCE_DEFINITION_NAME));
384

    
385
                                // Auto resize?
386
                                definition.addDynFieldBoolean(FIELD_AUTO_RESIZE)
387
                                        .setMandatory(true);
388
                                
389
                                // Font
390
                                definition.addDynFieldObject(FIELD_FONT)
391
                                        .setClassOfValue(Font.class)
392
                                        .setMandatory(true);
393
                                
394
                                // Rotation
395
                                definition.addDynFieldDouble(FIELD_ROTATION)
396
                                        .setMandatory(true);
397
                                
398
                                // Text
399
                                definition.addDynFieldString(FIELD_TEXT);
400
                                
401
                                // Text color
402
                                definition.addDynFieldObject(FIELD_TEXT_COLOR)
403
                                        .setClassOfValue(Color.class)
404
                                        .setMandatory(true);
405
                        }
406
                        return Boolean.TRUE;
407
                }
408
                
409
        }
410

    
411
        public static class RegisterSymbol implements Callable {
412

    
413
                public Object call() throws Exception {
414
                        int[] shapeTypes;
415
                        SymbolManager manager = MapContextLocator.getSymbolManager();
416

    
417
                shapeTypes = new int[] { Geometry.TYPES.TEXT };
418
                manager.registerSymbol(ITextSymbol.SYMBOL_NAME,
419
                    shapeTypes,
420
                    SimpleTextSymbol.class);
421

    
422
                        return Boolean.TRUE;
423
                }
424
                
425
        }
426

    
427
}