001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
005: * (C) 2001, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.resources;
018:
019: // Graphics and geometry
020: import java.awt.Component;
021: import java.awt.Font;
022: import java.awt.Graphics2D;
023: import java.awt.Rectangle;
024: import java.awt.font.FontRenderContext;
025: import java.awt.font.GlyphVector;
026: import java.awt.geom.Rectangle2D;
027: import java.io.PrintWriter;
028: import java.io.StringWriter;
029: import java.util.ArrayList;
030: import java.util.List;
031:
032: import org.geotools.io.ExpandedTabWriter;
033:
034: /**
035: * A set of utilities methods for painting in a {@link Graphics2D} handle.
036: * Method in this class was used to be in {@link org.geotools.gui.swing.ExceptionMonitor}.
037: * We had to extract them in a separated class in order to avoid dependencies of renderer
038: * module toward the GUI one, especially since the extracted methods are not Swing specific.
039: *
040: * @since 2.0
041: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/metadata/src/main/java/org/geotools/resources/GraphicsUtilities.java $
042: * @version $Id: GraphicsUtilities.java 22443 2006-10-27 20:47:22Z desruisseaux $
043: * @author Martin Desruisseaux
044: */
045: public final class GraphicsUtilities {
046: /**
047: * Number of spaces to leave between each tab.
048: */
049: private static final int TAB_WIDTH = 4;
050:
051: /**
052: * The creation of {@code GraphicsUtilities} class objects is forbidden.
053: */
054: private GraphicsUtilities() {
055: }
056:
057: /**
058: * Writes the specified exception trace in the specified graphics
059: * context. This method is useful when an exception has occurred
060: * inside a {@link Component#paint} method and we want to write it
061: * rather than leaving an empty window.
062: *
063: * @param exception Exception whose trace we want to write.
064: * @param graphics Graphics context in which to write exception. The
065: * graphics context should be in its initial state (default affine
066: * transform, default colour, etc...)
067: * @param widgetBounds Size of the trace which was being drawn.
068: */
069: public static void paintStackTrace(final Graphics2D graphics,
070: final Rectangle widgetBounds, final Throwable exception) {
071: /*
072: * Obtains the exception trace in the form of a character chain.
073: * The carriage returns in this chain can be "\r", "\n" or "r\n".
074: */
075: final String message = printStackTrace(exception);
076: /*
077: * Examines the character chain line by line.
078: * "Glyphs" will be created as we go along and we will take advantage
079: * of this to calculate the necessary space.
080: */
081: double width = 0, height = 0;
082: final List glyphs = new ArrayList();
083: final List bounds = new ArrayList();
084: final int length = message.length();
085: final Font font = graphics.getFont();
086: final FontRenderContext context = graphics
087: .getFontRenderContext();
088: for (int i = 0; i < length;) {
089: int ir = message.indexOf('\r', i);
090: int in = message.indexOf('\n', i);
091: if (ir < 0)
092: ir = length;
093: if (in < 0)
094: in = length;
095: final int irn = Math.min(ir, in);
096: final GlyphVector line = font.createGlyphVector(context,
097: message.substring(i, irn));
098: final Rectangle2D rect = line.getVisualBounds();
099: final double w = rect.getWidth();
100: if (w > width)
101: width = w;
102: height += rect.getHeight();
103: glyphs.add(line);
104: bounds.add(rect);
105: i = (Math.abs(ir - in) <= 1 ? Math.max(ir, in) : irn) + 1;
106: }
107: /*
108: * Proceeds to draw all the previously calculated glyphs.
109: */
110: float xpos = (float) (0.5 * (widgetBounds.width - width));
111: float ypos = (float) (0.5 * (widgetBounds.height - height));
112: final int size = glyphs.size();
113: for (int i = 0; i < size; i++) {
114: final GlyphVector line = (GlyphVector) glyphs.get(i);
115: final Rectangle2D rect = (Rectangle2D) bounds.get(i);
116: ypos += rect.getHeight();
117: graphics.drawGlyphVector(line, xpos, ypos);
118: }
119: }
120:
121: /**
122: * Returns an exception trace. All tabs will have been replaced by 4 white spaces.
123: * This method was used to be a private one in {@link org.geotools.gui.swing.ExceptionMonitor}.
124: * Do not rely on it.
125: */
126: public static String printStackTrace(final Throwable exception) {
127: final StringWriter writer = new StringWriter();
128: exception.printStackTrace(new PrintWriter(
129: new ExpandedTabWriter(writer, TAB_WIDTH)));
130: return writer.toString();
131: }
132: }
|