/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2001-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.resources; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.font.FontRenderContext; import java.awt.font.GlyphVector; import java.awt.geom.Rectangle2D; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import org.geotools.io.ExpandedTabWriter; /** * A set of utilities methods for painting in a {@link Graphics2D} handle. * Method in this class was used to be in {@link org.geotools.gui.swing.ExceptionMonitor}. * We had to extract them in a separated class in order to avoid dependencies of renderer * module toward the GUI one, especially since the extracted methods are not Swing specific. * * @since 2.0 * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) */ public final class GraphicsUtilities { /** * Number of spaces to leave between each tab. */ private static final int TAB_WIDTH = 4; /** * The creation of {@code GraphicsUtilities} class objects is forbidden. */ private GraphicsUtilities() { } /** * Writes the specified exception trace in the specified graphics * context. This method is useful when an exception has occurred * inside a {@link java.awt.Component#paint} method and we want to * write it rather than leaving an empty window. * * @param exception Exception whose trace we want to write. * @param graphics Graphics context in which to write exception. The * graphics context should be in its initial state (default affine * transform, default colour, etc...) * @param widgetBounds Size of the trace which was being drawn. */ public static void paintStackTrace(final Graphics2D graphics, final Rectangle widgetBounds, final Throwable exception) { /* * Obtains the exception trace in the form of a character chain. * The carriage returns in this chain can be "\r", "\n" or "r\n". */ final String message = printStackTrace(exception); /* * Examines the character chain line by line. * "Glyphs" will be created as we go along and we will take advantage * of this to calculate the necessary space. */ double width = 0, height = 0; final List<GlyphVector> glyphs = new ArrayList<GlyphVector>(); final List<Rectangle2D> bounds = new ArrayList<Rectangle2D>(); final int length = message.length(); final Font font = graphics.getFont(); final FontRenderContext context = graphics.getFontRenderContext(); for (int i = 0; i < length;) { int ir = message.indexOf('\r', i); int in = message.indexOf('\n', i); if (ir < 0) ir = length; if (in < 0) in = length; final int irn = Math.min(ir, in); final GlyphVector line = font.createGlyphVector(context, message.substring(i, irn)); final Rectangle2D rect = line.getVisualBounds(); final double w = rect.getWidth(); if (w > width) width = w; height += rect.getHeight(); glyphs.add(line); bounds.add(rect); i = (Math.abs(ir - in) <= 1 ? Math.max(ir, in) : irn) + 1; } /* * Proceeds to draw all the previously calculated glyphs. */ float xpos = (float) (0.5 * (widgetBounds.width - width)); float ypos = (float) (0.5 * (widgetBounds.height - height)); final int size = glyphs.size(); for (int i = 0; i < size; i++) { final GlyphVector line = glyphs.get(i); final Rectangle2D rect = bounds.get(i); ypos += rect.getHeight(); graphics.drawGlyphVector(line, xpos, ypos); } } /** * Returns an exception trace. All tabs will have been replaced by 4 white spaces. * This method was used to be a private one in {@link org.geotools.gui.swing.ExceptionMonitor}. * Do not rely on it. */ public static String printStackTrace(final Throwable exception) { final StringWriter writer = new StringWriter(); exception.printStackTrace(new PrintWriter(new ExpandedTabWriter(writer, TAB_WIDTH))); return writer.toString(); } }