/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2011, 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.swing.dialog; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.Toolkit; import java.awt.Window; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.SwingUtilities; import javax.swing.text.View; /** * Static utility methods for common dialog and GUI related tasks. * * @author Michael Bedward * @since 2.7 * @source $URL$ * @version $Id$ */ public class DialogUtils { /** * Shows a dialog centred on the screen. May be called safely * from any thread. * * @param dialog the dialog */ public static void showCentred(final Window dialog) { showCentredOnParent(null, dialog); } /** * Shows a dialog centred on its parent. May be called safely * from any thread. If {@code parent} is {@code null} the dialog * is centred on the screen. * * @param parent the parent component * @param dialog the dialog */ public static void showCentredOnParent(final Window parent, final Window dialog) { if (EventQueue.isDispatchThread()) { doShowCentred(parent, dialog); } else { EventQueue.invokeLater(new Runnable() { @Override public void run() { doShowCentred(parent, dialog); } }); } } /** * Gets all child components that are, or derive from, the given class. * This method is adapted from the SwingUtils class written by Darryl Burke. * (Accessed from: http://tips4java.wordpress.com/2008/11/13/swing-utils/). * * @param <T> Swing type derived from JComponent * @param clazz the component class * @param parent the parent container * @param includeNested whether to recursively collect nested components * * @return list of child components */ public static <T extends JComponent> List<T> getChildComponents( Class<T> clazz, Container parent, boolean includeNested) { List<T> children = new ArrayList<T>(); for (Component c : parent.getComponents()) { boolean isClazz = clazz.isAssignableFrom(c.getClass()); if (isClazz) { children.add(clazz.cast(c)); } if (includeNested && c instanceof Container) { children.addAll(getChildComponents(clazz, (Container) c, includeNested)); } } return children; } /** * Returns {@code input} if not {@code null} or empty, otherwise returns * {@code fallback}. This is handy for setting dialog titles etc. Note that * the input string is considered empty if {@code input.trim().length() == 0}. * * @param input input string * @param fallback fallback string (may be {@code null}) * * @return {@code input} unless it is {@code null} or empty, in which case * {@code fallback} is returned */ public static String getString(String input, String fallback) { if (input == null || input.trim().length() == 0) { return fallback; } return input; } private static void doShowCentred(Window parent, Window dialog) { if (parent == null) { doCentre(dialog, Toolkit.getDefaultToolkit().getScreenSize()); } else { doCentre(dialog, parent.getSize()); } dialog.setVisible(true); } private static void doCentre(Window dialog, Dimension parentDim) { Dimension dialogDim = dialog.getSize(); int x = Math.max(0, parentDim.width / 2 - dialogDim.width / 2); int y = Math.max(0, parentDim.height / 2 - dialogDim.height / 2); dialog.setLocation(x, y); } /** * Calculates the dimensions that a given text string requires when rendered * as HTML text in a label component. * <p> * The method used is adapted from that described in a blog post by Morten Nobel: * <blockquote> * http://blog.nobel-joergensen.com/2009/01/18/changing-preferred-size-of-a-html-jlabel/ * </blockquote> * * @param labelText the text to render, optionally enclosed in {@code <html>...</html>} tags * @param fixedDimSize the size of the fixed dimension (either width or height * @param width {@code true} if the fixed dimension is width; {@code false} for height * * @return the rendered label text extent */ public static Dimension getHtmlLabelTextExtent(final String labelText, final int fixedDimSize, final boolean width) { final Dimension[] result = new Dimension[1]; if (SwingUtilities.isEventDispatchThread()) { result[0] = doGetHtmlTextExtent(labelText, fixedDimSize, width); } else { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { result[0] = doGetHtmlTextExtent(labelText, fixedDimSize, width); } }); } catch (Exception ex) { // Either an InterruptedException or an InvocationTargetException // both of which are fatal throw new RuntimeException(ex); } } return result[0]; } /** * Helper method for {@linkplain #getHtmlLabelTextExtent(java.lang.String, int, boolean)}. * This is required because we are creating and invisibly rendering a {@code JLabel} * object in this method, and being virtuous in our Swing usage we should only do that * on the event dispatch thread. * * @param labelText the text to render, optionally enclosed in {@code <html>...</html>} tags * @param fixedDimSize the size of the fixed dimension (either width or height * @param width {@code true} if the fixed dimension is width; {@code false} for height * * @return the rendered label text extent */ private static Dimension doGetHtmlTextExtent(String labelText, int fixedDimSize, boolean width) { final JLabel label = new JLabel(); if (labelText.startsWith("<html>")) { label.setText(labelText); } else { label.setText("<html>" + labelText + "</html>"); } View view = (View) label.getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey); view.setSize(width ? fixedDimSize : 0, width? 0 : fixedDimSize); float w = view.getPreferredSpan(View.X_AXIS); float h = view.getPreferredSpan(View.Y_AXIS); return new java.awt.Dimension((int) Math.ceil(w), (int) Math.ceil(h)); } }