// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/gui/OpenMapFrame.java,v $ // $RCSfile: OpenMapFrame.java,v $ // $Revision: 1.13 $ // $Date: 2006/02/27 15:11:34 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.gui; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Toolkit; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.beans.beancontext.BeanContext; import java.beans.beancontext.BeanContextChild; import java.beans.beancontext.BeanContextChildSupport; import java.beans.beancontext.BeanContextMembershipEvent; import java.beans.beancontext.BeanContextMembershipListener; import java.util.Iterator; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JMenuBar; import com.bbn.openmap.Environment; import com.bbn.openmap.I18n; import com.bbn.openmap.MapHandler; import com.bbn.openmap.PropertyConsumer; import com.bbn.openmap.util.PropUtils; /** * The OpenMapFrame is the application window frame that holds the MapPanel, and * eventually the MapBean. It listens to the MapHandler for the addition of * Beans to the MapHandler BeanContext, and then positions the widgets it can * deal with within itself. The frame does not present itself until an MapPanel * is found. * * <p> * The OpenMapFrame is intended to be used in an application environment. The * applet checks and code to handle the applet environment was moved to the * OpenMapApplet class. */ public class OpenMapFrame extends JFrame implements BeanContextMembershipListener, BeanContextChild, PropertyConsumer { public static Logger logger = Logger.getLogger("com.bbn.openmap.gui.OpenMapFrame"); /** Starting X coordinate of window, x */ public static final String xProperty = "x"; /** Starting Y coordinate of window, y */ public static final String yProperty = "y"; /** * The property to set the pixel width of the frame, width. */ public static final String WidthProperty = "Width"; /** * The property to set the pixel height of the frame, height. */ public static final String HeightProperty = "Height"; /** * The property to set the title of the frame, title. */ public static final String TitleProperty = "Title"; /** * useAsInternalFrameRootPaneIfNecessary will tell the OpenMapFrame to set * its root pane as the Environment's desktop if the Environment has been * told to use internal frames, and if a root pane hasn't been set. True by * default. */ protected boolean useAsInternalFrameRootPaneIfNecessary = true; /** * BeanContextChildSupport object provides helper functions for * BeanContextChild interface. */ private BeanContextChildSupport beanContextChildSupport = new BeanContextChildSupport(); protected String propertyPrefix; protected int frameLocX = -1; protected int frameLocY = -1; protected int frameWidth = Integer.MAX_VALUE; protected int frameHeight = Integer.MAX_VALUE; /** * All OMComponentPanels have access to an I18n object, which is provided by * the Environment. */ protected I18n i18n = Environment.getI18n(); /** * Create the frame with "OpenMap <version>" in the title. */ public OpenMapFrame() { this(""); } /** * @param useAsInternalFrameRootPaneIfNecessary will tell the OpenMapFrame * to set its root pane as the Environment's desktop if the * Environment has been told to use internal frames, and if a root * pane hasn't been set. */ public OpenMapFrame(boolean useAsInternalFrameRootPaneIfNecessary) { this(Environment.get(Environment.Title), useAsInternalFrameRootPaneIfNecessary); } /** * Create a OpenMap frame with a title. * * @param title The Frame title. */ public OpenMapFrame(String title) { this(title, true); } /** * Create a OpenMap frame with a title, with a WindowListner that says what * to do when the OpenMapFrame is closed. * * @param title The Frame title. * @param useAsInternalFrameRootPaneIfNecessary will tell the OpenMapFrame * to set its root pane as the Environment's desktop if the * Environment has been told to use internal frames, and if a root * pane hasn't been set. */ public OpenMapFrame(String title, boolean useAsInternalFrameRootPaneIfNecessary) { super(title); this.useAsInternalFrameRootPaneIfNecessary = useAsInternalFrameRootPaneIfNecessary; } /** * For applications, checks where the properties says the window should be * placed, and then uses the packed height and width to make adjustments. */ protected void setPosition() { setPosition(getWidth(), getHeight()); } protected void setPosition(int w, int h) { // get starting width and height pack(); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); logger.fine("Screen dimensions are " + d); if (w > d.width) w = d.width - d.width / 10; if (h > d.height) h = d.height - d.height / 10; if (frameLocX < 0) frameLocX = d.width / 2 - w / 2; if (frameLocY < 0) frameLocY = d.height / 2 - h / 2; if (logger.isLoggable(Level.FINE)) { logger.fine("Setting window bounds from " + frameLocX + ", " + frameLocY + " for size " + w + ", " + h); } // compose the frame, but don't show it here // contentPane.setBounds(x, y, w, h); setBounds(frameLocX, frameLocY, w, h); } /** * Called when the OpenMapFrame is added to a BeanContext, and when other * objects are added to the BeanContext. The OpenMapFrame looks for objects * that it knows how to place upon itself (MapPanel, JMenuBar). The * OpenMapFrame does not check to see if the objects looked for are already * added to itself. It assumes that if some object type is getting added to * it, the caller must know what they are doing - just like a regular * JFrame. * * @param it Iterator to use to go through the BeanContext objects. */ public void findAndInit(Iterator<?> it) { while (it.hasNext()) { findAndInit(it.next()); } } /** * Called when an object is added to the MapHandler. */ public void findAndInit(Object someObj) { considerForContent(someObj); // We shouldn't find this if we've already defined one // in the MapPanel, but we have this for backward // compatibility. if (someObj instanceof JMenuBar) { logger.fine("OpenMapFrame: Found a MenuBar"); getRootPane().setJMenuBar((JMenuBar) someObj); invalidate(); } } /** * Method used to determine if an object should be added as content. Method * is here to make it easier for subclasses to override and add what they * want to content pane. * * @param someObj */ public void considerForContent(Object someObj) { if (someObj instanceof MapPanel && someObj instanceof Component && getContentPane().getComponentCount() == 0) { logger.fine("Found a MapPanel"); setContent((Component) someObj); } } /** * Called with the MapPanel to be set in the Content Pane of this Frame. If * a MapPanel, a JMenuBar will be retrieved and added as well. * * @param component component to be used as content. */ public void setContent(Component component) { getContentPane().add(component); if (component instanceof MapPanel) { MapPanel mapPanel = (MapPanel) component; JMenuBar jmb = mapPanel.getMapMenuBar(); if (jmb != null) { logger.fine("OpenMapFrame: Got MenuBar from MapPanel"); getRootPane().setJMenuBar(jmb); } } setPosition(frameWidth, frameHeight); invalidate(); pack(); setVisible(true); } /** * BeanContextMembership interface method. Called when objects are added to * the BeanContext. * * @param bcme contains an Iterator that lets you go through the new * objects. */ public void childrenAdded(BeanContextMembershipEvent bcme) { findAndInit(bcme.iterator()); } /** * BeanContextMembership interface method. Called by BeanContext when * children are being removed. Unhooks itself from the objects that are * being removed if they are contained within the Frame. * * @param bcme event that contains an Iterator to use to go through the * removed objects. */ public void childrenRemoved(BeanContextMembershipEvent bcme) { Iterator<?> it = bcme.iterator(); while (it.hasNext()) { findAndUndo(it.next()); } } /** * Called when an object is removed from the MapHandler. */ public void findAndUndo(Object someObj) { if (someObj instanceof MapPanel && someObj instanceof Container) { logger.fine("OpenMapFrame: MapBean is being removed from frame"); getContentPane().remove((Container) someObj); if (getJMenuBar() == ((MapPanel) someObj).getMapMenuBar()) { logger.fine("OpenMapFrame: Menu Bar is being removed"); setJMenuBar(null); } } if (someObj instanceof JMenuBar) { if (getJMenuBar() == (JMenuBar) someObj) { logger.fine("OpenMapFrame: Menu Bar is being removed"); setJMenuBar(null); } } if (this.equals(someObj)) { dispose(); } } /** Method for BeanContextChild interface. */ public BeanContext getBeanContext() { if (beanContextChildSupport != null) { return beanContextChildSupport.getBeanContext(); } return null; } /** * Method for BeanContextChild interface. * * @param in_bc The context to which this object is being added */ public void setBeanContext(BeanContext in_bc) throws PropertyVetoException { if (in_bc != null) { in_bc.addBeanContextMembershipListener(this); beanContextChildSupport.setBeanContext(in_bc); findAndInit(in_bc.iterator()); } } /** Method for BeanContextChild interface. */ public void addVetoableChangeListener(String propertyName, VetoableChangeListener in_vcl) { beanContextChildSupport.addVetoableChangeListener(propertyName, in_vcl); } /** Method for BeanContextChild interface. */ public void removeVetoableChangeListener(String propertyName, VetoableChangeListener in_vcl) { beanContextChildSupport.removeVetoableChangeListener(propertyName, in_vcl); } // Implementation of PropertyConsumer Interface /** * Method to set the properties in the PropertyConsumer. It is assumed that * the properties do not have a prefix associated with them, or that the * prefix has already been set. * * @param setList a properties object that the PropertyConsumer can use to * retrieve expected properties it can use for configuration. */ public void setProperties(Properties setList) { setProperties(null, setList); } /** * Method to set the properties in the PropertyConsumer. The prefix is a * string that should be prepended to each property key (in addition to a * separating '.') in order for the PropertyConsumer to uniquely identify * properties meant for it, in the midst of of Properties meant for several * objects. * * @param prefix a String used by the PropertyConsumer to prepend to each * property value it wants to look up - * setList.getProperty(prefix.propertyKey). If the prefix had already * been set, then the prefix passed in should replace that previous * value. * @param setList a Properties object that the PropertyConsumer can use to * retrieve expected properties it can use for configuration. */ public void setProperties(String prefix, Properties setList) { setPropertyPrefix(prefix); prefix = PropUtils.getScopedPropertyPrefix(prefix); frameLocX = PropUtils.intFromProperties(setList, prefix + xProperty, frameLocX); frameLocY = PropUtils.intFromProperties(setList, prefix + yProperty, frameLocY); frameWidth = PropUtils.intFromProperties(setList, prefix + WidthProperty, frameWidth); frameHeight = PropUtils.intFromProperties(setList, prefix + HeightProperty, frameHeight); setTitle(setList.getProperty(prefix + TitleProperty, getTitle())); if (getContentPane().getComponentCount() > 0) { logger.fine("setting window dimensions"); setPosition(frameWidth, frameHeight); } if (useAsInternalFrameRootPaneIfNecessary) { boolean useInternalFrames = PropUtils.booleanFromProperties(setList, Environment.UseInternalFrames, false); if (useInternalFrames && Environment.getInternalFrameDesktop() == null) { logger.fine("Setting OpenMapFrame as internal pane."); Environment.useInternalFrames(getRootPane()); } } } /** * Method to fill in a Properties object, reflecting the current values of * the PropertyConsumer. If the PropertyConsumer has a prefix set, the * property keys should have that prefix plus a separating '.' prepended to * each property key it uses for configuration. * * @param getList a Properties object to load the PropertyConsumer * properties into. If getList equals null, then a new Properties * object should be created. * @return Properties object containing PropertyConsumer property values. If * getList was not null, this should equal getList. Otherwise, it * should be the Properties object created by the PropertyConsumer. */ public Properties getProperties(Properties getList) { if (getList == null) { getList = new Properties(); } getList.setProperty(xProperty, "" + getBounds().x); getList.setProperty(yProperty, "" + getBounds().y); getList.setProperty(Environment.Width, Integer.toString(getWidth())); getList.setProperty(Environment.Height, Integer.toString(getHeight())); return getList; } /** * Method to fill in a Properties object with values reflecting the * properties able to be set on this PropertyConsumer. The key for each * property should be the raw property name (without a prefix) with a value * that is a String that describes what the property key represents, along * with any other information about the property that would be helpful * (range, default value, etc.). * * @param list a Properties object to load the PropertyConsumer properties * into. If getList equals null, then a new Properties object should * be created. * @return Properties object containing PropertyConsumer property values. If * getList was not null, this should equal getList. Otherwise, it * should be the Properties object created by the PropertyConsumer. */ public Properties getPropertyInfo(Properties list) { if (list == null) { list = new Properties(); } list.setProperty("x", "Starting X coordinate of window"); list.setProperty("y", "Starting Y coordinate of window"); return list; } /** * Doesn't do anything. The OpenMapFrame looks for properties set with the * "openmap" property prefix. This method is part of the PropertyConsumer * interface. * * @param prefix the prefix String. */ public void setPropertyPrefix(String prefix) { propertyPrefix = prefix; } /** * Get the property key prefix that is being used to prepend to the property * keys for Properties lookups. * * @return the property prefix for the frame */ public String getPropertyPrefix() { return propertyPrefix; } public void setUseAsInternalFrameRootPaneIfNecessary(boolean val) { useAsInternalFrameRootPaneIfNecessary = true; } public boolean getUseAsInternalFrameRootPaneIfNecessary() { return useAsInternalFrameRootPaneIfNecessary; } /** * Calls dispose on the BeanContext (MapHandler) and then removes references * to other children. */ public void dispose() { MapHandler mh = ((MapHandler) getBeanContext()); if (mh != null) { mh.dispose(); } beanContextChildSupport = null; getContentPane().removeAll(); JMenuBar jmb = getJMenuBar(); if (jmb != null) { jmb.removeAll(); } setJMenuBar(null); getRootPane().remove(this); super.dispose(); } }