root / trunk / extensions / extSymbology / src / org / gvsig / symbology / fmap / symbols / SmartTextSymbol.java @ 20768
History | View | Annotate | Download (14.1 KB)
1 |
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
|
---|---|
2 |
*
|
3 |
* Copyright (C) 2005 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 |
|
42 |
/* CVS MESSAGES:
|
43 |
*
|
44 |
* $Id: SmartTextSymbol.java 13953 2007-09-21 12:26:04Z jaume $
|
45 |
* $Log$
|
46 |
* Revision 1.6 2007-09-21 12:25:32 jaume
|
47 |
* cancellation support extended down to the IGeometry and ISymbol level
|
48 |
*
|
49 |
* Revision 1.5 2007/08/16 06:55:19 jvidal
|
50 |
* javadoc updated
|
51 |
*
|
52 |
* Revision 1.4 2007/08/13 11:36:50 jvidal
|
53 |
* javadoc
|
54 |
*
|
55 |
* Revision 1.3 2007/03/28 16:48:14 jaume
|
56 |
* *** empty log message ***
|
57 |
*
|
58 |
* Revision 1.2 2007/03/21 17:36:22 jaume
|
59 |
* *** empty log message ***
|
60 |
*
|
61 |
* Revision 1.1 2007/03/09 11:20:56 jaume
|
62 |
* Advanced symbology (start committing)
|
63 |
*
|
64 |
* Revision 1.1.2.8 2007/02/21 07:34:09 jaume
|
65 |
* labeling starts working
|
66 |
*
|
67 |
* Revision 1.1.2.7 2007/02/16 10:54:12 jaume
|
68 |
* multilayer splitted to multilayerline, multilayermarker,and multilayerfill
|
69 |
*
|
70 |
* Revision 1.1.2.6 2007/02/15 16:23:44 jaume
|
71 |
* *** empty log message ***
|
72 |
*
|
73 |
* Revision 1.1.2.5 2007/02/09 07:47:05 jaume
|
74 |
* Isymbol moved
|
75 |
*
|
76 |
* Revision 1.1.2.4 2007/02/08 07:36:38 jaume
|
77 |
* *** empty log message ***
|
78 |
*
|
79 |
* Revision 1.1.2.3 2007/02/06 16:54:36 jaume
|
80 |
* *** empty log message ***
|
81 |
*
|
82 |
* Revision 1.1.2.2 2007/02/06 16:47:35 jaume
|
83 |
* first steps, follows a line
|
84 |
*
|
85 |
* Revision 1.1.2.1 2007/02/02 16:21:24 jaume
|
86 |
* start commiting labeling stuff
|
87 |
*
|
88 |
* Revision 1.1 2007/01/24 17:58:22 jaume
|
89 |
* new features and architecture error fixes
|
90 |
*
|
91 |
*
|
92 |
*/
|
93 |
package org.gvsig.symbology.fmap.symbols; |
94 |
|
95 |
import java.awt.BorderLayout; |
96 |
import java.awt.Color; |
97 |
import java.awt.Dimension; |
98 |
import java.awt.Font; |
99 |
import java.awt.Graphics; |
100 |
import java.awt.Graphics2D; |
101 |
import java.awt.Rectangle; |
102 |
import java.awt.event.ActionEvent; |
103 |
import java.awt.event.ActionListener; |
104 |
import java.awt.geom.AffineTransform; |
105 |
import java.util.ArrayList; |
106 |
|
107 |
import javax.swing.JCheckBox; |
108 |
import javax.swing.JFrame; |
109 |
import javax.swing.JPanel; |
110 |
import javax.swing.JTextField; |
111 |
|
112 |
import org.gvsig.gui.beans.swing.GridBagLayoutPanel; |
113 |
import org.gvsig.gui.beans.swing.JComboBoxFonts; |
114 |
import org.gvsig.gui.beans.swing.JIncrementalNumberField; |
115 |
|
116 |
import com.iver.cit.gvsig.fmap.ViewPort; |
117 |
import com.iver.cit.gvsig.fmap.core.FPolygon2D; |
118 |
import com.iver.cit.gvsig.fmap.core.FPolyline2D; |
119 |
import com.iver.cit.gvsig.fmap.core.FShape; |
120 |
import com.iver.cit.gvsig.fmap.core.GeneralPathX; |
121 |
import com.iver.cit.gvsig.fmap.core.IGeometry; |
122 |
import com.iver.cit.gvsig.fmap.core.SymbologyFactory; |
123 |
import com.iver.cit.gvsig.fmap.core.TextPath; |
124 |
import com.iver.cit.gvsig.fmap.core.symbols.IFillSymbol; |
125 |
import com.iver.cit.gvsig.fmap.core.symbols.ITextSymbol; |
126 |
import com.iver.cit.gvsig.fmap.core.symbols.SimpleTextSymbol; |
127 |
import com.iver.cit.gvsig.fmap.core.symbols.SymbolDrawingException; |
128 |
import com.iver.cit.gvsig.fmap.core.v02.FConstant; |
129 |
import com.iver.utiles.XMLEntity; |
130 |
import com.iver.utiles.swing.JComboBox; |
131 |
import com.iver.utiles.swing.threads.Cancellable; |
132 |
|
133 |
/**
|
134 |
* Class used to create symbols composed using a text defined by
|
135 |
* the user.This text can be edited (changing the color, the font of the characters, and
|
136 |
* the rotation of the text)and has the property that can follow a path.If this path
|
137 |
* does not exist, the text is treated as a simpletextsymbol (when is drawn).
|
138 |
* @author jaume dominguez faus - jaume.dominguez@iver.es
|
139 |
*/
|
140 |
public class SmartTextSymbol extends SimpleTextSymbol implements ITextSymbol { |
141 |
|
142 |
private char[] text; |
143 |
// Background: ITextBackground
|
144 |
// Case
|
145 |
private double characterSpacing; |
146 |
private double characterWidth; |
147 |
// Direction
|
148 |
private IFillSymbol fillSymbol;
|
149 |
private double flipAngle; |
150 |
// boolean kerning;
|
151 |
private double leading; |
152 |
// Position: textPosition
|
153 |
private Color ShadowColor; |
154 |
private double ShadowXOffset; |
155 |
private double ShadowYOffset; |
156 |
// TypeSetting: Boolean
|
157 |
private double wordSpacing; |
158 |
// ISimpleTextSymbol : ITextSymbol
|
159 |
// BreakCharacter: Long
|
160 |
// Clip: Boolean
|
161 |
private TextPath textPath;
|
162 |
private double xOffset; |
163 |
private double yOffset; |
164 |
private double angle; |
165 |
// Color: IColor
|
166 |
|
167 |
// HorizontalAlignment:
|
168 |
// esriTextHorizontalAlignment
|
169 |
private boolean rightToLeft; |
170 |
// VerticalAlignment
|
171 |
private double maskSize; |
172 |
// MaskStyle
|
173 |
private IFillSymbol maskSymbol;
|
174 |
private double margin; |
175 |
private int alignment; |
176 |
private boolean kerning = false; |
177 |
|
178 |
/**
|
179 |
* Draws the text according. If this symbol has the text path set, then
|
180 |
* it is used as the text line, otherwise shp <b>must be an FPoint2D</b>
|
181 |
* indicating the starting point of the text and then the text will
|
182 |
* be rendered from there and following the rotation previously set.
|
183 |
*/
|
184 |
@Override
|
185 |
public void draw(Graphics2D g, AffineTransform affineTransform, FShape shp, Cancellable cancel) { |
186 |
if (!isShapeVisible()) return; |
187 |
TextPath tp = new TextPath(g, shp, text, getFont(),
|
188 |
(float) characterSpacing, (float) characterWidth, kerning, |
189 |
(float) leading, alignment, (float) wordSpacing, (float) margin, rightToLeft); |
190 |
g.setFont(getFont()); |
191 |
|
192 |
for (int i = 0; i < tp.getGlyphCount(); i++) { |
193 |
double[] coords = tp.nextPosForGlyph(i); |
194 |
if (coords[0] == TextPath.NO_POS || coords[1] == TextPath.NO_POS) |
195 |
continue;
|
196 |
g.translate(coords[0], coords[1]); |
197 |
g.rotate(coords[2]);
|
198 |
|
199 |
g.drawString(new String(new char[] {text[i]}), 0, 0); |
200 |
|
201 |
g.rotate(-coords[2]);
|
202 |
g.translate(-coords[0], -coords[1]); |
203 |
} |
204 |
} |
205 |
|
206 |
@Override
|
207 |
public void getPixExtentPlus(FShape shp, float[] distances, ViewPort viewPort, int dpi) { |
208 |
// TODO Implement it
|
209 |
throw new Error("Not yet implemented!"); |
210 |
|
211 |
} |
212 |
|
213 |
@Override
|
214 |
public int getOnePointRgb() { |
215 |
return getTextColor().getRGB();
|
216 |
} |
217 |
|
218 |
@Override
|
219 |
public XMLEntity getXMLEntity() {
|
220 |
XMLEntity xml = new XMLEntity();
|
221 |
xml.putProperty("className", getClassName());
|
222 |
xml.putProperty("desc", getDescription());
|
223 |
xml.putProperty("isShapeVisible", isShapeVisible());
|
224 |
return xml;
|
225 |
} |
226 |
|
227 |
@Override
|
228 |
public int getSymbolType() { |
229 |
return FShape.TEXT;
|
230 |
} |
231 |
|
232 |
@Override
|
233 |
public boolean isSuitableFor(IGeometry geom) { |
234 |
return geom.getGeometryType() == FShape.LINE;
|
235 |
} |
236 |
|
237 |
@Override
|
238 |
public void drawInsideRectangle(Graphics2D g, AffineTransform scaleInstance, Rectangle r) throws SymbolDrawingException { |
239 |
// let's take the bottom segment of the rectangle as the line
|
240 |
|
241 |
GeneralPathX gpx = new GeneralPathX();
|
242 |
gpx.moveTo(r.getX(), r.getY()); |
243 |
gpx.lineTo(r.getX()+r.getWidth(), r.getY()); |
244 |
draw(g, scaleInstance, new FPolygon2D(gpx), null); |
245 |
} |
246 |
|
247 |
@Override
|
248 |
public String getClassName() { |
249 |
return getClass().getName();
|
250 |
} |
251 |
|
252 |
@Override
|
253 |
public void setXMLEntity(XMLEntity xml) { |
254 |
setFont(new Font("Arial", Font.PLAIN, 18)); |
255 |
setText("this is my TEST text that follows a line");
|
256 |
setDescription(xml.getStringProperty("desc"));
|
257 |
setIsShapeVisible(xml.getBooleanProperty("isShapeVisible"));
|
258 |
|
259 |
} |
260 |
|
261 |
@Override
|
262 |
public void setText(String text) { |
263 |
this.text = text.toCharArray();
|
264 |
} |
265 |
|
266 |
@Override
|
267 |
public String getText() { |
268 |
return new String(text); |
269 |
} |
270 |
|
271 |
public void setCharacterSpacing(double charSpacing) { |
272 |
this.characterSpacing = charSpacing;
|
273 |
} |
274 |
|
275 |
public void setWordSpacing(double wordSpacing) { |
276 |
this.wordSpacing = wordSpacing;
|
277 |
} |
278 |
|
279 |
public void setAlignment(int alignment) { |
280 |
this.alignment = alignment;
|
281 |
} |
282 |
|
283 |
public void setKerning(boolean kerning) { |
284 |
this.kerning = kerning;
|
285 |
} |
286 |
|
287 |
public void setMargin(double margin) { |
288 |
this.margin = margin;
|
289 |
} |
290 |
|
291 |
public void setRightToLeft(boolean rightToLeft) { |
292 |
this.rightToLeft = rightToLeft;
|
293 |
} |
294 |
|
295 |
public static void main(String[] args) { |
296 |
class Item { |
297 |
int value;
|
298 |
String text;
|
299 |
public Item(int value, String text) { |
300 |
this.value = value;
|
301 |
this.text = text;
|
302 |
} |
303 |
@Override
|
304 |
public String toString() { |
305 |
return text;
|
306 |
} |
307 |
|
308 |
public int getValue() { |
309 |
return value;
|
310 |
} |
311 |
} |
312 |
|
313 |
final int initialWidth = 300; |
314 |
final int initialHeight = 300; |
315 |
|
316 |
final JTextField textField = new JTextField("write your text here"); |
317 |
final JIncrementalNumberField textFontSize = new JIncrementalNumberField(); |
318 |
textFontSize.setDouble(15);
|
319 |
final JIncrementalNumberField textCharSpacing = new JIncrementalNumberField(); |
320 |
textCharSpacing.setDouble(1);
|
321 |
final JIncrementalNumberField textWordSpacing = new JIncrementalNumberField(); |
322 |
textCharSpacing.setDouble(10);
|
323 |
final JCheckBox chkKerning = new JCheckBox("Kerning:"); |
324 |
final JCheckBox chkRightToLeft = new JCheckBox("Rigth to left:"); |
325 |
final JComboBoxFonts cmbFonts = new JComboBoxFonts(); |
326 |
|
327 |
ArrayList<Integer> alignments = new ArrayList<Integer>(); |
328 |
final JComboBox cmbAlign = new JComboBox(new Item[] { |
329 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_LEFT, "LEFT"), |
330 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_RIGHT, "RIGHT"), |
331 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_CENTERED, "CENTER"), |
332 |
new Item(FConstant.SYMBOL_STYLE_TEXTALIGNMENT_JUSTIFY, "JUSTIFY"), |
333 |
}); |
334 |
|
335 |
final JIncrementalNumberField txtMargin = new JIncrementalNumberField(); |
336 |
txtMargin.setDouble(10);
|
337 |
|
338 |
|
339 |
|
340 |
final JFrame f = new JFrame("test Smart Text Symbol"); |
341 |
JPanel content = new JPanel(new BorderLayout(20,20)); |
342 |
GridBagLayoutPanel controlPanel = new GridBagLayoutPanel();
|
343 |
controlPanel.addComponent("Text: ", textField);
|
344 |
controlPanel.addComponent("Font: ", cmbFonts);
|
345 |
controlPanel.addComponent("Font size: ", textFontSize);
|
346 |
controlPanel.addComponent("Char spacing: ", textCharSpacing);
|
347 |
controlPanel.addComponent("Word spacing: ", textWordSpacing);
|
348 |
controlPanel.addComponent("Alignment: ", cmbAlign);
|
349 |
controlPanel.addComponent("Margin: ", txtMargin);
|
350 |
controlPanel.addComponent(chkKerning); |
351 |
controlPanel.addComponent(chkRightToLeft); |
352 |
|
353 |
final SmartTextSymbol sms = new SmartTextSymbol(); |
354 |
|
355 |
content.add(controlPanel, BorderLayout.NORTH);
|
356 |
|
357 |
final JPanel canvas = new JPanel() { |
358 |
private static final long serialVersionUID = 623038680274774722L; |
359 |
|
360 |
@Override
|
361 |
protected void paintComponent(Graphics g) { |
362 |
Graphics2D g2 = (Graphics2D) g; |
363 |
double width = getBounds().getWidth();
|
364 |
double height= getBounds().getHeight();
|
365 |
GeneralPathX gpx = new GeneralPathX();
|
366 |
gpx.moveTo(0.033*width, 0.033*height); |
367 |
gpx.lineTo(0.066*width, 0.5*height); |
368 |
gpx.lineTo(0.5*width, 0.266*height); |
369 |
gpx.lineTo(0.66*width, 0.4*height); |
370 |
gpx.lineTo(0.933*width, 0.733*height); |
371 |
gpx.lineTo(0.933*width, 0.866*height); |
372 |
gpx.lineTo(0.833*width, 0.933*height); |
373 |
gpx.lineTo(0.666*width, 0.933*height); |
374 |
|
375 |
|
376 |
FPolyline2D theLineShape = new FPolyline2D(gpx);
|
377 |
SymbologyFactory.createDefaultLineSymbol().draw(g2, null, theLineShape, null); |
378 |
sms.setFont(new Font((String) cmbFonts.getSelectedItem(), Font.PLAIN, 10)); |
379 |
sms.setFontSize(textFontSize.getDouble()); |
380 |
sms.setText(textField.getText()); |
381 |
sms.setCharacterSpacing(textCharSpacing.getDouble()); |
382 |
sms.setWordSpacing(textWordSpacing.getDouble()); |
383 |
sms.setAlignment(((Item) cmbAlign.getSelectedItem()).getValue()); |
384 |
sms.setKerning(chkKerning.isSelected()); |
385 |
sms.setRightToLeft(chkRightToLeft.isSelected()); |
386 |
sms.setMargin(txtMargin.getDouble()); |
387 |
sms.draw(g2, null, theLineShape, null); |
388 |
} |
389 |
}; |
390 |
|
391 |
ActionListener action = new ActionListener() { |
392 |
public void actionPerformed(ActionEvent e) { |
393 |
f.repaint(); |
394 |
} |
395 |
}; |
396 |
textFontSize.addActionListener(action); |
397 |
textCharSpacing.addActionListener(action); |
398 |
textWordSpacing.addActionListener(action); |
399 |
cmbAlign.addActionListener(action); |
400 |
txtMargin.addActionListener(action); |
401 |
chkKerning.addActionListener(action); |
402 |
chkRightToLeft.addActionListener(action); |
403 |
cmbFonts.addActionListener(action); |
404 |
|
405 |
|
406 |
canvas.setPreferredSize(new Dimension(initialWidth, initialHeight)); |
407 |
canvas.setSize(new Dimension(initialWidth, initialHeight)); |
408 |
content.add(canvas, BorderLayout.CENTER);
|
409 |
f.setContentPane(content); |
410 |
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
411 |
|
412 |
|
413 |
f.pack(); |
414 |
f.setVisible(true);
|
415 |
} |
416 |
|
417 |
} |
418 |
|
419 |
/*
|
420 |
private double factor = 0.4;
|
421 |
private int starPointCount = 5;
|
422 |
|
423 |
public void draw(Graphics2D g, AffineTransform affineTransform, FShape shp,
|
424 |
Cancellable cancel) {
|
425 |
FPoint2D p = (FPoint2D) shp;
|
426 |
g.rotate(getRotation(), p.getX(), p.getY());
|
427 |
double bigRadius = getSize()*0.5 ;
|
428 |
Shape star = createStar((float) p.getX(), (float) p.getY(), (float) bigRadius, (float) (bigRadius*factor), starPointCount);
|
429 |
g.setColor(getColor());
|
430 |
g.fill(star);
|
431 |
g.rotate(-getRotation(), p.getX(), p.getY());
|
432 |
|
433 |
}
|
434 |
|
435 |
private Shape createStar(float centerX, float centerY, float bigRadius, float smallRadius, int starPointCount) {
|
436 |
GeneralPath gp = new GeneralPath();
|
437 |
gp.moveTo(centerX, centerY-bigRadius);
|
438 |
double TWO_PI = Math.PI*2;
|
439 |
double subdivisionTheta = TWO_PI / (2*starPointCount);
|
440 |
for (int i = 1; i <= starPointCount*2; i++) {
|
441 |
double theta = i * subdivisionTheta;
|
442 |
double radius = i % 2 == 0 ? bigRadius : smallRadius;
|
443 |
gp.lineTo(centerX - (float) ( radius*Math.sin(theta)),
|
444 |
centerY - (float) ( radius*Math.cos(theta)));
|
445 |
|
446 |
}
|
447 |
return gp;
|
448 |
}
|
449 |
|
450 |
public ISymbol getSymbolForSelection() {
|
451 |
return this;
|
452 |
}
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
public void setXMLEntity(XMLEntity xml) {
|
459 |
factor = xml.getDoubleProperty("factor");
|
460 |
starPointCount = xml.getIntProperty("starPointCount");
|
461 |
setColor(StringUtilities.string2Color(xml.getStringProperty("color")));
|
462 |
setRotation(xml.getDoubleProperty("rotation"));
|
463 |
setDescription(xml.getStringProperty("desc"));
|
464 |
setSize(xml.getDoubleProperty("size"));
|
465 |
setIsShapeVisible(xml.getBooleanProperty("isShapeVisible"));
|
466 |
setUnit(xml.getIntProperty("unit"));
|
467 |
setReferenceSystem(xml.getIntProperty("referenceSystem"));
|
468 |
}
|
469 |
|
470 |
|
471 |
*/
|