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 / symbol / text / impl / SimpleTextSymbol.java @ 40560

History | View | Annotate | Download (13.7 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.symbol.text.impl;
25

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

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

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

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

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

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

    
89
        private Font font;
90

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

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

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

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

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

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

    
170

    
171
        }
172

    
173
        public int getOnePointRgb() {
174
                return textColor.getRGB();
175
        }
176

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

    
181
        }
182

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

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

    
193
        public boolean isSuitableFor(Geometry geom) {
194
                return true;
195
        }
196

    
197
        public String getClassName() {
198
                return getClass().getName();
199
        }
200

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

    
218
        public String getText() {
219
                return text;
220
        }
221

    
222
        public Font getFont() {
223
                return font;
224
        }
225

    
226
        public Color getTextColor() {
227
                return textColor;
228
        }
229

    
230
        public void setText(String text) {
231
                this.text = text;
232
        }
233

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

    
238
                        return;
239
                }
240
                this.font = font;
241
        }
242

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

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

    
266
        public double getRotation() {
267
                return rotation;
268
        }
269

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

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

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

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

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

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

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

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

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

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

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

    
351
                return copy;
352
        }
353

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

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

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

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

    
380
        public static class RegisterPersistence implements Callable {
381

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

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

    
421
        public static class RegisterSymbol implements Callable {
422

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

    
434
                        return Boolean.TRUE;
435
                }
436
                
437
        }
438

    
439
}