Source code: jplot/GraphLabel.java
1 /*
2 * JPLOT -- Java Plotting Interface for any programme or
3 * as an independent GUI
4 *
5 * Copyright (C) 1999-2000 Jan van der Lee
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 *
22 * Send bugs, suggestions or queries to <jplot@cig.ensmp.fr>
23 * The latest releases are found at
24 * http://www.cig.ensmp.fr/~vanderlee/jplot.html
25 *
26 * Initally developed for use by the Centre d'Informatique Geologique
27 * Ecole des Mines de Paris, Fontainebleau, France.
28 */
29
30 package jplot;
31
32 import java.awt.font.*;
33 import java.awt.*;
34 import java.text.*;
35 import javax.swing.*;
36 import java.util.*;
37 import java.io.*;
38
39 /**
40 * This class defines a label in terms of the actual text, font, color
41 * and position but also stuff like rotation, whether to hide or show etc.
42 * Some special treatment for standard X, Y labels and a title. Random labels
43 * are considered to be of type OTHER, which places them, by default, in the
44 * lower-left corner of the graph.
45 *
46 * Extends Rectangle, since a label has a rectangular bounding box,
47 * used to select, drag and drop the label. Note that the bounding box
48 * is defined by the upper-left corner, width (to the right) and
49 * height (directed towards the bottom).
50 */
51 public class GraphLabel {
52
53 static final int UNKNOWN=-1;
54 static final int XLABEL=0; // X label for a 2D graph
55 static final int YLABEL=1; // Y label for a 2D graph
56 static final int TITLE=2; // title for a 2D graph
57 static final int PIPER_X1=3; // first X label for a piper diagram
58 static final int PIPER_X2=4; // second X label for a piper diagram
59 static final int PIPER_Y1=5; // lower-left Y label for a piper diagram
60 static final int PIPER_Y2=6; // lower-right Y label for a piper diagram
61 static final int PIPER_Y3=7; // upper-left Y label for a piper diagram
62 static final int PIPER_Y4=8; // upper-right Y label for a piper diagram
63 static final int DATA=9; // labels defined by the data x,y coordinates
64 static final int OTHER=10; // random labels
65 static final int CHECK=11; // DATA labels which must be checked
66
67
68 private String text;
69 private Font font;
70 private Color color;
71 private boolean active;
72 private boolean usePos;
73 private FontMetrics fm;
74 private double rotation;
75 private int whoAmI;
76 private double xPos; // x-position of the text
77 private double yPos; // y-position of the text
78 private double bbX; // x-position of the bounding box
79 private double bbY; // x-position of the bounding box
80 private double textWidth;
81 private double textHeight;
82 private double bbWidth;
83 private double bbHeight;
84 private double sin,cos;
85 private AttributedString attributedString;
86 private File file; // label belongs to this file
87 private boolean hideLabel;
88
89 private final String lf = System.getProperty("line.separator");
90
91 /**
92 * Constructor, sets the text of the label.
93 * @param t type of this label
94 * @param s text of the label
95 * @param f font of the label
96 * @param c text color of the label
97 */
98 public GraphLabel(int t, String s, Font f, Color c) {
99 font = f;
100 color = c;
101 usePos = false;
102 active = false;
103 rotation = 0.0;
104 sin = 0.0;
105 hideLabel = false;
106 cos = 1.0;
107 xPos = yPos = 0.0;
108 bbX = bbY = 0.0;
109 bbWidth = bbHeight = 0.0;
110 file = null;
111 setID(t); // might change rotate if it is an YLABEL
112 setFont(f);
113 setText(s); // should be at the end
114 }
115
116 /*
117 * Sets the size of the bounding box.
118 * Note that this doesn't work perfectly well since rotated text
119 * is set closer together, at least in the current jvm (1.3).
120 * Hence we have to introduce some ugly empirical corrections.
121 */
122 private void setBoundingBox() {
123 if (rotation != 0.0) {
124 setSize(textWidth*cos + textHeight*sin,
125 textHeight*cos + textWidth*sin);
126 }
127 else setSize(textWidth,textHeight);
128 }
129
130 /*
131 * Determine the font metrics of the current text.
132 * Wouldn't it be nice if I could get the font-metrics of
133 * the text *without* this ugly memory allocation???
134 */
135 private void setTextMetrics() {
136 if (text != null && !text.equals("")) {
137 attributedString = new AttributedString(text);
138 attributedString.addAttribute(TextAttribute.FONT,font);
139 if (fm == null) fm = (new JPanel()).getFontMetrics(font);
140 textWidth = fm.stringWidth(text);
141 textHeight = fm.getHeight();
142 setBoundingBox();
143 }
144 else textWidth = textHeight = 0.0;
145 }
146
147 /**
148 * Constructor, sets the text of the label.
149 * @param s new text of the label
150 */
151 public GraphLabel(int t, String s) {
152 this(t,s,Utils.getDefaultFont(),Color.black);
153 }
154
155 /**
156 * Constructor, sets the text of the label.
157 * @param s new text of the label
158 */
159 public GraphLabel(String s) {
160 this(UNKNOWN,s);
161 }
162
163 /**
164 * Constructor, sets the ID of the label but no text.
165 * @param t ID of the label
166 */
167 public GraphLabel(int t) {
168 this(t,"");
169 }
170
171 /**
172 * Constructor, does nothing but initializing.
173 */
174 public GraphLabel() {
175 this("");
176 }
177
178 /**
179 * Constructor, builds the class with another graph label.
180 */
181 public GraphLabel(GraphLabel gl) {
182 copy(gl);
183 }
184
185 /**
186 * Constructor, builds the class with another graph label.
187 */
188 public void copy(GraphLabel gl) {
189 bbX = gl.getX();
190 bbY = gl.getY();
191 bbWidth = gl.getWidth();
192 bbHeight = gl.getHeight();
193 active = gl.isActive();
194 usePos = gl.usePosition();
195 setRotation(gl.getRotation());
196 setID(gl.getID());
197 hideLabel = gl.hide();
198 xPos = gl.getXPos();
199 yPos = gl.getYPos();
200 textWidth = gl.getTextWidth();
201 textHeight = gl.getTextHeight();
202 file = gl.getFile();
203 setFont(new Font(gl.getFont().getName(),
204 gl.getFont().getStyle(),gl.getFont().getSize()));
205 color = new Color(gl.getColor().getRed(),
206 gl.getColor().getGreen(),gl.getColor().getBlue());
207 setText(gl.getText());
208 }
209
210 /**
211 * Sets the text of the label to something new.
212 * @param s new text for the label
213 */
214 public void setText(String s) {
215 text = s;
216 setTextMetrics();
217 setLocation(bbX,bbY);
218 }
219
220 /**
221 * @returns the current text of the label
222 */
223 public String getText() {
224 return text;
225 }
226
227 /**
228 * @returns an attributedCharacterIterator instance of the
229 * current text
230 */
231 public AttributedCharacterIterator getCharIterator() {
232 return attributedString.getIterator();
233 }
234
235 /**
236 * Sets the color to a specific value
237 * @param c color used to draw the label
238 */
239 public void setColor(Color c) {
240 color = c;
241 }
242
243 /**
244 * @return the color used to draw the label
245 */
246 public Color getColor() {
247 return color;
248 }
249
250 /**
251 * Sets the font to a specific value
252 * @param f font used to draw the label
253 */
254 public void setFont(Font f) {
255 font = f;
256 fm = (new JPanel()).getFontMetrics(font);
257 setTextMetrics();
258 }
259
260 /**
261 * Sets the font to a specific value
262 * @return the font used to draw the label
263 */
264 public Font getFont() {
265 return font;
266 }
267
268 /**
269 * @param b true if the user starts to draw the label
270 */
271 public void setActive(boolean b) {
272 active = b;
273 }
274
275 /**
276 * @return true if the label is actually being drawn by the mouse
277 */
278 public boolean isActive() {
279 return active;
280 }
281
282 /**
283 * Allows the user to used the current x- and y-positions,
284 * will use default positions otherwise
285 * @param b true if the positions should be used
286 */
287 public void setUsePosition(boolean b) {
288 usePos = b;
289 }
290
291 /**
292 * @return true if the positions should be used
293 */
294 public boolean usePosition() {
295 return usePos;
296 }
297
298 /**
299 * @return true if we should hide this label (do not show)
300 */
301 public boolean hide() {
302 return hideLabel;
303 }
304
305 /**
306 * sets the hide attribute of this label
307 * @param h flag, true if the label should'nt show
308 */
309 public void hide(boolean h) {
310 hideLabel = h;
311 }
312
313 /**
314 * returns true if the current label corresponds to one of
315 * the pre-defined label types (X-label, Y-label etc).
316 * @param type type to compare with (must be an int)
317 * @return true if 'type' corresponds to the current 'whoAmI'
318 */
319 public boolean equals(int type) {
320 return (type == whoAmI);
321 }
322
323 /**
324 * returns true if the current label corresponds to one of
325 * the pre-defined label types (X-label, Y-label etc).
326 * @param name name to compare with (must be a string)
327 * @return true if 'name' corresponds to the current label text
328 */
329 public boolean equals(String name) {
330 return text.equals(name);
331 }
332
333 /**
334 * Sets the current identity of the label to some specific value
335 * The idientity must be an int and, in principle, something predefined
336 * such as GraphLabel.XLABEL).
337 * @param type type of the current label
338 */
339 public void setID(int type) {
340 whoAmI = type;
341 }
342
343 /**
344 * @return the current identity of the label to some specific value.
345 */
346 public int getID() {
347 return whoAmI;
348 }
349
350 /**
351 * Sets the rotation angle.
352 * @param r angle for this label
353 */
354 public void setDataRotation(double r) {
355 rotation = r;
356 }
357
358 /**
359 * Sets the rotation angle. Although all kind of angles (in PI-units)
360 * are allowed, internally we only use the interval 0-2pi hence we
361 * take care of all other cases.
362 * @param r angle for this label
363 */
364 public void setRotation(double r) {
365 rotation = r;
366 while (rotation < 0.0) rotation += 2.0*Math.PI;
367 while (rotation > 2.0*Math.PI) rotation -= 2.0*Math.PI;
368 if (rotation != 0.0) {
369 sin = Math.abs(Math.sin(rotation));
370 cos = Math.abs(Math.cos(rotation));
371 }
372 else {
373 sin = 0.0;
374 cos = 1.0;
375 }
376 setBoundingBox();
377 setLocation(bbX,bbY);
378 }
379
380 /**
381 * Returns the rotation angle.
382 * @return angle for this label
383 */
384 public double getRotation() {
385 return rotation;
386 }
387
388 /**
389 * This function also sets the text location of the label text
390 * itself, slightly different from the x,y position of the box.
391 * Optimize this function since it is used for drag'n drop.
392 *
393 * @param x x-position of the lower-left corner of the text
394 * @param y y-position of the lower-left corner of the text
395 */
396 public void setLocation(double x, double y) {
397 bbX = x;
398 bbY = y;
399 if (rotation <= Math.PI/2.0) {
400 xPos = x;
401 yPos = y + textHeight*cos;
402 }
403 else if (rotation <= Math.PI) {
404 xPos = x + getWidth() - textHeight*sin;
405 yPos = y;
406 }
407 else if (rotation <= 3.0*Math.PI/2.0) {
408 xPos = x + getWidth() - textHeight*sin;
409 yPos = y + getHeight() - textHeight*cos;
410 }
411 else if (rotation <= 2.0*Math.PI) {
412 xPos = x + textHeight*sin;
413 yPos = y + getHeight();
414 }
415 }
416
417 /**
418 * Sets the location of this label in data coordinates.
419 * Ones set this way, you cannot plot the label, it must first
420 * define the location in pixel-coordinates (setLocation(x,y));
421 * @param x x-position of the lower-left corner of the text
422 * @param y y-position of the lower-left corner of the text
423 */
424 public void setDataLocation(double x, double y) {
425 xPos = x;
426 yPos = y;
427 }
428
429 /**
430 * Returns the X position of the text.
431 * @return the x-position of the text
432 */
433 public double getXPos() {
434 return xPos;
435 }
436
437 /**
438 * Returns the Y position of the text.
439 * @return the y-position of the text
440 */
441 public double getYPos() {
442 return yPos;
443 }
444
445 /**
446 * Returns the X position of the bounding box.
447 * @return the x-position of the bounding box
448 */
449 public double getX() {
450 return bbX;
451 }
452
453 /**
454 * Returns the Y position of the bounding box.
455 * @return the y-position of the bounding box
456 */
457 public double getY() {
458 return bbY;
459 }
460
461 /**
462 * Sets the size of the bounding box:
463 * @param w width of the bb
464 * @param h height of the bb
465 */
466 public void setSize(double w, double h) {
467 bbWidth = w;
468 bbHeight = h;
469 }
470
471 /**
472 * Sets the size of the text-label:
473 * @param w width of the label
474 * @param h height of the label
475 */
476 public void setTextSize(double w, double h) {
477 textWidth = w;
478 textHeight = h;
479 }
480
481 /**
482 * Returns the width of the bounding box of the label
483 * @return the width of the bounding box
484 */
485 public double getWidth() {
486 return bbWidth;
487 }
488
489 /**
490 * Returns the height of the bounding box of the label
491 * @return the height of the bounding box
492 */
493 public double getHeight() {
494 return bbHeight;
495 }
496
497 /**
498 * Returns the width of the text of the label
499 * @return the width of the text
500 */
501 public double getTextWidth() {
502 return textWidth;
503 }
504
505 /**
506 * Returns the height of the text of the label
507 * @return the height of the text
508 */
509 public double getTextHeight() {
510 return textHeight;
511 }
512
513 /**
514 * @return the file to which the label belongs
515 */
516 public File getFile() {
517 return file;
518 }
519
520 /**
521 * Sets the file to which the label belongs. Can be null.
522 * @param f file to which the label belongs
523 */
524 public void setFile(File f) {
525 file = f;
526 }
527
528 /**
529 * @return a string representation of this label, the text.
530 */
531 public String toString() {
532 return text;
533 }
534
535 /**
536 * Checks whether x,y falls within the bounding box of the
537 * current text.
538 * @param x x-position
539 * @param y y-position
540 * @return true if the point x,y falls withing the bounding box.
541 */
542 public boolean contains(double x, double y) {
543 return (x>bbX && x<bbX+bbWidth && y>bbY && y<bbY+bbHeight);
544 }
545
546 /**
547 * Returns the settings of the current label in a string.
548 * Calling this method creates a string containing the name
549 * and settings of the current label in string-format, formatted
550 * such that it can directly be used for a script file.
551 * @return the settings of the current label in a string.
552 */
553 public String getSettings() {
554 StringBuffer sb = new StringBuffer(200);
555 sb.append(lf);
556 sb.append(" label \"" + text + "\" {");
557 sb.append(lf);
558 sb.append(" whoami = ").append(whoAmI);
559 sb.append(lf);
560 sb.append(" color = ").append(color.getRed()).append(",");
561 sb.append(color.getGreen()).append(",").append(color.getBlue());
562 sb.append(lf);
563 sb.append(" font ").append(" = \"").append(font.getName()).append("\",");
564 sb.append(font.getStyle()).append(",").append(font.getSize());
565 if (usePos) {
566 sb.append(lf);
567 sb.append(" location = ").append((int)bbX).append(",");
568 sb.append((int)bbY);
569 }
570 sb.append(lf);
571 sb.append(" rotation = ").append(rotation/Math.PI*180.0);
572 sb.append(lf).append(" }");
573 return sb.toString();
574 }
575
576 }