View Javadoc

1   /* ============================================================
2    * JRobin : Pure java implementation of RRDTool's functionality
3    * ============================================================
4    *
5    * Project Info:  http://www.jrobin.org
6    * Project Lead:  Sasa Markovic (saxon@jrobin.org)
7    *
8    * Developers:    Sasa Markovic (saxon@jrobin.org)
9    *
10   *
11   * (C) Copyright 2003-2005, by Sasa Markovic.
12   *
13   * This library is free software; you can redistribute it and/or modify it under the terms
14   * of the GNU Lesser General Public License as published by the Free Software Foundation;
15   * either version 2.1 of the License, or (at your option) any later version.
16   *
17   * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18   * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19   * See the GNU Lesser General Public License for more details.
20   *
21   * You should have received a copy of the GNU Lesser General Public License along with this
22   * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23   * Boston, MA 02111-1307, USA.
24   */
25  package org.jrobin.graph;
26  
27  import java.util.ArrayList;
28  import java.util.List;
29  
30  class LegendComposer implements RrdGraphConstants {
31  	private RrdGraphDef gdef;
32  	private ImageWorker worker;
33  	private int legX, legY, legWidth;
34  	private double interlegendSpace;
35  	private double leading;
36  	private double smallLeading;
37  	private double boxSpace;
38  
39  	LegendComposer(RrdGraph rrdGraph, int legX, int legY, int legWidth) {
40  		this.gdef = rrdGraph.gdef;
41  		this.worker = rrdGraph.worker;
42  		this.legX = legX;
43  		this.legY = legY;
44  		this.legWidth = legWidth;
45  		interlegendSpace = rrdGraph.getInterlegendSpace();
46  		leading = rrdGraph.getLeading();
47  		smallLeading = rrdGraph.getSmallLeading();
48  		boxSpace = rrdGraph.getBoxSpace();
49  	}
50  
51  	int placeComments() {
52  		Line line = new Line();
53  		for (CommentText comment : gdef.comments) {
54  			if (comment.isValidGraphElement()) {
55  				if (!line.canAccomodate(comment)) {
56  					line.layoutAndAdvance(false);
57  					line.clear();
58  				}
59  				line.add(comment);
60  			}
61  		}
62  		line.layoutAndAdvance(true);
63  		worker.dispose();
64  		return legY;
65  	}
66  
67  	class Line {
68  		private String lastMarker;
69  		private double width;
70  		private int spaceCount;
71  		private boolean noJustification;
72  		private List<CommentText> comments = new ArrayList<CommentText>();
73  
74  		Line() {
75  			clear();
76  		}
77  
78  		void clear() {
79  			lastMarker = "";
80  			width = 0;
81  			spaceCount = 0;
82  			noJustification = false;
83  			comments.clear();
84  		}
85  
86  		boolean canAccomodate(CommentText comment) {
87  			// always accommodate if empty
88  			if (comments.size() == 0) {
89  				return true;
90  			}
91  			// cannot accommodate if the last marker was \j, \l, \r, \c, \s
92  			if (lastMarker.equals(ALIGN_LEFT_MARKER) || lastMarker.equals(ALIGN_CENTER_MARKER) ||
93  					lastMarker.equals(ALIGN_RIGHT_MARKER) || lastMarker.equals(ALIGN_JUSTIFIED_MARKER) ||
94  					lastMarker.equals(VERTICAL_SPACING_MARKER)) {
95  				return false;
96  			}
97  			// cannot accommodate if line would be too long
98  			double commentWidth = getCommentWidth(comment);
99  			if (!lastMarker.equals(GLUE_MARKER)) {
100 				commentWidth += interlegendSpace;
101 			}
102 			return width + commentWidth <= legWidth;
103 		}
104 
105 		void add(CommentText comment) {
106 			double commentWidth = getCommentWidth(comment);
107 			if (comments.size() > 0 && !lastMarker.equals(GLUE_MARKER)) {
108 				commentWidth += interlegendSpace;
109 				spaceCount++;
110 			}
111 			width += commentWidth;
112 			lastMarker = comment.marker;
113 			noJustification |= lastMarker.equals(NO_JUSTIFICATION_MARKER);
114 			comments.add(comment);
115 		}
116 
117 		void layoutAndAdvance(boolean isLastLine) {
118 			if (comments.size() > 0) {
119 				if (lastMarker.equals(ALIGN_LEFT_MARKER)) {
120 					placeComments(legX, interlegendSpace);
121 				}
122 				else if (lastMarker.equals(ALIGN_RIGHT_MARKER)) {
123 					placeComments(legX + legWidth - width, interlegendSpace);
124 				}
125 				else if (lastMarker.equals(ALIGN_CENTER_MARKER)) {
126 					placeComments(legX + (legWidth - width) / 2.0, interlegendSpace);
127 				}
128 				else if (lastMarker.equals(ALIGN_JUSTIFIED_MARKER)) {
129 					// anything to justify?
130 					if (spaceCount > 0) {
131 						placeComments(legX, (legWidth - width) / spaceCount + interlegendSpace);
132 					}
133 					else {
134 						placeComments(legX, interlegendSpace);
135 					}
136 				}
137 				else if (lastMarker.equals(VERTICAL_SPACING_MARKER)) {
138 					placeComments(legX, interlegendSpace);
139 				}
140 				else {
141 					// nothing specified, align with respect to '\J'
142 					if (noJustification || isLastLine) {
143 						placeComments(legX, interlegendSpace);
144 					}
145 					else {
146 						placeComments(legX, (legWidth - width) / spaceCount + interlegendSpace);
147 					}
148 				}
149 				if (lastMarker.equals(VERTICAL_SPACING_MARKER)) {
150 					legY += smallLeading;
151 				}
152 				else {
153 					legY += leading;
154 				}
155 			}
156 		}
157 
158 		private double getCommentWidth(CommentText comment) {
159 			double commentWidth = worker.getStringWidth(comment.resolvedText, gdef.smallFont);
160 			if (comment instanceof LegendText) {
161 				commentWidth += boxSpace;
162 			}
163 			return commentWidth;
164 		}
165 
166 		private void placeComments(double xStart, double space) {
167 			double x = xStart;
168 			for (CommentText comment : comments) {
169 				comment.x = (int) x;
170 				comment.y = legY;
171 				x += getCommentWidth(comment);
172 				if (!comment.marker.equals(GLUE_MARKER)) {
173 					x += space;
174 				}
175 			}
176 		}
177 	}
178 }