001: package net.refractions.udig.legend.ui;
002:
003: import java.awt.Color;
004: import java.awt.Dimension;
005: import java.awt.Point;
006: import java.awt.Rectangle;
007: import java.awt.geom.Rectangle2D;
008: import java.awt.image.BufferedImage;
009: import java.awt.image.RenderedImage;
010: import java.util.ArrayList;
011: import java.util.Collections;
012: import java.util.List;
013: import java.util.Map;
014:
015: import net.refractions.udig.mapgraphic.MapGraphic;
016: import net.refractions.udig.mapgraphic.MapGraphicContext;
017: import net.refractions.udig.mapgraphic.internal.MapGraphicResource;
018: import net.refractions.udig.project.IBlackboard;
019: import net.refractions.udig.project.ILayer;
020: import net.refractions.udig.project.internal.Layer;
021: import net.refractions.udig.project.internal.StyleBlackboard;
022: import net.refractions.udig.project.ui.internal.LayerGeneratedGlyphDecorator;
023: import net.refractions.udig.ui.PlatformGIS;
024: import net.refractions.udig.ui.graphics.AWTGraphics;
025: import net.refractions.udig.ui.graphics.ViewportGraphics;
026:
027: import org.eclipse.swt.graphics.Image;
028: import org.geotools.styling.FeatureTypeStyle;
029: import org.geotools.styling.Rule;
030: import org.geotools.styling.Style;
031:
032: public class LegendGraphic implements MapGraphic {
033:
034: private int verticalMargin; //distance between border and icons/text
035: private int horizontalMargin; //distance between border and icons/text
036: private int verticalSpacing; //distance between layers
037: private int horizontalSpacing; //space between image and text
038: private Color foregroundColour;
039: private Color backgroundColour;
040: private Point location;
041: private int indentSize;
042: private int imageWidth;
043: private int imageHeight; //size of image
044: private int maxHeight;
045: private int maxWidth;
046:
047: public void draw(MapGraphicContext context) {
048:
049: IBlackboard blackboard = context.getLayer()
050: .getStyleBlackboard();
051: LegendStyle legendStyle = (LegendStyle) blackboard
052: .get(LegendStyleContent.ID);
053:
054: if (legendStyle == null) {
055: legendStyle = LegendStyleContent.createDefault();
056: blackboard.put(LegendStyleContent.ID, legendStyle);
057: }
058:
059: this .backgroundColour = legendStyle.backgroundColour;
060: this .foregroundColour = legendStyle.foregroundColour;
061: this .horizontalMargin = legendStyle.horizontalMargin;
062: this .verticalMargin = legendStyle.verticalMargin;
063: this .horizontalSpacing = legendStyle.horizontalSpacing;
064: this .verticalSpacing = legendStyle.verticalSpacing;
065: this .indentSize = legendStyle.indentSize;
066: this .imageHeight = legendStyle.imageHeight;
067: this .imageWidth = legendStyle.imageWidth;
068: this .maxHeight = legendStyle.maxHeight;
069: this .maxWidth = legendStyle.maxWidth;
070:
071: final ViewportGraphics graphics = context.getGraphics();
072:
073: List<Map<ILayer, FeatureTypeStyle>> layers = new ArrayList<Map<ILayer, FeatureTypeStyle>>();
074:
075: int longestRow = 0; //used to calculate the width of the graphic
076: final int[] numberOfEntries = new int[1]; //total number of entries to draw
077: numberOfEntries[0] = 0;
078: /*
079: * Set up the layers that we want to draw so we can operate just on
080: * those ones. Layers at index 0 are on the bottom of the map, so we
081: * must iterate in reverse.
082: *
083: * While we are doing this, determine the longest row so we can properly
084: * draw the graphic's border.
085: */
086: for (int i = context.getMapLayers().size() - 1; i >= 0; i--) {
087: ILayer layer = context.getMapLayers().get(i);
088: if (!(layer.getGeoResource() instanceof MapGraphicResource)
089: && layer.isVisible()) {
090:
091: //String layerName = LayerGeneratedGlyphDecorator.generateLabel((Layer) layer);
092: String layerName = layer.getName();
093: if (layerName != null && layerName.length() != 0) {
094:
095: FeatureTypeStyle style = locateStyle(layer);
096:
097: if (style != null && style.getRules() != null
098: && style.getRules().length > 0) {
099: numberOfEntries[0] += style.getRules().length;
100:
101: for (Rule rule : style.getRules()) {
102: String text = getText(rule);
103: Rectangle2D bounds = graphics
104: .getStringBounds(text);
105: int length = indentSize + imageWidth
106: + horizontalSpacing
107: + (int) bounds.getWidth();
108:
109: if (length > longestRow) {
110: longestRow = length;
111: }
112: }
113: } else if (!layer.hasResource(MapGraphic.class)) {
114: //TODO for other layer types
115: continue;
116: } else {
117: continue;
118: }
119:
120: Map<ILayer, FeatureTypeStyle> map = Collections
121: .singletonMap(layer, style);
122: layers.add(map);
123: numberOfEntries[0]++; //add a line for the layer label
124: Rectangle2D bounds = graphics
125: .getStringBounds(layerName);
126: int length = (int) bounds.getWidth();
127: if (style != null && style.getRules().length < 2) {
128: length += imageWidth + horizontalSpacing;
129: }
130:
131: if (length > longestRow) {
132: longestRow = length;
133: }
134: }
135: }
136: }
137:
138: if (numberOfEntries[0] == 0) {
139: //nothing to draw!
140: return;
141: }
142:
143: final int rowHeight = Math.max(imageHeight, graphics
144: .getFontHeight()); //space allocated to each layer
145:
146: //total width of the graphic
147: int width = longestRow + horizontalMargin * 2;
148: if (maxWidth > 0) {
149: width = Math.min(width, maxWidth);
150: }
151: //total height of the graphic
152: int height = rowHeight * numberOfEntries[0] + verticalMargin
153: * 2 + verticalSpacing * (numberOfEntries[0] - 1);
154: if (maxHeight > 0) {
155: height = Math.min(height, maxHeight);
156: }
157:
158: //HACK FIXME make this customizable
159: Dimension displaySize = context.getMapDisplay()
160: .getDisplaySize();
161: location = new Point(displaySize.width - width - 5,
162: displaySize.height - height - 5);
163:
164: graphics.setClip(new Rectangle(location.x, location.y,
165: width + 1, height + 1));
166:
167: /*
168: * Draw the box containing the layers/icons
169: */
170: drawOutline(graphics, width, height);
171:
172: /*
173: * Draw the layer names/icons
174: */
175: final int[] rowsDrawn = new int[1];
176: rowsDrawn[0] = 0;
177: final int[] x = new int[1];
178: x[0] = location.x + horizontalMargin;
179: final int[] y = new int[1];
180: y[0] = location.y + verticalMargin;
181: for (int i = 0; i < layers.size(); i++) {
182: Map map = layers.get(i);
183: final Layer layer = (Layer) map.keySet().iterator().next();
184: final FeatureTypeStyle style = (FeatureTypeStyle) map
185: .values().iterator().next();
186:
187: //String layerName = LayerGeneratedGlyphDecorator.generateLabel((Layer) layer);
188: final String layerName = layer.getName();
189:
190: PlatformGIS.syncInDisplayThread(new Runnable() {
191: public void run() {
192: if (style != null && style.getRules().length > 1) {
193: drawRow(graphics, x[0], y[0], null, layerName,
194: false);
195:
196: y[0] += rowHeight;
197: if ((rowsDrawn[0] + 1) < numberOfEntries[0]) {
198: y[0] += verticalSpacing;
199: }
200: rowsDrawn[0]++;
201: for (Rule rule : style.getRules()) {
202: Image swtIcon = LayerGeneratedGlyphDecorator
203: .generateStyledIcon(layer, rule)
204: .createImage();
205: BufferedImage awtIcon = AWTGraphics
206: .toAwtImage(swtIcon.getImageData());
207:
208: drawRow(graphics, x[0], y[0], awtIcon,
209: getText(rule), true);
210:
211: y[0] += rowHeight;
212: if ((rowsDrawn[0] + 1) < numberOfEntries[0]) {
213: y[0] += verticalSpacing;
214: }
215: rowsDrawn[0]++;
216: }
217: } else {
218: Image swtIcon = LayerGeneratedGlyphDecorator
219: .generateIcon(layer).createImage();
220: BufferedImage awtIcon = AWTGraphics
221: .toAwtImage(swtIcon.getImageData());
222:
223: drawRow(graphics, x[0], y[0], awtIcon,
224: layerName, false);
225:
226: y[0] += rowHeight;
227: if ((rowsDrawn[0] + 1) < numberOfEntries[0]) {
228: y[0] += verticalSpacing;
229: }
230: rowsDrawn[0]++;
231: }
232:
233: }
234: });
235: }
236: }
237:
238: private String getText(Rule rule) {
239: String text = ""; //$NON-NLS-1$
240: if (!"".equals(rule.getTitle())) { //$NON-NLS-1$
241: text = rule.getTitle();
242: } else if (!"".equals(rule.getName())) { //$NON-NLS-1$
243: text = rule.getName();
244: } else {
245: text = rule.getFilter().toString();
246: }
247: if (text.length() > 19) {
248: return text.substring(0, 18) + "..."; //$NON-NLS-1$
249: } else {
250: return text;
251: }
252: }
253:
254: private void drawRow(ViewportGraphics graphics, int x, int y,
255: RenderedImage icon, String text, boolean indent) {
256:
257: Rectangle2D stringBounds = graphics.getStringBounds(text);
258:
259: /*
260: * Center the smaller item (text or icon) according to the taller one.
261: */
262: int textVerticalOffset = 0;
263: int iconVerticalOffset = 0;
264: if (imageHeight == (int) stringBounds.getHeight()) {
265: //items are the same height; do nothing.
266: } else if (imageHeight > (int) stringBounds.getHeight()) {
267: int difference = imageHeight
268: - (int) stringBounds.getHeight();
269: textVerticalOffset = difference / 2;
270: } else if (imageHeight < (int) stringBounds.getHeight()) {
271: int difference = (int) stringBounds.getHeight()
272: - imageHeight;
273: iconVerticalOffset = difference / 2;
274: }
275:
276: if (indent) {
277: x += indentSize;
278: }
279:
280: if (icon != null) {
281: graphics.drawImage(icon, x, y + iconVerticalOffset);
282:
283: x += imageWidth;
284: }
285:
286: if (text != null || text.length() != 0) {
287: graphics.drawString(text, x + horizontalMargin, y
288: + graphics.getFontAscent() + textVerticalOffset,
289: ViewportGraphics.ALIGN_LEFT,
290: ViewportGraphics.ALIGN_LEFT);
291: }
292: }
293:
294: private FeatureTypeStyle locateStyle(ILayer layer) {
295: StyleBlackboard blackboard = (StyleBlackboard) layer
296: .getStyleBlackboard();
297: if (blackboard == null) {
298: return null;
299: }
300:
301: Style sld = (Style) blackboard.lookup(Style.class);
302: if (sld == null) {
303: return null;
304: }
305:
306: FeatureTypeStyle firstBlankStyle = null;
307: for (FeatureTypeStyle style : sld.getFeatureTypeStyles()) {
308: //HACK FIXME problem with SLD parser (type name "Feature")
309: if (style.getFeatureTypeName() == null
310: || style.getFeatureTypeName().equals("Feature")) { //$NON-NLS-1$
311: if (firstBlankStyle == null) {
312: firstBlankStyle = style;
313: }
314: } else {
315: if (layer.getSchema() != null
316: && layer.getSchema().getTypeName() != null) {
317: if (layer.getSchema().getTypeName().equals(
318: style.getFeatureTypeName())) {
319: //Direct match!
320: return style;
321: }
322: }
323: }
324: }
325: return firstBlankStyle;
326: }
327:
328: private void drawOutline(ViewportGraphics graphics, int width,
329: int height) {
330: Rectangle outline = new Rectangle(location.x, location.y,
331: width, height);
332:
333: graphics.setColor(backgroundColour);
334: graphics.fill(outline);
335:
336: graphics.setColor(foregroundColour);
337: graphics.setBackground(backgroundColour);
338: graphics.draw(outline);
339: }
340: }
|