package org.gnue.forms; import javax.swing.JFrame; import java.awt.Dimension; import java.awt.BorderLayout; import java.io.InputStream; import java.io.IOException; import java.util.Vector; import java.util.Enumeration; import java.net.URL; import java.net.MalformedURLException; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.beans.VetoableChangeListener; import java.beans.PropertyVetoException; /** * The ViewFrame is the main window used to display GNU Enterprise Forms. * * When a document is loaded, a new ViewFrame is created with the content * of the document displayed in the content pane * * @see javax.swing.JFrame#getContentPane() * @see javax.swing.JFrame#setContentPane(java.awt.Container) */ public class ViewFrame extends JFrame implements ContainerController, DirectionKind { /** * The property name for the location of this Frame */ public static String locationProperty = "location"; /** * A string representation of the location of the current document * * For URLs, this will be the absulute form of the URL. For local * files, it will be the full path to the document *

* This is a constrained property. Any registered listeners will be * notified each time a request to change this property is made. * If any of the listeners veto the change, the property will retain * its old value. Otherwise the property will be set to the new * value. * * @see #locationProperty */ protected String url; /** * The Object containing modelling data for this Frame * * This is a bounded property. Any registered listeners will be notified * each time this property is changed. * * @see #modelProperty */ protected Object model; private Vector listenerList; /** * Create a new ViewFrame. * * This ViewFrame will have an initially empty content pane. Use * setLocation() to load a Forms document * * @see #setLocation(java.lang.String) */ public ViewFrame() { this(null); } /** * Create a new ViewFrame and display the document at the specified location * * @param location the location of the document */ public ViewFrame(String url) { super("GNUe Forms"); System.out.println("ViewFrame::ViewFrame(java.lang.String)"); listenerList = new Vector(); addVetoableChangeListener(new LocationObserver()); addPropertyChangeListener(new FrameInitializer()); setURL(url); } /** * Returns a string representation of the location of the document * being displayed * * @return the location of the current document, or null * if no document is being displayed */ public String getURL() { return url; } /** * Specify the location of the document to be displayed by this frame * * The new document will take the place of the currently displayed * document * * @param url the new location */ public void setURL(String url) { System.out.println("ViewFrame->setURL(java.lang.String)"); String oldLoc = this.url; this.url = url; if (oldLoc == null || !(url.equalsIgnoreCase(oldLoc))) { try { fireVetoableChange(locationProperty, oldLoc, url); } catch (PropertyVetoException veto) { this.url = oldLoc; } } } /** * Register the specified listener to be notified when a constrained * property has changed * * @param listener the listener * @see #removeVetoableChangeListener(java.beans.VetoableChangeListener) * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) */ public void addVetoableChangeListener(VetoableChangeListener listener) { listenerList.addElement(listener); } /** * Remove the specified the listener from the list of objects being * notified when a constrained property changes * * @param listener * @see #addVetoableChangeListener(java.beans.VetoableChangeListener) * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) */ public void removeVetoableChangeListener(VetoableChangeListener listener) { listenerList.removeElement(listener); } protected void fireVetoableChange(String property, java.lang.Object oldValue, java.lang.Object newValue) throws PropertyVetoException { Enumeration listeners = listenerList.elements(); PropertyChangeEvent event = new PropertyChangeEvent(this, property, oldValue, newValue); while (listeners.hasMoreElements()) { try { VetoableChangeListener listener = (VetoableChangeListener)listeners.nextElement(); listener.vetoableChange(event); } catch (ClassCastException cce) { } } } // ControllerContainer methods public Controller getParentController() { return null; } /** * Return the object responsible for providing modelling data * for this Frame * * @return the model * @see #setModel(java.lang.Object) */ public Object getModel() { return model; } /** * Specify the object to provide modelling data for this Frame * * @param model the model * @see #getModel() */ public void setModel(Object model) { System.out.println("ViewFrame->setModel()"); Object oldModel = this.model; this.model = model; firePropertyChange(Controller.modelProperty, oldModel, model); } public void transferFocus(int dir) { } public Controller[] getTraversibleComponents() { try { Form form = (Form)getModel(); Page[] pages = form.pages(); Controller[] retval = new Controller[pages.length]; for (int i = 0; i < pages.length; i++) { Controller controller = new PageController(); controller.setModel(pages[i]); retval[i] = controller; } return retval; } catch (NullPointerException npe) { return null; } } /** * This class ensures that a new Form object is associated * with this Frame each time the location changes */ class LocationObserver implements VetoableChangeListener { public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException { System.out.println("ViewFrame::LocationObserver->vetoableChange()"); if (event.getPropertyName().equals(locationProperty)) { try { setModel(FormManager.parseURL((String)event.getNewValue())); } catch (IOException ioe) { System.err.println(ioe); throw new PropertyVetoException(ioe.getMessage(), event); } } } } /** * This class sets various properties of this Frame when a new model * is established. */ class FrameInitializer implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent event) { System.out.println("ViewFrame::FrameInitializer->propertyChange()"); if (event.getPropertyName().equals(Controller.modelProperty)) { Form form = (Form)event.getNewValue(); String title = form.getTitle(); int width = form.getWidth()*8; int height = form.getHeight()*22; if (title.equals("")) { ViewFrame.this.setTitle("GNUe Forms - Untitled"); } else { ViewFrame.this.setTitle("GNUe Forms - " + title); } if (width == 0 || height == 0) { ViewFrame.this.pack(); } else { ViewFrame.this.setSize(width, height); } PageController firstPage = new PageController(); firstPage.setModel(form.getFirstPage()); ViewFrame.this.getContentPane().add(firstPage, BorderLayout.CENTER); } } } /** * This class handles registering PropertyChangeListeners whenever * a new model is specified * * @see #setModel(java.lang.Object) */ class FormListenerRegistrar implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent event) { if (event.getPropertyName().equals(Controller.modelProperty)) { Form form = (Form)event.getNewValue(); form.addVetoableChangeListener(new FormDimensionObserver()); } } } /** * This makes sure that the width and height * attributes of the underlying model are accurately reflected * by this frame */ class FormDimensionObserver implements VetoableChangeListener { public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException { if (event.getPropertyName().equals(Form.dimensionProperty)) { Dimension dim = (Dimension)event.getNewValue(); if (dim.width < 0 || dim.height < 0) { throw new PropertyVetoException("dimensions must be positive", event); } ViewFrame.this.setSize(dim); } } } }