/* Created on Aug 17, 2011 by mschilli ALMA - Atacama Large Millimiter Array (c) European Southern Observatory, 2011 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; either version 2.1 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package alma.acs.gui.util; import java.awt.Frame; import java.awt.Rectangle; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Helper methods for dealing with Java Windows. * * @since August 2011 * @author M.Schilling, ESO */ public class WindowUtil { /* * Code reviewed on 17 Aug 2011 by Rodrigo and Marcus. */ /** * Assigns position and size to a desktop frame from a textual * geometry definition. For allowed formats of geometry definition, * see {@link #parseGeometry(String)}. * * If {@code geometry} is {@code null} or cannot be understood, this call * will do nothing and return {@code false}. * * @param frame - a desktop frame to position and size * @param geometry - a geometry definition string * @return whether the geometry definition was valid and thus applied */ public static boolean applyGeometry (Frame frame, String geometry) { Rectangle rect = null; try { rect = parseGeometry(geometry); } catch (IllegalArgumentException exc) { return false; } if (rect.width <= 0 || rect.height <= 0) { frame.pack(); frame.setLocation (rect.x, rect.y); return true; } frame.setBounds(rect); return true; } /** * Parses a geometry string made up of positional parameters * <i>"width height xpos ypos"</i> or <i>"xpos ypos"</i> (ie. X server format), * or named parameters <i>"x=...,y=...,w=...,h=..."</i>. * <p> * <u>Examples:</u><ul> * <li>400x500+200+300 * <li>+200+300 * <li>x=200, y=300, w=400, h=500 * <li>x=200y=300w=400h=500 * <li>w=400;h=500;x=200;y=300; * </ul> * * Note that negative x/y coordinates (ie. positioning leftwards from the * screen's right border) are not supported. * <p> * This method throws {@code IllegalArgumentException} if the geometry string is invalid. * Using this method and catching that exception provides a simple way of testing a geometry * string before use, e.g. when you are parsing command-line arguments. * <p> * The returned rectangle will contain {@code 0} for any coordinate that was * not defined in the geometry string. This can happen for strings specified in * "X server short notation" (where only x and y are defined), and for strings * specified in "named parameters" notation (if parameters were omitted). * * @param geometry - the geometry as text * @return the geometry as a rectangle * @throws IllegalArgumentException if the argument is null or cannot be parsed */ public static Rectangle parseGeometry (String geometry) throws IllegalArgumentException { /* msc 2011-08: for allowing negative x/y (ie. counting leftwards from the right border) * it is necessary to change "PositiveNumber" below to become "SignedNumber", and * to find out the real screen size in a multi-screen environment (GraphicsEnvironment). * the latter seems to be unpredictable on some machines/platforms, so i'm skipping it. */ if (geometry == null) throw new IllegalArgumentException("Bad geometry: null"); Rectangle r = new Rectangle(); Matcher m; m = p1.matcher (geometry); if (m.matches()) { r.width = asInt(m.group(1)); r.height = asInt(m.group(2)); r.x = asInt(m.group(3)); r.y = asInt(m.group(4)); return r; } m = p2.matcher (geometry); if (m.matches()) { r.x = asInt(m.group(1)); r.y = asInt(m.group(2)); return r; } m = p3.matcher(geometry); if (m.matches()) { for (int i = 1; i <= m.groupCount(); i++) { if (m.group(i).equals("w")) r.width = asInt(m.group(++i)); if (m.group(i).equals("h")) r.height = asInt(m.group(++i)); if (m.group(i).equals("x")) r.x = asInt(m.group(++i)); if (m.group(i).equals("y")) r.y = asInt(m.group(++i)); } return r; } throw new IllegalArgumentException("Bad geometry "+geometry+". Must be "+hr1+" or "+hr2+" or "+hr3); } private final static String Number = "(\\d+)"; private final static String AnyNaN = "\\D*"; private final static String NamVal = "([whxy])=" + Number; private final static String Multiply = "[xX]"; private final static String PositiveNumber = "([\\+]\\d+)"; private final static String hr1 = "WIDTHxHEIGHT+XPOS+YPOS"; private final static Pattern p1 = Pattern.compile (Number + Multiply + Number + PositiveNumber + PositiveNumber); private final static String hr2 = "+XPOS+YPOS"; private final static Pattern p2 = Pattern.compile (PositiveNumber + PositiveNumber); private final static String hr3 = "x=XPOS,y=YPOS,w=WIDTH,h=HEIGHT"; private final static Pattern p3 = Pattern.compile(NamVal + AnyNaN + NamVal + AnyNaN + NamVal + AnyNaN + NamVal + AnyNaN); private static int asInt (String number) { if (number.charAt(0) == '+') // Integer class cannot parse "+" prefix number = number.substring(1); return Integer.parseInt (number); } // ============================================================================ }