diff options
Diffstat (limited to 'libjava/classpath/javax/swing')
469 files changed, 141866 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/AbstractAction.java b/libjava/classpath/javax/swing/AbstractAction.java new file mode 100644 index 00000000000..6bb42339439 --- /dev/null +++ b/libjava/classpath/javax/swing/AbstractAction.java @@ -0,0 +1,278 @@ +/* AbstractAction.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.HashMap; + +import javax.swing.event.SwingPropertyChangeSupport; + +/** + * A base class for implementing the {@link Action} interface. + * + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class AbstractAction + implements Action, Cloneable, Serializable +{ + private static final long serialVersionUID = -6803159439231523484L; + + /** + * A flag that indicates whether or not the action is enabled. + */ + protected boolean enabled = true; + + /** + * Provides support for property change event notification. + */ + protected SwingPropertyChangeSupport changeSupport = + new SwingPropertyChangeSupport(this); + + /** + * store + */ + private transient HashMap store = new HashMap(); + + /** + * Creates a new action with an empty string for the name. All other + * properties are initialised to <code>null</code> + */ + public AbstractAction() + { + this(""); // TODO: default name + } + + /** + * Creates a new action with the specified name. All other properties are + * initialised to <code>null</code>. + * + * @param name the name (<code>null</code> permitted). + */ + public AbstractAction(String name) + { + this(name, null); // TODO: default icon?? + } + + /** + * Creates a new action with the specified name and icon. All other + * properties are initialised to <code>null</code>. + * + * @param name the name (<code>null</code> permitted). + * @param icon the icon (<code>null</code> permitted). + */ + public AbstractAction(String name, Icon icon) + { + putValue(NAME, name); + putValue(SMALL_ICON, icon); + } + + /** + * readObject + * + * @param stream the stream to read from + * + * @exception ClassNotFoundException TODO + * @exception IOException if an error occurs + */ + private void readObject(ObjectInputStream stream) + throws ClassNotFoundException, IOException + { + // TODO + } + + /** + * writeObject + * + * @param stream the stream to write to + * + * @exception IOException if an error occurs + */ + private void writeObject(ObjectOutputStream stream) throws IOException + { + // TODO + } + + /** + * clone + * + * @return Object + * + * @exception CloneNotSupportedException TODO + */ + protected Object clone() throws CloneNotSupportedException + { + AbstractAction copy = (AbstractAction) super.clone(); + copy.store = (HashMap) store.clone(); + return copy; + } + + /** + * Returns the value associated with the specified key. + * + * @param key the key (not <code>null</code>). + * + * @return The value associated with the specified key, or + * <code>null</code> if the key is not found. + */ + public Object getValue(String key) + { + return store.get(key); + } + + /** + * Sets the value associated with the specified key and sends a + * {@link java.beans.PropertyChangeEvent} to all registered listeners. + * The standard keys are: {@link #NAME}, {@link #SHORT_DESCRIPTION}, + * {@link #LONG_DESCRIPTION}, {@link #SMALL_ICON}, + * {@link #ACTION_COMMAND_KEY}, {@link #ACCELERATOR_KEY} and + * {@link #MNEMONIC_KEY}. Any existing value associated with the key will be + * overwritten. + * + * @param key the key (not <code>null</code>). + * @param value the value (<code>null</code> permitted). + */ + public void putValue(String key, Object value) + { + Object old = getValue(key); + if (old != value) + { + store.put(key, value); + firePropertyChange(key, old, value); + } + } + + /** + * Returns the flag that indicates whether or not the action is enabled. + * + * @return The flag. + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * Sets the flag that indicates whether or not the action is enabled and, if + * the value of the flag changed from the previous setting, sends a + * {@link java.beans.PropertyChangeEvent} to all registered listeners. + * + * @param enabled the new flag value. + */ + public void setEnabled(boolean enabled) + { + if (enabled != this.enabled) + { + this.enabled = enabled; + firePropertyChange("enabled", !this.enabled, this.enabled); + } + } + + /** + * getKeys + * @returns Object[] + */ + public Object[] getKeys() + { + return store.keySet().toArray(); + } + + /** + * This method fires a PropertyChangeEvent given the propertyName + * and the old and new values. + * + * @param propertyName The property that changed. + * @param oldValue The old value of the property. + * @param newValue The new value of the property. + */ + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * This convenience method fires a PropertyChangeEvent given + * the propertyName and the old and new values. + * + * @param propertyName The property that changed. + * @param oldValue The old value of the property. + * @param newValue The new value of the property. + */ + private void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) + { + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * addPropertyChangeListener + * + * @param listener the listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.addPropertyChangeListener(listener); + } + + /** + * removePropertyChangeListener + * + * @param listener the listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns all registered listeners. + * + * @return array of listeners. + * + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport.getPropertyChangeListeners(); + } +} diff --git a/libjava/classpath/javax/swing/AbstractButton.java b/libjava/classpath/javax/swing/AbstractButton.java new file mode 100644 index 00000000000..0b5859bf591 --- /dev/null +++ b/libjava/classpath/javax/swing/AbstractButton.java @@ -0,0 +1,2014 @@ +/* AbstractButton.java -- Provides basic button functionality. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.ItemSelectable; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.Serializable; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleIcon; +import javax.accessibility.AccessibleRelationSet; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.accessibility.AccessibleValue; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ButtonUI; +import javax.swing.text.AttributeSet; + + +/** + * <p>The purpose of this class is to serve as a facade over a number of + * classes which collectively represent the semantics of a button: the + * button's model, its listeners, its action, and its look and feel. Some + * parts of a button's state are stored explicitly in this class, other + * parts are delegates to the model. Some methods related to buttons are + * implemented in this class, other methods pass through to the current + * model or look and feel.</p> + * + * <p>Furthermore this class is supposed to serve as a base class for + * several kinds of buttons with similar but non-identical semantics: + * toggle buttons (radio buttons and checkboxes), simple "push" buttons, + * menu items.</p> + * + * <p>Buttons have many properties, some of which are stored in this class + * while others are delegated to the button's model. The following properties + * are available:</p> + * + * <table> + * <tr><th>Property </th><th>Stored in</th><th>Bound?</th></tr> + * + * <tr><td>action </td><td>button</td> <td>no</td></tr> + * <tr><td>actionCommand </td><td>model</td> <td>no</td></tr> + * <tr><td>borderPainted </td><td>button</td> <td>yes</td></tr> + * <tr><td>contentAreaFilled </td><td>button</td> <td>yes</td></tr> + * <tr><td>disabledIcon </td><td>button</td> <td>yes</td></tr> + * <tr><td>disabledSelectedIcon </td><td>button</td> <td>yes</td></tr> + * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr> + * <tr><td>enabled </td><td>model</td> <td>no</td></tr> + * <tr><td>focusPainted </td><td>button</td> <td>yes</td></tr> + * <tr><td>horizontalAlignment </td><td>button</td> <td>yes</td></tr> + * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr> + * <tr><td>icon </td><td>button</td> <td>yes</td></tr> + * <tr><td>iconTextGap </td><td>button</td> <td>no</td></tr> + * <tr><td>label (same as text) </td><td>model</td> <td>yes</td></tr> + * <tr><td>margin </td><td>button</td> <td>yes</td></tr> + * <tr><td>multiClickThreshold </td><td>button</td> <td>no</td></tr> + * <tr><td>pressedIcon </td><td>button</td> <td>yes</td></tr> + * <tr><td>rolloverEnabled </td><td>button</td> <td>yes</td></tr> + * <tr><td>rolloverIcon </td><td>button</td> <td>yes</td></tr> + * <tr><td>rolloverSelectedIcon </td><td>button</td> <td>yes</td></tr> + * <tr><td>selected </td><td>model</td> <td>no</td></tr> + * <tr><td>selectedIcon </td><td>button</td> <td>yes</td></tr> + * <tr><td>selectedObjects </td><td>button</td> <td>no</td></tr> + * <tr><td>text </td><td>model</td> <td>yes</td></tr> + * <tr><td>UI </td><td>button</td> <td>yes</td></tr> + * <tr><td>verticalAlignment </td><td>button</td> <td>yes</td></tr> + * <tr><td>verticalTextPosition </td><td>button</td> <td>yes</td></tr> + * + * </table> + * + * <p>The various behavioral aspects of these properties follows:</p> + * + * <ul> + * + * <li>When non-bound properties stored in the button change, the button + * fires ChangeEvents to its ChangeListeners.</li> + * + * <li>When bound properties stored in the button change, the button fires + * PropertyChangeEvents to its PropertyChangeListeners</li> + * + * <li>If any of the model's properties change, it fires a ChangeEvent to + * its ChangeListeners, which include the button.</li> + * + * <li>If the button receives a ChangeEvent from its model, it will + * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's + * "source" property set to refer to the button, rather than the model. The + * the button will request a repaint, to paint its updated state.</li> + * + * <li>If the model's "selected" property changes, the model will fire an + * ItemEvent to its ItemListeners, which include the button, in addition to + * the ChangeEvent which models the property change. The button propagates + * ItemEvents directly to its ItemListeners.</li> + * + * <li>If the model's armed and pressed properties are simultaneously + * <code>true</code>, the model will fire an ActionEvent to its + * ActionListeners, which include the button. The button will propagate + * this ActionEvent to its ActionListeners, with the ActionEvent's "source" + * property set to refer to the button, rather than the model.</li> + * + * </ul> + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + * @author Graydon Hoare (graydon@redhat.com) + */ + +public abstract class AbstractButton extends JComponent + implements ItemSelectable, SwingConstants +{ + private static final long serialVersionUID = -937921345538462020L; + + /** + * An extension of ChangeListener to be serializable. + */ + protected class ButtonChangeListener + implements ChangeListener, Serializable + { + private static final long serialVersionUID = 1471056094226600578L; + + /** + * Notified when the target of the listener changes its state. + * + * @param ev the ChangeEvent describing the change + */ + public void stateChanged(ChangeEvent ev) + { + } + } + + /** The icon displayed by default. */ + Icon default_icon; + + /** The icon displayed when the button is pressed. */ + Icon pressed_icon; + + /** The icon displayed when the button is disabled. */ + Icon disabeldIcon; + + /** The icon displayed when the button is selected. */ + Icon selectedIcon; + + /** The icon displayed when the button is selected but disabled. */ + Icon disabledSelectedIcon; + + /** The icon displayed when the button is rolled over. */ + Icon rolloverIcon; + + /** The icon displayed when the button is selected and rolled over. */ + Icon rolloverSelectedIcon; + + /** The icon currently displayed. */ + Icon current_icon; + + /** The text displayed in the button. */ + String text; + + /** + * The gap between icon and text, if both icon and text are + * non-<code>null</code>. + */ + int iconTextGap; + + /** The vertical alignment of the button's text and icon. */ + int verticalAlignment; + + /** The horizontal alignment of the button's text and icon. */ + int horizontalAlignment; + + /** The horizontal position of the button's text relative to its icon. */ + int horizontalTextPosition; + + /** The vertical position of the button's text relative to its icon. */ + int verticalTextPosition; + + /** Whether or not the button paints its border. */ + boolean borderPainted; + + /** Whether or not the button paints its focus state. */ + boolean focusPainted; + + /** Whether or not the button fills its content area. */ + boolean contentAreaFilled; + + /** Whether rollover is enabled. */ + boolean rollOverEnabled; + + /** The action taken when the button is clicked. */ + Action action; + + /** The button's current state. */ + protected ButtonModel model; + + /** The margin between the button's border and its label. */ + Insets margin; + + /** + * A hint to the look and feel class, suggesting which character in the + * button's label should be underlined when drawing the label. + */ + int mnemonicIndex; + + /** Listener the button uses to receive ActionEvents from its model. */ + protected ActionListener actionListener; + + /** Listener the button uses to receive ItemEvents from its model. */ + protected ItemListener itemListener; + + /** Listener the button uses to receive ChangeEvents from its model. */ + protected ChangeListener changeListener; + + /** + * The time in miliseconds in which clicks get coalesced into a single + * <code>ActionEvent</code>. + */ + long multiClickThreshhold; + + /** + * Listener the button uses to receive PropertyChangeEvents from its + * Action. + */ + PropertyChangeListener actionPropertyChangeListener; + + /** ChangeEvent that is fired to button's ChangeEventListeners */ + protected ChangeEvent changeEvent = new ChangeEvent(this); + + /** + * Fired in a PropertyChangeEvent when the "borderPainted" property changes. + */ + public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted"; + + /** + * Fired in a PropertyChangeEvent when the "contentAreaFilled" property + * changes. + */ + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = + "contentAreaFilled"; + + /** + * Fired in a PropertyChangeEvent when the "disabledIcon" property changes. + */ + public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon"; + + /** + * Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property + * changes. + */ + public static final String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = + "disabledSelectedIcon"; + + /** + * Fired in a PropertyChangeEvent when the "focusPainted" property changes. + */ + public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted"; + + /** + * Fired in a PropertyChangeEvent when the "horizontalAlignment" property + * changes. + */ + public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = + "horizontalAlignment"; + + /** + * Fired in a PropertyChangeEvent when the "horizontalTextPosition" property + * changes. + */ + public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = + "horizontalTextPosition"; + + /** + * Fired in a PropertyChangeEvent when the "icon" property changes. */ + public static final String ICON_CHANGED_PROPERTY = "icon"; + + /** Fired in a PropertyChangeEvent when the "margin" property changes. */ + public static final String MARGIN_CHANGED_PROPERTY = "margin"; + + /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */ + public static final String MNEMONIC_CHANGED_PROPERTY = "mnemonic"; + + /** Fired in a PropertyChangeEvent when the "model" property changes. */ + public static final String MODEL_CHANGED_PROPERTY = "model"; + + /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */ + public static final String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon"; + + /** + * Fired in a PropertyChangeEvent when the "rolloverEnabled" property + * changes. + */ + public static final String ROLLOVER_ENABLED_CHANGED_PROPERTY = + "rolloverEnabled"; + + /** + * Fired in a PropertyChangeEvent when the "rolloverIcon" property changes. + */ + public static final String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon"; + + /** + * Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property + * changes. + */ + public static final String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = + "rolloverSelectedIcon"; + + /** + * Fired in a PropertyChangeEvent when the "selectedIcon" property changes. + */ + public static final String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon"; + + /** Fired in a PropertyChangeEvent when the "text" property changes. */ + public static final String TEXT_CHANGED_PROPERTY = "text"; + + /** + * Fired in a PropertyChangeEvent when the "verticalAlignment" property + * changes. + */ + public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = + "verticalAlignment"; + + /** + * Fired in a PropertyChangeEvent when the "verticalTextPosition" property + * changes. + */ + public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = + "verticalTextPosition"; + + /** + * A Java Accessibility extension of the AbstractButton. + */ + protected abstract class AccessibleAbstractButton + extends AccessibleJComponent implements AccessibleAction, AccessibleValue, + AccessibleText + { + private static final long serialVersionUID = -5673062525319836790L; + + protected AccessibleAbstractButton() + { + } + + public AccessibleStateSet getAccessibleStateSet() + { + return null; // TODO + } + + public String getAccessibleName() + { + return null; // TODO + } + + public AccessibleIcon[] getAccessibleIcon() + { + return null; // TODO + } + + public AccessibleRelationSet getAccessibleRelationSet() + { + return null; // TODO + } + + public AccessibleAction getAccessibleAction() + { + return null; // TODO + } + + public AccessibleValue getAccessibleValue() + { + return null; // TODO + } + + public int getAccessibleActionCount() + { + return 0; // TODO + } + + public String getAccessibleActionDescription(int value0) + { + return null; // TODO + } + + public boolean doAccessibleAction(int value0) + { + return false; // TODO + } + + public Number getCurrentAccessibleValue() + { + return null; // TODO + } + + public boolean setCurrentAccessibleValue(Number value0) + { + return false; // TODO + } + + public Number getMinimumAccessibleValue() + { + return null; // TODO + } + + public Number getMaximumAccessibleValue() + { + return null; // TODO + } + + public AccessibleText getAccessibleText() + { + return null; // TODO + } + + public int getIndexAtPoint(Point value0) + { + return 0; // TODO + } + + public Rectangle getCharacterBounds(int value0) + { + return null; // TODO + } + + public int getCharCount() + { + return 0; // TODO + } + + public int getCaretPosition() + { + return 0; // TODO + } + + public String getAtIndex(int value0, int value1) + { + return null; // TODO + } + + public String getAfterIndex(int value0, int value1) + { + return null; // TODO + } + + public String getBeforeIndex(int value0, int value1) + { + return null; // TODO + } + + public AttributeSet getCharacterAttribute(int value0) + { + return null; // TODO + } + + public int getSelectionStart() + { + return 0; // TODO + } + + public int getSelectionEnd() + { + return 0; // TODO + } + + public String getSelectedText() + { + return null; // TODO + } + + private Rectangle getTextRectangle() + { + return null; // TODO + } + } + + /** + * Creates a new AbstractButton object. + */ + public AbstractButton() + { + init("", null); + updateUI(); + } + + /** + * Get the model the button is currently using. + * + * @return The current model + */ + public ButtonModel getModel() + { + return model; + } + + /** + * Set the model the button is currently using. This un-registers all + * listeners associated with the current model, and re-registers them + * with the new model. + * + * @param newModel The new model + */ + public void setModel(ButtonModel newModel) + { + if (newModel == model) + return; + + if (model != null) + { + model.removeActionListener(actionListener); + model.removeChangeListener(changeListener); + model.removeItemListener(itemListener); + } + ButtonModel old = model; + model = newModel; + if (model != null) + { + model.addActionListener(actionListener); + model.addChangeListener(changeListener); + model.addItemListener(itemListener); + } + firePropertyChange(MODEL_CHANGED_PROPERTY, old, model); + revalidate(); + repaint(); + } + + protected void init(String text, Icon icon) + { + // If text is null, we fall back to the empty + // string (which is set using AbstractButton's + // constructor). + // This way the behavior of the JDK is matched. + if(text != null) + this.text = text; + + default_icon = icon; + actionListener = createActionListener(); + changeListener = createChangeListener(); + itemListener = createItemListener(); + + horizontalAlignment = CENTER; + horizontalTextPosition = TRAILING; + verticalAlignment = CENTER; + verticalTextPosition = CENTER; + borderPainted = true; + contentAreaFilled = true; + + focusPainted = true; + setFocusable(true); + + setAlignmentX(LEFT_ALIGNMENT); + setAlignmentY(CENTER_ALIGNMENT); + + setDisplayedMnemonicIndex(-1); + } + + /** + * <p>Returns the action command string for this button's model.</p> + * + * <p>If the action command was set to <code>null</code>, the button's + * text (label) is returned instead.</p> + * + * @return The current action command string from the button's model + */ + public String getActionCommand() + { + String ac = model.getActionCommand(); + if (ac != null) + return ac; + else + return text; + } + + /** + * Sets the action command string for this button's model. + * + * @param actionCommand The new action command string to set in the button's + * model. + */ + public void setActionCommand(String actionCommand) + { + model.setActionCommand(actionCommand); + } + + /** + * Adds an ActionListener to the button's listener list. When the + * button's model is clicked it fires an ActionEvent, and these + * listeners will be called. + * + * @param l The new listener to add + */ + public void addActionListener(ActionListener l) + { + listenerList.add(ActionListener.class, l); + } + + /** + * Removes an ActionListener from the button's listener list. + * + * @param l The listener to remove + */ + public void removeActionListener(ActionListener l) + { + listenerList.remove(ActionListener.class, l); + } + + /** + * Returns all added <code>ActionListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public ActionListener[] getActionListeners() + { + return (ActionListener[]) listenerList.getListeners(ActionListener.class); + } + + /** + * Adds an ItemListener to the button's listener list. When the button's + * model changes state (between any of ARMED, ENABLED, PRESSED, ROLLOVER + * or SELECTED) it fires an ItemEvent, and these listeners will be + * called. + * + * @param l The new listener to add + */ + public void addItemListener(ItemListener l) + { + listenerList.add(ItemListener.class, l); + } + + /** + * Removes an ItemListener from the button's listener list. + * + * @param l The listener to remove + */ + public void removeItemListener(ItemListener l) + { + listenerList.remove(ItemListener.class, l); + } + + /** + * Returns all added <code>ItemListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public ItemListener[] getItemListeners() + { + return (ItemListener[]) listenerList.getListeners(ItemListener.class); + } + + /** + * Adds a ChangeListener to the button's listener list. When the button's + * model changes any of its (non-bound) properties, these listeners will be + * called. + * + * @param l The new listener to add + */ + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + /** + * Removes a ChangeListener from the button's listener list. + * + * @param l The listener to remove + */ + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + /** + * Returns all added <code>ChangeListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Calls {@link ItemListener.itemStateChanged} on each ItemListener in + * the button's listener list. + * + * @param e The event signifying that the button's model changed state + */ + protected void fireItemStateChanged(ItemEvent e) + { + e.setSource(this); + ItemListener[] listeners = getItemListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners[i].itemStateChanged(e); + } + + /** + * Calls {@link ActionListener.actionPerformed} on each {@link + * ActionListener} in the button's listener list. + * + * @param e The event signifying that the button's model was clicked + */ + protected void fireActionPerformed(ActionEvent e) + { + // Dispatch a copy of the given ActionEvent in order to + // set the source and action command correctly. + ActionEvent ae = new ActionEvent( + this, + e.getID(), + getActionCommand(), + e.getWhen(), + e.getModifiers()); + + ActionListener[] listeners = getActionListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners[i].actionPerformed(ae); + } + + /** + * Calls {@link ChangeEvent.stateChanged} on each {@link ChangeListener} + * in the button's listener list. + */ + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners[i].stateChanged(changeEvent); + } + + /** + * Get the current keyboard mnemonic value. This value corresponds to a + * single key code (one of the {@link java.awt.event.KeyEvent} VK_* + * codes) and is used to activate the button when pressed in conjunction + * with the "mouseless modifier" of the button's look and feel class, and + * when focus is in one of the button's ancestors. + * + * @return The button's current keyboard mnemonic + */ + public int getMnemonic() + { + return getModel().getMnemonic(); + } + + /** + * Set the current keyboard mnemonic value. This value corresponds to a + * single key code (one of the {@link java.awt.event.KeyEvent} VK_* + * codes) and is used to activate the button when pressed in conjunction + * with the "mouseless modifier" of the button's look and feel class, and + * when focus is in one of the button's ancestors. + * + * @param mne A new mnemonic to use for the button + */ + public void setMnemonic(char mne) + { + setMnemonic((int) mne); + } + + /** + * Set the current keyboard mnemonic value. This value corresponds to a + * single key code (one of the {@link java.awt.event.KeyEvent} VK_* + * codes) and is used to activate the button when pressed in conjunction + * with the "mouseless modifier" of the button's look and feel class, and + * when focus is in one of the button's ancestors. + * + * @param mne A new mnemonic to use for the button + */ + public void setMnemonic(int mne) + { + int old = getModel().getMnemonic(); + + if (old != mne) + { + getModel().setMnemonic(mne); + + if (text != null && !text.equals("")) + { + // Since lower case char = upper case char for + // mnemonic, we will convert both text and mnemonic + // to upper case before checking if mnemonic character occurs + // in the menu item text. + int upperCaseMne = Character.toUpperCase((char) mne); + String upperCaseText = text.toUpperCase(); + setDisplayedMnemonicIndex(upperCaseText.indexOf(upperCaseMne)); + } + + firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, mne); + revalidate(); + repaint(); + } + } + + /** + * Sets the button's mnemonic index. The mnemonic index is a hint to the + * look and feel class, suggesting which character in the button's label + * should be underlined when drawing the label. If the mnemonic index is + * -1, no mnemonic will be displayed. + * + * If no mnemonic index is set, the button will choose a mnemonic index + * by default, which will be the first occurrence of the mnemonic + * character in the button's text. + * + * @param index An offset into the "text" property of the button + * @throws IllegalArgumentException If <code>index</code> is not within the + * range of legal offsets for the "text" property of the button. + * @since 1.4 + */ + + public void setDisplayedMnemonicIndex(int index) + { + if (index < -1 || (text != null && index >= text.length())) + throw new IllegalArgumentException(); + + mnemonicIndex = index; + } + + /** + * Get the button's mnemonic index, which is an offset into the button's + * "text" property. The character specified by this offset should be + * underlined when the look and feel class draws this button. + * + * @return An index into the button's "text" property + */ + public int getDisplayedMnemonicIndex() + { + return mnemonicIndex; + } + + + /** + * Set the "rolloverEnabled" property. When rollover is enabled, and the + * look and feel supports it, the button will change its icon to + * rolloverIcon, when the mouse passes over it. + * + * @param r Whether or not to enable rollover icon changes + */ + public void setRolloverEnabled(boolean r) + { + if (rollOverEnabled != r) + { + rollOverEnabled = r; + firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, !r, r); + revalidate(); + repaint(); + } + } + + /** + * Returns whether or not rollover icon changes are enabled on the + * button. + * + * @return The state of the "rolloverEnabled" property + */ + public boolean isRolloverEnabled() + { + return rollOverEnabled; + } + + /** + * Set the value of the button's "selected" property. Selection is only + * meaningful for toggle-type buttons (check boxes, radio buttons). + * + * @param s New value for the property + */ + public void setSelected(boolean s) + { + getModel().setSelected(s); + } + + /** + * Get the value of the button's "selected" property. Selection is only + * meaningful for toggle-type buttons (check boxes, radio buttons). + * + * @return The value of the property + */ + public boolean isSelected() + { + return getModel().isSelected(); + } + + /** + * Enables or disables the button. A button will neither be selectable + * nor preform any actions unless it is enabled. + * + * @param b Whether or not to enable the button + */ + public void setEnabled(boolean b) + { + super.setEnabled(b); + getModel().setEnabled(b); + } + + /** + * Set the horizontal alignment of the button's text and icon. The + * alignment is a numeric constant from {@link SwingConstants}. It must + * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, + * <code>LEADING</code> or <code>TRAILING</code>. The default is + * <code>RIGHT</code>. + * + * @return The current horizontal alignment + */ + public int getHorizontalAlignment() + { + return horizontalAlignment; + } + + /** + * Set the horizontal alignment of the button's text and icon. The + * alignment is a numeric constant from {@link SwingConstants}. It must + * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, + * <code>LEADING</code> or <code>TRAILING</code>. The default is + * <code>RIGHT</code>. + * + * @param a The new horizontal alignment + * @throws IllegalArgumentException If alignment is not one of the legal + * constants. + */ + public void setHorizontalAlignment(int a) + { + if (horizontalAlignment == a) + return; + + int old = horizontalAlignment; + horizontalAlignment = a; + firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a); + revalidate(); + repaint(); + } + + /** + * Get the horizontal position of the button's text relative to its + * icon. The position is a numeric constant from {@link + * SwingConstants}. It must be one of: <code>RIGHT</code>, + * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or + * <code>TRAILING</code>. The default is <code>TRAILING</code>. + * + * @return The current horizontal text position + */ + public int getHorizontalTextPosition() + { + return horizontalTextPosition; + } + + /** + * Set the horizontal position of the button's text relative to its + * icon. The position is a numeric constant from {@link + * SwingConstants}. It must be one of: <code>RIGHT</code>, + * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or + * <code>TRAILING</code>. The default is <code>TRAILING</code>. + * + * @param t The new horizontal text position + * @throws IllegalArgumentException If position is not one of the legal + * constants. + */ + public void setHorizontalTextPosition(int t) + { + if (horizontalTextPosition == t) + return; + + int old = horizontalTextPosition; + horizontalTextPosition = t; + firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t); + revalidate(); + repaint(); + } + + /** + * Get the vertical alignment of the button's text and icon. The + * alignment is a numeric constant from {@link SwingConstants}. It must + * be one of: <code>CENTER</code>, <code>TOP</code>, or + * <code>BOTTOM</code>. The default is <code>CENTER</code>. + * + * @return The current vertical alignment + */ + public int getVerticalAlignment() + { + return verticalAlignment; + } + + /** + * Set the vertical alignment of the button's text and icon. The + * alignment is a numeric constant from {@link SwingConstants}. It must + * be one of: <code>CENTER</code>, <code>TOP</code>, or + * <code>BOTTOM</code>. The default is <code>CENTER</code>. + * + * @param a The new vertical alignment + * @throws IllegalArgumentException If alignment is not one of the legal + * constants. + */ + public void setVerticalAlignment(int a) + { + if (verticalAlignment == a) + return; + + int old = verticalAlignment; + verticalAlignment = a; + firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a); + revalidate(); + repaint(); + } + + /** + * Get the vertical position of the button's text relative to its + * icon. The alignment is a numeric constant from {@link + * SwingConstants}. It must be one of: <code>CENTER</code>, + * <code>TOP</code>, or <code>BOTTOM</code>. The default is + * <code>CENTER</code>. + * + * @return The current vertical position + */ + public int getVerticalTextPosition() + { + return verticalTextPosition; + } + + /** + * Set the vertical position of the button's text relative to its + * icon. The alignment is a numeric constant from {@link + * SwingConstants}. It must be one of: <code>CENTER</code>, + * <code>TOP</code>, or <code>BOTTOM</code>. The default is + * <code>CENTER</code>. + * + * @param t The new vertical position + * @throws IllegalArgumentException If position is not one of the legal + * constants. + */ + public void setVerticalTextPosition(int t) + { + if (verticalTextPosition == t) + return; + + int old = verticalTextPosition; + verticalTextPosition = t; + firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t); + revalidate(); + repaint(); + } + + /** + * Set the value of the "borderPainted" property. If set to + * <code>false</code>, the button's look and feel class should not paint + * a border for the button. The default is <code>true</code>. + * + * @return The current value of the property. + */ + public boolean isBorderPainted() + { + return borderPainted; + } + + /** + * Set the value of the "borderPainted" property. If set to + * <code>false</code>, the button's look and feel class should not paint + * a border for the button. The default is <code>true</code>. + * + * @param b The new value of the property. + */ + public void setBorderPainted(boolean b) + { + if (borderPainted == b) + return; + + boolean old = borderPainted; + borderPainted = b; + firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b); + revalidate(); + repaint(); + } + + /** + * Get the value of the "action" property. + * + * @return The current value of the "action" property + */ + public Action getAction() + { + return action; + } + + /** + * <p>Set the button's "action" property, subscribing the new action to the + * button, as an ActionListener, if it is not already subscribed. The old + * Action, if it exists, is unsubscribed, and the button is unsubscribed + * from the old Action if it was previously subscribed as a + * PropertyChangeListener.</p> + * + * <p>This method also configures several of the button's properties from + * the Action, by calling {@link configurePropertiesFromAction}, and + * subscribes the button to the Action as a PropertyChangeListener. + * Subsequent changes to the Action will thus reconfigure the button + * automatically.</p> + * + * @param a The new value of the "action" property + */ + public void setAction(Action a) + { + if (action != null) + { + action.removePropertyChangeListener(actionPropertyChangeListener); + removeActionListener(action); + if (actionPropertyChangeListener != null) + { + action.removePropertyChangeListener(actionPropertyChangeListener); + actionPropertyChangeListener = null; + } + } + + Action old = action; + action = a; + configurePropertiesFromAction(action); + if (action != null) + { + actionPropertyChangeListener = createActionPropertyChangeListener(a); + action.addPropertyChangeListener(actionPropertyChangeListener); + addActionListener(action); + } + } + + /** + * Return the button's default "icon" property. + * + * @return The current default icon + */ + public Icon getIcon() + { + return default_icon; + } + + /** + * Set the button's default "icon" property. This icon is used as a basis + * for the pressed and disabled icons, if none are explicitly set. + * + * @param i The new default icon + */ + public void setIcon(Icon i) + { + if (default_icon == i) + return; + + Icon old = default_icon; + default_icon = i; + firePropertyChange(ICON_CHANGED_PROPERTY, old, i); + revalidate(); + repaint(); + } + + /** + * Return the button's "text" property. This property is synonymous with + * the "label" property. + * + * @return The current "text" property + */ + public String getText() + { + return text; + } + + /** + * Set the button's "label" property. This property is synonymous with the + * "text" property. + * + * @param label The new "label" property + * + * @deprecated use <code>setText(text)</code> + */ + public void setLabel(String label) + { + setText(label); + } + + /** + * Return the button's "label" property. This property is synonymous with + * the "text" property. + * + * @return The current "label" property + * + * @deprecated use <code>getText()</code> + */ + public String getLabel() + { + return getText(); + } + + /** + * Set the button's "text" property. This property is synonymous with the + * "label" property. + * + * @param t The new "text" property + */ + public void setText(String t) + { + if (text == t) + return; + + String old = text; + text = t; + firePropertyChange(TEXT_CHANGED_PROPERTY, old, t); + revalidate(); + repaint(); + } + + /** + * Set the value of the {@link #iconTextGap} property. + * + * @param i The new value of the property + */ + public void setIconTextGap(int i) + { + if (iconTextGap == i) + return; + + int old = iconTextGap; + iconTextGap = i; + fireStateChanged(); + revalidate(); + repaint(); + } + + /** + * Get the value of the {@link #iconTextGap} property. + * + * @return The current value of the property + */ + public int getIconTextGap() + { + return iconTextGap; + } + + /** + * Return the button's "margin" property, which is an {@link Insets} object + * describing the distance between the button's border and its text and + * icon. + * + * @return The current "margin" property + */ + public Insets getMargin() + { + return margin; + } + + /** + * Set the button's "margin" property, which is an {@link Insets} object + * describing the distance between the button's border and its text and + * icon. + * + * @param m The new "margin" property + */ + public void setMargin(Insets m) + { + if (margin == m) + return; + + Insets old = margin; + margin = m; + firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m); + revalidate(); + repaint(); + } + + /** + * Return the button's "pressedIcon" property. The look and feel class + * should paint this icon when the "pressed" property of the button's + * {@link ButtonModel} is <code>true</code>. This property may be + * <code>null</code>, in which case the default icon is used. + * + * @return The current "pressedIcon" property + */ + public Icon getPressedIcon() + { + return pressed_icon; + } + + /** + * Set the button's "pressedIcon" property. The look and feel class + * should paint this icon when the "pressed" property of the button's + * {@link ButtonModel} is <code>true</code>. This property may be + * <code>null</code>, in which case the default icon is used. + * + * @param pressedIcon The new "pressedIcon" property + */ + public void setPressedIcon(Icon pressedIcon) + { + if (pressed_icon == pressedIcon) + return; + + Icon old = pressed_icon; + pressed_icon = pressedIcon; + firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon); + revalidate(); + repaint(); + } + + /** + * Return the button's "disabledIcon" property. The look and feel class + * should paint this icon when the "enabled" property of the button's + * {@link ButtonModel} is <code>false</code>. This property may be + * <code>null</code>, in which case an icon is constructed, based on the + * default icon. + * + * @return The current "disabledIcon" property + */ + public Icon getDisabledIcon() + { + if (disabeldIcon == null && default_icon instanceof ImageIcon) + { + Image iconImage = ((ImageIcon) default_icon).getImage(); + Image grayImage = GrayFilter.createDisabledImage(iconImage); + disabeldIcon = new ImageIcon(grayImage); + } + + return disabeldIcon; + } + + /** + * Set the button's "disabledIcon" property. The look and feel class should + * paint this icon when the "enabled" property of the button's {@link + * ButtonModel} is <code>false</code>. This property may be + * <code>null</code>, in which case an icon is constructed, based on the + * default icon. + * + * @param disabledIcon The new "disabledIcon" property + */ + public void setDisabledIcon(Icon d) + { + disabeldIcon = d; + revalidate(); + repaint(); + } + + /** + * Return the button's "paintFocus" property. This property controls + * whether or not the look and feel class will paint a special indicator + * of focus state for the button. If it is false, the button still paints + * when focused, but no special decoration is painted to indicate the + * presence of focus. + * + * @return The current "paintFocus" property + */ + public boolean isFocusPainted() + { + return focusPainted; + } + + /** + * Set the button's "paintFocus" property. This property controls whether + * or not the look and feel class will paint a special indicator of focus + * state for the button. If it is false, the button still paints when + * focused, but no special decoration is painted to indicate the presence + * of focus. + * + * @param b The new "paintFocus" property + */ + public void setFocusPainted(boolean p) + { + if (focusPainted == p) + return; + + boolean old = focusPainted; + focusPainted = p; + firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, p); + revalidate(); + repaint(); + } + + /** + * Verifies that a particular key is one of the valid constants used for + * describing horizontal alignment and positioning. The valid constants + * are the following members of {@link SwingConstants}: + * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>, + * <code>LEADING</code> or <code>TRAILING</code>. + * + * @param key The key to check + * @param exception A message to include in an IllegalArgumentException + * + * @return the value of key + * + * @throws IllegalArgumentException If key is not one of the valid constants + * + * @see setHorizontalTextPosition() + * @see setHorizontalAlignment() + */ + protected int checkHorizontalKey(int key, String exception) + { + switch (key) + { + case SwingConstants.RIGHT: + case SwingConstants.LEFT: + case SwingConstants.CENTER: + case SwingConstants.LEADING: + case SwingConstants.TRAILING: + break; + default: + throw new IllegalArgumentException(exception); + } + return key; + } + + /** + * Verifies that a particular key is one of the valid constants used for + * describing vertical alignment and positioning. The valid constants are + * the following members of {@link SwingConstants}: <code>TOP</code>, + * <code>BOTTOM</code> or <code>CENTER</code>. + * + * @param key The key to check + * @param exception A message to include in an IllegalArgumentException + * + * @return the value of key + * + * @throws IllegalArgumentException If key is not one of the valid constants + * + * @see setVerticalTextPosition() + * @see setVerticalAlignment() + */ + protected int checkVerticalKey(int key, String exception) + { + switch (key) + { + case SwingConstants.TOP: + case SwingConstants.BOTTOM: + case SwingConstants.CENTER: + break; + default: + throw new IllegalArgumentException(exception); + } + return key; + } + + /** + * Configure various properties of the button by reading properties + * of an {@link Action}. The mapping of properties is as follows: + * + * <table> + * + * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr> + * + * <tr><td>NAME </td> <td>text </td></tr> + * <tr><td>SMALL_ICON </td> <td>icon </td></tr> + * <tr><td>SHORT_DESCRIPTION </td> <td>toolTipText </td></tr> + * <tr><td>MNEMONIC_KEY </td> <td>mnemonic </td></tr> + * <tr><td>ACTION_COMMAND_KEY </td> <td>actionCommand </td></tr> + * + * </table> + * + * <p>In addition, this method always sets the button's "enabled" property to + * the value of the Action's "enabled" property.</p> + * + * <p>If the provided Action is <code>null</code>, the text, icon, and + * toolTipText properties of the button are set to <code>null</code>, and + * the "enabled" property is set to <code>true</code>; the mnemonic and + * actionCommand properties are unchanged.</p> + * + * @param a An Action to configure the button from + */ + protected void configurePropertiesFromAction(Action a) + { + if (a == null) + { + setText(null); + setIcon(null); + setEnabled(true); + setToolTipText(null); + } + else + { + setText((String) (a.getValue(Action.NAME))); + setIcon((Icon) (a.getValue(Action.SMALL_ICON))); + setEnabled(a.isEnabled()); + setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION))); + if (a.getValue(Action.MNEMONIC_KEY) != null) + setMnemonic(((Integer) (a.getValue(Action.MNEMONIC_KEY))).intValue()); + String actionCommand = (String) (a.getValue(Action.ACTION_COMMAND_KEY)); + + // Set actionCommand to button's text by default if it is not specified + if (actionCommand != null) + setActionCommand((String) (a.getValue(Action.ACTION_COMMAND_KEY))); + else + setActionCommand(getText()); + } + } + + /** + * <p>A factory method which should return an {@link ActionListener} that + * propagates events from the button's {@link ButtonModel} to any of the + * button's ActionListeners. By default, this is an inner class which + * calls {@link AbstractButton.fireActionPerformed} with a modified copy + * of the incoming model {@link ActionEvent}.</p> + * + * <p>The button calls this method during construction, stores the + * resulting ActionListener in its <code>actionListener</code> member + * field, and subscribes it to the button's model. If the button's model + * is changed, this listener is unsubscribed from the old model and + * subscribed to the new one.</p> + * + * @return A new ActionListener + */ + protected ActionListener createActionListener() + { + return new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + AbstractButton.this.fireActionPerformed(e); + } + }; + } + + /** + * <p>A factory method which should return a {@link PropertyChangeListener} + * that accepts changes to the specified {@link Action} and reconfigure + * the {@link AbstractButton}, by default using the {@link + * configurePropertiesFromAction} method.</p> + * + * <p>The button calls this method whenever a new Action is assigned to + * the button's "action" property, via {@link setAction}, and stores the + * resulting PropertyChangeListener in its + * <code>actionPropertyChangeListener</code> member field. The button + * then subscribes the listener to the button's new action. If the + * button's action is changed subsequently, the listener is unsubscribed + * from the old action and subscribed to the new one.</p> + * + * @param a The Action which will be listened to, and which should be + * the same as the source of any PropertyChangeEvents received by the + * new listener returned from this method. + * + * @return A new PropertyChangeListener + */ + protected PropertyChangeListener createActionPropertyChangeListener(Action a) + { + return new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent e) + { + Action act = (Action) (e.getSource()); + if (e.getPropertyName().equals("enabled")) + setEnabled(act.isEnabled()); + else if (e.getPropertyName().equals(Action.NAME)) + setText((String) (act.getValue(Action.NAME))); + else if (e.getPropertyName().equals(Action.SMALL_ICON)) + setIcon((Icon) (act.getValue(Action.SMALL_ICON))); + else if (e.getPropertyName().equals(Action.SHORT_DESCRIPTION)) + setToolTipText((String) (act.getValue(Action.SHORT_DESCRIPTION))); + else if (e.getPropertyName().equals(Action.MNEMONIC_KEY)) + if (act.getValue(Action.MNEMONIC_KEY) != null) + setMnemonic(((Integer) (act.getValue(Action.MNEMONIC_KEY))) + .intValue()); + else if (e.getPropertyName().equals(Action.ACTION_COMMAND_KEY)) + setActionCommand((String) (act.getValue(Action.ACTION_COMMAND_KEY))); + } + }; + } + + /** + * <p>Factory method which creates a {@link ChangeListener}, used to + * subscribe to ChangeEvents from the button's model. Subclasses of + * AbstractButton may wish to override the listener used to subscribe to + * such ChangeEvents. By default, the listener just propagates the + * {@link ChangeEvent} to the button's ChangeListeners, via the {@link + * AbstractButton.fireStateChanged} method.</p> + * + * <p>The button calls this method during construction, stores the + * resulting ChangeListener in its <code>changeListener</code> member + * field, and subscribes it to the button's model. If the button's model + * is changed, this listener is unsubscribed from the old model and + * subscribed to the new one.</p> + * + * @return The new ChangeListener + */ + protected ChangeListener createChangeListener() + { + return new ChangeListener() + { + public void stateChanged(ChangeEvent e) + { + AbstractButton.this.fireStateChanged(); + AbstractButton.this.repaint(); + } + }; + } + + /** + * <p>Factory method which creates a {@link ItemListener}, used to + * subscribe to ItemEvents from the button's model. Subclasses of + * AbstractButton may wish to override the listener used to subscribe to + * such ItemEvents. By default, the listener just propagates the + * {@link ItemEvent} to the button's ItemListeners, via the {@link + * AbstractButton.fireItemStateChanged} method.</p> + * + * <p>The button calls this method during construction, stores the + * resulting ItemListener in its <code>changeListener</code> member + * field, and subscribes it to the button's model. If the button's model + * is changed, this listener is unsubscribed from the old model and + * subscribed to the new one.</p> + * + * <p>Note that ItemEvents are only generated from the button's model + * when the model's <em>selected</em> property changes. If you want to + * subscribe to other properties of the model, you must subscribe to + * ChangeEvents. + * + * @return The new ItemListener + */ + protected ItemListener createItemListener() + { + return new ItemListener() + { + public void itemStateChanged(ItemEvent e) + { + AbstractButton.this.fireItemStateChanged(e); + } + }; + } + + /** + * Programmatically perform a "click" on the button: arming, pressing, + * waiting, un-pressing, and disarming the model. + */ + public void doClick() + { + doClick(100); + } + + /** + * Programmatically perform a "click" on the button: arming, pressing, + * waiting, un-pressing, and disarming the model. + * + * @param pressTime The number of milliseconds to wait in the pressed state + */ + public void doClick(int pressTime) + { + getModel().setArmed(true); + getModel().setPressed(true); + try + { + java.lang.Thread.sleep(pressTime); + } + catch (java.lang.InterruptedException e) + { + // probably harmless + } + getModel().setPressed(false); + getModel().setArmed(false); + } + + /** + * Return the button's disabled selected icon. The look and feel class + * should paint this icon when the "enabled" property of the button's model + * is <code>false</code> and its "selected" property is + * <code>true</code>. This icon can be <code>null</code>, in which case + * it is synthesized from the button's selected icon. + * + * @return The current disabled selected icon + */ + public Icon getDisabledSelectedIcon() + { + return disabledSelectedIcon; + } + + /** + * Set the button's disabled selected icon. The look and feel class + * should paint this icon when the "enabled" property of the button's model + * is <code>false</code> and its "selected" property is + * <code>true</code>. This icon can be <code>null</code>, in which case + * it is synthesized from the button's selected icon. + * + * @param icon The new disabled selected icon + */ + public void setDisabledSelectedIcon(Icon icon) + { + if (disabledSelectedIcon == icon) + return; + + Icon old = disabledSelectedIcon; + disabledSelectedIcon = icon; + firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, icon); + revalidate(); + repaint(); + } + + /** + * Return the button's rollover icon. The look and feel class should + * paint this icon when the "rolloverEnabled" property of the button is + * <code>true</code> and the mouse rolls over the button. + * + * @return The current rollover icon + */ + public Icon getRolloverIcon() + { + return rolloverIcon; + } + + /** + * Set the button's rollover icon. The look and feel class should + * paint this icon when the "rolloverEnabled" property of the button is + * <code>true</code> and the mouse rolls over the button. + * + * @param rolloverIcon The new rollover icon + */ + public void setRolloverIcon(Icon r) + { + if (rolloverIcon == r) + return; + + Icon old = rolloverIcon; + rolloverIcon = r; + firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon); + revalidate(); + repaint(); + } + + /** + * Return the button's rollover selected icon. The look and feel class + * should paint this icon when the "rolloverEnabled" property of the button + * is <code>true</code>, the "selected" property of the button's model is + * <code>true</code>, and the mouse rolls over the button. + * + * @return The current rollover selected icon + */ + public Icon getRolloverSelectedIcon() + { + return rolloverSelectedIcon; + } + + /** + * Set the button's rollover selected icon. The look and feel class + * should paint this icon when the "rolloverEnabled" property of the button + * is <code>true</code>, the "selected" property of the button's model is + * <code>true</code>, and the mouse rolls over the button. + * + * @param rolloverSelectedIcon The new rollover selected icon + */ + public void setRolloverSelectedIcon(Icon r) + { + if (rolloverSelectedIcon == r) + return; + + Icon old = rolloverSelectedIcon; + rolloverSelectedIcon = r; + firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r); + revalidate(); + repaint(); + } + + /** + * Return the button's selected icon. The look and feel class should + * paint this icon when the "selected" property of the button's model is + * <code>true</code>, and either the "rolloverEnabled" property of the + * button is <code>false</code> or the mouse is not currently rolled + * over the button. + * + * @return The current selected icon + */ + public Icon getSelectedIcon() + { + return selectedIcon; + } + + /** + * Set the button's selected icon. The look and feel class should + * paint this icon when the "selected" property of the button's model is + * <code>true</code>, and either the "rolloverEnabled" property of the + * button is <code>false</code> or the mouse is not currently rolled + * over the button. + * + * @param selectedIcon The new selected icon + */ + public void setSelectedIcon(Icon s) + { + if (selectedIcon == s) + return; + + Icon old = selectedIcon; + selectedIcon = s; + firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, s); + revalidate(); + repaint(); + } + + /** + * Returns an single-element array containing the "text" property of the + * button if the "selected" property of the button's model is + * <code>true</code>, otherwise returns <code>null</code>. + * + * @return The button's "selected object" array + */ + public Object[] getSelectedObjects() + { + if (isSelected()) + { + Object[] objs = new Object[1]; + objs[0] = getText(); + return objs; + } + else + { + return null; + } + } + + /** + * Called when image data becomes available for one of the button's icons. + * + * @param img The image being updated + * @param infoflags One of the constant codes in {@link ImageObserver} used + * to describe updated portions of an image. + * @param x X coordinate of the region being updated + * @param y Y coordinate of the region being updated + * @param w Width of the region beign updated + * @param h Height of the region being updated + * + * @return <code>true</code> if img is equal to the button's current icon, + * otherwise <code>false</code> + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, + int h) + { + return current_icon == img; + } + + /** + * Returns the value of the button's "contentAreaFilled" property. This + * property indicates whether the area surrounding the text and icon of + * the button should be filled by the look and feel class. If this + * property is <code>false</code>, the look and feel class should leave + * the content area transparent. + * + * @return The current value of the "contentAreaFilled" property + */ + public boolean isContentAreaFilled() + { + return contentAreaFilled; + } + + /** + * Sets the value of the button's "contentAreaFilled" property. This + * property indicates whether the area surrounding the text and icon of + * the button should be filled by the look and feel class. If this + * property is <code>false</code>, the look and feel class should leave + * the content area transparent. + * + * @param b The new value of the "contentAreaFilled" property + */ + public void setContentAreaFilled(boolean b) + { + if (contentAreaFilled == b) + return; + + boolean old = contentAreaFilled; + contentAreaFilled = b; + firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b); + // The JDK sets the opaque property to the value of the contentAreaFilled + // property, so should we do. + setOpaque(b); + } + + /** + * Paints the button's border, if the button's "borderPainted" property is + * <code>true</code>, by out calling to the button's look and feel class. + * + * @param g The graphics context used to paint the border + */ + protected void paintBorder(Graphics g) + { + if (isBorderPainted()) + super.paintBorder(g); + } + + /** + * Returns a string, used only for debugging, which identifies or somehow + * represents this button. The exact value is implementation-defined. + * + * @return A string representation of the button + */ + protected String paramString() + { + StringBuffer sb = new StringBuffer(); + sb.append(super.paramString()); + sb.append(",defaultIcon="); + if (getIcon() != null) + sb.append(getIcon()); + sb.append(",disabledIcon="); + if (getDisabledIcon() != null) + sb.append(getDisabledIcon()); + sb.append(",disabledSelectedIcon="); + if (getDisabledSelectedIcon() != null) + sb.append(getDisabledSelectedIcon()); + sb.append(",margin="); + if (getMargin() != null) + sb.append(getMargin()); + sb.append(",paintBorder=").append(isBorderPainted()); + sb.append(",paintFocus=").append(isFocusPainted()); + sb.append(",pressedIcon="); + if (getPressedIcon() != null) + sb.append(getPressedIcon()); + sb.append(",rolloverEnabled=").append(isRolloverEnabled()); + sb.append(",rolloverIcon="); + if (getRolloverIcon() != null) + sb.append(getRolloverIcon()); + sb.append(",rolloverSelected="); + if (getRolloverSelectedIcon() != null) + sb.append(getRolloverSelectedIcon()); + sb.append(",selectedIcon="); + if (getSelectedIcon() != null) + sb.append(getSelectedIcon()); + sb.append(",text="); + if (getText() != null) + sb.append(getText()); + return sb.toString(); + } + + /** + * Set the "UI" property of the button, which is a look and feel class + * responsible for handling the button's input events and painting it. + * + * @param ui The new "UI" property + */ + public void setUI(ButtonUI ui) + { + super.setUI(ui); + } + + /** + * Set the "UI" property of the button, which is a look and feel class + * responsible for handling the button's input events and painting it. + * + * @return The current "UI" property + */ + public ButtonUI getUI() + { + return (ButtonUI) ui; + } + + /** + * Set the "UI" property to a class constructed, via the {@link + * UIManager}, from the current look and feel. This should be overridden + * for each subclass of AbstractButton, to retrieve a suitable {@link + * ButtonUI} look and feel class. + */ + public void updateUI() + { + } + + /** + * Returns the current time in milliseconds in which clicks gets coalesced + * into a single <code>ActionEvent</code>. + * + * @return the time in milliseconds + * + * @since 1.4 + */ + public long getMultiClickThreshhold() + { + return multiClickThreshhold; + } + + /** + * Sets the time in milliseconds in which clicks gets coalesced into a single + * <code>ActionEvent</code>. + * + * @param threshhold the time in milliseconds + * + * @since 1.4 + */ + public void setMultiClickThreshhold(long threshhold) + { + if (threshhold < 0) + throw new IllegalArgumentException(); + + multiClickThreshhold = threshhold; + } +} diff --git a/libjava/classpath/javax/swing/AbstractCellEditor.java b/libjava/classpath/javax/swing/AbstractCellEditor.java new file mode 100644 index 00000000000..86d3017f73d --- /dev/null +++ b/libjava/classpath/javax/swing/AbstractCellEditor.java @@ -0,0 +1,191 @@ +/* AbstractCellEditor.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.Serializable; +import java.util.EventObject; + +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.EventListenerList; + +/** + * The abstract superclass for table and tree cells. This provides some + * common shared functionality. + * + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class AbstractCellEditor + implements CellEditor, Serializable +{ + private static final long serialVersionUID = -1048006551406220959L; + + /** + * Our Swing event listeners. + */ + protected EventListenerList listenerList; + + /** + * The cached ChangeEvent. + */ + protected transient ChangeEvent changeEvent; + + /** + * Creates a new instance of AbstractCellEditor. + */ + public AbstractCellEditor() { + listenerList = new EventListenerList(); + changeEvent = new ChangeEvent(this); + } // AbstractCellEditor() + + /** + * Returns <code>true</code> if the cell is editable using + * <code>event</code>, <code>false</code> + * if it's not. The default behaviour is to return <code>true</code>. + * + * @param event an event + * + * @return <code>true</code> if the cell is editable using + * <code>event</code>, <code>false</code> if it's not + */ + public boolean isCellEditable(EventObject event) { + return true; + } // isCellEditable() + + /** + * Returns <code>true</code> if the editing cell should be selected, + * <code>false</code> otherwise. This is usually returning <code>true</code>, + * but in some special cases it might be useful not to switch cell selection + * when editing one cell. + * + * @param event an event + * + * @return <code>true</code> if the editing cell should be selected, + * <code>false</code> otherwise + */ + public boolean shouldSelectCell(EventObject event) { + return true; + } // shouldSelectCell() + + /** + * Stop editing the cell and accept any partial value that has been entered + * into the cell. + * + * @returns <code>true</code> if editing has been stopped successfully, + * <code>false</code>otherwise + */ + public boolean stopCellEditing() { + fireEditingStopped(); + return true; + } // stopCellEditing() + + /** + * Stop editing the cell and do not accept any partial value that has + * been entered into the cell. + */ + public void cancelCellEditing() { + fireEditingCanceled(); + } // cancelCellEditing() + + /** + * Adds a CellEditorListener to the list of CellEditorListeners of this + * CellEditor. + * + * @param listener the CellEditorListener to add + */ + public void addCellEditorListener (CellEditorListener listener) + { + listenerList.add (CellEditorListener.class, listener); + } + + /** + * Removes the specified CellEditorListener from the list of the + * CellEditorListeners of this CellEditor. + * + * @param listener the CellEditorListener to remove + */ + public void removeCellEditorListener (CellEditorListener listener) + { + listenerList.remove (CellEditorListener.class, listener); + } + + /** + * Returns the list of CellEditorListeners that have been registered + * in this CellEditor. + * + * @return the list of CellEditorListeners that have been registered + * in this CellEditor + * + * @since 1.4 + */ + public CellEditorListener[] getCellEditorListeners() + { + return (CellEditorListener[]) listenerList.getListeners + (CellEditorListener.class); + } + + /** + * Notifies all registered listeners that the editing of the cell has has been + * stopped. + */ + protected void fireEditingStopped() + { + CellEditorListener[] listeners = getCellEditorListeners(); + + for (int index = 0; index < listeners.length; index++) + { + listeners[index].editingStopped(changeEvent); + } + } + + /** + * Notifies all registered listeners that the editing of the cell has + * has been canceled. + */ + protected void fireEditingCanceled() + { + CellEditorListener[] listeners = getCellEditorListeners(); + + for (int index = 0; index < listeners.length; index++) + { + listeners[index].editingCanceled(changeEvent); + } + } +} diff --git a/libjava/classpath/javax/swing/AbstractListModel.java b/libjava/classpath/javax/swing/AbstractListModel.java new file mode 100644 index 00000000000..a924b73a25f --- /dev/null +++ b/libjava/classpath/javax/swing/AbstractListModel.java @@ -0,0 +1,179 @@ +/* AbstractListModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.EventListenerList; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; + +/** + * AbstractListModel + * + * @author Ronald Veldema + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class AbstractListModel implements ListModel, Serializable +{ + private static final long serialVersionUID = -3285184064379168730L; + + /** List of ListDataListeners called for each change to the list. */ + protected EventListenerList listenerList; + + public AbstractListModel() + { + listenerList = new EventListenerList(); + } + + /** + * Add a listener object to this model. The listener will be called + * any time the set of elements in the model is changed. + * + * @param listener The listener to add + */ + public void addListDataListener(ListDataListener listener) + { + listenerList.add(ListDataListener.class, listener); + } + + /** + * Add a listener object to this model. The listener will no longer be + * called when the set of elements in the model is changed. + * + * @param listener The listener to remove + */ + public void removeListDataListener(ListDataListener listener) + { + listenerList.remove(ListDataListener.class, listener); + } + + /** + * Call {@link ListDataListener#contentsChanged} on each element of the + * {@link listenerList} which is a {@link ListDataListener}. The event + * fired has type {@ListDataEvent.CONTENTS_CHANGED} and represents a + * change to the data elements in the range [startIndex, endIndex] + * inclusive. + * + * @param source The source of the change, typically <code>this</code> + * @param startIndex The index of the first element which changed + * @param endIndex The index of the last element which changed + */ + protected void fireContentsChanged(Object source, int startIndex, + int endIndex) + { + ListDataEvent event = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, + startIndex, endIndex); + ListDataListener[] listeners = getListDataListeners(); + + for (int index = 0; index < listeners.length; index++) + listeners[index].contentsChanged(event); + } + + /** + * Call {@link ListDataListener#intervalAdded} on each element of the + * {@link listenerList} which is a {@link ListDataListener}. The event + * fired has type {@ListDataEvent.INTERVAL_ADDED} and represents an + * addition of the data elements in the range [startIndex, endIndex] + * inclusive. + * + * @param source The source of the change, typically <code>this</code> + * @param startIndex The index of the first new element + * @param endIndex The index of the last new element + */ + protected void fireIntervalAdded(Object source, int startIndex, int endIndex) + { + ListDataEvent event = + new ListDataEvent(source, ListDataEvent.INTERVAL_ADDED, + startIndex, endIndex); + ListDataListener[] listeners = getListDataListeners(); + + for (int index = 0; index < listeners.length; index++) + listeners[index].intervalAdded(event); + } + + /** + * Call {@link ListDataListener#intervalRemoved} on each element of the + * {@link listenerList} which is a {@link ListDataListener}. The event + * fired has type {@ListDataEvent.INTERVAL_REMOVED} and represents a + * removal of the data elements in the range [startIndex, endIndex] + * inclusive. + * + * @param source The source of the change, typically <code>this</code> + * @param startIndex The index of the first element removed + * @param endIndex The index of the last element removed + */ + protected void fireIntervalRemoved(Object source, int startIndex, + int endIndex) + { + ListDataEvent event = + new ListDataEvent(source, ListDataEvent.INTERVAL_REMOVED, + startIndex, endIndex); + ListDataListener[] listeners = getListDataListeners(); + + for (int index = 0; index < listeners.length; index++) + listeners[index].intervalRemoved(event); + } + + /** + * Return the subset of {@link EventListener} objects found in this + * object's {@link listenerList} which are elements of the specified + * type. + * + * @param listenerType The type of listeners to select + * + * @return The set of listeners of the specified type + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * A synonym for <code>getListeners(ListDataListener.class)</code>. + * + * @return The set of ListDataListeners found in the {@link listenerList} + */ + public ListDataListener[] getListDataListeners() + { + return (ListDataListener[]) getListeners(ListDataListener.class); + } +} diff --git a/libjava/classpath/javax/swing/AbstractSpinnerModel.java b/libjava/classpath/javax/swing/AbstractSpinnerModel.java new file mode 100644 index 00000000000..05a98923fb0 --- /dev/null +++ b/libjava/classpath/javax/swing/AbstractSpinnerModel.java @@ -0,0 +1,117 @@ +/* AbstractSpinnerModel.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.util.EventListener; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +/** + * AbstractSpinnerModel + * @author Ka-Hing Cheung + * @version 1.0 + */ +public abstract class AbstractSpinnerModel implements SpinnerModel +{ + private ChangeEvent changeEvent = new ChangeEvent(this); + + protected EventListenerList listenerList = new EventListenerList(); + + /** + * Creates an <code>AbstractSpinnerModel</code>. + */ + public AbstractSpinnerModel() + { + } + + /** + * Adds a <code>ChangeListener</code>. + * + * @param listener the listener to add + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * Gets all the listeners that are of a particular type. + * + * @param c the type of listener + * @return the listeners that are of the specific type + */ + public EventListener[] getListeners(Class c) + { + return listenerList.getListeners(c); + } + + /** + * Gets all the <code>ChangeListener</code>s. + * + * @return all the <code>ChangeListener</code>s + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Remove a particular listener. + * + * @param listener the listener to remove + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * Fires a <code>ChangeEvent</code> to all the <code>ChangeListener</code>s + * added to this model + */ + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + for(int i = 0; i < listeners.length; ++i) + listeners[i].stateChanged(changeEvent); + } +} diff --git a/libjava/classpath/javax/swing/Action.java b/libjava/classpath/javax/swing/Action.java new file mode 100644 index 00000000000..17168c3be18 --- /dev/null +++ b/libjava/classpath/javax/swing/Action.java @@ -0,0 +1,153 @@ +/* Action.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.event.ActionListener; +import java.beans.PropertyChangeListener; + +/** + * An action provides a convenient central point of control for some task + * that can be triggered by more than one control in a Swing user interface + * (for example, a menu item and a toolbar button). + * + * @see AbstractButton#setAction(Action) + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + * @author Andrew Selkirk + */ +public interface Action extends ActionListener { + + /** + * A key to access the default property for the action (this is not used). + */ + String DEFAULT = "Default"; + + /** + * A key to access the long description for the action. + */ + String LONG_DESCRIPTION = "LongDescription"; + + /** + * A key to access the name for the action. + */ + String NAME = "Name"; + + /** + * A key to access the short description for the action (the short + * description is typically used as the tool tip text). + */ + String SHORT_DESCRIPTION = "ShortDescription"; + + /** + * A key to access the icon for the action. + */ + String SMALL_ICON = "SmallIcon"; + + /** + * A key to access the {@link KeyStroke} used as the accelerator for the + * action. + */ + String ACCELERATOR_KEY = "AcceleratorKey"; + + /** + * A key to access the action command string for the action. + */ + String ACTION_COMMAND_KEY = "ActionCommandKey"; + + /** + * A key to access the mnemonic for the action. + */ + String MNEMONIC_KEY = "MnemonicKey"; + + /** + * Returns the value associated with the specified key. + * + * @param key the key (not <code>null</code>). + * + * @return The value associated with the specified key, or + * <code>null</code> if the key is not found. + */ + Object getValue(String key); + + /** + * Sets the value associated with the specified key and sends a + * {@link java.beans.PropertyChangeEvent} to all registered listeners. + * The standard keys are defined in this interface: {@link #NAME}, + * {@link #SHORT_DESCRIPTION}, {@link #LONG_DESCRIPTION}, + * {@link #SMALL_ICON}, {@link #ACTION_COMMAND_KEY}, + * {@link #ACCELERATOR_KEY} and {@link #MNEMONIC_KEY}. Any existing value + * associated with the key will be overwritten. + * + * @param key the key (not <code>null</code>). + * @param value the value (<code>null</code> permitted). + */ + void putValue(String key, Object value); + + /** + * Returns the flag that indicates whether or not this action is enabled. + * + * @return The flag. + */ + boolean isEnabled(); + + /** + * Sets the flag that indicates whether or not this action is enabled. If + * the value changes, a {@link java.beans.PropertyChangeEvent} is sent to + * all registered listeners. + * + * @param b the new value of the flag. + */ + void setEnabled(boolean b); + + /** + * Registers a listener to receive notification whenever one of the + * action's properties is modified. + * + * @param listener the listener. + */ + void addPropertyChangeListener(PropertyChangeListener listener); + + /** + * Deregisters a listener so that it no longer receives notification of + * changes to the action's properties. + * + * @param listener the listener. + */ + void removePropertyChangeListener(PropertyChangeListener listener); + +} // Action diff --git a/libjava/classpath/javax/swing/ActionMap.java b/libjava/classpath/javax/swing/ActionMap.java new file mode 100644 index 00000000000..c6092578a5e --- /dev/null +++ b/libjava/classpath/javax/swing/ActionMap.java @@ -0,0 +1,211 @@ +/* ActionMap.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + + +/** + * @author Andrew Selkirk + * @author Michael Koch + */ +public class ActionMap + implements Serializable +{ + private static final long serialVersionUID = -6277518704513986346L; + + /** + * actionMap + */ + private Map actionMap = new HashMap(); + + /** + * parent + */ + private ActionMap parent; + + /** + * Creates a new <code>ActionMap</code> instance. + */ + public ActionMap() + { + } + + /** + * Returns an action associated with an object. + * + * @param key the key of the enty + * + * @return the action associated with key, may be null + */ + public Action get(Object key) + { + Object result = actionMap.get(key); + + if (result == null && parent != null) + result = parent.get(key); + + return (Action) result; + } + + /** + * Puts a new <code>Action</code> into the <code>ActionMap</code>. + * If action is null an existing entry will be removed. + * + * @param key the key for the entry + * @param action the action. + */ + public void put(Object key, Action action) + { + if (action == null) + actionMap.remove(key); + else + actionMap.put(key, action); + } + + /** + * Remove an entry from the <code>ActionMap</code>. + * + * @param key the key of the entry to remove + */ + public void remove(Object key) + { + actionMap.remove(key); + } + + /** + * Returns the parent of this <code>ActionMap</code>. + * + * @return the parent, may be null. + */ + public ActionMap getParent() + { + return parent; + } + + /** + * Sets a parent for this <code>ActionMap</code>. + * + * @param parentMap the new parent + */ + public void setParent(ActionMap parentMap) + { + if (parentMap != this) + parent = parentMap; + } + + /** + * Returns the number of entries in this <code>ActionMap</code>. + * + * @return the number of entries + */ + public int size() + { + return actionMap.size(); + } + + /** + * Clears the <code>ActionMap</code>. + */ + public void clear() + { + actionMap.clear(); + } + + /** + * Returns all keys of entries in this <code>ActionMap</code>. + * + * @return an array of keys + */ + public Object[] keys() + { + return actionMap.keySet().toArray(); + } + + /** + * Returns all keys of entries in this <code>ActionMap</code> + * and all its parents. + * + * @return an array of keys + */ + public Object[] allKeys() + { + Set set = new HashSet(); + + if (parent != null) + set.addAll(Arrays.asList(parent.allKeys())); + + set.addAll(actionMap.keySet()); + return set.toArray(); + } + + /** + * writeObject + * + * @param stream the stream to write to + * + * @exception IOException If an error occurs + */ + private void writeObject(ObjectOutputStream stream) + throws IOException + { + // TODO + } + + /** + * readObject + * + * @param stream the stream to read from + * + * @exception ClassNotFoundException If the serialized class cannot be found + * @exception IOException If an error occurs + */ + private void readObject(ObjectInputStream stream) + throws ClassNotFoundException, IOException + { + // TODO + } +} diff --git a/libjava/classpath/javax/swing/BorderFactory.java b/libjava/classpath/javax/swing/BorderFactory.java new file mode 100644 index 00000000000..b084b61a16a --- /dev/null +++ b/libjava/classpath/javax/swing/BorderFactory.java @@ -0,0 +1,451 @@ +/* BorderFactory.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Color; +import java.awt.Font; + +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.EtchedBorder; +import javax.swing.border.LineBorder; +import javax.swing.border.MatteBorder; +import javax.swing.border.TitledBorder; + +public class BorderFactory +{ + private BorderFactory() + { + // Do nothing. + } + + /** + * Creates a line border withe the specified color. + * + * @param color A color to use for the line. + * + * @return The Border object + */ + public static Border createLineBorder(Color color) + { + return null; + } + + /** + * Creates a line border withe the specified color and width. The width + * applies to all 4 sides of the border. To specify widths individually for + * the top, bottom, left, and right, use + * createMatteBorder(int,int,int,int,Color). + * + * @param color A color to use for the line. + * @param thickness An int specifying the width in pixels. + * + * @return The Border object + */ + public static Border createLineBorder(Color color, int thickness) + { + return new LineBorder(color, thickness); + } + + /** + * Created a border with a raised beveled edge, using brighter shades of + * the component's current background color for highlighting, and darker + * shading for shadows. (In a raised border, highlights are on top and + * shadows are underneath.) + * + * @return The Border object + */ + public static Border createRaisedBevelBorder() + { + return new BevelBorder(BevelBorder.RAISED); + } + + /** + * Created a border with a lowered beveled edge, using brighter shades of + * the component's current background color for highlighting, and darker + * shading for shadows. (In a lowered border, shadows are on top and + * highlights are underneath.) + * + * @return The Border object + */ + public static Border createLoweredBevelBorder() + { + return new BevelBorder(BevelBorder.LOWERED); + } + + /** + * Create a beveled border of the specified type, using brighter shades of + * the component's current background color for highlighting, and darker + * shading for shadows. (In a lowered border, shadows are on top and + * highlights are underneath.). + * + * @param type An int specifying either BevelBorder.LOWERED or + * BevelBorder.RAISED + * + * @return The Border object + */ + public static Border createBevelBorder(int type) + { + return new BevelBorder(type); + } + + /** + * Create a beveled border of the specified type, using the specified + * highlighting and shadowing. The outer edge of the highlighted area uses + * a brighter shade of the highlight color. The inner edge of the shadow + * area uses a brighter shade of the shadaw color. + * + * @param type An int specifying either BevelBorder.LOWERED or + * BevelBorder.RAISED + * @param highlight A Color object for highlights + * @param shadow A Color object for shadows + * + * @return The Border object + */ + public static Border createBevelBorder(int type, Color highlight, Color shadow) + { + return new BevelBorder(type, highlight, shadow); + } + + /** + * Create a beveled border of the specified type, using the specified colors + * for the inner and outer highlight and shadow areas. + * + * @param type An int specifying either BevelBorder.LOWERED or + * BevelBorder.RAISED + * @param highlightOuter A Color object for the outer edge of the + * highlight area + * @param highlightInner A Color object for the inner edge of the + * highlight area + * @param shadowOuter A Color object for the outer edge of the shadow area + * @param shadowInner A Color object for the inner edge of the shadow area + * + * @return The Border object + */ + public static Border createBevelBorder(int type, Color highlightOuter, + Color highlightInner, + Color shadowOuter, Color shadowInner) + { + return new BevelBorder(type, highlightOuter, highlightInner, shadowOuter, + shadowInner); + } + + /** + * Create a border with an "etched" look using the component's current + * background color for highlighting and shading. + * + * @return The Border object + */ + public static Border createEtchedBorder() + { + return new EtchedBorder(); + } + + /** + * Create a border with an "etched" look using the component's current + * background color for highlighting and shading. + * + * @return The Border object + */ + public static Border createEtchedBorder(int etchType) + { + return new EtchedBorder(etchType); + } + + /** + * Create a border with an "etched" look using the specified highlighting and + * shading colors. + * + * @param highlight A Color object for the border highlights + * @param shadow A Color object for the border shadows + * + * @return The Border object + */ + public static Border createEtchedBorder(Color highlight, Color shadow) + { + return new EtchedBorder(highlight, shadow); + } + + /** + * Create a border with an "etched" look using the specified highlighting and + * shading colors. + * + * @param highlight A Color object for the border highlights + * @param shadow A Color object for the border shadows + * + * @return The Border object + */ + public static Border createEtchedBorder(int etchType, Color highlight, + Color shadow) + { + return new EtchedBorder(etchType, highlight, shadow); + } + + /** + * Create a new title border specifying the text of the title, using the + * default border (etched), using the default text position (sitting on the + * top line) and default justification (left) and using the default font and + * text color determined by the current look and feel. + * + * @param title A String containing the text of the title + * + * @return The TitledBorder object + */ + public static TitledBorder createTitledBorder(String title) + { + return new TitledBorder(title); + } + + /** + * Create a new title border with an empty title specifying the border + * object, using the default text position (sitting on the top line) and + * default justification (left) and using the default font, text color, + * and border determined by the current look and feel. (The Motif and Windows + * look and feels use an etched border; The Java look and feel use a + * gray border.) + * + * @param border The Border object to add the title to + * + * @return The TitledBorder object + */ + public static TitledBorder createTitledBorder(Border border) + { + return new TitledBorder(border); + } + + /** + * Add a title to an existing border, specifying the text of the title, using + * the default positioning (sitting on the top line) and default + * justification (left) and using the default font and text color determined + * by the current look and feel. + * + * @param order The Border object to add the title to + * @param title A String containing the text of the title + * + * @return The TitledBorder object + */ + public static TitledBorder createTitledBorder(Border border, String title) + { + return new TitledBorder(border, title); + } + + /** + * Add a title to an existing border, specifying the text of the title along + * with its positioning, using the default font and text color determined by + * the current look and feel. + * + * @param border The Border object to add the title to + * @param title A String containing the text of the title + * @param titleJustification An int specifying the left/right position of + * the title -- one of TitledBorder.LEFT, TitledBorder.CENTER, or + * TitledBorder.RIGHT, TitledBorder.DEFAULT_JUSTIFICATION (left). + * @param titlePosition An int specifying the vertical position of the text + * in relation to the border -- one of: TitledBorder.ABOVE_TOP, + * TitledBorder.TOP (sitting on the top line), TitledBorder.BELOW_TOP, + * TitledBorder.ABOVE_BOTTOM, TitledBorder.BOTTOM (sitting on the bottom + * line), TitledBorder.BELOW_BOTTOM, or TitledBorder.DEFAULT_POSITION + * (top). + * + * @return The TitledBorder object + */ + public static TitledBorder createTitledBorder(Border border, String title, + int titleJustification, + int titlePosition) + { + return new TitledBorder(border, title, titleJustification, titlePosition); + } + + /** + * Add a title to an existing border, specifying the text of the title along + * with its positioning and font, using the default text color determined by + * the current look and feel. + * + * @param border - the Border object to add the title to + * @param title - a String containing the text of the title + * @param titleJustification - an int specifying the left/right position of + * the title -- one of TitledBorder.LEFT, TitledBorder.CENTER, or + * TitledBorder.RIGHT, TitledBorder.DEFAULT_JUSTIFICATION (left). + * @param titlePosition - an int specifying the vertical position of the + * text in relation to the border -- one of: TitledBorder.ABOVE_TOP, + * TitledBorder.TOP (sitting on the top line), TitledBorder.BELOW_TOP, + * TitledBorder.ABOVE_BOTTOM, TitledBorder.BOTTOM (sitting on the bottom + * line), TitledBorder.BELOW_BOTTOM, or TitledBorder.DEFAULT_POSITION (top). + * @param titleFont - a Font object specifying the title font + * + * @return The TitledBorder object + */ + public static TitledBorder createTitledBorder(Border border, String title, + int titleJustification, + int titlePosition, + Font titleFont) + { + return new TitledBorder(border, title, titleJustification, titlePosition, + titleFont); + } + + /** + * Add a title to an existing border, specifying the text of the title along + * with its positioning, font, and color. + * + * @param border - the Border object to add the title to + * @param title - a String containing the text of the title + * @param titleJustification - an int specifying the left/right position of + * the title -- one of TitledBorder.LEFT, TitledBorder.CENTER, or + * TitledBorder.RIGHT, TitledBorder.DEFAULT_JUSTIFICATION (left). + * @param titlePosition - an int specifying the vertical position of the text + * in relation to the border -- one of: TitledBorder.ABOVE_TOP, + * TitledBorder.TOP (sitting on the top line), TitledBorder.BELOW_TOP, + * TitledBorder.ABOVE_BOTTOM, TitledBorder.BOTTOM (sitting on the bottom + * line), TitledBorder.BELOW_BOTTOM, or TitledBorder.DEFAULT_POSITION (top). + * @param titleFont - a Font object specifying the title font + * @param titleColor - a Color object specifying the title color + * + * @return The TitledBorder object + */ + public static TitledBorder createTitledBorder(Border border, String title, + int titleJustification, + int titlePosition, + Font titleFont, Color titleColor) + { + return new TitledBorder(border, title, titleJustification, titlePosition, + titleFont, titleColor); + } + + /** + * Creates an empty border that takes up no space. (The width of the top, + * bottom, left, and right sides are all zero.) + * + * @return The Border object + */ + public static Border createEmptyBorder() + { + return new EmptyBorder(0, 0, 0, 0); + } + + /** + * Creates an empty border that takes up no space but which does no drawing, + * specifying the width of the top, left, bottom, and right sides. + * + * @param top An int specifying the width of the top in pixels + * @param left An int specifying the width of the left side in pixels + * @param bottom An int specifying the width of the right side in pixels + * @param right An int specifying the width of the bottom in pixels + * + * @return The Border object + */ + public static Border createEmptyBorder(int top, int left, int bottom, + int right) + { + return new EmptyBorder(top, left, bottom, right); + } + + /** + * Create a compound border with a null inside edge and a null outside edge. + * + * @return The CompoundBorder object + */ + public static CompoundBorder createCompoundBorder() + { + return new CompoundBorder(); + } + + /** + * Create a compound border specifying the border objects to use for the + * outside and inside edges. + * + * @param outsideBorder A Border object for the outer edge of the + * compound border + * @param insideBorder A Border object for the inner edge of the + * compound border + * + * @return The CompoundBorder object + */ + public static CompoundBorder createCompoundBorder(Border outsideBorder, + Border insideBorder) + { + return new CompoundBorder(outsideBorder, insideBorder); + } + + /** + * Create a matte-look border using a solid color. (The difference between + * this border and a line border is that you can specify the individual border + * dimensions.) + * + * @param top + * An int specifying the width of the top in pixels + * @param left + * An int specifying the width of the left side in pixels + * @param bottom + * An int specifying the width of the right side in pixels + * @param right + * An int specifying the width of the bottom in pixels + * @param color + * A Color to use for the border + * @return The MatteBorder object + */ + public static MatteBorder createMatteBorder(int top, int left, int bottom, + int right, Color color) + { + return new MatteBorder(top, left, bottom, right, color); + } + + /** + * Create a matte-look border that consists of multiple tiles of a specified + * icon. Multiple copies of the icon are placed side-by-side to fill up the + * border area. + * + * Note: + * If the icon doesn't load, the border area is painted gray. + * + * @param top An int specifying the width of the top in pixels + * @param left An int specifying the width of the left side in pixels + * @param bottom An int specifying the width of the right side in pixels + * @param right An int specifying the width of the bottom in pixels + * @param tileIcon The Icon object used for the border tiles + * + * @return The MatteBorder object + */ + public static MatteBorder createMatteBorder(int top, int left, int bottom, + int right, Icon tileIcon) + { + return new MatteBorder(top, left, bottom, right, tileIcon); + } +} diff --git a/libjava/classpath/javax/swing/BoundedRangeModel.java b/libjava/classpath/javax/swing/BoundedRangeModel.java new file mode 100644 index 00000000000..5f85000d66b --- /dev/null +++ b/libjava/classpath/javax/swing/BoundedRangeModel.java @@ -0,0 +1,171 @@ +/* BoundedRangeModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import javax.swing.event.ChangeListener; + +/** + * The data model that is used in components that display a range of values, + * like {@link JProgressBar} and {@link JSlider}. + * + * @author Andrew Selkirk + */ +public interface BoundedRangeModel +{ + /** + * getValue + * + * @return int + * + * @see #setValue(int) + */ + int getValue(); + + /** + * setValue + * + * @param value the value + * + * @see #getValue() + */ + void setValue(int value); + + /** + * getMinimum + * + * @return int + * + * @see #setMinimum(int) + */ + int getMinimum(); + + /** + * setMinimum + * + * @param minimum the minimum value + * + * @see #getMinimum() + */ + void setMinimum(int minimum); + + /** + * getMaximum + * + * @return int + * + * @see #setMaximum(int) + */ + int getMaximum(); + + /** + * setMaximum + * + * @param maximum the maximum value + * + * @see #getMaximum() + */ + void setMaximum(int maximum); + + /** + * Returns the value of the <code>valueIsAdjusting</code> property. + * + * @return <code>true</code> if value is adjusting, + * otherwise <code>false</code> + * + * @see setValueIsAdjusting(boolean) + */ + boolean getValueIsAdjusting(); + + /** + * setValueIsAdjusting + * + * @param adjusting <code>true</code> if adjusting, + * <code>false</code> otherwise + * + * @see #getValueIsAdjusting() + */ + void setValueIsAdjusting(boolean adjusting); + + /** + * Returns the current extent. + * + * @return the extent + * + * @see #setExtent(int) + */ + int getExtent(); + + /** + * setExtent + * + * @param extent the extent + * + * @see #getExtent() + */ + void setExtent(int extent); + + /** + * setRangeProperties + * @param value the value + * @param extent the extent + * @param minnimum the minimum value + * @param maximum the maximum value + * @param adjusting TODO + */ + void setRangeProperties(int value, int extent, int minimum, int maximum, + boolean adjusting); + + /** + * Adds a <code>ChangeListener</code> to this object. + * + * @param listener the listener to add + * + * @see #removeChangeListener(javax.swing.event.ChangeListener) + */ + void addChangeListener(ChangeListener listener); + + /** + * Removes a <code>ChangeListener</code> from this object. + * + * @param listener the listener to remove + * + * @see #addChangeListener(javax.swing.event.ChangeListener) + */ + void removeChangeListener(ChangeListener listener); +} diff --git a/libjava/classpath/javax/swing/Box.java b/libjava/classpath/javax/swing/Box.java new file mode 100644 index 00000000000..546a2822088 --- /dev/null +++ b/libjava/classpath/javax/swing/Box.java @@ -0,0 +1,287 @@ +/* Box.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.AWTError; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.LayoutManager; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * A component that uses a {@link BoxLayout} as Layout Manager. + * + * In addition to that, this class provides a set of static methods for + * creating some filler components ('struts' and 'glue') for use in + * containers that are laid out using BoxLayout. + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class Box extends JComponent implements Accessible +{ + private static final long serialVersionUID = 1525417495883046342L; + + // FIXME: disable to make libjava compile; visibility rules are broken + protected class AccessibleBox // extends Container.AccessibleAWTContainer + { + private static final long serialVersionUID = -7775079816389931944L; + + protected AccessibleBox() + { + } + + public AccessibleRole getAccessibleRole() + { + return null; + } + } + + /** + * A component that servers as a filler in BoxLayout controlled containers. + */ + public static class Filler extends JComponent implements Accessible + { + private static final long serialVersionUID = -1204263191910183998L; + + // FIXME: disable to make libjava compile; visibility rules are broken + protected class AccessibleBoxFiller // extends Component.AccessibleAWTComponent + { + private static final long serialVersionUID = 164963348357479321L; + + protected AccessibleBoxFiller() + { + } + + public AccessibleRole getAccessibleRole() + { + return null; + } + } + + protected AccessibleContext accessibleContext; + + private transient Dimension min, pref, max; + + /** + * Creates a new instance of Filler. + * + * @param min the minimum size of the filler. + * @param pref the preferred size of the filler. + * @param max the maximum size of the filler. + */ + public Filler(Dimension min, Dimension pref, Dimension max) + { + changeShape(min, pref, max); + } + + /** + * Changes the dimensions of this Filler. + * + * @param min the new minimum size of the filler. + * @param pref the new preferred size of the filler. + * @param max the new maximum size of the filler. + */ + public void changeShape(Dimension min, Dimension pref, Dimension max) + { + this.min = min; + this.pref = pref; + this.max = max; + } + + public AccessibleContext getAccessibleContext() + { + // FIXME: disable to make libjava compile; visibility rules are broken + // if (accessibleContext == null) + // accessibleContext = new AccessibleBoxFiller(); + return accessibleContext; + } + + /** + * Returns the maximum size of this Filler. + * + * @return the maximum size of this Filler. + */ + public Dimension getMaximumSize() + { + return max; + } + + /** + * Returns the minimum size of this Filler. + * + * @return the minimum size of this Filler. + */ + public Dimension getMinimumSize() + { + return min; + } + + /** + * Returns the preferred size of this Filler. + * + * @return the preferred size of this Filler. + */ + public Dimension getPreferredSize() + { + return pref; + } + } + + /** + * Creates a new Box component, that lays out its children according + * to the <code>axis</code> parameter. + * + * @param axis the orientation of the BoxLayout. + * + * @see BoxLayout#X_AXIS + * @see BoxLayout#Y_AXIS + * @see BoxLayout#LINE_AXIS + * @see BoxLayout#PAGE_AXIS + */ + public Box(int axis) + { + super.setLayout(new BoxLayout(this, axis)); + } + + /** + * Creates a filler component which acts as glue between components. + * It does not take space unless some extra space is available. If extra + * space is available, this component can expand in both X and Y directions. + * + * @return a glue-like filler component. + */ + public static Component createGlue() + { + Filler glue = new Filler(new Dimension(0,0), new Dimension(0,0), + new Dimension(Short.MAX_VALUE,Short.MAX_VALUE) + ); + return glue; + } + + public static Box createHorizontalBox() + { + return new Box(BoxLayout.X_AXIS); + } + + /** + * Creates a filler component which acts as glue between components. + * It does not take space unless some extra space is available. If extra + * space is available, this component can expand in the X direction. + * + * @return a glue-like filler component. + */ + public static Component createHorizontalGlue() + { + Filler glue = new Filler(new Dimension(0,0), new Dimension(0,0), + new Dimension(Short.MAX_VALUE, 0) + ); + return glue; + } + + /** + * Creates a filler component which acts as strut between components. + * It will fill exactly the specified horizontal size. + * + * @param width the width of this strut in pixels. + * + * @return a strut-like filler component. + */ + public static Component createHorizontalStrut(int width) + { + Filler strut = new Filler(new Dimension(width, 0), + new Dimension(width, 0), + new Dimension(width, Integer.MAX_VALUE)); + return strut; + } + + public static Component createRigidArea(Dimension d) + { + return new Filler(d, d, d); + } + + public static Box createVerticalBox() + { + return new Box(BoxLayout.Y_AXIS); + } + + /** + * Creates a filler component which acts as glue between components. + * It does not take space unless some extra space is available. If extra + * space is available, this component can expand in the Y direction. + * + * @return a glue-like filler component. + */ + public static Component createVerticalGlue() + { + return createGlue(); + } + + /** + * Creates a filler component which acts as strut between components. + * It will fill exactly the specified vertical size. + * + * @param height the height of this strut in pixels. + * + * @return a strut-like filler component. + */ + public static Component createVerticalStrut(int height) + { + Filler strut = new Filler(new Dimension(0, height), + new Dimension(0, height), + new Dimension(Integer.MAX_VALUE, height)); + return strut; + } + + public void setLayout(LayoutManager l) + { + throw new AWTError("Not allowed to set layout managers for boxes."); + } + + public AccessibleContext getAccessibleContext() + { + // if (accessibleContext == null) + // accessibleContext = new AccessibleBox(); + return accessibleContext; + } + + +} diff --git a/libjava/classpath/javax/swing/BoxLayout.java b/libjava/classpath/javax/swing/BoxLayout.java new file mode 100644 index 00000000000..5dfe1d6b735 --- /dev/null +++ b/libjava/classpath/javax/swing/BoxLayout.java @@ -0,0 +1,746 @@ +/* BoxLayout.java -- A layout for swing components. + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.AWTError; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager2; +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import gnu.java.awt.AWTUtilities; + +/** + * A layout for swing components. + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + * @author Roman Kennke (roman@kennke.org) + */ +public class BoxLayout implements LayoutManager2, Serializable +{ + + /** + * This is an abstraction that allows the BoxLayout algorithm to + * be applied to both direction (X and Y) without duplicating the + * algorithm. It defines several methods that access properties of + * a component for a specific direction. + */ + static interface Direction + { + /** + * Returns the correct part of <code>d</code> for this direction. This will + * be <code>d.width</code> for horizontal and <code>d.height</code> for + * vertical direction. + * + * @param d the size as Dimension object + * + * @return the correct part of <code>d</code> for this direction + */ + int size(Dimension d); + + /** + * Returns the lower bounds of the {@link Insets} object according to this + * direction. This will be <code>insets.top</code> for vertical direction + * and <code>insets.left</code> for horizontal direction. + * + * @param the {@link Insets} object from which to return the lower bounds + * + * @return the lower bounds of the {@link Insets} object according to this + * direction + */ + int lower(Insets insets); + + /** + * Returns the alignment property according to this direction. + * + * @param comp the Component for which to return the alignment property + * + * @return the alignment property according to this direction + */ + float alignment(Component comp); + + /** + * Sets the location for Component <code>c</code>. <code>coord1</code> + * specifies the coordinate of the location in this direction, + * <code>coord2</code> the coordinate of the location in the opposite + * direction. + * + * @param c the Component for which to set the location + * @param coord1 the coordinate in this direction + * @param coord2 the coordinate in the opposite direction + */ + void setLocation(Component c, int coord1, int coord2); + + /** + * Sets the size for Component <code>c</code>. <code>coord1</code> + * specifies the size in this direction, + * <code>coord2</code> the size in the opposite + * direction. + * + * @param c the Component for which to set the size + * @param size1 the size in this direction + * @param size2 the size in the opposite direction + */ + void setSize(Component c, int size1, int size2); + } + + /** + * The horizontal direction. + */ + static class Horizontal implements Direction + { + /** + * Returns the correct part of <code>d</code> for this direction. This will + * be <code>d.width</code> for horizontal and <code>d.height</code> for + * vertical direction. + * + * @param d the size as Dimension object + * + * @return the correct part of <code>d</code> for this direction + */ + public int size(Dimension d) + { + return d.width; + } + + /** + * Returns the lower bounds of the {@link Insets} object according to this + * direction. This will be <code>insets.top</code> for vertical direction + * and <code>insets.left</code> for horizontal direction. + * + * @param the {@link Insets} object from which to return the lower bounds + * + * @return the lower bounds of the {@link Insets} object according to this + * direction + */ + public int lower(Insets insets) + { + return insets.left; + } + + /** + * Returns the alignment property according to this direction. + * + * @param comp the Component for which to return the alignment property + * + * @return the alignment property according to this direction + */ + public float alignment(Component comp) + { + return comp.getAlignmentX(); + } + + /** + * Sets the location for Component <code>c</code>. <code>coord1</code> + * specifies the coordinate of the location in this direction, + * <code>coord2</code> the coordinate of the location in the opposite + * direction. + * + * @param c the Component for which to set the location + * @param coord1 the coordinate in this direction + * @param coord2 the coordinate in the opposite direction + */ + public void setLocation(Component c, int coord1, int coord2) + { + c.setLocation(coord1, coord2); + } + + /** + * Sets the size for Component <code>c</code>. <code>coord1</code> + * specifies the size in this direction, + * <code>coord2</code> the size in the opposite + * direction. + * + * @param c the Component for which to set the size + * @param size1 the size in this direction + * @param size2 the size in the opposite direction + */ + public void setSize(Component c, int size1, int size2) + { + c.setSize(size1, size2); + } + } + /** + * The vertical direction. + */ + static class Vertical implements Direction + { + /** + * Returns the correct part of <code>d</code> for this direction. This will + * be <code>d.width</code> for horizontal and <code>d.height</code> for + * vertical direction. + * + * @param d the size as Dimension object + * + * @return the correct part of <code>d</code> for this direction + */ + public int size(Dimension d) + { + return d.height; + } + + /** + * Returns the lower bounds of the {@link Insets} object according to this + * direction. This will be <code>insets.top</code> for vertical direction + * and <code>insets.left</code> for horizontal direction. + * + * @param the {@link Insets} object from which to return the lower bounds + * + * @return the lower bounds of the {@link Insets} object according to this + * direction + */ + public int lower(Insets insets) + { + return insets.top; + } + + /** + * Returns the alignment property according to this direction. + * + * @param comp the Component for which to return the alignment property + * + * @return the alignment property according to this direction + */ + public float alignment(Component comp) + { + return comp.getAlignmentY(); + } + + /** + * Sets the location for Component <code>c</code>. <code>coord1</code> + * specifies the coordinate of the location in this direction, + * <code>coord2</code> the coordinate of the location in the opposite + * direction. + * + * @param c the Component for which to set the location + * @param coord1 the coordinate in this direction + * @param coord2 the coordinate in the opposite direction + */ + public void setLocation(Component c, int coord1, int coord2) + { + c.setLocation(coord2, coord1); + } + + /** + * Sets the size for Component <code>c</code>. <code>coord1</code> + * specifies the size in this direction, + * <code>coord2</code> the size in the opposite + * direction. + * + * @param c the Component for which to set the size + * @param size1 the size in this direction + * @param size2 the size in the opposite direction + */ + public void setSize(Component c, int size1, int size2) + { + c.setSize(size2, size1); + } + } + + /** + * A helper class that temporarily stores the size specs of a component. + */ + static class SizeReq + { + int size; + int min; + int pref; + int max; + float align; + Component comp; + SizeReq(Component comp, Direction dir) + { + this.min = dir.size(comp.getMinimumSize()); + this.pref = dir.size(comp.getPreferredSize()); + this.max = dir.size(comp.getMaximumSize()); + this.size = dir.size(comp.getSize()); + this.align = dir.alignment(comp); + this.comp = comp; + } + } + + /** + * Specifies that components are laid out left to right. + */ + public static final int X_AXIS = 0; + + /** + * Specifies that components are laid out top to bottom. + */ + public static final int Y_AXIS = 1; + + /** + * Specifies that components are laid out in the direction of a line of text. + */ + public static final int LINE_AXIS = 2; + + /** + * Sepcifies that components are laid out in the direction of the line flow. + */ + public static final int PAGE_AXIS = 3; + + /* + * Needed for serialization. + */ + private static final long serialVersionUID = -2474455742719112368L; + + /* + * The container given to the constructor. + */ + private Container container; + + /* + * Current type of component layouting. Defaults to X_AXIS. + */ + private int way = X_AXIS; + + /** Constant for the horizontal direction. */ + private static final Direction HORIZONTAL = new Horizontal(); + + /** Constant for the vertical direction. */ + private static final Direction VERTICAL = new Vertical(); + + /** + * Constructs a <code>BoxLayout</code> object. + * + * @param container The container that needs to be laid out. + * @param way The orientation of the components. + * + * @exception AWTError If way has an invalid value. + */ + public BoxLayout(Container container, int way) + { + int width = 0; + int height = 0; + this.container = container; + this.way = way; + } + + /** + * Adds a component to the layout. Not used in BoxLayout. + * + * @param name The name of the component to add. + * @param component the component to add to the layout. + */ + public void addLayoutComponent(String name, Component component) + { + } + + /** + * Removes a component from the layout. Not used in BoxLayout. + * + * @param component The component to remove from the layout. + */ + public void removeLayoutComponent(Component component) + { + } + + private boolean isHorizontalIn(Container parent) + { + ComponentOrientation orientation = parent.getComponentOrientation(); + return this.way == X_AXIS + || (this.way == LINE_AXIS + && orientation.isHorizontal()) + || (this.way == PAGE_AXIS + && (!orientation.isHorizontal())); + } + + + + /** + * Returns the preferred size of the layout. + * + * @param parent The container that needs to be laid out. + * + * @return The dimension of the layout. + */ + public Dimension preferredLayoutSize(Container parent) + { + if (parent != container) + throw new AWTError("invalid parent"); + + Insets insets = parent.getInsets(); + int x = 0; + int y = 0; + + List children = AWTUtilities.getVisibleChildren(parent); + + if (isHorizontalIn(parent)) + { + x = insets.left + insets.right; + // sum up preferred widths of components, find maximum of preferred + // heights + for (Iterator i = children.iterator(); i.hasNext();) + { + Component comp = (Component) i.next(); + Dimension sz = comp.getPreferredSize(); + x += sz.width; + y = Math.max(y, sz.height); + } + y += insets.bottom + insets.top; + } + else + { + y = insets.top + insets.bottom; + // sum up preferred heights of components, find maximum of + // preferred widths + for (Iterator i = children.iterator(); i.hasNext();) + { + Component comp = (Component) i.next(); + Dimension sz = comp.getPreferredSize(); + y += sz.height; + x = Math.max(x, sz.width); + } + x += insets.left + insets.right; + } + + return new Dimension(x, y); + } + + /** + * Returns the minimum size of the layout. + * + * @param parent The container that needs to be laid out. + * + * @return The dimension of the layout. + */ + public Dimension minimumLayoutSize(Container parent) + { + if (parent != container) + throw new AWTError("invalid parent"); + + Insets insets = parent.getInsets(); + int x = insets.left + insets.right; + int y = insets.bottom + insets.top; + + List children = AWTUtilities.getVisibleChildren(parent); + + if (isHorizontalIn(parent)) + { + // sum up preferred widths of components, find maximum of preferred + // heights + for (Iterator i = children.iterator(); i.hasNext();) + { + Component comp = (Component) i.next(); + Dimension sz = comp.getMinimumSize(); + x += sz.width; + y = Math.max(y, sz.height); + } + } + else + { + // sum up preferred heights of components, find maximum of + // preferred widths + for (Iterator i = children.iterator(); i.hasNext();) + { + Component comp = (Component) i.next(); + Dimension sz = comp.getMinimumSize(); + y += sz.height; + x = Math.max(x, sz.width); + } + } + + return new Dimension(x, y); + } + + /** + * Lays out the specified container using this layout. + * + * @param parent The container that needs to be laid out. + */ + public void layoutContainer(Container parent) + { + if (isHorizontalIn(parent)) + layoutAlgorithm(parent, HORIZONTAL, VERTICAL); + else + layoutAlgorithm(parent, VERTICAL, HORIZONTAL); + } + + /** + * Adds a component to the layout. Not used in BoxLayout + * + * @param child The component to add to the layout. + * @param constraints The constraints for the component in the layout. + */ + public void addLayoutComponent(Component child, Object constraints) + { + } + + /** + * Returns the alignment along the X axis for the container. + * + * @param parent The container that needs to be laid out. + * + * @return The alignment. + */ + public float getLayoutAlignmentX(Container parent) + { + if (parent != container) + throw new AWTError("invalid parent"); + + return 0; + } + + /** + * Returns the alignment along the Y axis for the container. + * + * @param parent The container that needs to be laid out. + * + * @return The alignment. + */ + public float getLayoutAlignmentY(Container parent) + { + if (parent != container) + throw new AWTError("invalid parent"); + + return 0; + } + + /** + * Invalidates the layout. + * + * @param parent The container that needs to be laid out. + */ + public void invalidateLayout(Container parent) + { + if (parent != container) + throw new AWTError("invalid parent"); + } + + /** + * Returns the maximum size of the layout gived the components + * in the given container. + * + * @param parent The container that needs to be laid out. + * + * @return The dimension of the layout. + */ + public Dimension maximumLayoutSize(Container parent) + { + if (parent != container) + throw new AWTError("invalid parent"); + + Insets insets = parent.getInsets(); + int x = insets.left + insets.right; + int y = insets.top + insets.bottom; + + List children = AWTUtilities.getVisibleChildren(parent); + + if (isHorizontalIn(parent)) + { + + // sum up preferred widths of components, find maximum of preferred + // heights + for (Iterator i = children.iterator(); i.hasNext();) + { + Component comp = (Component) i.next(); + Dimension sz = comp.getMaximumSize(); + x += sz.width; + // Check for overflow. + if (x < 0) + x = Integer.MAX_VALUE; + y = Math.max(y, sz.height); + } + } + else + { + // sum up preferred heights of components, find maximum of + // preferred widths + for (Iterator i = children.iterator(); i.hasNext();) + { + Component comp = (Component) i.next(); + Dimension sz = comp.getMaximumSize(); + y += sz.height; + // Check for overflow + if (y < 0) + y = Integer.MAX_VALUE; + x = Math.max(x, sz.width); + } + } + return new Dimension(x, y); + } + + /** + * Lays out the Container <code>c</code> in the layout direction + * <code>layoutDir</code>. The direction that is crossing the layout + * direction is specified in <code>crossDir</code>. + * + * @param parent + * @param layoutDir + * @param crossDir + */ + void layoutAlgorithm(Container parent, Direction layoutDir, Direction crossDir) + { + if (parent != container) + throw new AWTError("invalid parent"); + + Dimension parentSize = parent.getSize(); + Insets insets = parent.getInsets(); + Dimension innerSize = new Dimension(parentSize.width - insets.left + - insets.right, parentSize.height + - insets.bottom - insets.top); + + // Set all components to their preferredSizes and sum up the allocated + // space. Create SizeReqs for each component and store them in + // sizeReqs. Find the maximum size in the crossing direction. + List children = AWTUtilities.getVisibleChildren(parent); + Vector sizeReqs = new Vector(); + int allocated = 0; + for (Iterator i = children.iterator(); i.hasNext();) + { + Component c = (Component) i.next(); + SizeReq sizeReq = new SizeReq(c, layoutDir); + int preferred = layoutDir.size(c.getPreferredSize()); + sizeReq.size = preferred; + allocated += preferred; + sizeReqs.add(sizeReq); + } + + // Distribute remaining space (may be positive or negative) over components + int remainder = layoutDir.size(innerSize) - allocated; + distributeSpace(sizeReqs, remainder, layoutDir); + + // Resize and relocate components. If the component can be sized to + // take the full space in the crossing direction, then do so, otherwise + // align according to its alingnmentX or alignmentY property. + int loc = 0; + int offset1 = layoutDir.lower(insets); + int offset2 = crossDir.lower(insets); + for (Iterator i = sizeReqs.iterator(); i.hasNext();) + { + SizeReq sizeReq = (SizeReq) i.next(); + Component c = sizeReq.comp; + int availCrossSize = crossDir.size(innerSize); + int maxCross = crossDir.size(c.getMaximumSize()); + int crossSize = Math.min(availCrossSize, maxCross); + int crossRemainder = availCrossSize - crossSize; + int crossLoc = (int) (crossDir.alignment(c) * crossRemainder); + layoutDir.setSize(c, sizeReq.size, crossSize); + layoutDir.setLocation(c, offset1 + loc, offset2 + crossLoc); + loc += sizeReq.size; + } + } + + /** + * Distributes some space over a set of components. This implementation + * tries to set the components as close as possible to their + * <code>preferredSize</code>s, and respects the components + * <code>minimumSize</code> and <code>maximumSize</code>. + * + * The algorithm is implemented as follows: + * + * <ul> + * <li>The <code>remainder</code> is divided by the number of components + * in <code>freeComponents</code>.</li> + * <li>The result is added to (or substracted from) the size of each + * component.</li> + * <li>If the <code>minimumSize</code> or <code>maximumSize</code> of a + * component is exceeded, then this component is set to its + * <code>minimumSize</code> or <code>maximumSize</code>, it is removed from + * <code>freeComponents</code> and the difference is added to a new + * remainder.</li> + * <li>Finally, if there is a new remainer != 0 and the + * <code>freeComponents.size() != 0</code>, then this method is called + * recursivly to distribute the newly allocated remaining space.</li> + * </ul> + * + * @param freeComponents a SizeReq collection for components that have space + * left so that they can be moved freely + * @param remainder the space that should be distributed between the + * components + * @param dir the direction in which we operate + */ + void distributeSpace(Collection freeComponents, int remainder, Direction dir) + { + // Sum up total available space in components. If the remainder is negative + // then we sum up the difference between minSize and size. If remainder + // is positive we sum up the difference between maxSize and size. + double totalAvailable = 0; + for (Iterator i = freeComponents.iterator(); i.hasNext();) + { + SizeReq sizeReq = (SizeReq) i.next(); + if (remainder >= 0) + totalAvailable += sizeReq.max - sizeReq.size; + else + totalAvailable += sizeReq.min - sizeReq.size; + } + if (totalAvailable == 0) + if (remainder >= 0) + totalAvailable = 1; + else + totalAvailable = -1; + + int newRemainder = 0; + Vector stillFree = new Vector(); + for (Iterator i = freeComponents.iterator(); i.hasNext();) + { + // Add/substract share to component. + SizeReq sizeReq = (SizeReq) i.next(); + double available = 0; + if (remainder >= 0) + available = sizeReq.max - sizeReq.size; + else + available = sizeReq.min - sizeReq.size; + int share = (int) ((available / totalAvailable) * remainder); + sizeReq.size += share; + // check for min/maximumSize + if (sizeReq.size < sizeReq.min) + { + newRemainder += sizeReq.size - sizeReq.min; + sizeReq.size = sizeReq.min; + } + else if (sizeReq.size > sizeReq.max) + { + newRemainder += sizeReq.size - sizeReq.max; + sizeReq.size = sizeReq.max; + } + else + stillFree.add(sizeReq); + } + // recursivly call this method if necessary + if (newRemainder != 0 && stillFree.size() > 0) + distributeSpace(stillFree, newRemainder, dir); + } +} diff --git a/libjava/classpath/javax/swing/ButtonGroup.java b/libjava/classpath/javax/swing/ButtonGroup.java new file mode 100644 index 00000000000..bea8aea0311 --- /dev/null +++ b/libjava/classpath/javax/swing/ButtonGroup.java @@ -0,0 +1,179 @@ +/* ButtonGroup.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Vector; + + +/** + * DOCUMENT ME! + */ +public class ButtonGroup implements Serializable +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = 4259076101881721375L; + + /** The buttons added to this button group. */ + protected Vector buttons = new Vector(); + + /** The currently selected button model. */ + ButtonModel sel; + + /** + * Creates a new button group. + */ + public ButtonGroup() + { + } + + /** + * Adds a button to this group. + * + * @param b the button to add + */ + public void add(AbstractButton b) + { + b.getModel().setGroup(this); + buttons.addElement(b); + } + + /** + * Removed a given button from this group. + * + * @param b the button to remove + */ + public void remove(AbstractButton b) + { + b.getModel().setGroup(null); + buttons.removeElement(b); + } + + /** + * Returns the currently added buttons. + * + * @return <code>Enumeration</code> over all added buttons + */ + public Enumeration getElements() + { + return buttons.elements(); + } + + /** + * Returns the currently selected button model. + * + * @return the currently selected button model, null if none was selected + * yet + */ + public ButtonModel getSelection() + { + return sel; + } + + /** + * DOCUMENT ME! + * + * @param m DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + AbstractButton FindButton(ButtonModel m) + { + for (int i = 0; i < buttons.size(); i++) + { + AbstractButton a = (AbstractButton) buttons.get(i); + if (a.getModel() == m) + return a; + } + return null; + } + + /** + * Sets the currently selected button model. Only one button of a group can + * be selected at a time. + * + * @param m the model to select + * @param b true if this button is to be selected, false otherwise + */ + public void setSelected(ButtonModel m, boolean b) + { + if ((sel != m || b) && (! b || sel == m)) + return; + + if (b && sel != m) + { + ButtonModel old = sel; + sel = m; + + if (old != null) + old.setSelected(false); + AbstractButton button = FindButton(old); + if (button != null) + button.repaint(); + } + else if (!b && sel == m) + m.setSelected(true); + } + + /** + * Checks if the given <code>ButtonModel</code> is selected in this button + * group. + * + * @param m DOCUMENT ME! + * + * @return true of given <code>ButtonModel</code> is selected, false + * otherwise + */ + public boolean isSelected(ButtonModel m) + { + return m == sel; + } + + /** + * Return the number of buttons in this button group. + * + * @return the number of buttons + * + * @since 1.3 + */ + public int getButtonCount() + { + return buttons.size(); + } +} diff --git a/libjava/classpath/javax/swing/ButtonModel.java b/libjava/classpath/javax/swing/ButtonModel.java new file mode 100644 index 00000000000..1bdc5d1850d --- /dev/null +++ b/libjava/classpath/javax/swing/ButtonModel.java @@ -0,0 +1,85 @@ +/* ButtonModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.ItemSelectable; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; + +import javax.swing.event.ChangeListener; + +/** + * The data model that is used in all kinds of buttons. + */ +public interface ButtonModel extends ItemSelectable +{ + boolean isArmed(); + void setArmed(boolean b); + + + boolean isEnabled(); + void setEnabled(boolean b); + + void setPressed(boolean b); + boolean isPressed(); + + + void removeActionListener(ActionListener l); + void addActionListener(ActionListener l); + + void addItemListener(ItemListener l); + void removeItemListener(ItemListener l); + + void addChangeListener(ChangeListener l); + void removeChangeListener(ChangeListener l); + + void setRollover(boolean b); + boolean isRollover(); + + int getMnemonic(); + void setMnemonic(int key); + + void setActionCommand(String s); + String getActionCommand(); + + void setGroup(ButtonGroup group); + + void setSelected(boolean b); + boolean isSelected(); +} diff --git a/libjava/classpath/javax/swing/CellEditor.java b/libjava/classpath/javax/swing/CellEditor.java new file mode 100644 index 00000000000..bdb1665750d --- /dev/null +++ b/libjava/classpath/javax/swing/CellEditor.java @@ -0,0 +1,96 @@ +/* CellEditor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.util.EventObject; + +import javax.swing.event.CellEditorListener; + +/** + * Provides edit capabilities for components that display cells like + * {@link JTable}, {@link JList} and {@link JTree}. + * + * @author Andrew Selkirk + */ +public interface CellEditor +{ + /** + * getCellEditorValue + * @returns Object + */ + Object getCellEditorValue(); + + /** + * isCellEditable + * @param event TODO + * @returns boolean + */ + boolean isCellEditable(EventObject event); + + /** + * shouldSelectCell + * @param event TODO + * @returns boolean + */ + boolean shouldSelectCell(EventObject event); + + /** + * stopCellEditing + * @returns boolean + */ + boolean stopCellEditing(); + + /** + * cancelCellEditing + */ + void cancelCellEditing(); + + /** + * addCellEditorListener + * @param value0 TODO + */ + void addCellEditorListener(CellEditorListener listener); + + /** + * removeCellEditorListener + * @param listener TODO + */ + void removeCellEditorListener(CellEditorListener listener); + +} // CellEditor diff --git a/libjava/classpath/javax/swing/CellRendererPane.java b/libjava/classpath/javax/swing/CellRendererPane.java new file mode 100644 index 00000000000..db7a1434166 --- /dev/null +++ b/libjava/classpath/javax/swing/CellRendererPane.java @@ -0,0 +1,251 @@ +/* CellRendererPane.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * The CellRendererPane's purpose is to paint the cells of JList, JTable and + * JTree. It intercepts the usual paint tree, so that we don't walk up and + * repaint everything. + * + * @author Andrew Selkirk + * @version 1.0 + */ +public class CellRendererPane + extends Container + implements Accessible +{ + private static final long serialVersionUID = -7642183829532984273L; + + /** + * AccessibleCellRendererPane + */ + protected class AccessibleCellRendererPane extends AccessibleAWTContainer + { + private static final long serialVersionUID = -8981090083147391074L; + + /** + * Constructor AccessibleCellRendererPane + * @param component TODO + */ + protected AccessibleCellRendererPane() + { + } + + /** + * getAccessibleRole + * @returns AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PANEL; + } + } + + /** + * accessibleContext + */ + protected AccessibleContext accessibleContext = null; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructs a new CellRendererPane. + */ + public CellRendererPane() + { + } // CellRendererPane() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * Should not be called. + * + * @param graphics not used here + */ + public void update(Graphics graphics) + { + } // update() + + /** + * Despite normal behaviour this does <em>not</em> cause the container + * to be invalidated. This prevents propagating up the paint tree. + */ + public void invalidate() + { + } // invalidate() + + /** + * Should not be called. + * + * @param graphics not used here + */ + public void paint(Graphics graphics) + { + } + + /** + * Overridden to check if a component is already a child of this Container. + * If it's already a child, nothing is done. Otherwise we pass this to + * <code>super.addImpl()</code>. + * + * @param c the component to add + * @param constraints not used here + * @param index not used here + */ + protected void addImpl(Component c, Object constraints, int index) + { + if (!isAncestorOf(c)) + { + super.addImpl(c, constraints, index); + } + } // addImpl() + + /** + * Paints the specified component <code>c</code> on the {@link Graphics} + * context <code>graphics</code>. The Graphics context is tranlated to + * (x,y) and the components bounds are set to (w,h). If + * <code>shouldValidate</code> + * is set to true, then the component is validated before painting. + * + * @param graphics the graphics context to paint on + * @param c the component to be painted + * @param p the parent of the component + * @param x the X coordinate of the upper left corner where c should + be painted + * @param y the Y coordinate of the upper left corner where c should + be painted + * @param w the width of the components drawing area + * @param h the height of the components drawing area + * @param shouldValidate if <code>c</code> should be validated before + * painting + */ + public void paintComponent(Graphics graphics, Component c, + Container p, int x, int y, int w, int h, + boolean shouldValidate) + { + // reparent c + addImpl(c, null, 0); + + // translate to (x,y) + graphics.translate(x, y); + + // set bounds of c + c.setBounds(0, 0, w, h); + + // validate if necessary + if (shouldValidate) + { + c.validate(); + } + + // paint component + c.paint(graphics); + + // untranslate g + graphics.translate(-x, -y); + + } // paintComponent() + + /** + * Paints the specified component <code>c</code> on the {@link Graphics} + * context <code>graphics</code>. The Graphics context is tranlated to (x,y) + * and the components bounds are set to (w,h). The component is <em>not</em> + * validated before painting. + * + * @param graphics the graphics context to paint on + * @param c the component to be painted + * @param p the parent of the component + * @param x the X coordinate of the upper left corner where c should + be painted + * @param y the Y coordinate of the upper left corner where c should + be painted + * @param w the width of the components drawing area + * @param h the height of the components drawing area + */ + public void paintComponent(Graphics graphics, Component c, + Container p, int x, int y, int w, int h) + { + paintComponent(graphics, c, p, x, y, w, h, false); + } // paintComponent() + + /** + * Paints the specified component <code>c</code> on the {@link Graphics} + * context <code>g</code>. The Graphics context is tranlated to (r.x,r.y) and + * the components bounds are set to (r.width,r.height). + * The component is <em>not</em> + * validated before painting. + * + * @param graphics the graphics context to paint on + * @param c the component to be painted + * @param p the component on which we paint + * @param r the bounding rectangle of c + */ + public void paintComponent(Graphics graphics, Component c, + Container p, Rectangle r) + { + paintComponent(graphics, c, p, r.x, r.y, r.width, r.height); + } // paintComponent() + + /** + * getAccessibleContext <em>TODO</em> + * @return AccessibleContext + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleCellRendererPane(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/ComboBoxEditor.java b/libjava/classpath/javax/swing/ComboBoxEditor.java new file mode 100644 index 00000000000..4eb5fc56206 --- /dev/null +++ b/libjava/classpath/javax/swing/ComboBoxEditor.java @@ -0,0 +1,96 @@ +/* ComboBoxEditor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.event.ActionListener; + +/** + * Provides edit capabilities for {@link JComboBox}es. + * + * @author Andrew Selkirk + * @author Olga Rodimina + */ +public interface ComboBoxEditor +{ + /** + * This method returns component that will be used by the combo box to + * display/edit currently selected item in the combo box. + * + * @return Component that will be used by the combo box to display/edit + * currently selected item + */ + Component getEditorComponent(); + + /** + * Sets item that should be editted when any editting operation is performed + * by the user. The value is always equal to the currently selected value + * in the combo box. Thus, whenever a different value is selected from the + * combo box list then this method should be called to change editting item + * to the new selected item. + * + * @param selectedItem item that is currently selected in the combo box + */ + void setItem(Object item); + + /** + * This method returns item that is currently editable. + * + * @return Item in the combo box that is currently editable + */ + Object getItem(); + + /** + * selectAll + */ + void selectAll(); + + /** + * This method adds specified ActionListener to this ComboBoxEditor. + * + * @param listener + */ + void addActionListener(ActionListener listener); + + /** + * This method removes given ActionListener from this ComboBoxEditor. + * + * @param listener TODO + */ + void removeActionListener(ActionListener listener); +} // ComboBoxEditor diff --git a/libjava/classpath/javax/swing/ComboBoxModel.java b/libjava/classpath/javax/swing/ComboBoxModel.java new file mode 100644 index 00000000000..6968db49091 --- /dev/null +++ b/libjava/classpath/javax/swing/ComboBoxModel.java @@ -0,0 +1,67 @@ +/* ComboBoxModel.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + + +/** + * The data model for {@link JComboBox}. This model keeps + * track of elements contained in the JComboBox as well as the current + * combo box selection. Whenever selection in the JComboBox changes, the + * ComboBoxModel should fire ListDataEvents to ComboBox's ListDataListeners. + * + * @author Andrew Selkirk + */ +public interface ComboBoxModel extends ListModel +{ + /** + * This method sets the selected item in the combo box. Class + * implementing this interface should fire ListDataEvents to + * all registered ListDataListeners to indicated that the + * selection has changed. + * + * @param item item in the combo box that should be selected + */ + void setSelectedItem(Object item); + + /** + * The method returns currently selected item in the combo box + * + * @returns item that is currently selected in the combo box. + */ + Object getSelectedItem(); +} // ComboBoxModel diff --git a/libjava/classpath/javax/swing/ComponentInputMap.java b/libjava/classpath/javax/swing/ComponentInputMap.java new file mode 100644 index 00000000000..4ecc0585267 --- /dev/null +++ b/libjava/classpath/javax/swing/ComponentInputMap.java @@ -0,0 +1,130 @@ +/* ComponentInputMap.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + + +/** + * @author Andrew Selkirk + * @author Michael Koch + */ +public class ComponentInputMap extends InputMap +{ + /** + * The component to notify. + */ + private JComponent component; + + /** + * Creates <code>ComponentInputMap</code> object that notifies the given + * component about changes to it. + * + * @param comp the component to notify + * + * @exception IllegalArgumentException if comp is null + */ + public ComponentInputMap(JComponent comp) + { + if (comp == null) + throw new IllegalArgumentException(); + + this.component = comp; + } + + /** + * Puts a new entry into the <code>InputMap</code>. + * If actionMapKey is null an existing entry will be removed. + * + * @param keystroke the keystroke for the entry + * @param actionMapKey the action. + */ + public void put(KeyStroke keystroke, Object value) + { + super.put(keystroke, value); + // FIXME: Notify component. + } + + /** + * Clears the <code>InputMap</code>. + */ + public void clear() + { + super.clear(); + // FIXME: Notify component. + } + + /** + * Remove an entry from the <code>InputMap</code>. + * + * @param key the key of the entry to remove + */ + public void remove(KeyStroke keystroke) + { + super.remove(keystroke); + // FIXME: Notify component. + } + + /** + * Sets a parent for this <code>ComponentInputMap</code>. + * + * @param parentMap the new parent + * + * @exception IllegalArgument if parentMap is not a + * <code>ComponentInputMap</code> or not associated with the same component + */ + public void setParent(InputMap parentMap) + { + if (! (parentMap instanceof ComponentInputMap)) + throw new IllegalArgumentException(); + + if (((ComponentInputMap) parentMap).getComponent() != component) + throw new IllegalArgumentException(); + + super.setParent(parentMap); + // FIXME: Notify component. + } + + /** + * Returns the component to notify about changes. + * + * @return a <code>JComponent</code> object + */ + public JComponent getComponent() + { + return component; + } +} diff --git a/libjava/classpath/javax/swing/DebugGraphics.java b/libjava/classpath/javax/swing/DebugGraphics.java new file mode 100644 index 00000000000..e73c120e317 --- /dev/null +++ b/libjava/classpath/javax/swing/DebugGraphics.java @@ -0,0 +1,885 @@ +/* DebugGraphics.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.image.ImageObserver; +import java.io.PrintStream; +import java.text.AttributedCharacterIterator; + + +/** + * DebugGraphics + * @author Andrew Selkirk + * @version 1.0 + */ +public class DebugGraphics extends Graphics +{ + /** + * LOG_OPTION + */ + public static final int LOG_OPTION = 1; + + /** + * FLASH_OPTION + */ + public static final int FLASH_OPTION = 2; + + /** + * BUFFERED_OPTION + */ + public static final int BUFFERED_OPTION = 4; + + /** + * NONE_OPTION + */ + public static final int NONE_OPTION = -1; + + static Color debugFlashColor = Color.RED; + static int debugFlashCount = 10; + static int debugFlashTime = 1000; + static PrintStream debugLogStream = System.out; + + /** + * graphics + */ + Graphics graphics; + + /** + * color + */ + Color color = Color.BLACK; + + /** + * buffer + */ + Image buffer; + + /** + * debugOptions + */ + int debugOptions; + + /** + * graphicsID + */ + int graphicsID; + + /** + * xOffset + */ + int xOffset; + + /** + * yOffset + */ + int yOffset; + + /** + * Creates a <code>DebugGraphics</code> object. + */ + public DebugGraphics() + { + // TODO + } + + /** + * Creates a <code>DebugGraphics</code> object. + * + * @param graphics The <code>Graphics</code> object to wrap + * @param component TODO + */ + public DebugGraphics(Graphics graphics, JComponent component) + { + this.graphics = graphics; + // FIXME: What shall we do with component ? + } + + /** + * Creates a <code>DebugGraphics</code> object. + * + * @param graphics The <code>Graphics</code> object to wrap + */ + public DebugGraphics(Graphics graphics) + { + this.graphics = graphics; + } + + /** + * Sets the color to draw stuff with. + * + * @param color The color + */ + public void setColor(Color color) + { + this.color = color; + } + + /** + * Creates a overrides <code>Graphics.create</code> to create a + * <code>DebugGraphics</code> object. + * + * @return a new <code>DebugGraphics</code> object. + */ + public Graphics create() + { + return new DebugGraphics(graphics.create()); + } + + /** + * Creates a overrides <code>Graphics.create</code> to create a + * <code>DebugGraphics</code> object. + * + * @param x the x coordinate + * @param y the y coordinate + * @param width the width + * @param height the height + * + * @return a new <code>DebugGraphics</code> object. + */ + public Graphics create(int x, int y, int width, int height) + { + return new DebugGraphics(graphics.create(x, y, width, height)); + } + + /** + * flashColor + * + * @return Color + */ + public static Color flashColor() + { + return debugFlashColor; + } + + /** + * setFlashColor + * + * @param color the color to use for flashing + */ + public static void setFlashColor(Color color) + { + debugFlashColor = color; + } + + /** + * flashTime + * + * @return The time in milliseconds + */ + public static int flashTime() + { + return debugFlashTime; + } + + /** + * setFlashTime + * + * @param time The time in milliseconds + */ + public static void setFlashTime(int time) + { + debugFlashTime = time; + } + + /** + * flashCount + * + * @return The number of flashes + */ + public static int flashCount() + { + return debugFlashCount; + } + + /** + * setFlashCount + * + * @param count The number of flashes + */ + public static void setFlashCount(int count) + { + debugFlashCount = count; + } + + /** + * logStream + * + * @return The <code>PrintStream</code> to write logging messages to + */ + public static PrintStream logStream() + { + return debugLogStream; + } + + /** + * setLogStream + * + * @param stream The currently set <code>PrintStream</code>. + */ + public static void setLogStream(PrintStream stream) + { + debugLogStream = stream; + } + + /** + * getFont + * + * @return The font + */ + public Font getFont() + { + return graphics.getFont(); + } + + /** + * setFont + * + * @param font The font to use for drawing text + */ + public void setFont(Font font) + { + graphics.setFont(font); + } + + /** + * Returns the color used for drawing. + * + * @return The color. + */ + public Color getColor() + { + return color; + } + + /** + * Returns the font metrics of the current font. + * + * @return a <code>FontMetrics</code> object + */ + public FontMetrics getFontMetrics() + { + return graphics.getFontMetrics(); + } + + /** + * Returns the font metrics for a given font. + * + * @param font the font to get the metrics for + * + * @return a <code>FontMetrics</code> object + */ + public FontMetrics getFontMetrics(Font font) + { + return graphics.getFontMetrics(font); + } + + /** + * translate + * + * @param x the x coordinate + * @param y the y coordinate + */ + public void translate(int x, int y) + { + graphics.translate(x, y); + } + + /** + * setPaintMode + */ + public void setPaintMode() + { + graphics.setPaintMode(); + } + + /** + * setXORMode + * + * @param color the color + */ + public void setXORMode(Color color) + { + graphics.setXORMode(color); + } + + /** + * getClipBounds + * + * @return Rectangle + */ + public Rectangle getClipBounds() + { + return graphics.getClipBounds(); + } + + /** + * Intersects the current clip region with the given region. + * + * @param x The x-position of the region + * @param y The y-position of the region + * @param width The width of the region + * @param height The height of the region + */ + public void clipRect(int x, int y, int width, int height) + { + graphics.clipRect(x, y, width, height); + } + + /** + * Sets the clipping region. + * + * @param x The x-position of the region + * @param y The y-position of the region + * @param width The width of the region + * @param height The height of the region + */ + public void setClip(int x, int y, int width, int height) + { + graphics.setClip(x, y, width, height); + } + + /** + * Returns the current clipping region. + * + * @return Shape + */ + public Shape getClip() + { + return graphics.getClip(); + } + + /** + * Sets the current clipping region + * + * @param shape The clippin region + */ + public void setClip(Shape shape) + { + graphics.setClip(shape); + } + + private void sleep(int milliseconds) + { + try + { + Thread.sleep(milliseconds); + } + catch (InterruptedException e) + { + // Ignore this. + } + } + + /** + * Draws a rectangle. + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + */ + public void drawRect(int x, int y, int width, int height) + { + for (int index = 0; index < (debugFlashCount - 1); ++index) + { + graphics.setColor(color); + graphics.drawRect(x, y, width, height); + sleep(debugFlashTime); + + graphics.setColor(debugFlashColor); + graphics.drawRect(x, y, width, height); + sleep(debugFlashTime); + } + + graphics.setColor(color); + graphics.drawRect(x, y, width, height); + } + + /** + * Draws a filled rectangle. + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + */ + public void fillRect(int x, int y, int width, int height) + { + for (int index = 0; index < (debugFlashCount - 1); ++index) + { + graphics.setColor(color); + graphics.fillRect(x, y, width, height); + sleep(debugFlashTime); + + graphics.setColor(debugFlashColor); + graphics.fillRect(x, y, width, height); + sleep(debugFlashTime); + } + + graphics.setColor(color); + graphics.fillRect(x, y, width, height); + } + + /** + * clearRect + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + */ + public void clearRect(int x, int y, int width, int height) + { + graphics.clearRect(x, y, width, height); + } + + /** + * drawRoundRect + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param arcWidth TODO + * @param arcHeight TODO + */ + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + graphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + /** + * fillRoundRect + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param arcWidth TODO + * @param arcHeight TODO + */ + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + graphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + /** + * drawLine + * + * @param x1 The x-position of the start + * @param y1 The y-position of the start + * @param x2 The x-position of the end + * @param y2 The y-position of the end + */ + public void drawLine(int x1, int y1, int x2, int y2) + { + graphics.drawLine(x1, y1, x2, y2); + } + + /** + * draw3DRect + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param raised TODO + */ + public void draw3DRect(int x, int y, int width, int height, boolean raised) + { + graphics.draw3DRect(x, y, width, height, raised); + } + + /** + * fill3DRect + * + * @param x The x-position of the rectangle + * @param y The y-position of the rectangle + * @param width The width of the rectangle + * @param height The height of the rectangle + * @param raised TODO + */ + public void fill3DRect(int x, int y, int width, int height, boolean raised) + { + graphics.fill3DRect(x, y, width, height, raised); + } + + /** + * drawOval + * + * @param x the x coordinate + * @param y the y coordiante + * @param width the width + * @param height the height + */ + public void drawOval(int x, int y, int width, int height) + { + graphics.drawOval(x, y, width, height); + } + + /** + * fillOval + * + * @param x the x coordinate + * @param y the y coordinate + * @param width the width + * @param height the height + */ + public void fillOval(int x, int y, int width, int height) + { + graphics.fillOval(x, y, width, height); + } + + /** + * drawArc + * + * @param x the x coordinate + * @param y the y coordinate + * @param width the width + * @param height the height + * @param startAngle TODO + * @param arcAngle TODO + */ + public void drawArc(int x, int y, int width, int height, + int startAngle, int arcAngle) + { + graphics.drawArc(x, y, width, height, startAngle, arcAngle); + } + + /** + * fillArc + * + * @param x the coordinate + * @param y the y coordinate + * @param width the width + * @param height the height + * @param startAngle TODO + * @param arcAngle TODO + */ + public void fillArc(int x, int y, int width, int height, + int startAngle, int arcAngle) + { + graphics.fillArc(x, y, width, height, startAngle, arcAngle); + } + + /** + * drawPolyline + * + * @param xpoints TODO + * @param ypoints TODO + * @param npoints TODO + */ + public void drawPolyline(int[] xpoints, int[] ypoints, int npoints) + { + graphics.drawPolyline(xpoints, ypoints, npoints); + } + + /** + * drawPolygon + * + * @param xpoints TODO + * @param ypoints TODO + * @param npoints TODO + */ + public void drawPolygon(int[] xpoints, int[] ypoints, int npoints) + { + graphics.drawPolygon(xpoints, ypoints, npoints); + } + + /** + * fillPolygon + * + * @param xpoints TODO + * @param ypoints TODO + * @param npoints TODO + */ + public void fillPolygon(int[] xpoints, int[] ypoints, int npoints) + { + graphics.fillPolygon(xpoints, ypoints, npoints); + } + + /** + * drawString + * + * @param string the string + * @param x the x coordinate + * @param y the y coordinate + */ + public void drawString(String string, int x, int y) + { + graphics.drawString(string, x, y); + } + + /** + * drawString + * + * @param iterator TODO + * @param x the x coordinate + * @param y the y coordinate + */ + public void drawString(AttributedCharacterIterator iterator, + int x, int y) + { + graphics.drawString(iterator, x, y); + } + + /** + * drawBytes + * + * @param data TODO + * @param offset TODO + * @param length TODO + * @param x the x coordinate + * @param y the y coordinate + */ + public void drawBytes(byte[] data, int offset, int length, + int x, int y) + { + graphics.drawBytes(data, offset, length, x, y); + } + + /** + * drawChars + * + * @param data array of characters to draw + * @param offset offset in array + * @param length number of characters in array to draw + * @param x x-position + * @param y y-position + */ + public void drawChars(char[] data, int offset, int length, + int x, int y) + { + for (int index = 0; index < (debugFlashCount - 1); ++index) + { + graphics.setColor(color); + graphics.drawChars(data, offset, length, x, y); + sleep(debugFlashTime); + + graphics.setColor(debugFlashColor); + graphics.drawChars(data, offset, length, x, y); + sleep(debugFlashTime); + } + + graphics.setColor(color); + graphics.drawChars(data, offset, length, x, y); + } + + /** + * drawImage + * + * @param image The image to draw + * @param x The x position + * @param y The y position + * @param observer The image observer + * @return boolean + */ + public boolean drawImage(Image image, int x, int y, + ImageObserver observer) + { + return graphics.drawImage(image, x, y, observer); + } + + /** + * drawImage + * + * @param image The image to draw + * @param x The x position + * @param y The y position + * @param width The width of the area to draw the image + * @param height The height of the area to draw the image + * @param observer The image observer + * + * @return boolean + */ + public boolean drawImage(Image image, int x, int y, int width, + int height, ImageObserver observer) + { + return graphics.drawImage(image, x, y, width, height, observer); + } + + /** + * drawImage + * + * @param image The image to draw + * @param x The x position + * @param y The y position + * @param background The color for the background in the opaque regions + * of the image + * @param observer The image observer + * + * @return boolean + */ + public boolean drawImage(Image image, int x, int y, + Color background, ImageObserver observer) + { + return graphics.drawImage(image, x, y, background, observer); + } + + /** + * drawImage + * + * @param image The image to draw + * @param x The x position + * @param y The y position + * @param width The width of the area to draw the image + * @param height The height of the area to draw the image + * @param background The color for the background in the opaque regions + * of the image + * @param observer The image observer + * + * @return boolean + */ + public boolean drawImage(Image image, int x, int y, int width, int height, + Color background, ImageObserver observer) + { + return graphics.drawImage(image, x, y, width, height, background, observer); + } + + /** + * drawImage + * + * @param image The image to draw + * @param dx1 TODO + * @param dy1 TODO + * @param dx2 TODO + * @param dy2 TODO + * @param sx1 TODO + * @param sy1 TODO + * @param sx2 TODO + * @param sy2 TODO + * @param observer The image observer + * + * @return boolean + */ + public boolean drawImage(Image image, int dx1, int dy1, + int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + return graphics.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); + } + + /** + * drawImage + * + * @param image The image to draw + * @param dx1 TODO + * @param dy1 TODO + * @param dx2 TODO + * @param dy2 TODO + * @param sx1 TODO + * @param sy1 TODO + * @param sx2 TODO + * @param sy2 TODO + * @param background The color for the background in the opaque regions + * of the image + * @param observer The image observer + * + * @return boolean + */ + public boolean drawImage(Image image, int dx1, int dy1, + int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, + Color background, ImageObserver observer) + { + return graphics.drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, background, observer); + } + + /** + * copyArea + * + * @param x The x position of the source area + * @param y The y position of the source area + * @param width The width of the area + * @param height The height of the area + * @param destx The x position of the destination area + * @param desty The y posiiton of the destination area + */ + public void copyArea(int x, int y, int width, int height, + int destx, int desty) + { + graphics.copyArea(x, y, width, height, destx, desty); + } + + /** + * Releases all system resources that this <code>Graphics</code> is using. + */ + public void dispose() + { + graphics.dispose(); + graphics = null; + } + + /** + * isDrawingBuffer + * + * @return boolean + */ + public boolean isDrawingBuffer() + { + return false; // TODO + } + + /** + * setDebugOptions + * + * @param options the debug options + */ + public void setDebugOptions(int options) + { + debugOptions = options; + } + + /** + * getDebugOptions + * + * @return the debug options + */ + public int getDebugOptions() + { + return debugOptions; + } +} diff --git a/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java b/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java new file mode 100644 index 00000000000..53c0fb34343 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java @@ -0,0 +1,443 @@ +/* DefaultBoundedRangeModel.java -- Default implementation + of BoundedRangeModel. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +/** + * A default implementation of <code>BoundedRangeModel</code>. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class DefaultBoundedRangeModel + implements BoundedRangeModel, Serializable +{ + /** + * The identifier of this class in object serialization. Verified + * using the serialver tool of Sun J2SE 1.4.1_01. + */ + private static final long serialVersionUID = 5034068491295259790L; + + /** + * An event that is sent to all registered {@link ChangeListener}s + * when the state of this range model has changed. + * + * <p>The event object is created on demand, the first time it + * is actually needed.</p> + * + * @see #fireStateChanged() + */ + protected transient ChangeEvent changeEvent; + + /** + * The list of the currently registered EventListeners. + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * The current value of the range model, which is always between + * {@link #minimum} and ({@link #maximum} - {@link #extent}). In a + * scroll bar visualization of a {@link BoundedRangeModel}, the + * <code>value</code> is displayed as the position of the thumb. + */ + private int value; + + /** + * The current extent of the range model, which is a number greater + * than or equal to zero. In a scroll bar visualization of a {@link + * BoundedRangeModel}, the <code>extent</code> is displayed as the + * size of the thumb. + */ + private int extent; + + /** + * The current minimum value of the range model, which is always + * less than or equal to {@link #maximum}. + */ + private int minimum; + + /** + * The current maximum value of the range model, which is always + * greater than or equal to {@link #minimum}. + */ + private int maximum; + + /** + * A property that indicates whether the value of this {@link + * BoundedRangeModel} is going to change in the immediate future. + */ + private boolean isAdjusting; + + /** + * Constructs a <code>DefaultBoundedRangeModel</code> with default + * values for the properties. The properties <code>value</code>, + * <code>extent</code> and <code>minimum</code> will be initialized + * to zero; <code>maximum</code> will be set to 100; the property + * <code>valueIsAdjusting</code> will be <code>false</code>. + */ + public DefaultBoundedRangeModel() + { + // The fields value, extent, minimum have the default value 0, and + // isAdjusting is already false. These fields no not need to be + // set explicitly. + maximum = 100; + } + + /** + * Constructs a <code>DefaultBoundedRangeModel</code> with the + * specified values for some properties. + * + * @param value the initial value of the range model, which must be + * a number between <code>minimum</code> and <code>(maximum - + * extent)</code>. In a scroll bar visualization of a {@link + * BoundedRangeModel}, the <code>value</code> is displayed as the + * position of the thumb. + * @param extent the initial extent of the range model, which is a + * number greater than or equal to zero. In a scroll bar + * visualization of a {@link BoundedRangeModel}, the + * <code>extent</code> is displayed as the size of the thumb. + * @param minimum the initial minimal value of the range model. + * @param maximum the initial maximal value of the range model. + * + * @throws IllegalArgumentException if the following condition is + * not satisfied: <code>minimum <= value <= value + extent <= + * maximum</code>. + */ + public DefaultBoundedRangeModel(int value, int extent, int minimum, + int maximum) + { + if (!(minimum <= value && extent >= 0 && (value + extent) <= maximum)) + throw new IllegalArgumentException(); + + this.value = value; + this.extent = extent; + this.minimum = minimum; + this.maximum = maximum; + + // The isAdjusting field already has a false value by default. + } + + /** + * Returns a string with all relevant properties of this range + * model. + * + * @return a string representing the object + */ + public String toString() + { + return getClass().getName() + + "[value=" + value + + ", extent=" + extent + + ", min=" + minimum + + ", max=" + maximum + + ", adj=" + isAdjusting + + ']'; + } + + /** + * Returns the current value of this bounded range model. In a + * scroll bar visualization of a {@link BoundedRangeModel}, the + * <code>value</code> is displayed as the position of the thumb. + * + * @return the value + */ + public int getValue() + { + return value; + } + + /** + * Changes the current value of this bounded range model. In a + * scroll bar visualization of a {@link BoundedRangeModel}, the + * <code>value</code> is displayed as the position of the thumb; + * changing the <code>value</code> of a scroll bar's model + * thus moves the thumb to a different position. + * + * @param value the value + */ + public void setValue(int value) + { + value = Math.max(minimum, value); + if (value + extent > maximum) + value = maximum - extent; + + if (value != this.value) + { + this.value = value; + fireStateChanged(); + } + } + + /** + * Returns the current extent of this bounded range model, which is + * a number greater than or equal to zero. In a scroll bar + * visualization of a {@link BoundedRangeModel}, the + * <code>extent</code> is displayed as the size of the thumb. + * + * @return the extent + */ + public int getExtent() + { + return extent; + } + + /** + * Changes the current extent of this bounded range model. In a + * scroll bar visualization of a {@link BoundedRangeModel}, the + * <code>extent</code> is displayed as the size of the thumb. + * + * @param extent the new extent of the range model, which is a + * number greater than or equal to zero. + */ + public void setExtent(int extent) + { + extent = Math.max(extent, 0); + if (value + extent > maximum) + extent = maximum - value; + + if (extent != this.extent) + { + this.extent = extent; + fireStateChanged(); + } + } + + /** + * Returns the current minimal value of this bounded range model. + */ + public int getMinimum() + { + return minimum; + } + + /** + * Changes the current minimal value of this bounded range model. + * + * @param minimum the new minimal value. + */ + public void setMinimum(int minimum) + { + int value, maximum; + + maximum = Math.max(minimum, this.maximum); + value = Math.max(minimum, this.value); + + setRangeProperties(value, extent, minimum, maximum, isAdjusting); + } + + /** + * Returns the current maximal value of this bounded range model. + * + * @return the maximum + */ + public int getMaximum() + { + return maximum; + } + + /** + * Changes the current maximal value of this bounded range model. + * + * @param maximum the new maximal value. + */ + public void setMaximum(int maximum) + { + int value, extent, minimum; + + minimum = Math.min(this.minimum, maximum); + extent = Math.min(this.extent, maximum - minimum); + value = Math.min(this.value, maximum - extent); + + setRangeProperties(value, extent, minimum, maximum, isAdjusting); + } + + /** + * Returns whether or not the value of this bounded range model is + * going to change in the immediate future. Scroll bars set this + * property to <code>true</code> while the thumb is being dragged + * around; when the mouse is relased, they set the property to + * <code>false</code> and post a final {@link ChangeEvent}. + * + * @return <code>true</code> if the value will change soon again; + * <code>false</code> if the value will probably not change soon. + */ + public boolean getValueIsAdjusting() + { + return isAdjusting; + } + + /** + * Specifies whether or not the value of this bounded range model is + * going to change in the immediate future. Scroll bars set this + * property to <code>true</code> while the thumb is being dragged + * around; when the mouse is relased, they set the property to + * <code>false</code>. + * + * @param isAdjusting <code>true</code> if the value will change + * soon again; <code>false</code> if the value will probably not + * change soon. + */ + public void setValueIsAdjusting(boolean isAdjusting) + { + if (isAdjusting == this.isAdjusting) + return; + + this.isAdjusting = isAdjusting; + fireStateChanged(); + } + + /** + * Sets all properties. + * + * @param value the new value of the range model. In a scroll bar + * visualization of a {@link BoundedRangeModel}, the + * <code>value</code> is displayed as the position of the thumb. + * @param extent the new extent of the range model, which is a + * number greater than or equal to zero. In a scroll bar + * visualization of a {@link BoundedRangeModel}, the + * <code>extent</code> is displayed as the size of the thumb. + * @param minimum the new minimal value of the range model. + * @param maximum the new maximal value of the range model. + * @param isAdjusting whether or not the value of this bounded range + * model is going to change in the immediate future. Scroll bars set + * this property to <code>true</code> while the thumb is being + * dragged around; when the mouse is relased, they set the property + * to <code>false</code>. + */ + public void setRangeProperties(int value, int extent, int minimum, + int maximum, boolean isAdjusting) + { + minimum = Math.min(Math.min(minimum, maximum), value); + maximum = Math.max(value, maximum); + if (extent + value > maximum) + extent = maximum - value; + extent = Math.max(0, extent); + + if ((value == this.value) + && (extent == this.extent) + && (minimum == this.minimum) + && (maximum == this.maximum) + && (isAdjusting == this.isAdjusting)) + return; + + this.value = value; + this.extent = extent; + this.minimum = minimum; + this.maximum = maximum; + this.isAdjusting = isAdjusting; + + fireStateChanged(); + } + + /** + * Subscribes a ChangeListener to state changes. + * + * @param listener the listener to be subscribed. + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * Cancels the subscription of a ChangeListener. + * + * @param listener the listener to be unsubscribed. + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * Sends a {@link ChangeEvent} to any registered {@link + * ChangeListener}s. + * + * @see #addChangeListener(ChangeListener) + * @see #removeChangeListener(ChangeListener) + */ + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + + for (int i = listeners.length - 1; i >= 0; --i) + listeners[i].stateChanged(changeEvent); + } + + /** + * Retrieves the current listeners of the specified class. + * + * @param c the class of listeners; usually {@link + * ChangeListener}<code>.class</code>. + * + * @return an array with the currently subscribed listeners, or + * an empty array if there are currently no listeners. + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Returns all <code>ChangeListeners</code> that are currently + * subscribed for changes to this + * <code>DefaultBoundedRangeModel</code>. + * + * @return an array with the currently subscribed listeners, or + * an empty array if there are currently no listeners. + * + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) getListeners(ChangeListener.class); + } +} diff --git a/libjava/classpath/javax/swing/DefaultButtonModel.java b/libjava/classpath/javax/swing/DefaultButtonModel.java new file mode 100644 index 00000000000..2cfb9e96eb8 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultButtonModel.java @@ -0,0 +1,575 @@ +/* DefaultButtonModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +/** + * The pUrpose of this class is to model the dynamic state of an abstract + * button. The concrete button type holding this state may be a a "toggle" + * button (checkbox, radio button) or a "push" button (menu button, button). + * If the model is disabled, only the "selected" property can be changed. An + * attempt to change the "armed", "rollover" or "pressed" properties while + * the model is disabled will be blocked. Any successful (non-blocked) change + * to the model's properties will trigger the firing of a ChangeEvent. Any + * change to the "selected" property will trigger the firing of an ItemEvent + * in addition to ChangeEvent. This is true whether the model is enabled or + * not. One other state change is special: the transition from "enabled, + * armed and pressd" to "enabled, armed and not-pressed". This is considered + * the "trailing edge" of a successful mouse click, and therefore fires an + * ActionEvent in addition to a ChangeEvent. In all other respects this class + * is just a container of boolean flags. + * + * @author Graydon Hoare (graydon_at_redhat.com) + */ +public class DefaultButtonModel implements ButtonModel, Serializable +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = -5342609566534980231L; + + /** + * Indicates that the button is <em>partially</em> committed to being + * pressed, but not entirely. This usually happens when a user has pressed + * but not yet released the mouse button. + */ + public static final int ARMED = 1; + + /** + * State constant indicating that the button is enabled. Buttons cannot be + * pressed or selected unless they are enabled. + */ + public static final int ENABLED = 8; + + /** + * State constant indicating that the user is holding down the button. When + * this transitions from true to false, an ActionEvent may be fired, + * depending on the value of the "armed" property. + */ + public static final int PRESSED = 4; + + /** + * State constant indicating that the mouse is currently positioned over the + * button. + */ + public static final int ROLLOVER = 16; + + /** + * State constant indicating that the button is selected. This constant is + * only meaningful for toggle-type buttons (radio buttons, checkboxes). + */ + public static final int SELECTED = 2; + + /** + * Represents the "state properties" (armed, enabled, pressed, rollover and + * selected) by a bitwise combination of integer constants. + */ + protected int stateMask = ENABLED; + + /** + * List of ItemListeners, ChangeListeners, and ActionListeners registered on + * this model. + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** The single ChangeEvent this model (re)uses to call its ChangeListeners. */ + protected ChangeEvent changeEvent = new ChangeEvent(this); + + /** + * The group this model belongs to. Only one button in a group may be + * selected at any given time. + */ + protected ButtonGroup group; + + /** + * The key code (one of {@link java.awt.event.KeyEvent} VK_) used to press + * this button via a keyboard interface. + */ + protected int mnemonic = KeyEvent.VK_UNDEFINED; + + /** + * The string used as the "command" property of any ActionEvent this model + * sends. + */ + protected String actionCommand; + + /** + * Creates a new DefaultButtonModel object. + */ + public DefaultButtonModel() + { + } + + /** + * Return <code>null</code>. Use {@link AbstractButton} if you wish to + * interface with a button via an {@link ItemSelectable} interface. + * + * @return <code>null</code> + */ + public Object[] getSelectedObjects() + { + return null; + } + + /** + * Returns a specified class of listeners. + * + * @param listenerType the type of listener to return + * + * @return array of listeners + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Add an ActionListener to the model. Usually only called to subscribe an + * AbstractButton's listener to the model. + * + * @param l The listener to add + */ + public void addActionListener(ActionListener l) + { + listenerList.add(ActionListener.class, l); + } + + /** + * Remove an ActionListener to the model. Usually only called to unsubscribe + * an AbstractButton's listener to the model. + * + * @param l The listener to remove + */ + public void removeActionListener(ActionListener l) + { + listenerList.remove(ActionListener.class, l); + } + + /** + * Returns all registered <code>ActionListener</code> objects. + * + * @return array of <code>ActionListener</code> objects + */ + public ActionListener[] getActionListeners() + { + return (ActionListener[]) listenerList.getListeners(ActionListener.class); + } + + /** + * Add an ItemListener to the model. Usually only called to subscribe an + * AbstractButton's listener to the model. + * + * @param l The listener to add + */ + public void addItemListener(ItemListener l) + { + listenerList.add(ItemListener.class, l); + } + + /** + * Remove an ItemListener to the model. Usually only called to unsubscribe + * an AbstractButton's listener to the model. + * + * @param l The listener to remove + */ + public void removeItemListener(ItemListener l) + { + listenerList.remove(ItemListener.class, l); + } + + /** + * Returns all registered <code>ItemListener</code> objects. + * + * @return array of <code>ItemListener</code> objects + */ + public ItemListener[] getItemListeners() + { + return (ItemListener[]) listenerList.getListeners(ItemListener.class); + } + + /** + * Add a ChangeListener to the model. Usually only called to subscribe an + * AbstractButton's listener to the model. + * + * @param l The listener to add + */ + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + /** + * Remove a ChangeListener to the model. Usually only called to unsubscribe + * an AbstractButton's listener to the model. + * + * @param l The listener to remove + */ + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + /** + * Returns all registered <code>ChangeListener</code> objects. + * + * @return array of <code>ChangeListener</code> objects + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Inform each ItemListener in the {@link listenerList} that an ItemEvent + * has occurred. This happens in response to any change to the {@link + * stateMask} field. + * + * @param e The ItemEvent to fire + */ + protected void fireItemStateChanged(ItemEvent e) + { + ItemListener[] ll = getItemListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].itemStateChanged(e); + } + + /** + * Inform each ActionListener in the {@link listenerList} that an + * ActionEvent has occurred. This happens in response to the any change to + * the {@link stateMask} field which makes the enabled, armed and pressed + * properties all simultaneously <code>true</code>. + * + * @param e The ActionEvent to fire + */ + protected void fireActionPerformed(ActionEvent e) + { + ActionListener[] ll = getActionListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].actionPerformed(e); + } + + /** + * Inform each ChangeListener in the {@link listenerList} that a ChangeEvent + * has occurred. This happens in response to the any change to a property + * of the model. + */ + protected void fireStateChanged() + { + ChangeListener[] ll = getChangeListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].stateChanged(changeEvent); + } + + /** + * Get the value of the model's "armed" property. + * + * @return The current "armed" property + */ + public boolean isArmed() + { + return (stateMask & ARMED) == ARMED; + } + + /** + * Set the value of the model's "armed" property. + * + * @param a The new "armed" property + */ + public void setArmed(boolean a) + { + // if this call does not represent a CHANGE in state, then return + if ((a && isArmed()) || (!a && !isArmed())) + return; + + // cannot change ARMED state unless button is enabled + if (!isEnabled()) + return; + + // make the change + if (a) + stateMask = stateMask | ARMED; + else + stateMask = stateMask & (~ARMED); + + // notify interested ChangeListeners + fireStateChanged(); + } + + /** + * Get the value of the model's "enabled" property. + * + * @return The current "enabled" property. + */ + public boolean isEnabled() + { + return (stateMask & ENABLED) == ENABLED; + } + + /** + * Set the value of the model's "enabled" property. + * + * @param e The new "enabled" property + */ + public void setEnabled(boolean e) + { + // if this call does not represent a CHANGE in state, then return + if ((e && isEnabled()) || (!e && !isEnabled())) + return; + + // make the change + if (e) + stateMask = stateMask | ENABLED; + else + stateMask = stateMask & (~ENABLED); + + // notify interested ChangeListeners + fireStateChanged(); + } + + /** + * Set the value of the model's "pressed" property. + * + * @param p The new "pressed" property + */ + public void setPressed(boolean p) + { + // if this call does not represent a CHANGE in state, then return + if ((p && isPressed()) || (!p && !isPressed())) + return; + + // cannot changed PRESSED state unless button is enabled + if (!isEnabled()) + return; + + // make the change + if (p) + stateMask = stateMask | PRESSED; + else + stateMask = stateMask & (~PRESSED); + + // notify interested ChangeListeners + fireStateChanged(); + + // if button is armed and was released, fire action event + if (!p && isArmed()) + fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, + actionCommand)); + } + + /** + * Get the value of the model's "pressed" property. + * + * @return The current "pressed" property + */ + public boolean isPressed() + { + return (stateMask & PRESSED) == PRESSED; + } + + /** + * Set the value of the model's "rollover" property. + * + * @param r The new "rollover" property + */ + public void setRollover(boolean r) + { + // if this call does not represent a CHANGE in state, then return + if ((r && isRollover()) || (!r && !isRollover())) + return; + + // cannot set ROLLOVER property unless button is enabled + if (!isEnabled()) + return; + + // make the change + if (r) + stateMask = stateMask | ROLLOVER; + else + stateMask = stateMask & (~ROLLOVER); + + // notify interested ChangeListeners + fireStateChanged(); + } + + /** + * Set the value of the model's "selected" property. + * + * @param s The new "selected" property + */ + public void setSelected(boolean s) + { + // if this call does not represent a CHANGE in state, then return + if ((s && isSelected()) || (!s && !isSelected())) + return; + + // make the change + if (s) + stateMask = stateMask | SELECTED; + else + stateMask = stateMask & (~SELECTED); + + // notify interested ChangeListeners + fireStateChanged(); + + // fire ItemStateChanged events + if (s) + { + fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, + null, ItemEvent.SELECTED)); + if (group != null) + group.setSelected(this, true); + } + else + { + fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, + null, ItemEvent.DESELECTED)); + if (group != null) + group.setSelected(this, false); + } + } + + /** + * Get the value of the model's "selected" property. + * + * @return The current "selected" property + */ + public boolean isSelected() + { + return (stateMask & SELECTED) == SELECTED; + } + + /** + * Get the value of the model's "rollover" property. + * + * @return The current "rollover" property + */ + public boolean isRollover() + { + return (stateMask & ROLLOVER) == ROLLOVER; + } + + /** + * Get the value of the model's "mnemonic" property. + * + * @return The current "mnemonic" property + */ + public int getMnemonic() + { + return mnemonic; + } + + /** + * Set the value of the model's "mnemonic" property. + * + * @param key The new "mnemonic" property + */ + public void setMnemonic(int key) + { + if (mnemonic != key) + { + mnemonic = key; + fireStateChanged(); + } + } + + /** + * Set the value of the model's "actionCommand" property. This property is + * used as the "command" property of the {@link ActionEvent} fired from the + * model. + * + * @param s The new "actionCommand" property. + */ + public void setActionCommand(String s) + { + if (actionCommand != s) + { + actionCommand = s; + fireStateChanged(); + } + } + + /** + * Returns the current value of the model's "actionCommand" property. + * + * @return The current "actionCommand" property + */ + public String getActionCommand() + { + return actionCommand; + } + + /** + * Set the value of the model's "group" property. The model is said to be a + * member of the {@link ButtonGroup} held in its "group" property, and only + * one model in a given group can have their "selected" property be + * <code>true</code> at a time. + * + * @param g The new "group" property + */ + public void setGroup(ButtonGroup g) + { + if (group != g) + { + group = g; + fireStateChanged(); + } + } + + /** + * Returns the current value of the model's "group" property. + * + * @return The value of the "group" property + */ + public ButtonGroup getGroup() + { + return group; + } +} diff --git a/libjava/classpath/javax/swing/DefaultCellEditor.java b/libjava/classpath/javax/swing/DefaultCellEditor.java new file mode 100644 index 00000000000..e67e2f5a403 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultCellEditor.java @@ -0,0 +1,344 @@ +/* DefaultCellEditor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.io.Serializable; +import java.util.EventObject; + +import javax.swing.table.TableCellEditor; +import javax.swing.tree.TreeCellEditor; + +/** + * DefaultCellEditor + * @author Andrew Selkirk + * @version 1.0 + */ +public class DefaultCellEditor + extends AbstractCellEditor + implements TableCellEditor, TreeCellEditor +{ + private static final long serialVersionUID = 3564035141373880027L; + + /** + * EditorDelegate + */ + protected class EditorDelegate + implements ActionListener, ItemListener, Serializable + { + private static final long serialVersionUID = -1420007406015481933L; + + /** + * value + */ + protected Object value; + + /** + * Constructor EditorDelegate + * + * @param value0 TODO + */ + protected EditorDelegate() + { + } + + /** + * setValue + * + * @param event TODO + */ + public void setValue(Object event) + { + } + + /** + * getCellEditorValue + * + * @returns Object + */ + public Object getCellEditorValue() + { + return null; // TODO + } // getCellEditorValue() + + /** + * isCellEditable + * + * @param event TODO + * + * @returns boolean + */ + public boolean isCellEditable(EventObject event) + { + return false; // TODO + } // isCellEditable() + + /** + * shouldSelectCell + * + * @param event TODO + * + * @returns boolean + */ + public boolean shouldSelectCell(EventObject event) + { + return false; // TODO + } // shouldSelectCell() + + /** + * stopCellEditing + * + * @returns boolean + */ + public boolean stopCellEditing() + { + return false; // TODO + } // stopCellEditing() + + /** + * cancelCellEditing + */ + public void cancelCellEditing() + { + // TODO + } // cancelCellEditing() + + /** + * startCellEditing + * + * @param event TODO + * + * @returns boolean + */ + public boolean startCellEditing(EventObject event) + { + return false; // TODO + } // startCellEditing() + + /** + * actionPerformed + * + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } // actionPerformed() + + /** + * itemStateChanged + * + * @param event TODO + */ + public void itemStateChanged(ItemEvent event) + { + // TODO + } // itemStateChanged() + + } // EditorDelegate + + /** + * editorComponent + */ + protected JComponent editorComponent; + + /** + * delegate + */ + protected EditorDelegate delegate; + + /** + * clickCountToStart + */ + protected int clickCountToStart; + + /** + * Constructor DefaultCellEditor + * + * @param textfield TODO + */ + public DefaultCellEditor(JTextField textfield) + { + // TODO + } // DefaultCellEditor() + + /** + * Constructor DefaultCellEditor + * + * @param checkbox TODO + */ + public DefaultCellEditor(JCheckBox checkbox) + { + // TODO + } // DefaultCellEditor() + + /** + * Constructor DefaultCellEditor + * + * @param combobox TODO + */ + public DefaultCellEditor(JComboBox combobox) + { + // TODO + } // DefaultCellEditor() + + /** + * getComponent + * + * @returns Component + */ + public Component getComponent() + { + return null; // TODO + } // getComponent() + + /** + * getClickCountToStart + * + * @returns int + */ + public int getClickCountToStart() + { + return 0; // TODO + } // getClickCountToStart() + + /** + * setClickCountToStart + * + * @param count TODO + */ + public void setClickCountToStart(int count) + { + // TODO + } // setClickCountToStart() + + /** + * getCellEditorValue + * + * @returns Object + */ + public Object getCellEditorValue() + { + return null; // TODO + } // getCellEditorValue() + + /** + * isCellEditable + * + * @param event TODO + * + * @returns boolean + */ + public boolean isCellEditable(EventObject event) + { + return false; // TODO + } // isCellEditable() + + /** + * shouldSelectCell + * + * @param event TODO + * + * @returns boolean + */ + public boolean shouldSelectCell(EventObject event) + { + return false; // TODO + } // shouldSelectCell() + + /** + * stopCellEditing + * + * @returns boolean + */ + public boolean stopCellEditing() + { + return false; // TODO + } // stopCellEditing() + + /** + * cancelCellEditing + */ + public void cancelCellEditing() + { + // TODO + } // cancelCellEditing() + + /** + * getTreeCellEditorComponent + * + * @param tree TODO + * @param value TODO + * @param isSelected TODO + * @param expanded TODO + * @param leaf TODO + * @param row TODO + * + * @returns Component + */ + public Component getTreeCellEditorComponent(JTree tree, Object value, + boolean isSelected, + boolean expanded, boolean leaf, + int row) + { + return null; // TODO + } // getTreeCellEditorComponent() + + /** + * getTableCellEditorComponent + * + * @param tree TODO + * @param value TODO + * @param isSelected TODO + * @param row TODO + * @param column TODO + * + * @returns Component + */ + public Component getTableCellEditorComponent(JTable tree, Object value, + boolean isSelected, int row, + int column) + { + return null; // TODO + } // getTableCellEditorComponent() +} diff --git a/libjava/classpath/javax/swing/DefaultComboBoxModel.java b/libjava/classpath/javax/swing/DefaultComboBoxModel.java new file mode 100644 index 00000000000..1cea886b793 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultComboBoxModel.java @@ -0,0 +1,238 @@ +/* DefaultComboBoxModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Vector; + + +/** + * DefaultComboBoxModel is a data model for JComboBox. This model keeps track + * of elements contained in the JComboBox as well as the current combo box + * selection. Whenever selection in the JComboBox changes, the ComboBoxModel + * will fire ListDataEvents to ComboBox's ListDataListeners. + * + * @author Andrew Selkirk + * @author Olga Rodimina + * @author Robert Schuster + * @version 1.0 + */ +public class DefaultComboBoxModel extends AbstractListModel + implements MutableComboBoxModel, Serializable +{ + private static final long serialVersionUID = 6698657703676921904L; + + /** + * List containing items in the combo box + */ + private Vector list; + + /** + * Currently selected item in the combo box list + */ + private Object selectedItem = null; + + /** + * Constructor DefaultComboBoxModel. Create empty JComboBox. + */ + public DefaultComboBoxModel() + { + list = new Vector(); + } + + /** + * Constructs new DefaultComboBoxModel object and initializes its item list + * to values in the given array. + * + * @param items array containing items of the combo box. + */ + public DefaultComboBoxModel(Object[] items) + { + list = new Vector(Arrays.asList(items)); + } + + /** + * Consturcts new DefaultComboBoxModel object and initializes its item list + * to values in the given vector. + * + * @param vector Vector containing items for this combo box. + */ + public DefaultComboBoxModel(Vector vector) + { + this.list = vector; + } + + /** + * This method adds element to the combo box list. It fires ListDataEvent + * indicating that component was added to the combo box to all of the + * JComboBox's registered ListDataListeners. + * + * @param object item to add to the combo box list + */ + public void addElement(Object object) + { + list.add(object); + fireIntervalAdded(this, list.size() - 1, list.size()); + } + + /** + * This method removes element at the specified index from the combo box + * list. It fires ListDataEvent indicating that component was removed from + * the combo box list to all of the JComboBox's registered + * ListDataListeners. + * + * @param index index specifying location of the element to remove in the + * combo box list. + */ + public void removeElementAt(int index) + { + list.remove(index); + fireIntervalRemoved(this, index, index); + } + + /** + * This method inserts given object to the combo box list at the specified + * index. It fires ListDataEvent indicating that component was inserted to + * the combo box list to all of the JComboBox's registered + * ListDataListeners. + * + * @param object element to insert + * @param index index specifing position in the list where given element + * should be inserted. + */ + public void insertElementAt(Object object, int index) + { + list.insertElementAt(object, index); + fireIntervalAdded(this, index, index); + } + + /** + * Removes given object from the combo box list. It fires ListDataEvent + * indicating that component was removed from the combo box list to all of + * the JComboBox's registered ListDataListeners. + * + * @param object Element that will be removed from the combo box list + */ + public void removeElement(Object object) + { + int index = getIndexOf(object); + if (index != -1) + removeElementAt(index); + } + + /** + * Removes all the items from the JComboBox's item list. It fires + * ListDataEvent indicating that all the elements were removed from the + * combo box list to all of the JComboBox's registered ListDataListeners. + */ + public void removeAllElements() + { + list.clear(); + int listSize = getSize(); + fireIntervalAdded(this, 0, listSize); + } + + /** + * Returns number of items in the combo box list + * + * @return number of items in the combo box list + */ + public int getSize() + { + return list.size(); + } + + /** + * Selects given object in the combo box list. This method fires + * ListDataEvent to all registered ListDataListeners of the JComboBox. The + * start and end index of the event is set to -1 to indicate combo box's + * selection has changed, and not its contents. + * + * <p>If the given object is not contained in the combo box list then nothing + * happens.</p> + * + * @param object item to select in the JComboBox + */ + public void setSelectedItem(Object object) + { + + // Updates the selected item only if the given object + // is null or in the list (this is how the JDK behaves). + if(object == null || list.contains(object)) { + selectedItem = object; + fireContentsChanged(this, -1, -1); + } + + } + + /** + * Returns currently selected item in the combo box list + * + * @return currently selected item in the combo box list + */ + public Object getSelectedItem() + { + return selectedItem; + } + + /** + * Returns element in the combo box list located at the given index + * + * @param index specifying location of the element in the list + * + * @return return element in the combo box list located at the given index + */ + public Object getElementAt(int index) + { + return list.elementAt(index); + } + + /** + * Returns index of the specified object in the combo box list. + * + * @param object element to look for in the combo box list . + * + * @return Index specifying position of the specified element in combo box + * list. + */ + public int getIndexOf(Object object) + { + return list.indexOf(object); + } +} diff --git a/libjava/classpath/javax/swing/DefaultDesktopManager.java b/libjava/classpath/javax/swing/DefaultDesktopManager.java new file mode 100644 index 00000000000..15ed262e8e8 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultDesktopManager.java @@ -0,0 +1,629 @@ +/* DefaultDesktopManager.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.Rectangle; +import java.beans.PropertyVetoException; +import java.io.Serializable; + +import javax.swing.JInternalFrame.JDesktopIcon; + +/** + * DefaultDesktopManager is the default implementation of DesktopManager for + * swing. It implements the basic beaviours for JInternalFrames in arbitrary + * parents. The methods provided by the class are not meant to be called by + * the user, instead, the JInternalFrame methods will call these methods. + */ +public class DefaultDesktopManager implements DesktopManager, Serializable +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = 4657624909838017887L; + + /** The property change event fired when the wasIcon property changes. */ + static final String WAS_ICON_ONCE_PROPERTY = "wasIconOnce"; + + /** + * The method of dragging used by the JDesktopPane that parents the + * JInternalFrame that is being dragged. + */ + private int currentDragMode = 0; + + /** + * The cache of the bounds used to draw the outline rectangle when + * OUTLINE_DRAG_MODE is used. + */ + private transient Rectangle dragCache = new Rectangle(); + + /** + * A cached JDesktopPane that is stored when the JInternalFrame is initially + * dragged. + */ + private transient Container pane; + + /** + * An array of Rectangles that holds the bounds of the JDesktopIcons in the + * JDesktopPane when looking for where to place a new icon. + */ + private transient Rectangle[] iconRects; + + /** + * This creates a new DefaultDesktopManager object. + */ + public DefaultDesktopManager() + { + } + + /** + * This method is not normally called since the user will typically add the + * JInternalFrame to a Container. If this is called, it will try to + * determine the parent of the JInternalFrame and remove any icon that + * represents this JInternalFrame and add this JInternalFrame. + * + * @param frame The JInternalFrame to open. + */ + public void openFrame(JInternalFrame frame) + { + Container c = frame.getParent(); + if (c == null) + c = frame.getDesktopIcon().getParent(); + if (c == null) + return; + + c.remove(frame.getDesktopIcon()); + c.add(frame); + frame.setVisible(true); + } + + /** + * This method removes the JInternalFrame and JDesktopIcon (if one is + * present) from their parents. + * + * @param frame The JInternalFrame to close. + */ + public void closeFrame(JInternalFrame frame) + { + Container c = frame.getParent(); + frame.doDefaultCloseAction(); + + if (c != null) + { + if (frame.isIcon()) + c.remove(frame.getDesktopIcon()); + else + c.remove(frame); + c.repaint(); + } + } + + /** + * This method resizes the JInternalFrame to match its parent's bounds. + * + * @param frame The JInternalFrame to maximize. + */ + public void maximizeFrame(JInternalFrame frame) + { + // Can't maximize from iconified state. + // It can only return to maximized state, but that would fall under + // deiconify. + if (frame.isIcon()) + return; + frame.setNormalBounds(frame.getBounds()); + + Container p = frame.getParent(); + if (p != null) + { + Rectangle pBounds = p.getBounds(); + Insets insets = p.getInsets(); + pBounds.width -= insets.left + insets.right; + pBounds.height -= insets.top + insets.bottom; + + setBoundsForFrame(frame, 0, 0, pBounds.width, pBounds.height); + } + if (p instanceof JDesktopPane) + ((JDesktopPane) p).setSelectedFrame(frame); + else + { + try + { + frame.setSelected(true); + } + catch (PropertyVetoException e) + { + // Do nothing. + } + } + } + + /** + * This method restores the JInternalFrame's bounds to what they were + * previous to the setMaximize call. + * + * @param frame The JInternalFrame to minimize. + */ + public void minimizeFrame(JInternalFrame frame) + { + Rectangle normalBounds = frame.getNormalBounds(); + + JDesktopPane p = frame.getDesktopPane(); + if (p != null) + p.setSelectedFrame(frame); + else + { + try + { + frame.setSelected(true); + } + catch (PropertyVetoException e) + { + // Do nothing. + } + } + + setBoundsForFrame(frame, normalBounds.x, normalBounds.y, + normalBounds.width, normalBounds.height); + } + + /** + * This method removes the JInternalFrame from its parent and adds its + * JDesktopIcon representation. + * + * @param frame The JInternalFrame to iconify. + */ + public void iconifyFrame(JInternalFrame frame) + { + JDesktopPane p = frame.getDesktopPane(); + JDesktopIcon icon = frame.getDesktopIcon(); + if (p != null && p.getSelectedFrame() == frame) + p.setSelectedFrame(null); + else + { + try + { + frame.setSelected(false); + } + catch (PropertyVetoException e) + { + } + } + + Container c = frame.getParent(); + + if (!wasIcon(frame)) + { + Rectangle r = getBoundsForIconOf(frame); + icon.setBounds(r); + setWasIcon(frame, Boolean.TRUE); + } + + if (c != null) + { + if (icon != null) + { + c.add(icon); + icon.setVisible(true); + } + c.remove(frame); + } + } + + /** + * This method removes the JInternalFrame's JDesktopIcon representation and + * adds the JInternalFrame back to its parent. + * + * @param frame The JInternalFrame to deiconify. + */ + public void deiconifyFrame(JInternalFrame frame) + { + JDesktopIcon icon = frame.getDesktopIcon(); + Container c = icon.getParent(); + + removeIconFor(frame); + c.add(frame); + frame.setVisible(true); + + if (!frame.isSelected()) + { + JDesktopPane p = frame.getDesktopPane(); + if (p != null) + p.setSelectedFrame(frame); + else + { + try + { + frame.setSelected(true); + } + catch (PropertyVetoException e) + { + // Do nothing. + } + } + } + + c.invalidate(); + } + + /** + * This method activates the JInternalFrame by moving it to the front and + * selecting it. + * + * @param frame The JInternalFrame to activate. + */ + public void activateFrame(JInternalFrame frame) + { + JDesktopPane p = frame.getDesktopPane(); + + if (p != null) + p.setSelectedFrame(frame); + else + { + try + { + frame.setSelected(true); + } + catch (PropertyVetoException e) + { + } + } + + frame.toFront(); + } + + /** + * This method is called when the JInternalFrame loses focus. + * + * @param frame The JInternalFram to deactivate. + */ + public void deactivateFrame(JInternalFrame frame) + { + JDesktopPane p = frame.getDesktopPane(); + if (p != null) + { + if (p.getSelectedFrame() == frame) + p.setSelectedFrame(null); + } + else + { + try + { + frame.setSelected(false); + } + catch (PropertyVetoException e) + { + } + } + } + + /** + * This method is called to indicate that the DesktopManager should prepare + * to drag the JInternalFrame. Any state information needed to drag the + * frame will be prepared now. + * + * @param component The JComponent to drag, usually a JInternalFrame. + */ + public void beginDraggingFrame(JComponent component) + { + if (component instanceof JDesktopIcon) + pane = ((JDesktopIcon) component).getInternalFrame().getDesktopPane(); + else + pane = ((JInternalFrame) component).getDesktopPane(); + if (pane == null) + return; + + dragCache = component.getBounds(); + + if (! (pane instanceof JDesktopPane)) + currentDragMode = JDesktopPane.LIVE_DRAG_MODE; + else + currentDragMode = ((JDesktopPane) pane).getDragMode(); + } + + /** + * This method is called to drag the JInternalFrame to a new location. + * + * @param component The JComponent to drag, usually a JInternalFrame. + * + * @param newX The new x coordinate. + * @param newY The new y coordinate. + */ + public void dragFrame(JComponent component, int newX, int newY) + { + if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE) + { + // FIXME: Do outline drag mode painting. + } + else + { + Rectangle b = component.getBounds(); + if (component instanceof JDesktopIcon) + component.setBounds(newX, newY, b.width, b.height); + else + setBoundsForFrame((JInternalFrame) component, newX, newY, b.width, + b.height); + } + } + + /** + * This method indicates that the dragging is done. Any state information + * stored by the DesktopManager can be cleared. + * + * @param component The JComponent that has finished dragging. + */ + public void endDraggingFrame(JComponent component) + { + if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE) + { + setBoundsForFrame((JInternalFrame) component, dragCache.x, dragCache.y, + dragCache.width, dragCache.height); + pane = null; + dragCache = null; + } + component.repaint(); + } + + /** + * This method is called to indicate that the given JComponent will be + * resized. Any state information necessary to resize the JComponent will + * be prepared now. + * + * @param component The JComponent to resize, usually a JInternalFrame. + * @param direction The direction to drag in (a SwingConstant). + */ + public void beginResizingFrame(JComponent component, int direction) + { + pane = ((JInternalFrame) component).getDesktopPane(); + if (pane == null) + return; + + dragCache = component.getBounds(); + if (! (pane instanceof JDesktopPane)) + currentDragMode = JDesktopPane.LIVE_DRAG_MODE; + else + currentDragMode = ((JDesktopPane) pane).getDragMode(); + } + + /** + * This method resizes the give JComponent. + * + * @param component The JComponent to resize. + * @param newX The new x coordinate. + * @param newY The new y coordinate. + * @param newWidth The new width. + * @param newHeight The new height. + */ + public void resizeFrame(JComponent component, int newX, int newY, + int newWidth, int newHeight) + { + dragCache.setBounds(newX, newY, newWidth, newHeight); + + if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE) + { + // FIXME: Do outline drag painting. + } + else + setBoundsForFrame(component, dragCache.x, dragCache.y, dragCache.width, + dragCache.height); + } + + /** + * This method is called to indicate that the given JComponent has finished + * dragging. Any state information stored by the DesktopManager can be + * cleared. + * + * @param component The JComponent that finished resizing. + */ + public void endResizingFrame(JComponent component) + { + if (currentDragMode == JDesktopPane.OUTLINE_DRAG_MODE) + { + setBoundsForFrame((JInternalFrame) component, dragCache.x, dragCache.y, + dragCache.width, dragCache.height); + pane = null; + dragCache = null; + } + component.repaint(); + } + + /** + * This method calls setBounds with the given parameters and repaints the + * JComponent. + * + * @param component The JComponent to set bounds for. + * @param newX The new x coordinate. + * @param newY The new y coordinate. + * @param newWidth The new width. + * @param newHeight The new height. + */ + public void setBoundsForFrame(JComponent component, int newX, int newY, + int newWidth, int newHeight) + { + component.setBounds(newX, newY, newWidth, newHeight); + component.revalidate(); + + // If not null, I'd rather repaint the parent + if (component.getParent() != null) + component.getParent().repaint(); + else + component.repaint(); + } + + /** + * This is a helper method that removes the JDesktopIcon of the given + * JInternalFrame from the parent. + * + * @param frame The JInternalFrame to remove an icon for. + */ + protected void removeIconFor(JInternalFrame frame) + { + JDesktopIcon icon = frame.getDesktopIcon(); + Container c = icon.getParent(); + if (c != null && icon != null) + c.remove(icon); + } + + /** + * This method is called by iconifyFrame to determine the bounds of the + * JDesktopIcon for the given JInternalFrame. + * + * @param frame The JInternalFrame to find the bounds of its JDesktopIcon + * for. + * + * @return The bounds of the JDesktopIcon. + */ + protected Rectangle getBoundsForIconOf(JInternalFrame frame) + { + // IconRects has no order to it. + // The icon _must_ be placed in the first free slot (working from + // the bottom left corner) + // The icon also must not be placed where another icon is placed + // (regardless whether that frame is an icon currently or not) + JDesktopPane desktopPane = frame.getDesktopPane(); + + if (desktopPane == null) + return frame.getDesktopIcon().getBounds(); + + Rectangle paneBounds = desktopPane.getBounds(); + Insets insets = desktopPane.getInsets(); + Dimension pref = frame.getDesktopIcon().getPreferredSize(); + + Component[] frames = desktopPane.getComponents(); + + int count = 0; + for (int i = 0, j = 0; i < frames.length; i++) + if (frames[i] instanceof JDesktopIcon + || frames[i] instanceof JInternalFrame + && ((JInternalFrame) frames[i]).getWasIcon() && frames[i] != frame) + count++; + iconRects = new Rectangle[count]; + for (int i = 0, j = 0; i < frames.length; i++) + if (frames[i] instanceof JDesktopIcon) + iconRects[--count] = frames[i].getBounds(); + else if (frames[i] instanceof JInternalFrame + && ((JInternalFrame) frames[i]).getWasIcon() + && frames[i] != frame) + iconRects[--count] = ((JInternalFrame) frames[i]) + .getDesktopIcon().getBounds(); + + int startingX = insets.left; + int startingY = paneBounds.height - insets.bottom - pref.height; + Rectangle ideal = new Rectangle(startingX, startingY, pref.width, + pref.height); + boolean clear = true; + + while (iconRects.length > 0) + { + clear = true; + for (int i = 0; i < iconRects.length; i++) + { + if (iconRects[i] != null && iconRects[i].intersects(ideal)) + { + clear = false; + break; + } + } + if (clear) + return ideal; + + startingX += pref.width; + if (startingX + pref.width > paneBounds.width - insets.right) + { + startingX = insets.left; + startingY -= pref.height; + } + ideal.setBounds(startingX, startingY, pref.width, pref.height); + } + + return ideal; + } + + /** + * This method sets the bounds of the JInternalFrame right before the + * maximizeFrame call. + * + * @param frame The JInternalFrame being maximized. + * @param rect The normal bounds. + */ + protected void setPreviousBounds(JInternalFrame frame, Rectangle rect) + { + frame.setNormalBounds(rect); + } + + /** + * This method returns the normal bounds of the JInternalFrame from before + * the maximize call. + * + * @param frame The JInternalFrame that is being restored. + * + * @return The previous bounds of the JInternalFrame. + */ + protected Rectangle getPreviousBounds(JInternalFrame frame) + { + return frame.getNormalBounds(); + } + + /** + * This method sets the value to true if the given JInternalFrame has been + * iconized and the bounds of its DesktopIcon are valid. + * + * @param frame The JInternalFrame for the JDesktopIcon. + * @param value True if the JInternalFrame has been iconized and the bounds + * of the JDesktopIcon are valid. + */ + protected void setWasIcon(JInternalFrame frame, Boolean value) + { + frame.setWasIcon(value.booleanValue(), WAS_ICON_ONCE_PROPERTY); + } + + /** + * This method returns true if the given JInternalFrame has been iconized + * and the bounds of its DesktopIcon are valid. + * + * @param frame The JInternalFrame for the JDesktopIcon. + * + * @return True if the given JInternalFrame has been iconized and the bounds + * of its DesktopIcon are valid. + */ + protected boolean wasIcon(JInternalFrame frame) + { + return frame.getWasIcon(); + } +} diff --git a/libjava/classpath/javax/swing/DefaultFocusManager.java b/libjava/classpath/javax/swing/DefaultFocusManager.java new file mode 100644 index 00000000000..dd8e6047bb8 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultFocusManager.java @@ -0,0 +1,166 @@ +/* DefaultFocusManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.event.KeyEvent; +import java.util.Stack; + +/** + * DefaultFocusManager + * @author Andrew Selkirk + * @version 1.0 + */ +public class DefaultFocusManager extends FocusManager { + + /** + * historyStack + */ + private Stack historyStack; + + /** + * Constructor DefaultFocusManager + */ + public DefaultFocusManager() + { + // TODO + } // DefaultFocusManager() + + /** + * processKeyEvent + * + * @param component + * TODO + * @param event + * TODO + */ + public void processKeyEvent(Component component, KeyEvent event) + { + // TODO + } // processKeyEvent() + + /** + * focusNextComponent + * + * @param component + * TODO + */ + public void focusNextComponent(Component component) + { + // TODO + } // focusNextComponent() + + /** + * focusPreviousComponent + * + * @param component + * TODO + */ + public void focusPreviousComponent(Component component) + { + // TODO + } // focusPreviousComponent() + + /** + * getFirstComponent + * + * @param container + * TODO + * @returns Component + */ + public Component getFirstComponent(Container container) + { + return null; // TODO + } // getFirstComponent() + + /** + * getLastComponent + * + * @param container + * TODO + * @returns Component + */ + public Component getLastComponent(Container container) + { + return null; // TODO + } // getLastComponent() + + /** + * getComponentBefore + * + * @param container + * TODO + * @param component + * TODO + * @returns Component + */ + public Component getComponentBefore(Container container, Component component) + { + return null; // TODO + } // getComponentBefore() + + /** + * getComponentAfter + * + * @param container + * TODO + * @param component + * TODO + * @returns Component + */ + public Component getComponentAfter(Container container, Component component) + { + return null; // TODO + } // getComponentAfter() + + /** + * compareTabOrder + * + * @param component1 + * TODO + * @param component2 + * TODO + * @returns boolean + */ + public boolean compareTabOrder(Component component1, Component component2) + { + return false; // TODO + } // compareTabOrder() + +} // DefaultFocusManager diff --git a/libjava/classpath/javax/swing/DefaultListCellRenderer.java b/libjava/classpath/javax/swing/DefaultListCellRenderer.java new file mode 100644 index 00000000000..0f2417d04d6 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultListCellRenderer.java @@ -0,0 +1,179 @@ +/* DefaultListCellRenderer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; + +/** + * DefaultListCellRenderer. This class is responsible for rendering list + * cells. + * + * @author Andrew Selkirk + * @version 1.0 + */ +public class DefaultListCellRenderer extends JLabel + implements ListCellRenderer, Serializable +{ + private static final long serialVersionUID = 7708947179685189462L; + + public static class UIResource extends DefaultListCellRenderer + implements javax.swing.plaf.UIResource + { + public UIResource() + { + } + } + + /** + * This border is used whenever renderer doesn't have a focus. + */ + protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); + + /** + * getListCellRendererComponent + * + * @param list JList list for the 'value' + * @param value object that should be rendered in the cell + * @param index index of the cell + * @param isSelected draw cell highlighted if isSelected is true + * @param cellHasFocus draw focus rectangle around cell if the cell has + * focus + * + * @return Component that will be painted to the desired cell. + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, + boolean cellHasFocus) + { + String s = value.toString(); + setText(s); + setOpaque(true); + setHorizontalAlignment(LEFT); + + if (isSelected) + { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } + else + { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + setEnabled(list.isEnabled()); + setFont(list.getFont()); + + // Use focusCellHighlightBorder when renderer has focus and + // noFocusBorder otherwise + + if (cellHasFocus) + setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); + else + setBorder(noFocusBorder); + + return this; + } + + public void validate() + { + } + + public void revalidate() + { + } + + public void repaint(long tm, int x, int y, int w, int h) + { + } + + public void repaint(Rectangle rect) + { + } + + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + } + + public void firePropertyChange(String propertyName, byte oldValue, + byte newValue) + { + } + + public void firePropertyChange(String propertyName, char oldValue, + char newValue) + { + } + + public void firePropertyChange(String propertyName, short oldValue, + short newValue) + { + } + + public void firePropertyChange(String propertyName, int oldValue, + int newValue) + { + } + + public void firePropertyChange(String propertyName, long oldValue, + long newValue) + { + } + + public void firePropertyChange(String propertyName, float oldValue, + float newValue) + { + } + + public void firePropertyChange(String propertyName, double oldValue, + double newValue) + { + } + + public void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) + { + } +} diff --git a/libjava/classpath/javax/swing/DefaultListModel.java b/libjava/classpath/javax/swing/DefaultListModel.java new file mode 100644 index 00000000000..d7ff2599b58 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultListModel.java @@ -0,0 +1,521 @@ +/* DefaultListModel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.util.Enumeration; +import java.util.Vector; + +/** + * This is a default subclass of the {@link AbstractListModel}, used by + * {@link javax.swing.JList} and similar objects as the model of a list of + * values. The implementation is based on an underlying {@link + * java.util.Vector}. + * + * @author Andrew Selkirk + * @author Graydon Hoare (graydon@redhat.com) + */ + +public class DefaultListModel extends AbstractListModel +{ + private static final long serialVersionUID = 2315945659722172272L; + + /** + * The vector of elements in this list model. + */ + private Vector elements = new Vector(); + + /** + * Gets an element of the list at the provided index. + * + * @param index The index of the element to get + * + * @return The object at the given index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public Object elementAt(int index) + { + return elements.elementAt(index); + } + + /** + * Convert the list to a string representation. + * + * @return A string representation of the list + */ + public String toString() + { + return elements.toString(); + } + + /** + * Gets the first index of a particular element in the list. + * + * @param element The element to search for + * + * @return The first index in the list at which an object + * <code>obj</code> exists such that <code>obj.equals(element)</code> is + * <code>true</code>; if no such object exists, the method returns + * <code>-1</code> + */ + public int indexOf(Object element) + { + return elements.indexOf(element); + } + + /** + * Gets the first index of a particular element in a list which occurs + * <em>at or after</em> a particular index. + * + * @param element The element to search for + * @param startIndex The index to begin searching at + * + * @return The first index in the list, greater than or equal to + * <code>startIndex</code>, at which an object <code>obj</code> exists + * such that <code>obj.equals(element)</code> is <code>true</code>; if no + * such object exists, the method returns <code>-1</code> + */ + public int indexOf(Object element, int startIndex) + { + return elements.indexOf(element, startIndex); + } + + /** + * Gets the last index of a particular element in the list. + * + * @param element The element to search for + * + * @return The last index in the list at which an object + * <code>obj</code> exists such that <code>obj.equals(element)</code> is + * <code>true</code>; if no such object exists, the method returns + * <code>-1</code> + */ + public int lastIndexOf(Object element) + { + return elements.lastIndexOf(element); + } + + /** + * Gets the last index of a particular element in a list which occurs + * <em>at or before</em> a particular index. + * + * @param element The element to search for + * @param endIndex The index to finish searching at + * + * @return The last index in the list, less than to or equal to + * <code>endIndexIndex</code>, at which an object <code>obj</code> exists + * such that <code>obj.equals(element)</code> is <code>true</code>; if no + * such object exists, the method returns <code>-1</code> + */ + public int lastIndexOf(Object element, int endIndex) + { + return elements.lastIndexOf(element, endIndex); + } + + /** + * Gets the list element at a particular index. + * + * @param index The index to get the list value at + * + * @return The list value at the provided index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public Object get(int index) + { + return elements.get(index); + } + + /** + * Sets the list element at a particular index. + * + * @param index The list index at which to set a value + * @param element The value to set at the specified index + * + * @return The value previously held at the specified index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public Object set(int index, Object element) + { + Object result; + result = elements.set(index, element); + fireContentsChanged(this, index, index); + return result; + } + + /** + * Inserts an element at a particular index in the list. Each element at + * index <code>i >= index</code> is shifted to position <code>i+1</code>. + * If <code>index</code> is equal to <code>size()</code>, this is + * equivalent to appending an element to the array. Any + * <code>index</code> greater than <code>size()</code> is illegal. + * + * @param index The index to insert the element at + * @param element The element to insert at the index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds <code>[0, size()]</code> + */ + public void add(int index, Object element) + { + elements.add(index, element); + fireIntervalAdded(this, index, index); + } + + /** + * Inserts an element at the end of the list. This is equivalent to + * calling <code>list.add(list.size(), element)</code>. + * + * @param element The element to add to the list + */ + public void addElement(Object element) + { + int s = elements.size(); + elements.add(element); + fireIntervalAdded(this, s, s); + } + + /** + * Gets the number of elements in the list. + * + * @return The number of elements in the list + */ + public int size() + { + return elements.size(); + } + + /** + * Gets an array containing the elements of the list. + * + * @return An array of the objects in the list, in the order they occur + * in the list + */ + public Object[] toArray() + { + return elements.toArray(); + } + + /** + * Determines whether a particular element is a member of the list. + * + * @param element The element to search for + * + * @return <code>true</code> if <code>element</code> is a member of the + * list, otherwise <code>false</code> + */ + public boolean contains(Object element) + { + return elements.contains(element); + } + + /** + * Copies the list into a provided array. The provided array must be at + * least as large as the list. + * + * @param array The array to copy the list into + * + * @throws IndexOutOfBoundsException if the array is too small to hold the + * elements of the list + */ + public void copyInto(Object[] array) + { + elements.copyInto(array); + } + + /** + * Erases all the elements of the list, setting the list's size to 0. + */ + public void clear() + { + int s = elements.size(); + if (s > 0) + { + elements.clear(); + fireIntervalRemoved(this, 0, s - 1); + } + } + + /** + * Removes the element at a particular index from the list. + * + * @param index The index of the element to remove + * + * @return The value at the index, which has been removed from the list + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public Object remove(int index) + { + Object result; + result = elements.remove(index); + fireIntervalRemoved(this, index, index); + return result; + } + + /** + * Determines whether the list is empty. + * + * @return <code>true</code> if the list is empty, otherwise + * <code>false</code> + */ + public boolean isEmpty() + { + return elements.isEmpty(); + } + + /** + * Returns an {@link java.util.Enumeration} over the elements of the list. + * + * @return A new enumeration which iterates over the list + */ + public Enumeration elements() + { + return elements.elements(); + } + + /** + * Sets the capacity of the list to be equal to its size. The list's capacity + * is the number of elements it can hold before it needs to be reallocated. + * The list's size is the number of elements it currently holds. + */ + public void trimToSize() + { + elements.trimToSize(); + } + + /** + * Ensures that the list's capacity is at least equal to + * <code>size</code>. The list's capacity is the number of elements it + * can hold before it needs to be reallocated. + * + * @param size The capacity to ensure the list can hold + */ + public void ensureCapacity(int size) + { + elements.ensureCapacity(size); + } + + /** + * Sets the size of the list to a particular value. If the specified size + * is greater than the current size, the values at the excess list + * indices are set to <code>null</code>. If the specified size is less + * than the current size, the excess elements are removed from the list. + * + * @param size The new size to set the list to + */ + public void setSize(int size) + { + int oldSize = elements.size(); + elements.setSize(size); + if (oldSize < size) + { + fireIntervalAdded(this, oldSize, size - 1); + } + else if (oldSize > size) + { + this.fireIntervalRemoved(this, size, oldSize - 1); + } + } + + /** + * Gets the capacity of the list. The list's capacity is the number of + * elements it can hold before it needs to be reallocated. + * + * @return The capacity of the list + */ + public int capacity() + { + return elements.capacity(); + } + + /** + * Gets the first element in the list. + * + * @return The first element in the list + */ + public Object firstElement() + { + return elements.firstElement(); + } + + /** + * Gets the last element in the list. + * + * @return The last element in the list + */ + public Object lastElement() + { + return elements.lastElement(); + } + + /** + * Sets the list element at a particular index. + * + * @param element The value to set at the specified index + * @param index The list index at which to set a value + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public void setElementAt(Object element, int index) + { + elements.setElementAt(element, index); + fireContentsChanged(this, index, index); + } + + /** + * Removes the element at a particular index from the list. + * + * @param index The index of the element to remove + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public void removeElementAt(int index) + { + elements.remove(index); + fireIntervalRemoved(this, index, index); + } + + /** + * Inserts an element at a particular index in the list. Each element at + * index <code>i >= index</code> is shifted to position <code>i+1</code>. + * If <code>index</code> is equal to <code>size()</code>, this is + * equivalent to appending an element to the array. Any + * <code>index</code> greater than <code>size()</code> is illegal. + * + * @param element The element to insert at the index + * @param index The index to insert the element at + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds <code>[0, size()]</code> + */ + public void insertElementAt(Object element, int index) + { + elements.insertElementAt(element, index); + fireIntervalAdded(this, index, index); + } + + /** + * Removes the first occurrence of a particular element in the list. If the + * element does not exist in the list, nothing happens. + * + * @param element The element to remove + * + * @return <code>true</code> if the element existed in the list (and was + * removed), <code>false</code> otherwise + */ + public boolean removeElement(Object element) + { + int index; + index = elements.indexOf(element); + if (index != -1) + { + elements.remove(index); + fireIntervalRemoved(this, index, index); + return true; + } + return false; + } + + /** + * Remove all elements in the list. + */ + public void removeAllElements() + { + int size; + size = size(); + if (size > 0) + { + elements.clear(); + fireIntervalRemoved(this, 0, size - 1); + } + } + + /** + * Remove all elements between <code>startIndex</code> and + * <code>endIndex</code> inclusive. + * + * @param startIndex The first index in the range to remove + * @param endIndex The last index in the range to remove + * + * @throws ArrayIndexOutOfBoundsException if either index is outside the + * valid range of indices for this list <code>[0, size())</code> + * @throws IllegalArgumentException if <code>startIndex > endIndex</code> + */ + public void removeRange(int startIndex, int endIndex) + { + int index; + if (startIndex > endIndex) + throw new IllegalArgumentException(); + for (index = endIndex; index >= startIndex; index--) + elements.remove(index); + fireIntervalRemoved(this, startIndex, endIndex); + } + + /** + * Gets the size of the list. + * + * @return The number of elements currently in the list + */ + public int getSize() + { + return elements.size(); + } + + /** + * Gets the list element at a particular index. + * + * @param index The index to get the list value at + * + * @return The list value at the provided index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list <code>[0, size())</code> + */ + public Object getElementAt(int index) + { + return elements.get(index); + } +} diff --git a/libjava/classpath/javax/swing/DefaultListSelectionModel.java b/libjava/classpath/javax/swing/DefaultListSelectionModel.java new file mode 100644 index 00000000000..d08ca6fc3d2 --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultListSelectionModel.java @@ -0,0 +1,706 @@ +/* DefaultListSelectionModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.Serializable; +import java.util.BitSet; +import java.util.EventListener; + +import javax.swing.event.EventListenerList; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +/** + * <p>This class provides a default implementation of {@link + * ListSelectioModel}, which is used by {@link javax.swing.JList} and + * similar classes to manage the selection status of a number of data + * elements. </p> + * + * <p>The class is organized <em>abstractly</em> as a set of intervals of + * integers. Each interval indicates an inclusive range of indices in a + * list -- held by some other object and unknown to this class -- which is + * considered "selected". There are various accessors for querying and + * modifying the set of intervals, with simplified forms accepting a single + * index, representing an interval with only one element. </p> + */ +public class DefaultListSelectionModel implements Cloneable, + ListSelectionModel, + Serializable +{ + private static final long serialVersionUID = -5718799865110415860L; + + /** The list of ListSelectionListeners subscribed to this selection model. */ + protected EventListenerList listenerList = new EventListenerList(); + + + /** + * The current list selection mode. Must be one of the numeric constants + * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code> + * or <code>MULTIPLE_INTERVAL_SELECTION</code> from {@link + * ListSelectionModel}. The default value is + * <code>MULTIPLE_INTERVAL_SELECTION</code>. + */ + int selectionMode = MULTIPLE_INTERVAL_SELECTION; + + /** + * The index of the "lead" of the most recent selection. The lead is the + * second argument in any call to {@link #setSelectionInterval}, {@link + * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally + * the lead refers to the most recent position a user dragged their mouse + * over. + */ + int leadSelectionIndex = -1; + + /** + * The index of the "anchor" of the most recent selection. The anchor is + * the first argument in any call to {@link #setSelectionInterval}, + * {@link #addSelectionInterval} or {@link + * #removeSelectionInterval}. Generally the anchor refers to the first + * recent position a user clicks when they begin to drag their mouse over + * a list. + * + * @see #getAnchorSelectionIndex + * @see #setAnchorSelectionIndex + */ + int anchorSelectionIndex = -1; + + /** + * controls the range of indices provided in any {@link + * ListSelectionEvent} fired by the selectionModel. Let + * <code>[A,L]</code> be the range of indices between {@link + * anchorSelectionIndex} and {@link leadSelectionIndex} inclusive, and + * let <code>[i0,i1]</code> be the range of indices changed in a given + * call which generates a {@link ListSelectionEvent}. Then when this + * property is <code>true</code>, the {@link ListSelectionEvent} contains + * the range <code>[A,L] union [i0,i1]</code>; when <code>false</code> it + * will contain only <code>[i0,i1]</code>. The default is + * <code>true</code>. + * + * @see #isLeadAnchorNotificationEnabled + * @see #setLeadAnchorNotificationEnabled + */ + protected boolean leadAnchorNotificationEnabled = true; + + /** + * Whether the selection is currently "adjusting". Any {@link + * ListSelectionEvent} events constructed in response to changes in this + * list selection model will have their {@link + * ListSelectionEvent#isAdjusting} field set to this value. + * + * @see #getValueIsAdjusting + * @see #setValueIsAdjusting + */ + boolean valueIsAdjusting = false; + + + /** + * The current set of "intervals", represented simply by a {@link + * java.util.BitSet}. A set bit indicates a selected index, whereas a + * cleared bit indicates a non-selected index. + */ + BitSet sel = new BitSet(); + + /** + * A variable to store the previous value of sel. + * Used to make sure we only fireValueChanged when the BitSet + * actually does change. + */ + Object oldSel; + + /** + * Whether this call of setLeadSelectionInterval was called locally + * from addSelectionInterval + */ + boolean setLeadCalledFromAdd = false; + + /** + * Gets the value of the {@link #selectionMode} property. + * + * @return The current value of the property + */ + public int getSelectionMode() + { + return selectionMode; + } + + /** + * Sets the value of the {@link #selectionMode} property. + * + * @param a The new value of the property + */ + public void setSelectionMode(int a) + { + selectionMode = a; + } + + /** + * Gets the value of the {@link #anchorSelectionIndex} property. + * + * @return The current property value + * + * @see #setAnchorSelectionIndex + */ + public int getAnchorSelectionIndex() + { + return anchorSelectionIndex; + } + + /** + * Sets the value of the {@link #anchorSelectionIndex} property. + * + * @param anchorIndex The new property value + * + * @see #getAnchorSelectionIndex + */ + public void setAnchorSelectionIndex(int anchorIndex) + { + anchorSelectionIndex = anchorIndex; + } + + /** + * Gets the value of the {@link #leadSelectionIndex} property. + * + * @return The current property value + * + * @see #setLeadSelectionIndex + */ + public int getLeadSelectionIndex() + { + return leadSelectionIndex; + } + + /** + * <p>Sets the value of the {@link #anchorSelectionIndex} property. As a + * side effect, alters the selection status of two ranges of indices. Let + * <code>OL</code> be the old lead selection index, <code>NL</code> be + * the new lead selection index, and <code>A</code> be the anchor + * selection index. Then if <code>A</code> is a valid selection index, + * one of two things happens depending on the seleciton status of + * <code>A</code>:</p> + * + * <ul> + * + * <li><code>isSelectedIndex(A) == true</code>: set <code>[A,OL]</code> + * to <em>deselected</em>, then set <code>[A,NL]</code> to + * <em>selected</em>.</li> + * + * <li><code>isSelectedIndex(A) == false</code>: set <code>[A,OL]</code> + * to <em>selected</em>, then set <code>[A,NL]</code> to + * <em>deselected</em>.</li> + * + * </ul> + * + * <p>This method generates at most a single {@link ListSelectionEvent} + * despite changing multiple ranges. The range of values provided to the + * {@link ListSelectionEvent} includes only the minimum range of values + * which changed selection status between the beginning and end of the + * method.</p> + * + * @param anchorIndex The new property value + * + * @see #getAnchorSelectionIndex + */ + public void setLeadSelectionIndex(int leadIndex) + { + int oldLeadIndex = leadSelectionIndex; + if (setLeadCalledFromAdd == false) + oldSel = sel.clone(); + leadSelectionIndex = leadIndex; + + if (anchorSelectionIndex == -1) + return; + + int R1 = Math.min(anchorSelectionIndex, oldLeadIndex); + int R2 = Math.max(anchorSelectionIndex, oldLeadIndex); + int S1 = Math.min(anchorSelectionIndex, leadIndex); + int S2 = Math.max(anchorSelectionIndex, leadIndex); + + int lo = Math.min(R1, S1); + int hi = Math.max(R2, S2); + + BitSet oldRange = sel.get(lo, hi+1); + + if (isSelectedIndex(anchorSelectionIndex)) + { + sel.clear(R1, R2+1); + sel.set(S1, S2+1); + } + else + { + sel.set(R1, R2+1); + sel.clear(S1, S2+1); + } + + BitSet newRange = sel.get(lo, hi+1); + newRange.xor(oldRange); + + int beg = sel.nextSetBit(0), end = -1; + for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) + end = i; + if (sel.equals(oldSel) == false) + fireValueChanged(beg, end, valueIsAdjusting); + } + + /** + * Gets the value of the {@link #leadAnchorNotificationEnabled} property. + * + * @return The current property value + * + * @see #setLeadAnchorNotificationEnabled + */ + public boolean isLeadAnchorNotificationEnabled() + { + return leadAnchorNotificationEnabled; + } + + /** + * Sets the value of the {@link #leadAnchorNotificationEnabled} property. + * + * @param flag The new property value + * + * @see #getLeadAnchorNotificationEnabled + */ + public void setLeadAnchorNotificationEnabled(boolean l) + { + leadAnchorNotificationEnabled = l; + } + + /** + * Gets the value of the {@link #valueIsAdjusting} property. + * + * @return The current property value + * + * @see #setValueIsAdjusting + */ + public boolean getValueIsAdjusting() + { + return valueIsAdjusting; + } + + /** + * Sets the value of the {@link #valueIsAdjusting} property. + * + * @param v The new property value + * + * @see #getValueIsAdjusting + */ + public void setValueIsAdjusting(boolean v) + { + valueIsAdjusting = v; + } + + /** + * Determines whether the selection is empty. + * + * @return <code>true</code> if the selection is empty, otherwise + * <code>false</code> + */ + public boolean isSelectionEmpty() + { + return sel.isEmpty(); + } + + /** + * Gets the smallest index which is currently a member of a selection + * interval. + * + * @return The least integer <code>i</code> such that <code>i >= + * 0</code> and <code>i</code> is a member of a selected interval, or + * <code>-1</code> if there are no selected intervals + * + * @see #getMaxSelectionIndex + */ + public int getMinSelectionIndex() + { + if (isSelectionEmpty()) + return -1; + + return sel.nextSetBit(0); + } + + /** + * Gets the largest index which is currently a member of a selection + * interval. + * + * @return The greatest integer <code>i</code> such that <code>i >= + * 0</code> and <code>i</code> is a member of a selected interval, or + * <code>-1</code> if there are no selected intervals + * + * @see #getMinSelectionIndex + */ + public int getMaxSelectionIndex() + { + if (isSelectionEmpty()) + return -1; + + int mx = -1; + for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1)) + { + mx = i; + } + return mx; + } + + /** + * Determines whether a particular index is a member of a selection + * interval. + * + * @param a The index to search for + * + * @return <code>true</code> if the index is a member of a selection interval, + * otherwise <code>false</code> + */ + public boolean isSelectedIndex(int a) + { + return sel.get(a); + } + + /** + * If the {@link #selectionMode} property is equal to + * <code>SINGLE_SELECTION</code> equivalent to calling + * <code>setSelectionInterval(index1, index2)</code>; + * If the {@link #selectionMode} property is equal to + * <code>SINGLE_INTERVAL_SELECTION</code> and the interval being + * added is not adjacent to an already selected interval, + * equivalent to <code>setSelectionInterval(index1, index2)</code>. + * Otherwise adds the range <code>[index0, index1]</code> + * to the selection interval set. + * + * @param index0 The beginning of the range of indices to select + * @param index1 The end of the range of indices to select + * + * @see #setSelectionInterval + * @see #removeSelectionInterval + */ + public void addSelectionInterval(int index0, int index1) + { + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + oldSel = sel.clone(); + + if (selectionMode == SINGLE_SELECTION) + sel.clear(); + + // COMPAT: Like Sun (but not like IBM), we allow calls to + // addSelectionInterval when selectionMode is + // SINGLE_SELECTION_INTERVAL iff the interval being added + // is adjacent to an already selected interval + if (selectionMode == SINGLE_INTERVAL_SELECTION) + if (!(isSelectedIndex(index0) || + isSelectedIndex(index1) || + isSelectedIndex(Math.max(lo-1,0)) || + isSelectedIndex(Math.min(hi+1,sel.size())))) + sel.clear(); + + if (selectionMode == SINGLE_SELECTION) + index0 = index1; + + // We have to update the anchorSelectionIndex and leadSelectionIndex + // variables + + // The next if statements breaks down to "if this selection is adjacent + // to the previous selection and going in the same direction" + if ((isSelectedIndex(leadSelectionIndex)) + && ((index0 - 1 == leadSelectionIndex + && (index1 >= index0) + && (leadSelectionIndex >= anchorSelectionIndex)) + || (index0 + 1 == leadSelectionIndex && (index1 <= index0) + && (leadSelectionIndex <= anchorSelectionIndex))) + && (anchorSelectionIndex != -1 || leadSelectionIndex != -1)) + { + // setting setLeadCalledFromAdd to true tells setLeadSelectionIndex + // not to update oldSel + setLeadCalledFromAdd = true; + setLeadSelectionIndex(index1); + setLeadCalledFromAdd = false; + } + else + { + leadSelectionIndex = index1; + anchorSelectionIndex = index0; + sel.set(lo, hi+1); + if (sel.equals(oldSel) == false) + fireValueChanged(lo, hi, valueIsAdjusting); + } + } + + + /** + * Deselects all indices in the inclusive range + * <code>[index0,index1]</code>. + * + * @param index0 The beginning of the range of indices to deselect + * @param index1 The end of the range of indices to deselect + * + * @see #addSelectionInterval + * @see #setSelectionInterval + */ + public void removeSelectionInterval(int index0, + int index1) + { + oldSel = sel.clone(); + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + + // if selectionMode is SINGLE_INTERVAL_SELECTION and removing the interval + // (index0,index1) would leave two disjoint selection intervals, remove all + // selected indices from lo to the last selected index + if (getMinSelectionIndex() > 0 && getMinSelectionIndex() < lo && + selectionMode == SINGLE_INTERVAL_SELECTION) + hi = sel.size() - 1; + + sel.clear(lo, hi+1); + //update anchorSelectionIndex and leadSelectionIndex variables + //TODO: will probably need MouseDragged to test properly and know if this works + setAnchorSelectionIndex(index0); + leadSelectionIndex = index1; + if (sel.equals(oldSel) == false) + fireValueChanged(lo, hi, valueIsAdjusting); + } + + /** + * Removes all intervals in the selection set. + */ + public void clearSelection() + { + oldSel = sel.clone(); + int sz = sel.size(); + sel.clear(); + if (sel.equals(oldSel) == false) + fireValueChanged(0, sz, valueIsAdjusting); + } + + /** + * Clears the current selection and marks a given interval as + * "selected". If the current selection mode is + * <code>SINGLE_SELECTION</code> only the index <code>index2</code> is + * selected. + * + * @param index0 The low end of the new selection + * @param index1 The high end of the new selection + */ + public void setSelectionInterval(int index0, int index1) + { + oldSel = sel.clone(); + sel.clear(); + if (selectionMode == SINGLE_SELECTION) + index0 = index1; + + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + sel.set(lo, hi+1); + // update the anchorSelectionIndex and leadSelectionIndex variables + setAnchorSelectionIndex(index0); + leadSelectionIndex=index1; + if (sel.equals(oldSel) == false) + fireValueChanged(lo, hi, valueIsAdjusting); + } + + /** + * Inserts a number of indices either before or after a particular + * position in the set of indices. Renumbers all indices after the + * inserted range. The new indices in the inserted range are not + * selected. This method is typically called to synchronize the selection + * model with an inserted range of elements in a {@link ListModel}. + * + * @param index The position to insert indices at + * @param length The number of indices to insert + * @param before Indicates whether to insert the indices before the index + * or after it + */ + public void insertIndexInterval(int index, + int length, + boolean before) + { + if (!before) + { + index++; + length--; + } + BitSet tmp = sel.get(index, sel.size()); + sel.clear(index, sel.size()); + int n = tmp.size(); + for (int i = 0; i < n; ++i) + sel.set(index + length + i, tmp.get(i)); + } + + /** + * Removes a range from the set of indices. Renumbers all indices after + * the removed range. This method is typically called to synchronize the + * selection model with a deleted range of elements in a {@link + * ListModel}. + * + * @param index0 The first index to remove (inclusive) + * @param index1 The last index to remove (inclusive) + */ + public void removeIndexInterval(int index0, + int index1) + { + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + + BitSet tmp = sel.get(hi, sel.size()); + sel.clear(lo, sel.size()); + int n = tmp.size(); + for (int i = 0; i < n; ++i) + sel.set(lo + i, tmp.get(i)); + } + + /** + * Fires a {@link ListSelectionEvent} to all the listeners of type {@link + * ListSelectionListener} registered with this selection model to + * indicate that a series of adjustment has just ended. + * + * The values of {@link #getMinSelectionIndex} and + * {@link getMaxSelectionIndex} are used in the {@link ListSelectionEvent} + * that gets fired. + * + * @param isAdjusting <code>true</code> if this is the final change + * in a series of adjustments, <code>false/code> otherwise + */ + protected void fireValueChanged(boolean isAdjusting) + { + fireValueChanged(getMinSelectionIndex(), getMaxSelectionIndex(), + isAdjusting); + } + + /** + * Fires a {@link ListSelectionEvent} to all the listeners of type {@link + * ListSelectionListener} registered with this selection model. + * + * @param firstIndex The low index of the changed range + * @param lastIndex The high index of the changed range + */ + protected void fireValueChanged(int firstIndex, int lastIndex) + { + fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting()); + } + + /** + * Fires a {@link ListSelectionEvent} to all the listeners of type {@link + * ListSelectionListener} registered with this selection model. + * + * @param firstIndex The low index of the changed range + * @param lastIndex The high index of the changed range + * @param isAdjusting Whether this change is part of a seqence of adjustments + * made to the selection, such as during interactive scrolling + */ + protected void fireValueChanged(int firstIndex, int lastIndex, + boolean isAdjusting) + { + ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, + lastIndex, isAdjusting); + ListSelectionListener[] listeners = getListSelectionListeners(); + for (int i = 0; i < listeners.length; ++i) + listeners[i].valueChanged(evt); + } + + /** + * Adds a listener. + * + * @param listener The listener to add + * + * @see removeListSelectionListener + * @see getListSelectionListeners + */ + public void addListSelectionListener(ListSelectionListener listener) + { + listenerList.add(ListSelectionListener.class, listener); + } + + /** + * Removes a registered listener. + * + * @param listener The listener to remove + * + * @see addListSelectionListener + * @see getListSelectionListeners + */ + public void removeListSelectionListener(ListSelectionListener listener) + { + listenerList.remove(ListSelectionListener.class, listener); + } + + /** + * Returns an array of all registerers listeners. + * + * @param listenerType The type of listener to retrieve + * + * @return The array + * + * @see getListSelectionListener + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Returns an array of all registerd list selection listeners. + * + * @return the array + * + * @see addListSelectionListener + * @see removeListSelectionListener + * @see getListeners + * @since 1.4 + */ + public ListSelectionListener[] getListSelectionListeners() + { + return (ListSelectionListener[]) getListeners(ListSelectionListener.class); + } + + /** + * Returns a clone of this object. + * <code>listenerList</code> don't gets duplicated. + * + * @return the cloned object + * + * @throws CloneNotSupportedException if an error occurs + */ + public Object clone() + throws CloneNotSupportedException + { + DefaultListSelectionModel model = + (DefaultListSelectionModel) super.clone(); + model.sel = (BitSet) sel.clone(); + return model; + } +} diff --git a/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java b/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java new file mode 100644 index 00000000000..039883e23ae --- /dev/null +++ b/libjava/classpath/javax/swing/DefaultSingleSelectionModel.java @@ -0,0 +1,172 @@ +/* DefaultSingleSelectionModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +/** + * DefaultSingleSelectionModel + * + * @author Andrew Selkirk + */ +public class DefaultSingleSelectionModel + implements SingleSelectionModel, Serializable +{ + private static final long serialVersionUID = 3676229404753786004L; + + /** + * changeEvent + */ + protected transient ChangeEvent changeEvent = new ChangeEvent(this); + + /** + * listenerList + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * index + */ + private int index = -1; + + /** + * Constructor DefaultSingleSelectionModel + */ + public DefaultSingleSelectionModel() + { + // Do nothing. + } + + /** + * getSelectedIndex + * @return int + */ + public int getSelectedIndex() + { + return index; + } + + /** + * setSelectedIndex + * @param index TODO + */ + public void setSelectedIndex(int index) + { + this.index = index; + fireStateChanged(); + } + + /** + * clearSelection + */ + public void clearSelection() + { + index = -1; + fireStateChanged(); + } + + /** + * isSelected + * @return boolean + */ + public boolean isSelected() + { + return index != -1; + } + + /** + * addChangeListener + * + * @param listener the listener to add + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * removeChangeListener + * + * @param listener the listener to remove + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * fireStateChanged + */ + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners[i].stateChanged(changeEvent); + } + + /** + * getListeners + * + * @param listenerClass the type fo listener + * + * @return an array of listeners + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerClass) + { + return listenerList.getListeners(listenerClass); + } + + /** + * getChangeListeners + * + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) getListeners(ChangeListener.class); + } +} diff --git a/libjava/classpath/javax/swing/DesktopManager.java b/libjava/classpath/javax/swing/DesktopManager.java new file mode 100644 index 00000000000..300d66517ba --- /dev/null +++ b/libjava/classpath/javax/swing/DesktopManager.java @@ -0,0 +1,177 @@ +/* DesktopManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +/** + * DesktopManagers are responsible for implementing the behaviours for the + * JInternalFrames that belong to JDesktopPanes. Actions such as maximizing, + * minimizing, iconifying, etc will be delegated to the DesktopManager. + */ +public interface DesktopManager +{ + /** + * This method will cause the JInternalFrame to be displayed in the set + * location. This usually is not needed since the user will add the + * JInternalFrame to a Container separately. + * + * @param frame The JInternalFrame to open. + */ + void openFrame(JInternalFrame frame); + + /** + * This method should remove the JInternalFrame from its parent. + * + * @param frame The JInternalFrame to close. + */ + void closeFrame(JInternalFrame frame); + + /** + * This method should maximize the JInternalFrame to match its parent's + * bounds. + * + * @param frame The JInternalFrame to maximize. + */ + void maximizeFrame(JInternalFrame frame); + + /** + * This method should restore the JInternalFrame to its normal bounds. + * + * @param frame The JInternalFrame to minimize. + */ + void minimizeFrame(JInternalFrame frame); + + /** + * This method should remove the JInternalFrame from its parent and replace + * it with a JDesktopIcon. + * + * @param frame The JInternalFrame to iconify. + */ + void iconifyFrame(JInternalFrame frame); + + /** + * This method should remove the JDesktopIcon from its parent and replace it + * with the JInternalFrame that the JDesktopIcon represents. + * + * @param frame The JInternalFrame to deiconify. + */ + void deiconifyFrame(JInternalFrame frame); + + /** + * This method should give focus to the JInternalFrame and its default focus + * owner. + * + * @param frame The JInternalFrame to activate. + */ + void activateFrame(JInternalFrame vframe); + + /** + * This method should be called when the JInternalFrame gets deselected and + * subsequently loses focus. + * + * @param frame The JInternalFrame to deactivate. + */ + void deactivateFrame(JInternalFrame frame); + + /** + * This method should be called in preparation for dragging. This needs to + * be called prior to dragFrame calls so that the DesktopManager can + * prepare any state information. + * + * @param frame The JInternalFrame to prepare for dragging. + */ + void beginDraggingFrame(JComponent frame); + + /** + * This method drags the given JInternalFrame to the given x and y + * coordinates. + * + * @param frame The JInternalFrame to drag. + * @param x The new x coordinate. + * @param y The new y coordinate. + */ + void dragFrame(JComponent frame, int x, int y); + + /** + * This method should be called after dragFrame calls. Any information used + * by the DesktopManager for dragging the JInternalFrame can be cleared. + * + * @param frame The JInternalFrame that finished dragging. + */ + void endDraggingFrame(JComponent frame); + + /** + * This method should be called prior to any resizeFrame calls. Any state + * information needed by the DesktopManager to resize the JInternalFrame + * will be prepared here. + * + * @param frame The JInternalFrame to resize. + * @param direction One of eight directions specified by SwingConstants. + */ + void beginResizingFrame(JComponent frame, int direction); + + /** + * This method is called to resize the given JInternalFrame to the given + * bounds. + * + * @param frame The JInternalFrame to resize. + * @param x The new x coordinate. + * @param y The new y coordinate. + * @param width The new width. + * @param height The new height. + */ + void resizeFrame(JComponent frame, int x, int y, int width, int height); + + /** + * This method is called to signify that the resize is finished. Any + * information used to resize the JInternalFrame can now be cleared. + * + * @param frame The JInternalFrame that just finished dragging. + */ + void endResizingFrame(JComponent frame); + + /** + * This method does the actual work for reshaping the JInternalFrame. + * + * @param frame The JInternalFrame to resize. + * @param x The new x coordinate. + * @param y The new y coordinate. + * @param width The new width. + * @param height The new height. + */ + void setBoundsForFrame(JComponent frame, int x, int y, int width, int height); +} // DesktopManager diff --git a/libjava/classpath/javax/swing/FocusManager.java b/libjava/classpath/javax/swing/FocusManager.java new file mode 100644 index 00000000000..9f898e69252 --- /dev/null +++ b/libjava/classpath/javax/swing/FocusManager.java @@ -0,0 +1,161 @@ +/* FocusManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.DefaultKeyboardFocusManager; +import java.awt.KeyboardFocusManager; +import java.awt.event.KeyEvent; + +/** + * FocusManager + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class FocusManager + extends DefaultKeyboardFocusManager +{ + /** + * DisabledFocusManager + */ + static class DisabledFocusManager + extends FocusManager + { + + /** + * Constructor DisabledFocusManager + */ + DisabledFocusManager() + { + // TODO + } + + /** + * processKeyEvent + * @param component TODO + * @param event TODO + */ + public void processKeyEvent(Component component, KeyEvent event) + { + // TODO + } + + /** + * focusNextComponent + * @param component TODO + */ + public void focusNextComponent(Component component) + { + // TODO + } + + /** + * focusPreviousComponent + * @param value0 TODO + */ + public void focusPreviousComponent(Component value0) + { + // TODO + } + } + + /** + * FOCUS_MANAGER_CLASS_PROPERTY + */ + public static final String FOCUS_MANAGER_CLASS_PROPERTY = + "FocusManagerClassName"; + + /** + * Constructor FocusManager + */ + public FocusManager() + { + super(); + } + + /** + * getCurrentManager + * @returns FocusManager + */ + public static FocusManager getCurrentManager() + { + KeyboardFocusManager fm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + if (fm instanceof FocusManager) + return (FocusManager) fm; + else + { + System.err.println("The Swing FocusManager API has been obsoleted by"); + System.err.println("the new KeyboardFocusManager system."); + System.err.println("You should either not use the Swing FocusManager"); + System.err.println("API or set the system property"); + System.err.println + ("gnu.java.awt.FocusManager=javax.swing.FocusManager"); + } + return null; + } + + /** + * setCurrentManager + * @param manager TODO + */ + public static void setCurrentManager(FocusManager manager) + { + KeyboardFocusManager.setCurrentKeyboardFocusManager(manager); + } + + /** + * disableSwingFocusManager + * @deprecated 1.4 + */ + public static void disableSwingFocusManager() + { + // TODO + } + + /** + * isFocusManagerEnabled + * @return boolean + * @deprecated 1.4 + */ + public static boolean isFocusManagerEnabled() + { + return false; // TODO + } +} diff --git a/libjava/classpath/javax/swing/GrayFilter.java b/libjava/classpath/javax/swing/GrayFilter.java new file mode 100644 index 00000000000..1a88f6f19a8 --- /dev/null +++ b/libjava/classpath/javax/swing/GrayFilter.java @@ -0,0 +1,92 @@ +/* GrayFilter.java -- Java class for filtering Pixels to produce Gray Pictures + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.FilteredImageSource; +import java.awt.image.RGBImageFilter; + +public class GrayFilter extends RGBImageFilter +{ + private boolean b; + private double p; + + /** + * Create a GrayFilter. If b is true then brighten. Also, indicate how much + * gray. + * + * @param b if brighten + * @param p percent of gray, 0 - 100 + */ + public GrayFilter(boolean b, int p) + { + this.b = b; //FIXME - HANDLE THIS + this.p = (1. - (p / 100.)) / 3.; + } + + /** + * Create grayed image + * + * @param src image to gray + * + * @return a grayed image + */ + public static Image createDisabledImage(Image src) + { + return (Toolkit.getDefaultToolkit(). + createImage(new FilteredImageSource(src.getSource(), + new GrayFilter(true, 0)))); + } + + /** + * Filter RGB to gray + */ + public int filterRGB(int x, int y, int rgb) + { + int alpha = 0xff000000 & rgb; + int red = (0xff0000 & rgb) >> 16; + int green = (0xff00 & rgb) >> 8; + int blue = (0xff & rgb); + int gray = (int) ((0.299 * red + 0.587 * green + 0.114 * blue) * p); + if (b) + gray = Math.min(gray + 128, 255); + return gray | gray << 8 | gray << 16 | alpha ; + } +} diff --git a/libjava/classpath/javax/swing/Icon.java b/libjava/classpath/javax/swing/Icon.java new file mode 100644 index 00000000000..c00eee46238 --- /dev/null +++ b/libjava/classpath/javax/swing/Icon.java @@ -0,0 +1,52 @@ +/* Icon.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Graphics; + +/** + * Defines the methods that an object must implement if it should be used + * as an icon in Swing. + */ +public interface Icon +{ + int getIconHeight(); + int getIconWidth(); + void paintIcon(Component c, Graphics g, int x, int y); +} diff --git a/libjava/classpath/javax/swing/ImageIcon.java b/libjava/classpath/javax/swing/ImageIcon.java new file mode 100644 index 00000000000..36f23d2b225 --- /dev/null +++ b/libjava/classpath/javax/swing/ImageIcon.java @@ -0,0 +1,361 @@ +/* ImageIcon.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.awt.image.ImageObserver; +import java.io.Serializable; +import java.net.URL; +import java.util.Locale; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleIcon; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; + +public class ImageIcon + implements Icon, Serializable, Accessible +{ + /** + * Accessibility support for ImageIcon. + */ + protected class AccessibleImageIcon + extends AccessibleContext + implements AccessibleIcon, Serializable + { + private static final long serialVersionUID = 2113430526551336564L; + + /** + * Creates a new instance of AccessibleImageIcon. + */ + protected AccessibleImageIcon() + { + } + + /** + * Returns the AccessibleRole of ImageIcon, which is + * {@link AccessibleRole#ICON}. + * + * @return {@link AccessibleRole#ICON} + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.ICON; + } + + /** + * Returns the accessible state of this ImageIcon. + * + * @return the accessible state of this ImageIcon + */ + public AccessibleStateSet getAccessibleStateSet() + { + // TODO: which state information from ImageIcon is returned here?? + return new AccessibleStateSet(); + } + + /** + * Returns the accessible parent of this object, which is <code>null</code> + * in this case, because ImageIcons have no parent. + * + * @return <code>null</code>, because ImageIcons have no parent + */ + public Accessible getAccessibleParent() + { + // TODO: ImageIcons have no parent, have they ?? + return null; + } + + /** + * Returns the index of this object in its accessible parent, which is + * -1 here, because ImageIcons have no accessible parent. + * + * @return -1 because ImageIcons have no parent + */ + public int getAccessibleIndexInParent() + { + // TODO: do ImageIcons have parents?? + return -1; + } + + /** + * Returns the number of accessible children of this component, + * which is 0, because ImageIcons have no children. + * + * @return 0 because ImageIcons have no children + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * Returns the accessible child at index <code>i</code>, which is + * <code>null</code> in this case because ImageIcons have no children. + * + * @param i the index of the child to be fetched + * + * @return <code>null</code> because ImageIcons have no children + */ + public Accessible getAccessibleChild(int i) + { + return null; + } + + /** + * Returns the locale of this object. This returns the default locale + * that is set for the current VM. + * + * @return the locale of this object + */ + public Locale getLocale() + { + return Locale.getDefault(); + } + + /** + * Returns the accessible Icon description. This returns the + * actual 'description' property of the ImageIcon. + * + * @return the accessible Icon description + */ + public String getAccessibleIconDescription() + { + return getDescription(); + } + + /** + * Sets the accessible Icon description. This sets the + * actual 'description' property of the ImageIcon. + * + * @param newDescr the description to be set + */ + public void setAccessibleIconDescription(String newDescr) + { + setDescription(newDescr); + } + + /** + * Returns the icon height. This returns the iconHeight property of + * the underlying Icon. + * + * @return the icon height + */ + public int getAccessibleIconHeight() + { + return getIconHeight(); + } + + /** + * Returns the icon width. This returns the iconWidth property of + * the underlying Icon. + * + * @return the icon width + */ + public int getAccessibleIconWidth() + { + return getIconWidth(); + } + } // AccessibleIcon + + private static final long serialVersionUID = 532615968316031794L; + + /** A dummy Component that is used in the MediaTracker. */ + protected static Component component = new Component(){}; + + /** The MediaTracker used to monitor the loading of images. */ + protected static MediaTracker tracker = new MediaTracker(component); + + /** The ID that is used in the tracker. */ + private static int id; + + Image image; + String description; + ImageObserver observer; + + /** The image loading status. */ + private int loadStatus; + + /** The AccessibleContext of this ImageIcon. */ + private AccessibleContext accessibleContext; + + public ImageIcon() + { + } + + public ImageIcon(String file) + { + this(file, file); + } + + public ImageIcon(String file, String description) + { + this(Toolkit.getDefaultToolkit().getImage(file), description); + } + + public ImageIcon(byte[] imageData) + { + this(imageData, null); + } + + public ImageIcon(byte[] imageData, String description) + { + this(Toolkit.getDefaultToolkit().createImage(imageData), description); + } + + public ImageIcon(URL url) + { + this(url, null); + } + + public ImageIcon(URL url, String description) + { + this(Toolkit.getDefaultToolkit().getImage(url), description); + } + + public ImageIcon(Image image) + { + this(image, null); + } + + public ImageIcon(Image image, String description) + { + setImage(image); + setDescription(description); + } + + public ImageObserver getImageObserver() + { + return observer; + } + + public void setImageObserver(ImageObserver newObserver) + { + observer = newObserver; + } + + public Image getImage() + { + return image; + } + + public void setImage(Image image) + { + loadImage(image); + this.image = image; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public int getIconHeight() + { + return image.getHeight(observer); + } + + public int getIconWidth() + { + return image.getWidth(observer); + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.drawImage(image, x, y, observer != null ? observer : c); + } + + /** + * Loads the image and blocks until the loading operation is finished. + * + * @param image the image to be loaded + */ + protected void loadImage(Image image) + { + try + { + tracker.addImage(image, id); + id++; + tracker.waitForID(id - 1); + } + catch (InterruptedException ex) + { + ; // ignore this for now + } + finally + { + loadStatus = tracker.statusID(id - 1, false); + } + } + + /** + * Returns the load status of the icon image. + * + * @return the load status of the icon image + * + * @see {@link MediaTracker.COMPLETE} + * @see {@link MediaTracker.ABORTED} + * @see {@link MediaTracker.ERRORED} + */ + public int getImageLoadStatus() + { + return loadStatus; + } + + /** + * Returns the AccessibleContext for this ImageIcon. + * + * @return the AccessibleContext for this ImageIcon + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleImageIcon(); + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/InputMap.java b/libjava/classpath/javax/swing/InputMap.java new file mode 100644 index 00000000000..afc431d4836 --- /dev/null +++ b/libjava/classpath/javax/swing/InputMap.java @@ -0,0 +1,213 @@ +/* InputMap.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + + +/** + * @author Andrew Selkirk + * @author Michael Koch + * + * @since 1.3 + */ +public class InputMap + implements Serializable +{ + private static final long serialVersionUID = -5429059542008604257L; + + /** + * inputMap + */ + private Map inputMap = new HashMap(); + + /** + * parent + */ + private InputMap parent; + + /** + * Creates a new <code>InputMap</code> instance. + */ + public InputMap() + { + // TODO + } + + /** + * Returns the binding for keystroke. + * + * @param key the key of the enty + * + * @return the binding associated with keystroke may be null + */ + public Object get(KeyStroke keystroke) + { + Object result = inputMap.get(keystroke); + + if (result == null && parent != null) + result = parent.get(keystroke); + return result; + } + + /** + * Puts a new entry into the <code>InputMap</code>. + * If actionMapKey is null an existing entry will be removed. + * + * @param keystroke the keystroke for the entry + * @param actionMapKey the action. + */ + public void put(KeyStroke keystroke, Object actionMapKey) + { + if (actionMapKey == null) + inputMap.remove(keystroke); + else + inputMap.put(keystroke, actionMapKey); + } + + /** + * Remove an entry from the <code>InputMap</code>. + * + * @param key the key of the entry to remove + */ + public void remove(KeyStroke keystroke) + { + inputMap.remove(keystroke); + } + + /** + * Returns the parent of this <code>InputMap</code>. + * + * @return the parent, may be null. + */ + public InputMap getParent() + { + return parent; + } + + /** + * Sets a parent for this <code>InputMap</code>. + * + * @param parentMap the new parent + */ + public void setParent(InputMap parentMap) + { + parent = parentMap; + } + + /** + * Returns the number of entries in this <code>InputMap</code>. + * + * @return the number of entries + */ + public int size() + { + return inputMap.size(); + } + + /** + * Clears the <code>InputMap</code>. + */ + public void clear() + { + inputMap.clear(); + } + + /** + * Returns all keys of entries in this <code>InputMap</code>. + * + * @return an array of keys + */ + public KeyStroke[] keys() + { + KeyStroke[] array = new KeyStroke[size()]; + return (KeyStroke[]) inputMap.keySet().toArray(array); + } + + /** + * Returns all keys of entries in this <code>InputMap</code> + * and all its parents. + * + * @return an array of keys + */ + public KeyStroke[] allKeys() + { + Set set = new HashSet(); + + if (parent != null) + set.addAll(Arrays.asList(parent.allKeys())); + + set.addAll(inputMap.keySet()); + KeyStroke[] array = new KeyStroke[size()]; + return (KeyStroke[]) set.toArray(array); + } + + /** + * writeObject + * + * @param stream the stream to write to + * + * @exception IOException If an error occurs + */ + private void writeObject(ObjectOutputStream stream) throws IOException + { + // TODO + } + + /** + * readObject + * + * @param stream the stream to read from + * + * @exception ClassNotFoundException If the serialized class cannot be found + * @exception IOException If an error occurs + */ + private void readObject(ObjectInputStream stream) + throws ClassNotFoundException, IOException + { + // TODO + } +} diff --git a/libjava/classpath/javax/swing/InputVerifier.java b/libjava/classpath/javax/swing/InputVerifier.java new file mode 100644 index 00000000000..836c1a558ad --- /dev/null +++ b/libjava/classpath/javax/swing/InputVerifier.java @@ -0,0 +1,75 @@ +/* InputVerifier.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + + +/** + * InputVerifier + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class InputVerifier +{ + /** + * Creates a <code>InputVerifier</code> + */ + public InputVerifier() + { + } + + /** + * verify + * + * @param component the component to verify + * + * @return <code>true</code> if valid, <code>false</code> otherwise. + */ + public abstract boolean verify(JComponent component); + + /** + * shouldYieldFocus + * + * @param component the component to verify + * + * @return <code>true</code> if valid, <code>false</code> otherwise. + */ + public boolean shouldYieldFocus(JComponent component) + { + return verify(component); + } +} diff --git a/libjava/classpath/javax/swing/InternalFrameFocusTraversalPolicy.java b/libjava/classpath/javax/swing/InternalFrameFocusTraversalPolicy.java new file mode 100644 index 00000000000..0609f09f8f2 --- /dev/null +++ b/libjava/classpath/javax/swing/InternalFrameFocusTraversalPolicy.java @@ -0,0 +1,55 @@ +/* InternalFrameFocusTraversalPolicy.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.FocusTraversalPolicy; + +/** + * @author Michael Koch + * + * @since 1.4 + */ +public abstract class InternalFrameFocusTraversalPolicy extends FocusTraversalPolicy +{ + public Component getInitialComponent(JInternalFrame frame) + { + return getDefaultComponent(frame); + } +} diff --git a/libjava/classpath/javax/swing/JApplet.java b/libjava/classpath/javax/swing/JApplet.java new file mode 100644 index 00000000000..95a05c0329f --- /dev/null +++ b/libjava/classpath/javax/swing/JApplet.java @@ -0,0 +1,213 @@ +/* JApplet.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.LayoutManager; +import java.awt.event.KeyEvent; + +import javax.accessibility.AccessibleContext; + +public class JApplet extends Applet + implements RootPaneContainer +{ + private static final long serialVersionUID = 7269359214497372587L; + + protected JRootPane rootPane; + + /** + * @specnote rootPaneCheckingEnabled is false to comply with J2SE 5.0 + */ + protected boolean rootPaneCheckingEnabled=false; + + /** + * Tells us if we're in the initialization stage. + * If so, adds go to top-level Container, otherwise they go + * to the content pane for this container + */ + private boolean initStageDone = false; + + public JApplet() + { + super.setLayout(new BorderLayout(1, 1)); + getRootPane(); // Will do set/create. + initStageDone = true; // Init stage is now over. + } + + public Dimension getPreferredSize() + { + return super.getPreferredSize(); + } + + public void setLayout(LayoutManager manager) + { + // Check if we're in initialization stage. If so, call super.setLayout + // otherwise, valid calls go to the content pane + if (initStageDone) + { + if (isRootPaneCheckingEnabled()) + throw new Error("Cannot set layout. Use getContentPane().setLayout()" + + "instead."); + getContentPane().setLayout(manager); + } + else + super.setLayout(manager); + } + + public void setLayeredPane(JLayeredPane layeredPane) + { + getRootPane().setLayeredPane(layeredPane); + } + + public JLayeredPane getLayeredPane() + { + return getRootPane().getLayeredPane(); + } + + public JRootPane getRootPane() + { + if (rootPane == null) + setRootPane(createRootPane()); + return rootPane; + } + + protected void setRootPane(JRootPane root) + { + if (rootPane != null) + remove(rootPane); + + rootPane = root; + add(rootPane, BorderLayout.CENTER); + } + + protected JRootPane createRootPane() + { + return new JRootPane(); + } + + public Container getContentPane() + { + return getRootPane().getContentPane(); + } + + public void setContentPane(Container contentPane) + { + getRootPane().setContentPane(contentPane); + } + + public Component getGlassPane() + { + return getRootPane().getGlassPane(); + } + + public void setGlassPane(Component glassPane) + { + getRootPane().setGlassPane(glassPane); + } + + protected void addImpl(Component comp, Object constraints, int index) + { + // If we're adding in the initialization stage use super.add. + // Otherwise pass the add onto the content pane. + if (!initStageDone) + super.addImpl(comp, constraints, index); + else + { + if (isRootPaneCheckingEnabled()) + throw new Error("Do not use add() on JApplet directly. Use " + + "getContentPane().add() instead"); + getContentPane().add(comp, constraints, index); + } + } + + public AccessibleContext getAccessibleContext() + { + return null; + } + + public JMenuBar getJMenuBar() + { + return getRootPane().getJMenuBar(); + } + + public void setJMenuBar(JMenuBar menubar) + { + getRootPane().setJMenuBar(menubar); + } + + protected String paramString() + { + return "JFrame"; + } + + protected void processKeyEvent(KeyEvent e) + { + super.processKeyEvent(e); + } + + public void remove(Component comp) + { + // If we're removing the root pane, use super.remove. Otherwise + // pass it on to the content pane instead + if (comp == rootPane) + super.remove(rootPane); + else + getContentPane().remove(comp); + } + + protected boolean isRootPaneCheckingEnabled() + { + return rootPaneCheckingEnabled; + } + + protected void setRootPaneCheckingEnabled(boolean enabled) + { + rootPaneCheckingEnabled = enabled; + } + + public void update(Graphics g) + { + paint(g); + } +} diff --git a/libjava/classpath/javax/swing/JButton.java b/libjava/classpath/javax/swing/JButton.java new file mode 100644 index 00000000000..0234e47afb6 --- /dev/null +++ b/libjava/classpath/javax/swing/JButton.java @@ -0,0 +1,155 @@ +/* JButton.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.plaf.ButtonUI; + + +/** + * An instance of JButton can be added to a panel, frame etc + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class JButton extends AbstractButton + implements Accessible +{ + private static final long serialVersionUID = -1907255238954382202L; + boolean def; + boolean is_def; + + public JButton() + { + this(null, null); + } + + public JButton(Action a) + { + this(); + setAction(a); + } + + public JButton(Icon icon) + { + this(null, icon); + } + + public JButton(String text) + { + this(text, null); + } + + public JButton(String text, Icon icon) + { + super(); + init(text, icon); + setModel(new DefaultButtonModel()); + } + + public Object[] getSelectedObjects() + { + return null; + } + + protected void configurePropertiesFromAction(Action a) + { + // Factory method which sets the AbstractButton's properties according to + // values from the Action instance. + super.configurePropertiesFromAction(a); + } + + public AccessibleContext getAccessibleContext() + { + // Gets the AccessibleContext associated with this JButton. + return null; + } + + public String getUIClassID() + { + // Returns a string that specifies the name of the L&F class that renders + // this component. + return "ButtonUI"; + } + + public boolean isDefaultButton() + { + // Returns whether or not this button is the default button on the + // RootPane. + return is_def; + } + + public boolean isDefaultCapable() + { + // Returns whether or not this button is capable of being the default + // button on the RootPane. + return def; + } + + protected String paramString() + { + String superParam = super.paramString(); + + // 41 is the maximum number of chars which may be needed. + StringBuffer sb = new StringBuffer(41); + sb.append(",defaultButton=").append(is_def); + sb.append(",defaultCapable=").append(def); + + return superParam + sb.toString(); + } + + /** + * Overrides JComponent.removeNotify to check if this button is currently + * set as the default button on the RootPane, and if so, sets the RootPane's + * default button to null to ensure the RootPane doesn't hold onto an invalid + * button reference. + */ + public void removeNotify() + { + } + + public void setDefaultCapable(boolean defaultCapable) + { + def = defaultCapable; + } + + public void updateUI() + { + setUI((ButtonUI) UIManager.getUI(this)); + } +} diff --git a/libjava/classpath/javax/swing/JCheckBox.java b/libjava/classpath/javax/swing/JCheckBox.java new file mode 100644 index 00000000000..5e7e80c94b9 --- /dev/null +++ b/libjava/classpath/javax/swing/JCheckBox.java @@ -0,0 +1,143 @@ +/* JCheckBox.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import javax.accessibility.AccessibleContext; + +/** + * An instance of JCheckbox can be added to a panel, frame etc + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class JCheckBox extends JToggleButton +{ + private static final long serialVersionUID = -5246739313864538930L; + + public static final String BORDER_PAINTED_FLAT_CHANGED_PROPERTY = + "borderPaintedFlat"; + + private boolean borderPaintedFlat; + + private void init() + { + borderPainted = false; + contentAreaFilled = false; + } + + public JCheckBox() + { + super(); + init(); + } + + public JCheckBox(Action action) + { + super(action); + init(); + } + + public JCheckBox(Icon icon) + { + super(icon); + init(); + } + + public JCheckBox(Icon icon, boolean selected) + { + super(icon, selected); + init(); + } + + public JCheckBox(String text) + { + super(text); + init(); + } + + public JCheckBox(String text, boolean selected) + { + super(text, selected); + init(); + } + + public JCheckBox(String text, Icon icon) + { + super(text, icon); + init(); + } + + public JCheckBox(String text, Icon icon, boolean selected) + { + super(text, icon, selected); + init(); + } + + /** + * Gets the AccessibleContext associated with this JCheckBox. + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * Returns a string that specifies the name of the Look and Feel class + * that renders this component. + */ + public String getUIClassID() + { + return "CheckBoxUI"; + } + + protected String paramString() + { + return super.paramString() + ",borderPaintedFlat=" + borderPaintedFlat; + } + + public boolean isBorderPaintedFlat() + { + return borderPaintedFlat; + } + + public void setBorderPaintedFlat(boolean newValue) + { + firePropertyChange("borderPaintedFlat", borderPaintedFlat, newValue); + borderPaintedFlat = newValue; + } +} diff --git a/libjava/classpath/javax/swing/JCheckBoxMenuItem.java b/libjava/classpath/javax/swing/JCheckBoxMenuItem.java new file mode 100644 index 00000000000..46a42ad210f --- /dev/null +++ b/libjava/classpath/javax/swing/JCheckBoxMenuItem.java @@ -0,0 +1,251 @@ +/* JCheckBoxMenuItem.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.IOException; +import java.io.ObjectOutputStream; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class represents JCheckBoxMenuItem. Its behaviour is very similar + * to JCheckBoxButton. Just like the JCheckBoxButton, user can check and + * uncheck this menu item by clicking on it. Also setSelected()/setState() + * can be use used for the same purpose. JCheckBoxMenuItem uses + * ToggleButtonModel to keep track of its selection. + */ +public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, + Accessible +{ + private static final long serialVersionUID = -6676402307973384715L; + + /** name for the UI delegate for this menuItem. */ + private static final String uiClassID = "CheckBoxMenuItemUI"; + + /** Indicates whether this menu item is checked. */ + private boolean state; + + /** + * This array contains text of this menu item if this menu item is in + * checked state and null it is not. + */ + private Object[] selectedObjects = new Object[1]; + + /** + * Creates a new JCheckBoxMenuItem object. + */ + public JCheckBoxMenuItem() + { + this(null, null); + } + + /** + * Creates a new JCheckBoxMenuItem with given icon + * + * @param icon Icon for this menu item + */ + public JCheckBoxMenuItem(Icon icon) + { + this(null, icon); + } + + /** + * Creates a new JCheckBoxMenuItem with given label + * + * @param text Label for this menu item + */ + public JCheckBoxMenuItem(String text) + { + this(text, null); + } + + /** + * Creates a new JCheckBoxMenuItem using given action + * + * @param action Action for this menu item. + */ + public JCheckBoxMenuItem(Action action) + { + this(); + setAction(action); + } + + /** + * Creates a new JCheckBoxMenuItem object with given label and icon + * + * @param text Label for this menu item + * @param icon Icon for this menu item + */ + public JCheckBoxMenuItem(String text, Icon icon) + { + this(text, icon, false); + } + + /** + * Creates a new JCheckBoxMenuItem object using specified label and + * marked as checked if given 'state' is true. + * + * @param text Label for this menu item + * @param state <code>true</code> if this item should be in checked state and + * <code>false</code> otherwise + */ + public JCheckBoxMenuItem(String text, boolean state) + { + this(text, null, state); + } + + /** + * Creates a new JCheckBoxMenuItem object with given label, icon, + * and marked as checked if given 'state' is true. + * + * @param text Label for this menu item + * @param icon icon for this menu item + * @param state <code>true</code> if this item should be in checked state and + * false otherwise + */ + public JCheckBoxMenuItem(String text, Icon icon, boolean state) + { + super(text, icon); + setModel(new JToggleButton.ToggleButtonModel()); + this.state = state; + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the menuItem. + * + * @return The Look and Feel classID. "JCheckBoxMenuItemUI" + */ + public String getUIClassID() + { + return uiClassID; + } + + /** + * Returns checked state for this check box menu item. + * + * @return Returns true if this menu item is in checked state + * and false otherwise. + */ + public boolean getState() + { + return state; + } + + /** + * Sets state for this check box menu item. If + * given 'state' is true, then mark menu item as checked, + * and uncheck this menu item otherwise. + * + * @param state new state for this menu item + */ + public synchronized void setState(boolean state) + { + this.state = state; + } + + /** + * This method returns array containing label of this + * menu item if it is selected and null otherwise. + * + * @return Array containing label of this + * menu item if this menu item is selected or null otherwise. + */ + public Object[] getSelectedObjects() + { + if (state == true) + selectedObjects[0] = this.getText(); + else + selectedObjects[0] = null; + + return selectedObjects; + } + + /** + * This method overrides JComponent.requestFocus with an empty + * implementation, since JCheckBoxMenuItems should not + * receve focus in general. + */ + public void requestFocus() + { + // Should do nothing here + } + + /** + * A string that describes this JCheckBoxMenuItem. Normally only used + * for debugging. + * + * @return A string describing this JCheckBoxMenuItem + */ + protected String paramString() + { + return "JCheckBoxMenuItem"; + } + + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJCheckBoxMenuItem(); + + return accessibleContext; + } + + protected class AccessibleJCheckBoxMenuItem extends AccessibleJMenuItem + { + private static final long serialVersionUID = 1079958073579370777L; + + /** + * Creates a new AccessibleJCheckBoxMenuItem object. + */ + protected AccessibleJCheckBoxMenuItem() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.CHECK_BOX; + } + } +} diff --git a/libjava/classpath/javax/swing/JColorChooser.java b/libjava/classpath/javax/swing/JColorChooser.java new file mode 100644 index 00000000000..e16b98112af --- /dev/null +++ b/libjava/classpath/javax/swing/JColorChooser.java @@ -0,0 +1,702 @@ +/* JColorChooser.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.AWTError; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.colorchooser.AbstractColorChooserPanel; +import javax.swing.colorchooser.ColorSelectionModel; +import javax.swing.colorchooser.DefaultColorSelectionModel; +import javax.swing.plaf.ColorChooserUI; + + +/** + * The JColorChooser is a Swing widget that offers users different ways to + * select a color. By default, three different panels are presented to the + * user that are capable of changing the selected color. There are three ways + * to utilize JColorChooser. The first is to build a JColorChooser and add it + * to the content pane. The second is to use the createDialog method to + * create a JDialog that holds a JColorChooser. The third is to show a + * JColorChooser in a JDialog directly using the showDialog method. + */ +public class JColorChooser extends JComponent implements Accessible +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = 9168066781620640889L; + + /** + * AccessibleJColorChooser + */ + protected class AccessibleJColorChooser + extends JComponent.AccessibleJComponent + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = -2038297864782299082L; + + /** + * Constructor AccessibleJColorChooser + */ + protected AccessibleJColorChooser() + { + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.COLOR_CHOOSER; + } // getAccessibleRole() + } // AccessibleJColorChooser + + /** The model used with the JColorChooser. */ + private ColorSelectionModel selectionModel; + + /** The preview panel associated with the JColorChooser. */ + private JComponent previewPanel; + + /** + * The set of AbstractColorChooserPanels associated with the JColorChooser. + */ + private AbstractColorChooserPanel[] chooserPanels; + + /** A Drag and Drop property. */ + private boolean dragEnabled; + + /** + * The property fired by the JColorChooser when the selectionModel property + * changes. + */ + public static final String SELECTION_MODEL_PROPERTY = "selectionModel"; + + /** + * The property fired by the JColorChooser when the previewPanel property + * changes. + */ + public static final String PREVIEW_PANEL_PROPERTY = "previewPanel"; + + /** + * The property fired by the JColorChooser when the chooserPanels property + * changes. + */ + public static final String CHOOSER_PANELS_PROPERTY = "chooserPanels"; + + /** accessibleContext */ + protected AccessibleContext accessibleContext; + + /** + * This method creates a new JColorChooser with the default initial color. + */ + public JColorChooser() + { + this(new DefaultColorSelectionModel()); + } // JColorChooser() + + /** + * This method creates a new JColorChooser with the given initial color. + * + * @param initial The initial color. + */ + public JColorChooser(Color initial) + { + this(new DefaultColorSelectionModel(initial)); + } // JColorChooser() + + /** + * This method creates a new JColorChooser with the given model. The model + * will dictate what the initial color for the JColorChooser is. + * + * @param model The Model to use with the JColorChooser. + */ + public JColorChooser(ColorSelectionModel model) + { + if (model == null) + model = new DefaultColorSelectionModel(); + selectionModel = model; + updateUI(); + } // JColorChooser() + + /** + * This method sets the current color for the JColorChooser. + * + * @param color The new color for the JColorChooser. + */ + public void setColor(Color color) + { + if (color != null) + selectionModel.setSelectedColor(color); + } // setColor() + + /** + * This method sets the current color for the JColorChooser using RGB + * values. + * + * @param r The red value. + * @param g The green value. + * @param b The blue value. + */ + public void setColor(int r, int g, int b) + { + selectionModel.setSelectedColor(new Color(r, g, b)); + } // setColor() + + /** + * This method sets the current color for the JColorChooser using the + * integer value. Bits 0-7 represent the blue value. Bits 8-15 represent + * the green value. Bits 16-23 represent the red value. + * + * @param color The new current color of the JColorChooser. + */ + public void setColor(int color) + { + setColor(new Color(color, false)); + } // setColor() + + /** + * This method shows a JColorChooser inside a JDialog. The JDialog will + * block until it is hidden. The JDialog comes with three buttons: OK, + * Cancel, and Reset. Pressing OK or Cancel hide the JDialog. Pressing + * Reset will reset the JColorChooser to its initial value. + * + * @param component The Component that parents the JDialog. + * @param title The title displayed in the JDialog. + * @param initial The initial color. + * + * @return The selected color. + */ + public static Color showDialog(Component component, String title, + Color initial) + { + JColorChooser choose = new JColorChooser(initial); + + JDialog dialog = createDialog(component, title, true, choose, null, null); + + dialog.getContentPane().add(choose); + dialog.pack(); + dialog.show(); + + return choose.getColor(); + } // showDialog() + + /** + * This is a helper method to make the given JDialog block until it is + * hidden. This is package-private to avoid an accessor method. + * + * @param dialog The JDialog to block. + */ + static void makeModal(JDialog dialog) + { + try + { + synchronized (dialog) + { + while (dialog.isVisible()) + dialog.wait(); + } + } + catch (InterruptedException e) + { + } + } + + /** + * This is a helper method to find the first Frame or Dialog ancestor of the + * given Component. + * + * @param c The Component to find ancestors for. + * + * @return A Frame or Dialog ancestor. Null if none are found. + */ + private static Component findParent(Component c) + { + Component parent = SwingUtilities.getAncestorOfClass(Frame.class, c); + if (parent != null) + return parent; + parent = SwingUtilities.getAncestorOfClass(Dialog.class, c); + return parent; + } + + /** + * This method will take the given JColorChooser and place it in a JDialog + * with the given modal property. Three buttons are displayed in the + * JDialog: OK, Cancel and Reset. If OK or Cancel are pressed, the JDialog + * is hidden. If Reset is pressed, then the JColorChooser will take on its + * default color value. The given okListener will be registered to the OK + * button and the cancelListener will be registered to the Cancel button. + * If the modal property is set, then the JDialog will block until it is + * hidden. + * + * @param component The Component that will parent the JDialog. + * @param title The title displayed in the JDialog. + * @param modal The modal property. + * @param chooserPane The JColorChooser to place in the JDialog. + * @param okListener The ActionListener to register to the OK button. + * @param cancelListener The ActionListener to register to the Cancel + * button. + * + * @return A JDialog with the JColorChooser inside of it. + * + * @throws AWTError If the component is not a suitable parent. + */ + public static JDialog createDialog(Component component, String title, + boolean modal, JColorChooser chooserPane, + ActionListener okListener, + ActionListener cancelListener) + { + Component parent = findParent(component); + if (parent == null) + throw new AWTError("No suitable parent found for Component."); + JDialog dialog; + if (parent instanceof Frame) + dialog = new ModalDialog((Frame) parent, title); + else + dialog = new ModalDialog((Dialog) parent, title); + dialog.setModal(modal); + + dialog.getContentPane().setLayout(new BorderLayout()); + + JPanel panel = new JPanel(); + panel.setLayout(new FlowLayout()); + + ActionListener al = new DefaultOKCancelListener(dialog); + + JButton ok = new JButton("OK"); + ok.addActionListener(okListener); + ok.addActionListener(al); + + JButton cancel = new JButton("Cancel"); + cancel.addActionListener(cancelListener); + cancel.addActionListener(al); + + JButton reset = new JButton("Reset"); + reset.addActionListener(new DefaultResetListener(chooserPane)); + + dialog.getContentPane().add(chooserPane, BorderLayout.NORTH); + + panel.add(ok); + panel.add(cancel); + panel.add(reset); + + dialog.getContentPane().add(panel, BorderLayout.SOUTH); + + return dialog; + } // createDialog() + + /** + * This method returns the UI Component used for this JColorChooser. + * + * @return The UI Component for this JColorChooser. + */ + public ColorChooserUI getUI() + { + return (ColorChooserUI) ui; + } // getUI() + + /** + * This method sets the UI Component used for this JColorChooser. + * + * @param ui The UI Component to use with this JColorChooser. + */ + public void setUI(ColorChooserUI ui) + { + super.setUI(ui); + } // setUI() + + /** + * This method resets the UI Component property to the Look and Feel + * default. + */ + public void updateUI() + { + setUI((ColorChooserUI) UIManager.getUI(this)); + revalidate(); + } // updateUI() + + /** + * This method returns a String identifier for the UI Class to be used with + * the JColorChooser. + * + * @return The String identifier for the UI Class. + */ + public String getUIClassID() + { + return "ColorChooserUI"; + } // getUIClassID() + + /** + * This method returns the current color for the JColorChooser. + * + * @return The current color for the JColorChooser. + */ + public Color getColor() + { + return selectionModel.getSelectedColor(); // TODO + } // getColor() + + /** + * This method changes the previewPanel property for the JTabbedPane. The + * previewPanel is responsible for indicating the current color of the + * JColorChooser. + * + * @param component The Component that will act as the previewPanel. + */ + public void setPreviewPanel(JComponent component) + { + if (component != previewPanel) + { + JComponent old = previewPanel; + previewPanel = component; + firePropertyChange(PREVIEW_PANEL_PROPERTY, old, previewPanel); + } + } // setPreviewPanel() + + /** + * This method returns the current previewPanel used with this + * JColorChooser. + * + * @return The current previewPanel. + */ + public JComponent getPreviewPanel() + { + return previewPanel; // TODO + } // getPreviewPanel() + + /** + * This method adds the given AbstractColorChooserPanel to the list of the + * JColorChooser's chooserPanels. + * + * @param panel The AbstractColorChooserPanel to add. + */ + public void addChooserPanel(AbstractColorChooserPanel panel) + { + if (panel == null) + return; + AbstractColorChooserPanel[] old = chooserPanels; + AbstractColorChooserPanel[] newPanels = + new AbstractColorChooserPanel[(old == null) ? 1 : old.length + 1]; + if (old != null) + System.arraycopy(old, 0, newPanels, 0, old.length); + newPanels[newPanels.length - 1] = panel; + chooserPanels = newPanels; + panel.installChooserPanel(this); + firePropertyChange(CHOOSER_PANELS_PROPERTY, old, newPanels); + } // addChooserPanel() + + /** + * This method removes the given AbstractColorChooserPanel from the + * JColorChooser's list of chooserPanels. + * + * @param panel The AbstractColorChooserPanel to remove. + * + * @return The AbstractColorChooserPanel that was removed. + */ + public AbstractColorChooserPanel removeChooserPanel(AbstractColorChooserPanel panel) + { + int index = -1; + for (int i = 0; i < chooserPanels.length; i++) + if (panel == chooserPanels[i]) + { + index = i; + break; + } + + if (index == -1) + return null; + + AbstractColorChooserPanel[] old = chooserPanels; + if (chooserPanels.length == 1) + chooserPanels = null; + else + { + AbstractColorChooserPanel[] newPanels = + new AbstractColorChooserPanel[chooserPanels.length - 1]; + System.arraycopy(chooserPanels, 0, newPanels, 0, index); + System.arraycopy(chooserPanels, index, newPanels, index - 1, + chooserPanels.length - index); + chooserPanels = newPanels; + } + panel.uninstallChooserPanel(this); + firePropertyChange(CHOOSER_PANELS_PROPERTY, old, chooserPanels); + return panel; + } + + /** + * This method sets the chooserPanels property for this JColorChooser. + * + * @param panels The new set of AbstractColorChooserPanels to use. + */ + public void setChooserPanels(AbstractColorChooserPanel[] panels) + { + if (panels != chooserPanels) + { + if (chooserPanels != null) + for (int i = 0; i < chooserPanels.length; i++) + if (chooserPanels[i] != null) + chooserPanels[i].uninstallChooserPanel(this); + + AbstractColorChooserPanel[] old = chooserPanels; + chooserPanels = panels; + + if (panels != null) + for (int i = 0; i < panels.length; i++) + if (panels[i] != null) + panels[i].installChooserPanel(this); + + firePropertyChange(CHOOSER_PANELS_PROPERTY, old, chooserPanels); + } + } // setChooserPanels() + + /** + * This method returns the AbstractColorChooserPanels used with this + * JColorChooser. + * + * @return The AbstractColorChooserPanels used with this JColorChooser. + */ + public AbstractColorChooserPanel[] getChooserPanels() + { + return chooserPanels; + } // getChooserPanels() + + /** + * This method returns the ColorSelectionModel used with this JColorChooser. + * + * @return The ColorSelectionModel. + */ + public ColorSelectionModel getSelectionModel() + { + return selectionModel; + } // getSelectionModel() + + /** + * This method sets the ColorSelectionModel to be used with this + * JColorChooser. + * + * @param model The ColorSelectionModel to be used with this JColorChooser. + * + * @throws AWTError If the given model is null. + */ + public void setSelectionModel(ColorSelectionModel model) + { + if (model == null) + throw new AWTError("ColorSelectionModel is not allowed to be null."); + selectionModel = model; + } // setSelectionModel() + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean getDragEnabled() + { + return dragEnabled; + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + public void setDragEnabled(boolean b) + { + dragEnabled = b; + } + + /** + * This method returns a String describing the JColorChooser. + * + * @return A String describing the JColorChooser. + */ + protected String paramString() + { + return "JColorChooser"; + } // paramString() + + /** + * getAccessibleContext + * + * @return AccessibleContext + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJColorChooser(); + + return accessibleContext; + } + + /** + * A helper class that hides a JDialog when the action is performed. + */ + static class DefaultOKCancelListener implements ActionListener + { + /** The JDialog to hide. */ + private JDialog dialog; + + /** + * Creates a new DefaultOKCancelListener with the given JDialog to hide. + * + * @param dialog The JDialog to hide. + */ + public DefaultOKCancelListener(JDialog dialog) + { + super(); + this.dialog = dialog; + } + + /** + * This method hides the JDialog when called. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + dialog.hide(); + } + } + + /** + * This method resets the JColorChooser color to the initial color when the + * action is performed. + */ + static class DefaultResetListener implements ActionListener + { + /** The JColorChooser to reset. */ + private JColorChooser chooser; + + /** The initial color. */ + private Color init; + + /** + * Creates a new DefaultResetListener with the given JColorChooser. + * + * @param chooser The JColorChooser to reset. + */ + public DefaultResetListener(JColorChooser chooser) + { + super(); + this.chooser = chooser; + init = chooser.getColor(); + } + + /** + * This method resets the JColorChooser to its initial color. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + chooser.setColor(init); + } + } + + /** + * This is a custom JDialog that will notify when it is hidden and the modal + * property is set. + */ + static class ModalDialog extends JDialog + { + /** The modal property. */ + private boolean modal; + + /** + * Creates a new ModalDialog object with the given parent and title. + * + * @param parent The parent of the JDialog. + * @param title The title of the JDialog. + */ + public ModalDialog(Frame parent, String title) + { + super(parent, title); + } + + /** + * Creates a new ModalDialog object with the given parent and title. + * + * @param parent The parent of the JDialog. + * @param title The title of the JDialog. + */ + public ModalDialog(Dialog parent, String title) + { + super(parent, title); + } + + /** + * This method sets the modal property. + * + * @param modal The modal property. + */ + public void setModal(boolean modal) + { + this.modal = modal; + } + + /** + * This method shows the ModalDialog. + */ + public void show() + { + super.show(); + if (modal) + makeModal(this); + } + + /** + * This method hides the ModalDialog. + */ + public synchronized void hide() + { + super.hide(); + notifyAll(); + } + } +} diff --git a/libjava/classpath/javax/swing/JComboBox.java b/libjava/classpath/javax/swing/JComboBox.java new file mode 100644 index 00000000000..4284ec8ea52 --- /dev/null +++ b/libjava/classpath/javax/swing/JComboBox.java @@ -0,0 +1,1223 @@ +/* JComboBox.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.ItemSelectable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.event.PopupMenuListener; +import javax.swing.plaf.ComboBoxUI; + +/** + * JComboBox. JComboBox is a container, that keeps track of elements added to + * it by the user. JComboBox allows user to select any item in its list and + * displays the selected item to the user. JComboBox also can show/hide popup + * menu containing its list of item whenever the mouse is pressed over it. + * + * @author Andrew Selkirk + * @author Olga Rodimina + * @author Robert Schuster + */ +public class JComboBox extends JComponent implements ItemSelectable, + ListDataListener, + ActionListener, + Accessible +{ + + private static final long serialVersionUID = 5654585963292734470L; + + /** + * Classes implementing this interface are + * responsible for matching key characters typed by the user with combo + * box's items. + */ + public static interface KeySelectionManager + { + int selectionForKey(char aKey, ComboBoxModel aModel); + } + + /** + * Maximum number of rows that should be visible by default in the + * JComboBox's popup + */ + private static final int DEFAULT_MAXIMUM_ROW_COUNT = 8; + + /** + * Data model used by JComboBox to keep track of its list data and currently + * selected element in the list. + */ + protected ComboBoxModel dataModel; + + /** + * Renderer renders(paints) every object in the combo box list in its + * associated list cell. This ListCellRenderer is used only when this + * JComboBox is uneditable. + */ + protected ListCellRenderer renderer; + + /** + * Editor that is responsible for editing an object in a combo box list. + */ + protected ComboBoxEditor editor; + + /** + * Number of rows that will be visible in the JComboBox's popup. + */ + protected int maximumRowCount; + + /** + * This field indicates if textfield of this JComboBox is editable or not. + */ + protected boolean isEditable; + + /** + * This field is reference to the current selection of the combo box. + */ + protected Object selectedItemReminder; + + /** + * keySelectionManager + */ + protected KeySelectionManager keySelectionManager; + + /** + * This actionCommand is used in ActionEvent that is fired to JComboBox's + * ActionListeneres. + */ + protected String actionCommand; + + /** + * This property indicates if heavyweight popup or lightweight popup will be + * used to diplay JComboBox's elements. + */ + protected boolean lightWeightPopupEnabled; + + /** + * The action taken when new item is selected in the JComboBox + */ + private Action action; + + /** + * since 1.4 If this field is set then comboBox's display area for the + * selected item will be set by default to this value. + */ + private Object prototypeDisplayValue; + + /** + * Constructs JComboBox object with specified data model for it. + * <p>Note that the JComboBox will not change the value that + * is preselected by your ComboBoxModel implementation.</p> + * + * @param model Data model that will be used by this JComboBox to keep track + * of its list of items. + */ + public JComboBox(ComboBoxModel model) + { + setEditable(false); + setEnabled(true); + setMaximumRowCount(DEFAULT_MAXIMUM_ROW_COUNT); + setModel(model); + setActionCommand("comboBoxChanged"); + + lightWeightPopupEnabled = true; + isEditable = false; + + updateUI(); + } + + /** + * Constructs JComboBox with specified list of items. + * + * @param itemArray array containing list of items for this JComboBox + */ + public JComboBox(Object[] itemArray) + { + this(new DefaultComboBoxModel(itemArray)); + + if (itemArray.length > 0) + setSelectedIndex(0); + } + + /** + * Constructs JComboBox object with specified list of items. + * + * @param itemVector vector containing list of items for this JComboBox. + */ + public JComboBox(Vector itemVector) + { + this(new DefaultComboBoxModel(itemVector)); + + if (itemVector.size() > 0) + setSelectedIndex(0); + } + + /** + * Constructor. Creates new empty JComboBox. ComboBox's data model is set to + * DefaultComboBoxModel. + */ + public JComboBox() + { + this(new DefaultComboBoxModel()); + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + } + + /** + * This method returns true JComboBox is editable and false otherwise + * + * @return boolean true if JComboBox is editable and false otherwise + */ + public boolean isEditable() + { + return isEditable; + } + + /* + * This method adds ancestor listener to this JComboBox. + */ + protected void installAncestorListener() + { + /* FIXME: Need to implement. + * + * Need to add ancestor listener to this JComboBox. This listener + * should close combo box's popup list of items whenever it + * receives an AncestorEvent. + */ + } + + /** + * Set the "UI" property of the combo box, which is a look and feel class + * responsible for handling comboBox's input events and painting it. + * + * @param ui The new "UI" property + */ + public void setUI(ComboBoxUI ui) + { + super.setUI(ui); + } + + /** + * This method sets this comboBox's UI to the UIManager's default for the + * current look and feel. + */ + public void updateUI() + { + setUI((ComboBoxUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns the String identifier for the UI class to the used + * with the JComboBox. + * + * @return The String identifier for the UI class. + */ + public String getUIClassID() + { + return "ComboBoxUI"; + } + + /** + * This method returns the UI used to display the JComboBox. + * + * @return The UI used to display the JComboBox. + */ + public ComboBoxUI getUI() + { + return (ComboBoxUI) ui; + } + + /** + * Set the data model for this JComboBox. This un-registers all listeners + * associated with the current model, and re-registers them with the new + * model. + * + * @param newDataModel The new data model for this JComboBox + */ + public void setModel(ComboBoxModel newDataModel) + { + // dataModel is null if it this method is called from inside the constructors. + if (dataModel != null) + { + // Prevents unneccessary updates. + if (dataModel == newDataModel) + return; + + // Removes itself (as DataListener) from the to-be-replaced model. + dataModel.removeListDataListener(this); + } + + /* Adds itself as a DataListener to the new model. + * It is intentioned that this operation will fail with a NullPointerException if the + * caller delivered a null argument. + */ + newDataModel.addListDataListener(this); + + // Stores old data model for event notification. + ComboBoxModel oldDataModel = dataModel; + dataModel = newDataModel; + + // Notifies the listeners of the model change. + firePropertyChange("model", oldDataModel, dataModel); + } + + /** + * This method returns data model for this comboBox. + * + * @return ComboBoxModel containing items for this combo box. + */ + public ComboBoxModel getModel() + { + return dataModel; + } + + /** + * This method sets JComboBox's popup to be either lightweight or + * heavyweight. If 'enabled' is true then lightweight popup is used and + * heavyweight otherwise. By default lightweight popup is used to display + * this JComboBox's elements. + * + * @param enabled indicates if lightweight popup or heavyweight popup should + * be used to display JComboBox's elements. + */ + public void setLightWeightPopupEnabled(boolean enabled) + { + lightWeightPopupEnabled = enabled; + } + + /** + * This method returns whether popup menu that is used to display list of + * combo box's item is lightWeight or not. + * + * @return boolean true if popup menu is lightweight and false otherwise. + */ + public boolean isLightWeightPopupEnabled() + { + return lightWeightPopupEnabled; + } + + /** + * This method sets editability of the combo box. If combo box is editable + * the user can choose component from the combo box list by typing + * component's name in the editor(JTextfield by default). Otherwise if not + * editable, the user should use the list to choose the component. This + * method fires PropertyChangeEvents to JComboBox's registered + * PropertyChangeListeners to indicate that 'editable' property of the + * JComboBox has changed. + * + * @param editable indicates if the JComboBox's textfield should be editable + * or not. + */ + public void setEditable(boolean editable) + { + if (isEditable != editable) + { + isEditable = editable; + firePropertyChange("editable", !isEditable, isEditable); + } + } + + /** + * Sets number of rows that should be visible in this JComboBox's popup. If + * this JComboBox's popup has more elements that maximum number or rows + * then popup will have a scroll pane to allow users to view other + * elements. + * + * @param rowCount number of rows that will be visible in JComboBox's popup. + */ + public void setMaximumRowCount(int rowCount) + { + if (maximumRowCount != rowCount) + { + int oldMaximumRowCount = maximumRowCount; + maximumRowCount = rowCount; + firePropertyChange("maximumRowCount", oldMaximumRowCount, + maximumRowCount); + } + } + + /** + * This method returns number of rows visible in the JComboBox's list of + * items. + * + * @return int maximun number of visible rows in the JComboBox's list. + */ + public int getMaximumRowCount() + { + return maximumRowCount; + } + + /** + * This method sets cell renderer for this JComboBox that will be used to + * paint combo box's items. The Renderer should only be used only when + * JComboBox is not editable. In the case when JComboBox is editable the + * editor must be used. This method also fires PropertyChangeEvent when + * cellRendered for this JComboBox has changed. + * + * @param aRenderer cell renderer that will be used by this JComboBox to + * paint its elements. + */ + public void setRenderer(ListCellRenderer aRenderer) + { + if (renderer != aRenderer) + { + ListCellRenderer oldRenderer = renderer; + renderer = aRenderer; + firePropertyChange("renderer", oldRenderer, renderer); + } + } + + /** + * This method returns renderer responsible for rendering selected item in + * the combo box + * + * @return ListCellRenderer + */ + public ListCellRenderer getRenderer() + { + return renderer; + } + + /** + * Sets editor for this JComboBox + * + * @param newEditor ComboBoxEditor for this JComboBox. This method fires + * PropertyChangeEvent when 'editor' property is changed. + */ + public void setEditor(ComboBoxEditor newEditor) + { + if (editor == newEditor) + return; + + if (editor != null) + editor.removeActionListener(this); + + ComboBoxEditor oldEditor = editor; + editor = newEditor; + + if (editor != null) + editor.addActionListener(this); + + firePropertyChange("editor", oldEditor, editor); + } + + /** + * Returns editor component that is responsible for displaying/editing + * selected item in the combo box. + * + * @return ComboBoxEditor + */ + public ComboBoxEditor getEditor() + { + return editor; + } + + /** + * Forces combo box to select given item + * + * @param item element in the combo box to select. + */ + public void setSelectedItem(Object item) + { + dataModel.setSelectedItem(item); + } + + /** + * Returns currently selected item in the combo box. + * The result may be <code>null</code> to indicate that nothing is + * currently selected. + * + * @return element that is currently selected in this combo box. + */ + public Object getSelectedItem() + { + return dataModel.getSelectedItem(); + } + + /** + * Forces JComboBox to select component located in the given index in the + * combo box. + * <p>If the index is below -1 or exceeds the upper bound an + * <code>IllegalArgumentException</code> is thrown.<p/> + * <p>If the index is -1 then no item gets selected.</p> + * + * @param index index specifying location of the component that should be + * selected. + */ + public void setSelectedIndex(int index) + { + if (index < -1 || index >= dataModel.getSize()) + // Fails because index is out of bounds. + throw new IllegalArgumentException("illegal index: " + index); + else + // Selects the item at the given index or clears the selection if the + // index value is -1. + setSelectedItem((index == -1) ? null : dataModel.getElementAt(index)); + } + + /** + * Returns index of the item that is currently selected in the combo box. If + * no item is currently selected, then -1 is returned. + * <p> + * Note: For performance reasons you should minimize invocation of this + * method. If the data model is not an instance of + * <code>DefaultComboBoxModel</code> the complexity is O(n) where n is the + * number of elements in the combo box. + * </p> + * + * @return int Index specifying location of the currently selected item in the + * combo box or -1 if nothing is selected in the combo box. + */ + public int getSelectedIndex() + { + Object selectedItem = getSelectedItem(); + + if (selectedItem != null) + { + if (dataModel instanceof DefaultComboBoxModel) + // Uses special method of DefaultComboBoxModel to retrieve the index. + return ((DefaultComboBoxModel) dataModel).getIndexOf(selectedItem); + else + { + // Iterates over all items to retrieve the index. + int size = dataModel.getSize(); + + for (int i = 0; i < size; i++) + { + Object o = dataModel.getElementAt(i); + + // XXX: Is special handling of ComparableS neccessary? + if ((selectedItem != null) ? selectedItem.equals(o) : o == null) + return i; + } + } + } + + // returns that no item is currently selected + return -1; + } + + public Object getPrototypeDisplayValue() + { + return prototypeDisplayValue; + } + + public void setPrototypeDisplayValue(Object newPrototypeDisplayValue) + { + prototypeDisplayValue = newPrototypeDisplayValue; + } + + /** + * This method adds given element to this JComboBox. + * <p>A <code>RuntimeException</code> is thrown if the data model is not + * an instance of {@link MutableComboBoxModel}.</p> + * + * @param element element to add + */ + public void addItem(Object element) + { + if (dataModel instanceof MutableComboBoxModel) + ((MutableComboBoxModel) dataModel).addElement(element); + else + throw new RuntimeException("Unable to add the item because the data " + + "model it is not an instance of " + + "MutableComboBoxModel."); + } + + /** + * Inserts given element at the specified index to this JComboBox. + * <p>A <code>RuntimeException</code> is thrown if the data model is not + * an instance of {@link MutableComboBoxModel}.</p> + * + * @param element element to insert + * @param index position where to insert the element + */ + public void insertItemAt(Object element, int index) + { + if (dataModel instanceof MutableComboBoxModel) + ((MutableComboBoxModel) dataModel).insertElementAt(element, index); + else + throw new RuntimeException("Unable to insert the item because the data " + + "model it is not an instance of " + + "MutableComboBoxModel."); + } + + /** + * This method removes given element from this JComboBox. + * <p>A <code>RuntimeException</code> is thrown if the data model is not + * an instance of {@link MutableComboBoxModel}.</p> + * + * @param element element to remove + */ + public void removeItem(Object element) + { + if (dataModel instanceof MutableComboBoxModel) + ((MutableComboBoxModel) dataModel).removeElement(element); + else + throw new RuntimeException("Unable to remove the item because the data " + + "model it is not an instance of " + + "MutableComboBoxModel."); + } + + /** + * This method remove element location in the specified index in the + * JComboBox. + * <p>A <code>RuntimeException</code> is thrown if the data model is not + * an instance of {@link MutableComboBoxModel}.</p> + * + * @param index index specifying position of the element to remove + */ + public void removeItemAt(int index) + { + if (dataModel instanceof MutableComboBoxModel) + ((MutableComboBoxModel) dataModel).removeElementAt(index); + else + throw new RuntimeException("Unable to remove the item because the data " + + "model it is not an instance of " + + "MutableComboBoxModel."); + } + + /** + * This method removes all elements from this JComboBox. + * <p> + * A <code>RuntimeException</code> is thrown if the data model is not an + * instance of {@link MutableComboBoxModel}. + * </p> + */ + public void removeAllItems() + { + if (dataModel instanceof DefaultComboBoxModel) + // Uses special method if we have a DefaultComboBoxModel. + ((DefaultComboBoxModel) dataModel).removeAllElements(); + else if (dataModel instanceof MutableComboBoxModel) + { + // Iterates over all items and removes each. + MutableComboBoxModel mcbm = (MutableComboBoxModel) dataModel; + + // We intentionally remove the items backwards to support models which + // shift their content to the beginning (e.g. linked lists) + for (int i = mcbm.getSize() - 1; i >= 0; i--) + mcbm.removeElementAt(i); + } + else + throw new RuntimeException("Unable to remove the items because the data " + +"model it is not an instance of " + + "MutableComboBoxModel."); + } + + /** + * This method displays popup with list of combo box's items on the screen + */ + public void showPopup() + { + setPopupVisible(true); + } + + /** + * This method hides popup containing list of combo box's items + */ + public void hidePopup() + { + setPopupVisible(false); + } + + /** + * This method either displayes or hides the popup containing list of combo + * box's items. + * + * @param visible show popup if 'visible' is true and hide it otherwise + */ + public void setPopupVisible(boolean visible) + { + getUI().setPopupVisible(this, visible); + } + + /** + * Checks if popup is currently visible on the screen. + * + * @return boolean true if popup is visible and false otherwise + */ + public boolean isPopupVisible() + { + return getUI().isPopupVisible(this); + } + + /** + * This method sets actionCommand to the specified string. ActionEvent fired + * to this JComboBox registered ActionListeners will contain this + * actionCommand. + * + * @param aCommand new action command for the JComboBox's ActionEvent + */ + public void setActionCommand(String aCommand) + { + actionCommand = aCommand; + } + + /** + * Returns actionCommand associated with the ActionEvent fired by the + * JComboBox to its registered ActionListeners. + * + * @return String actionCommand for the ActionEvent + */ + public String getActionCommand() + { + return actionCommand; + } + + /** + * setAction + * + * @param a action to set + */ + public void setAction(Action a) + { + Action old = action; + action = a; + configurePropertiesFromAction(action); + if (action != null) + // FIXME: remove from old action and add to new action + // PropertyChangeListener to listen to changes in the action + addActionListener(action); + } + + /** + * This method returns Action that is invoked when selected item is changed + * in the JComboBox. + * + * @return Action + */ + public Action getAction() + { + return action; + } + + /** + * Configure properties of the JComboBox by reading properties of specified + * action. This method always sets the comboBox's "enabled" property to the + * value of the Action's "enabled" property. + * + * @param a An Action to configure the combo box from + */ + protected void configurePropertiesFromAction(Action a) + { + if (a == null) + { + setEnabled(true); + setToolTipText(null); + } + else + { + setEnabled(a.isEnabled()); + setToolTipText((String) (a.getValue(Action.SHORT_DESCRIPTION))); + } + } + + /** + * Creates PropertyChangeListener to listen for the changes in comboBox's + * action properties. + * + * @param action action to listen to for property changes + * + * @return a PropertyChangeListener that listens to changes in + * action properties. + */ + protected PropertyChangeListener createActionPropertyChangeListener(Action action) + { + return new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent e) + { + Action act = (Action) (e.getSource()); + configurePropertiesFromAction(act); + } + }; + } + + /** + * This method fires ItemEvent to this JComboBox's registered ItemListeners. + * This method is invoked when currently selected item in this combo box + * has changed. + * + * @param e the ItemEvent describing the change in the combo box's + * selection. + */ + protected void fireItemStateChanged(ItemEvent e) + { + ItemListener[] ll = getItemListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].itemStateChanged(e); + } + + /** + * This method fires ActionEvent to this JComboBox's registered + * ActionListeners. This method is invoked when user explicitly changes + * currently selected item. + */ + protected void fireActionEvent() + { + ActionListener[] ll = getActionListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].actionPerformed(new ActionEvent(this, + ActionEvent.ACTION_PERFORMED, + actionCommand)); + } + + /** + * This method is invoked whenever selected item changes in the combo box's + * data model. It fires ItemEvent and ActionEvent to all registered + * ComboBox's ItemListeners and ActionListeners respectively, indicating + * the change. + */ + protected void selectedItemChanged() + { + // Fire ItemEvent to indicated that previously selected item is now + // deselected + if (selectedItemReminder != null) + fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, + selectedItemReminder, + ItemEvent.DESELECTED)); + + // Fire ItemEvent to indicate that new item is selected + Object newSelection = getSelectedItem(); + fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, + newSelection, ItemEvent.SELECTED)); + + // Fire Action Event to JComboBox's registered listeners + fireActionEvent(); + + selectedItemReminder = newSelection; + } + + /** + * Returns Object array of size 1 containing currently selected element in + * the JComboBox. + * + * @return Object[] Object array of size 1 containing currently selected + * element in the JComboBox. + */ + public Object[] getSelectedObjects() + { + return new Object[] { getSelectedItem() }; + } + + /** + * This method handles actionEvents fired by the ComboBoxEditor. It changes + * this JComboBox's selection to the new value currently in the editor and + * hides list of combo box items. + * + * @param e the ActionEvent + */ + public void actionPerformed(ActionEvent e) + { + setSelectedItem(((ComboBoxEditor) e.getSource()).getItem()); + setPopupVisible(false); + } + + /** + * This method selects item in this combo box that matches specified + * specified keyChar and returns true if such item is found. Otherwise + * false is returned. + * + * @param keyChar character indicating which item in the combo box should be + * selected. + * + * @return boolean true if item corresponding to the specified keyChar + * exists in the combo box. Otherwise false is returned. + */ + public boolean selectWithKeyChar(char keyChar) + { + // FIXME: Need to implement + return false; + } + + /** + * The part of implementation of ListDataListener interface. This method is + * invoked when some items where added to the JComboBox's data model. + * + * @param event ListDataEvent describing the change + */ + public void intervalAdded(ListDataEvent event) + { + // FIXME: Need to implement + repaint(); + } + + /** + * The part of implementation of ListDataListener interface. This method is + * invoked when some items where removed from the JComboBox's data model. + * + * @param event ListDataEvent describing the change. + */ + public void intervalRemoved(ListDataEvent event) + { + // FIXME: Need to implement + repaint(); + } + + /** + * The part of implementation of ListDataListener interface. This method is + * invoked when contents of the JComboBox's data model changed. + * + * @param event ListDataEvent describing the change + */ + public void contentsChanged(ListDataEvent event) + { + // if first and last index of the given ListDataEvent are both -1, + // then it indicates that selected item in the combo box data model + // have changed. + if (event.getIndex0() == -1 && event.getIndex1() == -1) + selectedItemChanged(); + } + + /** + * This method disables or enables JComboBox. If the JComboBox is enabled, + * then user is able to make item choice, otherwise if JComboBox is + * disabled then user is not able to make a selection. + * + * @param enabled if 'enabled' is true then enable JComboBox and disable it + */ + public void setEnabled(boolean enabled) + { + boolean oldEnabled = super.isEnabled(); + if (enabled != oldEnabled) + { + super.setEnabled(enabled); + firePropertyChange("enabled", oldEnabled, enabled); + } + } + + /** + * This method initializes specified ComboBoxEditor to display given item. + * + * @param anEditor ComboBoxEditor to initialize + * @param anItem Item that should displayed in the specified editor + */ + public void configureEditor(ComboBoxEditor anEditor, Object anItem) + { + anEditor.setItem(anItem); + } + + /** + * This method hides combo box's popup whenever TAB key is pressed. + * + * @param e The KeyEvent indicating which key was pressed. + */ + public void processKeyEvent(KeyEvent e) + { + } + + /** + * This method always returns false to indicate that JComboBox itself is + * not focus traversable. + * + * @return false to indicate that JComboBox itself is not focus traversable. + * + * @deprecated + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * setKeySelectionManager + * + * @param aManager + */ + public void setKeySelectionManager(KeySelectionManager aManager) + { + } + + /** + * getKeySelectionManager + * + * @return JComboBox.KeySelectionManager + */ + public KeySelectionManager getKeySelectionManager() + { + return null; + } + + /** + * This method returns number of elements in this JComboBox + * + * @return int number of elements in this JComboBox + */ + public int getItemCount() + { + return dataModel.getSize(); + } + + /** + * Returns elements located in the combo box at the given index. + * + * @param index index specifying location of the component to return. + * + * @return component in the combo box that is located in the given index. + */ + public Object getItemAt(int index) + { + return dataModel.getElementAt(index); + } + + /** + * createDefaultKeySelectionManager + * + * @return KeySelectionManager + */ + protected KeySelectionManager createDefaultKeySelectionManager() + { + return null; + } + + /** + * A string that describes this JComboBox. Normally only used for debugging. + * + * @return A string describing this JComboBox + */ + protected String paramString() + { + return "JComboBox"; + } + + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJComboBox(); + + return accessibleContext; + } + + /** + * This methods adds specified ActionListener to this JComboBox. + * + * @param listener to add + */ + public void addActionListener(ActionListener listener) + { + listenerList.add(ActionListener.class, listener); + } + + /** + * This method removes specified ActionListener from this JComboBox. + * + * @param listener ActionListener + */ + public void removeActionListener(ActionListener listener) + { + listenerList.remove(ActionListener.class, listener); + } + + /** + * This method returns array of ActionListeners that are registered with + * this JComboBox. + * + * @since 1.4 + */ + public ActionListener[] getActionListeners() + { + return (ActionListener[]) getListeners(ActionListener.class); + } + + /** + * This method registers given ItemListener with this JComboBox + * + * @param listener to remove + */ + public void addItemListener(ItemListener listener) + { + listenerList.add(ItemListener.class, listener); + } + + /** + * This method unregisters given ItemListener from this JComboBox + * + * @param listener to remove + */ + public void removeItemListener(ItemListener listener) + { + listenerList.remove(ItemListener.class, listener); + } + + /** + * This method returns array of ItemListeners that are registered with this + * JComboBox. + * + * @since 1.4 + */ + public ItemListener[] getItemListeners() + { + return (ItemListener[]) getListeners(ItemListener.class); + } + + /** + * Adds PopupMenuListener to combo box to listen to the events fired by the + * combo box's popup menu containing its list of items + * + * @param listener to add + */ + public void addPopupMenuListener(PopupMenuListener listener) + { + listenerList.add(PopupMenuListener.class, listener); + } + + /** + * Removes PopupMenuListener to combo box to listen to the events fired by + * the combo box's popup menu containing its list of items + * + * @param listener to add + */ + public void removePopupMenuListener(PopupMenuListener listener) + { + listenerList.remove(PopupMenuListener.class, listener); + } + + /** + * Returns array of PopupMenuListeners that are registered with combo box. + */ + public PopupMenuListener[] getPopupMenuListeners() + { + return (PopupMenuListener[]) getListeners(PopupMenuListener.class); + } + + /** + * AccessibleJComboBox + */ + protected class AccessibleJComboBox extends AccessibleJComponent + implements AccessibleAction, AccessibleSelection + { + private static final long serialVersionUID = 8217828307256675666L; + + protected AccessibleJComboBox() + { + } + + public int getAccessibleChildrenCount() + { + return 0; + } + + public Accessible getAccessibleChild(int value0) + { + return null; + } + + public AccessibleSelection getAccessibleSelection() + { + return null; + } + + public Accessible getAccessibleSelection(int value0) + { + return null; + } + + public boolean isAccessibleChildSelected(int value0) + { + return false; + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.COMBO_BOX; + } + + public AccessibleAction getAccessibleAction() + { + return null; + } + + public String getAccessibleActionDescription(int value0) + { + return null; + } + + public int getAccessibleActionCount() + { + return 0; + } + + public boolean doAccessibleAction(int value0) + { + return false; + } + + public int getAccessibleSelectionCount() + { + return 0; + } + + public void addAccessibleSelection(int value0) + { + } + + public void removeAccessibleSelection(int value0) + { + } + + public void clearAccessibleSelection() + { + } + + public void selectAllAccessibleSelection() + { + } + } +} diff --git a/libjava/classpath/javax/swing/JComponent.java b/libjava/classpath/javax/swing/JComponent.java new file mode 100644 index 00000000000..42a5317dc77 --- /dev/null +++ b/libjava/classpath/javax/swing/JComponent.java @@ -0,0 +1,2680 @@ +/* JComponent.java -- Every component in swing inherits from this class. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.AWTEvent; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.dnd.DropTarget; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.geom.Rectangle2D; +import java.awt.image.ImageObserver; +import java.awt.peer.LightweightPeer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; +import java.io.Serializable; +import java.util.EventListener; +import java.util.Hashtable; +import java.util.Locale; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleExtendedComponent; +import javax.accessibility.AccessibleKeyBinding; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.swing.border.Border; +import javax.swing.event.AncestorEvent; +import javax.swing.event.AncestorListener; +import javax.swing.event.EventListenerList; +import javax.swing.event.SwingPropertyChangeSupport; +import javax.swing.plaf.ComponentUI; + +/** + * Every component in swing inherits from this class (JLabel, JButton, etc). + * It contains generic methods to manage events, properties and sizes. Actual + * drawing of the component is channeled to a look-and-feel class that is + * implemented elsewhere. + * + * @author Ronald Veldema (rveldema&064;cs.vu.nl) + * @author Graydon Hoare (graydon&064;redhat.com) + */ +public abstract class JComponent extends Container implements Serializable +{ + private static final long serialVersionUID = -7908749299918704233L; + + /** + * Accessibility support is currently missing. + */ + protected AccessibleContext accessibleContext; + + public abstract class AccessibleJComponent + extends AccessibleAWTContainer + implements AccessibleExtendedComponent + { + protected class AccessibleFocusHandler + implements FocusListener + { + protected AccessibleFocusHandler(){} + public void focusGained(FocusEvent event){} + public void focusLost(FocusEvent valevent){} + } + + protected class AccessibleContainerHandler + implements ContainerListener + { + protected AccessibleContainerHandler() {} + public void componentAdded(ContainerEvent event) {} + public void componentRemoved(ContainerEvent valevent) {} + } + + private static final long serialVersionUID = -7047089700479897799L; + + protected ContainerListener accessibleContainerHandler; + protected FocusListener accessibleFocusHandler; + + protected AccessibleJComponent() {} + public void addPropertyChangeListener(PropertyChangeListener listener) {} + public void removePropertyChangeListener(PropertyChangeListener listener) {} + public int getAccessibleChildrenCount() { return 0; } + public Accessible getAccessibleChild(int value0) { return null; } + public AccessibleStateSet getAccessibleStateSet() { return null; } + public String getAccessibleName() { return null; } + public String getAccessibleDescription() { return null; } + public AccessibleRole getAccessibleRole() { return null; } + protected String getBorderTitle(Border value0) { return null; } + public String getToolTipText() { return null; } + public String getTitledBorderText() { return null; } + public AccessibleKeyBinding getAccessibleKeyBinding() { return null; } + } + + /** + * An explicit value for the component's preferred size; if not set by a + * user, this is calculated on the fly by delegating to the {@link + * ComponentUI.getPreferredSize} method on the {@link #ui} property. + */ + Dimension preferredSize; + + /** + * An explicit value for the component's minimum size; if not set by a + * user, this is calculated on the fly by delegating to the {@link + * ComponentUI.getMinimumSize} method on the {@link #ui} property. + */ + Dimension minimumSize; + + /** + * An explicit value for the component's maximum size; if not set by a + * user, this is calculated on the fly by delegating to the {@link + * ComponentUI.getMaximumSize} method on the {@link #ui} property. + */ + Dimension maximumSize; + + /** + * A value between 0.0 and 1.0 indicating the preferred horizontal + * alignment of the component, relative to its siblings. The values + * {@link #LEFT_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link + * #RIGHT_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>, + * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout + * managers use this property. + * + * @see #getAlignmentX + * @see #setAlignmentX + * @see javax.swing.OverlayLayout + * @see javax.swing.BoxLayout + */ + float alignmentX = 0.5f; + + /** + * A value between 0.0 and 1.0 indicating the preferred vertical + * alignment of the component, relative to its siblings. The values + * {@link #TOP_ALIGNMENT}, {@link #CENTER_ALIGNMENT}, and {@link + * #BOTTOM_ALIGNMENT} can also be used, as synonyms for <code>0.0</code>, + * <code>0.5</code>, and <code>1.0</code>, respectively. Not all layout + * managers use this property. + * + * @see #getAlignmentY + * @see #setAlignmentY + * @see javax.swing.OverlayLayout + * @see javax.swing.BoxLayout + */ + float alignmentY = 0.5f; + + /** + * The border painted around this component. + * + * @see #paintBorder + */ + Border border; + + /** + * The text to show in the tooltip associated with this component. + * + * @see #setToolTipText + * @see #getToolTipText + */ + String toolTipText; + + /** + * <p>Whether to double buffer this component when painting. This flag + * should generally be <code>false</code>, except for top level + * components such as {@link JFrame} or {@link JApplet}.</p> + * + * <p>All children of a double buffered component are painted into the + * double buffer automatically, so only the top widget in a window needs + * to be double buffered.</p> + * + * @see #setDoubleBuffered + * @see #isDoubleBuffered + * @see #paintLock + * @see #paint + */ + boolean doubleBuffered = false; + + /** + * A set of flags indicating which debugging graphics facilities should + * be enabled on this component. The values should be a combination of + * {@link DebugGraphics.NONE_OPTION}, {@link DebugGraphics.LOG_OPTION}, + * {@link DebugGraphics.FLASH_OPTION}, or {@link + * DebugGraphics.BUFFERED_OPTION}. + * + * @see setDebugGraphicsOptions + * @see getDebugGraphicsOptions + * @see DebugGraphics + * @see getComponentGraphics + */ + int debugGraphicsOptions; + + /** + * <p>This property controls two independent behaviors simultaneously.</p> + * + * <p>First, it controls whether to fill the background of this widget + * when painting its body. This affects calls to {@link + * JComponent#paintComponent}, which in turn calls {@link + * ComponentUI#update} on the component's {@link #ui} property. If the + * component is opaque during this call, the background will be filled + * before calling {@link ComponentUI#paint}. This happens merely as a + * convenience; you may fill the component's background yourself too, + * but there is no need to do so if you will be filling with the same + * color.</p> + * + * <p>Second, it the opaque property informs swing's repaint system + * whether it will be necessary to paint the components "underneath" this + * component, in Z-order. If the component is opaque, it is considered to + * completely occlude components "underneath" it, so they will not be + * repainted along with the opaque component.</p> + * + * <p>The default value for this property is <code>false</code>, but most + * components will want to set it to <code>true</code> when installing UI + * defaults in {@link ComponentUI#installUI}.</p> + * + * @see #setOpaque + * @see #isOpaque + * @see #paintComponent + */ + boolean opaque = false; + + /** + * The user interface delegate for this component. Event delivery and + * repainting of the component are usually delegated to this object. + * + * @see #setUI + * @see #getUI + * @see #updateUI + */ + protected ComponentUI ui; + + /** + * A hint to the focus system that this component should or should not + * get focus. If this is <code>false</code>, swing will not try to + * request focus on this component; if <code>true</code>, swing might + * try to request focus, but the request might fail. Thus it is only + * a hint guiding swing's behavior. + * + * @see #requestFocus + * @see #isRequestFocusEnabled + * @see #setRequestFocusEnabled + */ + boolean requestFocusEnabled; + + /** + * Flag indicating behavior of this component when the mouse is dragged + * outside the component and the mouse <em>stops moving</em>. If + * <code>true</code>, synthetic mouse events will be delivered on regular + * timed intervals, continuing off in the direction the mouse exited the + * component, until the mouse is released or re-enters the component. + * + * @see setAutoscrolls + * @see getAutoscrolls + */ + boolean autoscrolls = false; + + /** + * Listeners for events other than {@link PropertyChangeEvent} are + * handled by this listener list. PropertyChangeEvents are handled in + * {@link #changeSupport}. + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * Support for {@link PropertyChangeEvent} events. This is constructed + * lazily when the component gets its first {@link + * PropertyChangeListener} subscription; until then it's an empty slot. + */ + private SwingPropertyChangeSupport changeSupport; + + + /** + * Storage for "client properties", which are key/value pairs associated + * with this component by a "client", such as a user application or a + * layout manager. This is lazily constructed when the component gets its + * first client property. + */ + private Hashtable clientProperties; + + private InputMap inputMap_whenFocused; + private InputMap inputMap_whenAncestorOfFocused; + private InputMap inputMap_whenInFocusedWindow; + private ActionMap actionMap; + /** @since 1.3 */ + private boolean verifyInputWhenFocusTarget; + private InputVerifier inputVerifier; + + private TransferHandler transferHandler; + + /** + * A lock held during recursive painting; this is used to serialize + * access to the double buffer, and also to select the "top level" + * object which should acquire the double buffer in a given widget + * tree (which may have multiple double buffered children). + * + * @see #doubleBuffered + * @see #paint + */ + private static final Object paintLock = new Object(); + + /** + * The default locale of the component. + * + * @see #getDefaultLocale + * @see #setDefaultLocale + */ + private static Locale defaultLocale; + + public static final String TOOL_TIP_TEXT_KEY = "ToolTipText"; + + /** + * Constant used to indicate that no condition has been assigned to a + * particular action. + * + * @see #registerKeyboardAction + */ + public static final int UNDEFINED_CONDITION = -1; + + /** + * Constant used to indicate that an action should be performed only when + * the component has focus. + * + * @see #registerKeyboardAction + */ + public static final int WHEN_FOCUSED = 0; + + /** + * Constant used to indicate that an action should be performed only when + * the component is an ancestor of the component which has focus. + * + * @see #registerKeyboardAction + */ + public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1; + + /** + * Constant used to indicate that an action should be performed only when + * the component is in the window which has focus. + * + * @see #registerKeyboardAction + */ + public static final int WHEN_IN_FOCUSED_WINDOW = 2; + + /** + * Creates a new <code>JComponent</code> instance. + */ + public JComponent() + { + super(); + super.setLayout(new FlowLayout()); + setDropTarget(new DropTarget()); + defaultLocale = Locale.getDefault(); + debugGraphicsOptions = DebugGraphics.NONE_OPTION; + setRequestFocusEnabled(true); + } + + /** + * Helper to lazily construct and return the client properties table. + * + * @return The current client properties table + * + * @see #clientProperties + * @see #getClientProperty + * @see #putClientProperty + */ + private Hashtable getClientProperties() + { + if (clientProperties == null) + clientProperties = new Hashtable(); + return clientProperties; + } + + /** + * Get a client property associated with this component and a particular + * key. + * + * @param key The key with which to look up the client property + * + * @return A client property associated with this object and key + * + * @see #clientProperties + * @see #getClientProperties + * @see #putClientProperty + */ + public final Object getClientProperty(Object key) + { + return getClientProperties().get(key); + } + + /** + * Add a client property <code>value</code> to this component, associated + * with <code>key</code>. If there is an existing client property + * associated with <code>key</code>, it will be replaced. + * + * @param key The key of the client property association to add + * @param value The value of the client property association to add + * + * @see #clientProperties + * @see #getClientProperties + * @see #getClientProperty + */ + public final void putClientProperty(Object key, Object value) + { + getClientProperties().put(key, value); + } + + /** + * Unregister an <code>AncestorListener</code>. + * + * @param listener The listener to unregister + * + * @see addAncestorListener + */ + public void removeAncestorListener(AncestorListener listener) + { + listenerList.remove(AncestorListener.class, listener); + } + + /** + * Unregister a <code>PropertyChangeListener</code>. + * + * @param listener The listener to register + * + * @see #addPropertyChangeListener + * @see #changeSupport + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Unregister a <code>PropertyChangeListener</code>. + * + * @param propertyName The property name to unregister the listener from + * @param listener The listener to unregister + * + * @see #addPropertyChangeListener + * @see #changeSupport + */ + public void removePropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + if (changeSupport != null) + changeSupport.removePropertyChangeListener(propertyName, listener); + } + + /** + * Unregister a <code>VetoableChangeChangeListener</code>. + * + * @param listener The listener to unregister + * + * @see #addVetoableChangeListener + */ + public void removeVetoableChangeListener(VetoableChangeListener listener) + { + listenerList.remove(VetoableChangeListener.class, listener); + } + + /** + * Register an <code>AncestorListener</code>. + * + * @param listener The listener to register + * + * @see #removeVetoableChangeListener + */ + public void addAncestorListener(AncestorListener listener) + { + listenerList.add(AncestorListener.class, listener); + } + + /** + * Register a <code>PropertyChangeListener</code>. This listener will + * receive any PropertyChangeEvent, regardless of property name. To + * listen to a specific property name, use {@link + * #addPropertyChangeListener(String,PropertyChangeListener)} instead. + * + * @param listener The listener to register + * + * @see #removePropertyChangeListener + * @see #changeSupport + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + if (changeSupport == null) + changeSupport = new SwingPropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Register a <code>PropertyChangeListener</code> for a specific, named + * property. To listen to all property changes, regardless of name, use + * {@link #addPropertyChangeListener(PropertyChangeListener)} instead. + * + * @param propertyName The property name to listen to + * @param listener The listener to register + * + * @see #removePropertyChangeListener + * @see #changeSupport + */ + public void addPropertyChangeListener(String propertyName, + PropertyChangeListener listener) + { + listenerList.add(PropertyChangeListener.class, listener); + } + + /** + * Register a <code>VetoableChangeListener</code>. + * + * @param listener The listener to register + * + * @see #removeVetoableChangeListener + * @see #listenerList + */ + public void addVetoableChangeListener(VetoableChangeListener listener) + { + listenerList.add(VetoableChangeListener.class, listener); + } + + /** + * Return all registered listeners of a particular type. + * + * @param listenerType The type of listener to return + * + * @return All listeners in the {@link #listenerList} which + * are of the specified type + * + * @see #listenerList + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Return all registered <code>AncestorListener</code> objects. + * + * @return The set of <code>AncestorListener</code> objects in {@link + * #listenerList} + */ + public AncestorListener[] getAncestorListeners() + { + return (AncestorListener[]) getListeners(AncestorListener.class); + } + + /** + * Return all registered <code>VetoableChangeListener</code> objects. + * + * @return The set of <code>VetoableChangeListener</code> objects in {@link + * #listenerList} + */ + public VetoableChangeListener[] getVetoableChangeListeners() + { + return (VetoableChangeListener[]) getListeners(VetoableChangeListener.class); + } + + /** + * Return all <code>PropertyChangeListener</code> objects registered to listen + * for a particular property. + * + * @param property The property to return the listeners of + * + * @return The set of <code>PropertyChangeListener</code> objects in + * {@link #changeSupport} registered to listen on the specified property + */ + public PropertyChangeListener[] getPropertyChangeListeners(String property) + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(property); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>boolean</code> values. + */ + public void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, Boolean.valueOf(oldValue), + Boolean.valueOf(newValue)); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>byte</code> values. + */ + public void firePropertyChange(String propertyName, byte oldValue, + byte newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Byte(oldValue), + new Byte(newValue)); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>char</code> values. + */ + public void firePropertyChange(String propertyName, char oldValue, + char newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Character(oldValue), + new Character(newValue)); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>double</code> values. + */ + public void firePropertyChange(String propertyName, double oldValue, + double newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Double(oldValue), + new Double(newValue)); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>float</code> values. + */ + public void firePropertyChange(String propertyName, float oldValue, + float newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Float(oldValue), + new Float(newValue)); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>int</code> values. + */ + public void firePropertyChange(String propertyName, int oldValue, + int newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Integer(oldValue), + new Integer(newValue)); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>long</code> values. + */ + public void firePropertyChange(String propertyName, long oldValue, + long newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Long(oldValue), + new Long(newValue)); + } + + /** + * Call {@link PropertyChangeListener#propertyChange} on all listeners + * registered to listen to a given property. Any method which changes + * the specified property of this component should call this method. + * + * @param propertyName The property which changed + * @param oldValue The old value of the property + * @param newValue The new value of the property + * + * @see #changeSupport + * @see #addPropertyChangeListener + * @see #removePropertyChangeListener + */ + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * A variant of {@link #firePropertyChange(String,Object,Object)} + * for properties with <code>short</code> values. + */ + public void firePropertyChange(String propertyName, short oldValue, + short newValue) + { + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Short(oldValue), + new Short(newValue)); + } + + /** + * Call {@link VetoableChangeListener#vetoableChange} on all listeners + * registered to listen to a given property. Any method which changes + * the specified property of this component should call this method. + * + * @param propertyName The property which changed + * @param oldValue The old value of the property + * @param newValue The new value of the property + * + * @throws PropertyVetoException if the change was vetoed by a listener + * + * @see addVetoableChangeListener + * @see removeVetoableChangeListener + */ + protected void fireVetoableChange(String propertyName, Object oldValue, + Object newValue) + throws PropertyVetoException + { + VetoableChangeListener[] listeners = getVetoableChangeListeners(); + + PropertyChangeEvent evt = new PropertyChangeEvent(this, propertyName, oldValue, newValue); + + for (int i = 0; i < listeners.length; i++) + listeners[i].vetoableChange(evt); + } + + /** + * Get the value of the accessibleContext property for this component. + * + * @return the current value of the property + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * Get the value of the {@link #alignmentX} property. + * + * @return The current value of the property. + * + * @see #setAlignmentX + * @see #alignmentY + */ + public float getAlignmentX() + { + return alignmentX; + } + + /** + * Get the value of the {@link #alignmentY} property. + * + * @return The current value of the property. + * + * @see #setAlignmentY + * @see #alignmentX + */ + public float getAlignmentY() + { + return alignmentY; + } + + /** + * Get the current value of the {@link #autoscrolls} property. + * + * @return The current value of the property + */ + public boolean getAutoscrolls() + { + return autoscrolls; + } + + /** + * Set the value of the {@link #border} property. + * + * @param newBorder The new value of the property + * + * @see #getBorder + */ + public void setBorder(Border newBorder) + { + Border oldBorder = border; + border = newBorder; + firePropertyChange("border", oldBorder, newBorder); + } + + /** + * Get the value of the {@link #border} property. + * + * @return The property's current value + * + * @see #setBorder + */ + public Border getBorder() + { + return border; + } + + /** + * Get the component's current bounding box. If a rectangle is provided, + * use this as the return value (adjusting its fields in place); + * otherwise (of <code>null</code> is provided) return a new {@link + * Rectangle}. + * + * @param rv Optional return value to use + * + * @return A rectangle bounding the component + */ + public Rectangle getBounds(Rectangle rv) + { + if (rv == null) + return new Rectangle(getX(), getY(), getWidth(), getHeight()); + else + { + rv.setBounds(getX(), getY(), getWidth(), getHeight()); + return rv; + } + } + + /** + * Prepares a graphics context for painting this object. If {@link + * #debugGraphicsOptions} is not equal to {@link + * DebugGraphics#NONE_OPTION}, produce a new {@link DebugGraphics} object + * wrapping the parameter. Otherwise configure the parameter with this + * component's foreground color and font. + * + * @param g The graphics context to wrap or configure + * + * @return A graphics context to paint this object with + * + * @see #debugGraphicsOptions + * @see #paint + */ + protected Graphics getComponentGraphics(Graphics g) + { + g.setFont (this.getFont()); + g.setColor (this.getForeground()); + return g; + } + + /** + * Get the value of the {@link #debugGraphicsOptions} property. + * + * @return The current value of the property. + * + * @see #setDebugGraphicsOptions + * @see #debugGraphicsOptions + */ + public int getDebugGraphicsOptions() + { + return 0; + } + + /** + * Get the component's insets, which are calculated from + * the {@link #border} property. If the border is <code>null</code>, + * calls {@link Container#getInsets}. + * + * @return The component's current insets + */ + public Insets getInsets() + { + if (border == null) + return super.getInsets(); + return getBorder().getBorderInsets(this); + } + + /** + * Get the component's insets, which are calculated from the {@link + * #border} property. If the border is <code>null</code>, calls {@link + * Container#getInsets}. The passed-in {@link Insets} value will be + * used as the return value, if possible. + * + * @param insets Return value object to reuse, if possible + * + * @return The component's current insets + */ + public Insets getInsets(Insets insets) + { + Insets t = getInsets(); + + if (insets == null) + return t; + + insets.left = t.left; + insets.right = t.right; + insets.top = t.top; + insets.bottom = t.bottom; + return insets; + } + + /** + * Get the component's location. The passed-in {@link Point} value + * will be used as the return value, if possible. + * + * @param rv Return value object to reuse, if possible + * + * @return The component's current location + */ + public Point getLocation(Point rv) + { + if (rv == null) + return new Point(getX(), getY()); + + rv.setLocation(getX(), getY()); + return rv; + } + + /** + * Get the component's maximum size. If the {@link #maximumSize} property + * has been explicitly set, it is returned. If the {@link #maximumSize} + * property has not been set but the {@link ui} property has been, the + * result of {@link ComponentUI#getMaximumSize} is returned. If neither + * property has been set, the result of {@link Container#getMaximumSize} + * is returned. + * + * @return The maximum size of the component + * + * @see #maximumSize + * @see #setMaximumSize + */ + public Dimension getMaximumSize() + { + if (maximumSize != null) + return maximumSize; + + if (ui != null) + { + Dimension s = ui.getMaximumSize(this); + if (s != null) + return s; + } + + Dimension p = super.getMaximumSize(); + return p; + } + + /** + * Get the component's minimum size. If the {@link #minimumSize} property + * has been explicitly set, it is returned. If the {@link #minimumSize} + * property has not been set but the {@link ui} property has been, the + * result of {@link ComponentUI#getMinimumSize} is returned. If neither + * property has been set, the result of {@link Container#getMinimumSize} + * is returned. + * + * @return The minimum size of the component + * + * @see #minimumSize + * @see #setMinimumSize + */ + public Dimension getMinimumSize() + { + if (minimumSize != null) + return minimumSize; + + if (ui != null) + { + Dimension s = ui.getMinimumSize(this); + if (s != null) + return s; + } + + Dimension p = super.getMinimumSize(); + return p; + } + + /** + * Get the component's preferred size. If the {@link #preferredSize} + * property has been explicitly set, it is returned. If the {@link + * #preferredSize} property has not been set but the {@link ui} property + * has been, the result of {@link ComponentUI#getPreferredSize} is + * returned. If neither property has been set, the result of {@link + * Container#getPreferredSize} is returned. + * + * @return The preferred size of the component + * + * @see #preferredSize + * @see #setPreferredSize + */ + public Dimension getPreferredSize() + { + Dimension prefSize = null; + if (preferredSize != null) + prefSize = preferredSize; + + else if (ui != null) + { + Dimension s = ui.getPreferredSize(this); + if (s != null) + prefSize = s; + } + + if (prefSize == null) + prefSize = super.getPreferredSize(); + // make sure that prefSize is not smaller than minSize + if (minimumSize != null && prefSize != null + && (minimumSize.width > prefSize.width + || minimumSize.height > prefSize.height)) + prefSize = new Dimension(Math.max(minimumSize.width, prefSize.width), + Math.max(minimumSize.height, prefSize.height)); + return prefSize; + } + + /** + * Checks if a maximum size was explicitely set on the component. + * + * @return <code>true</code> if a maximum size was set, + * <code>false</code> otherwise + * + * @since 1.3 + */ + public boolean isMaximumSizeSet() + { + return maximumSize != null; + } + + /** + * Checks if a minimum size was explicitely set on the component. + * + * @return <code>true</code> if a minimum size was set, + * <code>false</code> otherwise + * + * @since 1.3 + */ + public boolean isMinimumSizeSet() + { + return minimumSize != null; + } + + /** + * Checks if a preferred size was explicitely set on the component. + * + * @return <code>true</code> if a preferred size was set, + * <code>false</code> otherwise + * + * @since 1.3 + */ + public boolean isPreferredSizeSet() + { + return preferredSize != null; + } + + /** + * Return the value of the {@link #nextFocusableComponent} property. + * + * @return The current value of the property, or <code>null</code> + * if none has been set. + * + * @deprecated See {@link java.awt.FocusTraversalPolicy} + */ + public Component getNextFocusableComponent() + { + return null; + } + + /** + * Return the set of {@link KeyStroke} objects which are registered + * to initiate actions on this component. + * + * @return An array of the registered keystrokes + */ + public KeyStroke[] getRegisteredKeyStrokes() + { + return null; + } + + /** + * Returns the first ancestor of this component which is a {@link JRootPane}. + * Equivalent to calling <code>SwingUtilities.getRootPane(this);</code>. + * + * @return An ancestral JRootPane, or <code>null</code> if none exists. + */ + public JRootPane getRootPane() + { + JRootPane p = SwingUtilities.getRootPane(this); + return p; + } + + /** + * Get the component's size. The passed-in {@link Dimension} value + * will be used as the return value, if possible. + * + * @param rv Return value object to reuse, if possible + * + * @return The component's current size + */ + public Dimension getSize(Dimension rv) + { + if (rv == null) + return new Dimension(getWidth(), getHeight()); + else + { + rv.setSize(getWidth(), getHeight()); + return rv; + } + } + + /** + * Return the {@link #toolTip} property of this component, creating it and + * setting it if it is currently <code>null</code>. This method can be + * overridden in subclasses which wish to control the exact form of + * tooltip created. + * + * @return The current toolTip + */ + public JToolTip createToolTip() + { + JToolTip toolTip = new JToolTip(); + toolTip.setComponent(this); + toolTip.setTipText(toolTipText); + + return toolTip; + } + + /** + * Return the location at which the {@link #toolTip} property should be + * displayed, when triggered by a particular mouse event. + * + * @param event The event the tooltip is being presented in response to + * + * @return The point at which to display a tooltip, or <code>null</code> + * if swing is to choose a default location. + */ + public Point getToolTipLocation(MouseEvent event) + { + return null; + } + + /** + * Set the value of the {@link #toolTipText} property. + * + * @param text The new property value + * + * @see #getToolTipText + */ + public void setToolTipText(String text) + { + if (text == null) + { + ToolTipManager.sharedInstance().unregisterComponent(this); + toolTipText = null; + return; + } + + // XXX: The tip text doesn't get updated unless you set it to null + // and then to something not-null. This is consistent with the behaviour + // of Sun's ToolTipManager. + + String oldText = toolTipText; + toolTipText = text; + + if (oldText == null) + ToolTipManager.sharedInstance().registerComponent(this); + } + + /** + * Get the value of the {@link #toolTipText} property. + * + * @return The current property value + * + * @see #setToolTipText + */ + public String getToolTipText() + { + return toolTipText; + } + + /** + * Get the value of the {@link #toolTipText} property, in response to a + * particular mouse event. + * + * @param event The mouse event which triggered the tooltip + * + * @return The current property value + * + * @see #setToolTipText + */ + public String getToolTipText(MouseEvent event) + { + return getToolTipText(); + } + + /** + * Return the top level ancestral container (usually a {@link + * java.awt.Window} or {@link java.awt.Applet}) which this component is + * contained within, or <code>null</code> if no ancestors exist. + * + * @return The top level container, if it exists + */ + public Container getTopLevelAncestor() + { + Container c = getParent(); + for (Container peek = c; peek != null; peek = peek.getParent()) + c = peek; + return c; + } + + /** + * Compute the component's visible rectangle, which is defined + * recursively as either the component's bounds, if it has no parent, or + * the intersection of the component's bounds with the visible rectangle + * of its parent. + * + * @param rect The return value slot to place the visible rectangle in + */ + public void computeVisibleRect(Rectangle rect) + { + Component c = getParent(); + if (c != null && c instanceof JComponent) + { + ((JComponent) c).computeVisibleRect(rect); + rect.translate(-getX(), -getY()); + Rectangle2D.intersect(rect, + new Rectangle(0, 0, getWidth(), getHeight()), + rect); + } + else + rect.setRect(0, 0, getWidth(), getHeight()); + } + + /** + * Return the component's visible rectangle in a new {@link Rectangle}, + * rather than via a return slot. + * + * @return The component's visible rectangle + * + * @see #computeVisibleRect(Rectangle) + */ + public Rectangle getVisibleRect() + { + Rectangle r = new Rectangle(); + computeVisibleRect(r); + return r; + } + + /** + * <p>Requests that this component receive input focus, giving window + * focus to the top level ancestor of this component. Only works on + * displayable, focusable, visible components.</p> + * + * <p>This method should not be called by clients; it is intended for + * focus implementations. Use {@link Component#requestFocus} instead.</p> + * + * @see {@link Component#requestFocus} + */ + public void grabFocus() + { + } + + /** + * Get the value of the {@link #doubleBuffered} property. + * + * @return The property's current value + */ + public boolean isDoubleBuffered() + { + return doubleBuffered; + } + + /** + * Return <code>true</code> if the provided component has no native peer; + * in other words, if it is a "lightweight component". + * + * @param c The component to test for lightweight-ness + * + * @return Whether or not the component is lightweight + */ + public static boolean isLightweightComponent(Component c) + { + return c.getPeer() instanceof LightweightPeer; + } + + /** + * Return <code>true</code> if you wish this component to manage its own + * focus. In particular: if you want this component to be sent + * <code>TAB</code> and <code>SHIFT+TAB</code> key events, and to not + * have its children considered as focus transfer targets. If + * <code>true</code>, focus traversal around this component changes to + * <code>CTRL+TAB</code> and <code>CTRL+SHIFT+TAB</code>. + * + * @return <code>true</code> if you want this component to manage its own + * focus, otherwise (by default) <code>false</code> + * + * @deprecated 1.4 Use {@link Component.setFocusTraversalKeys(int,Set)} and + * {@link Container.setFocusCycleRoot(boolean)} instead + */ + public boolean isManagingFocus() + { + return false; + } + + /** + * Return the current value of the {@link opaque} property. + * + * @return The current property value + */ + public boolean isOpaque() + { + return opaque; + } + + /** + * Return <code>true</code> if the component can guarantee that none of its + * children will overlap in Z-order. This is a hint to the painting system. + * The default is to return <code>true</code>, but some components such as + * {@link JLayeredPane} should override this to return <code>false</code>. + * + * @return Whether the component tiles its children + */ + public boolean isOptimizedDrawingEnabled() + { + return true; + } + + /** + * Return <code>true</code> if this component is currently painting a tile. + * + * @return Whether the component is painting a tile + */ + public boolean isPaintingTile() + { + return false; + } + + /** + * Get the value of the {@link #requestFocusEnabled} property. + * + * @return The current value of the property + */ + public boolean isRequestFocusEnabled() + { + return requestFocusEnabled; + } + + /** + * Return <code>true</code> if this component is a validation root; this + * will cause calls to {@link #invalidate} in this component's children + * to be "captured" at this component, and not propagate to its parents. + * For most components this should return <code>false</code>, but some + * components such as {@link JViewPort} will want to return + * <code>true</code>. + * + * @return Whether this component is a validation root + */ + public boolean isValidateRoot() + { + return false; + } + + /** + * <p>Paint the component. This is a delicate process, and should only be + * called from the repaint thread, under control of the {@link + * RepaintManager}. Client code should usually call {@link #repaint} to + * trigger painting.</p> + * + * <p>This method will acquire a double buffer from the {@link + * RepaintManager} if the component's {@link #doubleBuffered} property is + * <code>true</code> and the <code>paint</code> call is the + * <em>first</em> recursive <code>paint</code> call inside swing.</p> + * + * <p>The method will also modify the provided {@link Graphics} context + * via the {@link #getComponentGraphics} method. If you want to customize + * the graphics object used for painting, you should override that method + * rather than <code>paint</code>.</p> + * + * <p>The body of the <code>paint</code> call involves calling {@link + * #paintComponent}, {@link #paintBorder}, and {@link #paintChildren} in + * order. If you want to customize painting behavior, you should override + * one of these methods rather than <code>paint</code>.</p> + * + * <p>For more details on the painting sequence, see <a + * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html"> + * this article</a>.</p> + * + * @param g The graphics context to paint with + * + * @see #paintImmediately + */ + public void paint(Graphics g) + { + Graphics g2 = g; + Image doubleBuffer = null; + RepaintManager rm = RepaintManager.currentManager(this); + + if (isDoubleBuffered() + && (rm.isDoubleBufferingEnabled()) + && (! Thread.holdsLock(paintLock))) + { + doubleBuffer = rm.getOffscreenBuffer(this, getWidth(), getHeight()); + } + + synchronized (paintLock) + { + if (doubleBuffer != null) + { + g2 = doubleBuffer.getGraphics(); + g2.setClip(g.getClipBounds()); + } + + g2 = getComponentGraphics(g2); + paintComponent(g2); + paintBorder(g2); + paintChildren(g2); + + if (doubleBuffer != null) + g.drawImage(doubleBuffer, 0, 0, (ImageObserver) null); + } + } + + /** + * Paint the component's border. This usually means calling {@link + * Border#paintBorder} on the {@link #border} property, if it is + * non-<code>null</code>. You may override this if you wish to customize + * border painting behavior. The border is painted after the component's + * body, but before the component's children. + * + * @param g The graphics context with which to paint the border + * + * @see #paint + * @see #paintChildren + * @see #paintComponent + */ + protected void paintBorder(Graphics g) + { + if (getBorder() != null) + getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight()); + } + + /** + * Paint the component's children. This usually means calling {@link + * Container#paint}, which recursively calls {@link #paint} on any of the + * component's children, with appropriate changes to coordinate space and + * clipping region. You may override this if you wish to customize + * children painting behavior. The children are painted after the + * component's body and border. + * + * @param g The graphics context with which to paint the children + * + * @see #paint + * @see #paintBorder + * @see #paintComponent + */ + protected void paintChildren(Graphics g) + { + super.paint(g); + } + + /** + * Paint the component's body. This usually means calling {@link + * ComponentUI#update} on the {@link #ui} property of the component, if + * it is non-<code>null</code>. You may override this if you wish to + * customize the component's body-painting behavior. The component's body + * is painted first, before the border and children. + * + * @param g The graphics context with which to paint the body + * + * @see #paint + * @see #paintBorder + * @see #paintChildren + */ + protected void paintComponent(Graphics g) + { + if (ui != null) + { + Graphics g2 = g; + if (!(g instanceof Graphics2D)) + g2 = g.create(); + ui.update(getComponentGraphics(g2), this); + if (!(g instanceof Graphics2D)) + g2.dispose(); + } + } + + /** + * A variant of {@link #paintImmediately(Rectangle)} which takes + * integer parameters. + * + * @param x The left x coordinate of the dirty region + * @param y The top y coordinate of the dirty region + * @param w The width of the dirty region + * @param h The height of the dirty region + */ + public void paintImmediately(int x, int y, int w, int h) + { + paintImmediately(new Rectangle(x, y, w, h)); + } + + /** + * Transform the provided dirty rectangle for this component into the + * appropriate ancestral {@link JRootPane} and call {@link #paint} on + * that root pane. This method is called from the {@link RepaintManager} + * and should always be called within the painting thread. + * + * @param r The dirty rectangle to paint + */ + public void paintImmediately(Rectangle r) + { + Component root = SwingUtilities.getRoot(this); + if (root == null || ! root.isShowing()) + return; + Graphics g = root.getGraphics(); + if (g == null) + return; + + Rectangle clip = SwingUtilities.convertRectangle(this, r, root); + g.setClip(clip); + root.paint(g); + g.dispose(); + } + + /** + * Return a string representation for this component, for use in + * debugging. + * + * @return A string describing this component. + */ + protected String paramString() + { + StringBuffer sb = new StringBuffer(); + sb.append(super.paramString()); + sb.append(",alignmentX=").append(getAlignmentX()); + sb.append(",alignmentY=").append(getAlignmentY()); + sb.append(",border="); + if (getBorder() != null) + sb.append(getBorder()); + sb.append(",maximumSize="); + if (getMaximumSize() != null) + sb.append(getMaximumSize()); + sb.append(",minimumSize="); + if (getMinimumSize() != null) + sb.append(getMinimumSize()); + sb.append(",preferredSize="); + if (getPreferredSize() != null) + sb.append(getPreferredSize()); + return sb.toString(); + } + + /** + * A variant of {@link + * #registerKeyboardAction(ActionListener,String,KeyStroke,int)} which + * provides <code>null</code> for the command name. + */ + public void registerKeyboardAction(ActionListener act, + KeyStroke stroke, + int cond) + { + registerKeyboardAction(act, null, stroke, cond); + } + + /* + * There is some charmingly undocumented behavior sun seems to be using + * to simulate the old register/unregister keyboard binding API. It's not + * clear to me why this matters, but we shall endeavour to follow suit. + * + * Two main thing seem to be happening when you do registerKeyboardAction(): + * + * - no actionMap() entry gets created, just an entry in inputMap() + * + * - the inputMap() entry is a proxy class which invokes the the + * binding's actionListener as a target, and which clobbers the command + * name sent in the ActionEvent, providing the binding command name + * instead. + * + * This much you can work out just by asking the input and action maps + * what they contain after making bindings, and watching the event which + * gets delivered to the recipient. Beyond that, it seems to be a + * sun-private solution so I will only immitate it as much as it matters + * to external observers. + */ + private static class ActionListenerProxy + extends AbstractAction + { + ActionListener target; + String bindingCommandName; + + public ActionListenerProxy(ActionListener li, + String cmd) + { + target = li; + bindingCommandName = cmd; + } + + public void actionPerformed(ActionEvent e) + { + ActionEvent derivedEvent = new ActionEvent(e.getSource(), + e.getID(), + bindingCommandName, + e.getModifiers()); + target.actionPerformed(derivedEvent); + } + } + + + /** + * An obsolete method to register a keyboard action on this component. + * You should use <code>getInputMap</code> and <code>getActionMap</code> + * to fetch mapping tables from keystrokes to commands, and commands to + * actions, respectively, and modify those mappings directly. + * + * @param anAction The action to be registered + * @param aCommand The command to deliver in the delivered {@link + * java.awt.ActionEvent} + * @param aKeyStroke The keystroke to register on + * @param aCondition One of the values {@link #UNDEFINED_CONDITION}, + * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or + * {@link #WHEN_IN_FOCUSED_WINDOW}, indicating the condition which must + * be met for the action to be fired + * + * @see #unregisterKeyboardAction + * @see #getConditionForKeystroke + * @see #resetKeyboardActiond + */ + public void registerKeyboardAction(ActionListener act, + String cmd, + KeyStroke stroke, + int cond) + { + getInputMap(cond).put(stroke, new ActionListenerProxy(act, cmd)); + } + + public final void setInputMap(int condition, InputMap map) + { + enableEvents(AWTEvent.KEY_EVENT_MASK); + switch (condition) + { + case WHEN_FOCUSED: + inputMap_whenFocused = map; + break; + + case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: + inputMap_whenAncestorOfFocused = map; + break; + + case WHEN_IN_FOCUSED_WINDOW: + inputMap_whenInFocusedWindow = map; + break; + + case UNDEFINED_CONDITION: + default: + throw new IllegalArgumentException(); + } + } + + public final InputMap getInputMap(int condition) + { + enableEvents(AWTEvent.KEY_EVENT_MASK); + switch (condition) + { + case WHEN_FOCUSED: + if (inputMap_whenFocused == null) + inputMap_whenFocused = new InputMap(); + return inputMap_whenFocused; + + case WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: + if (inputMap_whenAncestorOfFocused == null) + inputMap_whenAncestorOfFocused = new InputMap(); + return inputMap_whenAncestorOfFocused; + + case WHEN_IN_FOCUSED_WINDOW: + if (inputMap_whenInFocusedWindow == null) + inputMap_whenInFocusedWindow = new InputMap(); + return inputMap_whenInFocusedWindow; + + case UNDEFINED_CONDITION: + default: + return null; + } + } + + public final InputMap getInputMap() + { + return getInputMap(WHEN_FOCUSED); + } + + public final ActionMap getActionMap() + { + if (actionMap == null) + actionMap = new ActionMap(); + return actionMap; + } + + public final void setActionMap(ActionMap map) + { + actionMap = map; + } + + /** + * Return the condition that determines whether a registered action + * occurs in response to the specified keystroke. + * + * @param aKeyStroke The keystroke to return the condition of + * + * @return One of the values {@link #UNDEFINED_CONDITION}, {@link + * #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}, {@link #WHEN_FOCUSED}, or {@link + * #WHEN_IN_FOCUSED_WINDOW} + * + * @deprecated As of 1.3 KeyStrokes can be registered with multiple + * simultaneous conditions. + * + * @see #registerKeyboardAction + * @see #unregisterKeyboardAction + * @see #resetKeyboardActiond + */ + public int getConditionForKeyStroke(KeyStroke ks) + { + if (inputMap_whenFocused != null + && inputMap_whenFocused.get(ks) != null) + return WHEN_FOCUSED; + else if (inputMap_whenAncestorOfFocused != null + && inputMap_whenAncestorOfFocused.get(ks) != null) + return WHEN_ANCESTOR_OF_FOCUSED_COMPONENT; + else if (inputMap_whenInFocusedWindow != null + && inputMap_whenInFocusedWindow.get(ks) != null) + return WHEN_IN_FOCUSED_WINDOW; + else + return UNDEFINED_CONDITION; + } + + /** + * Get the ActionListener (typically an {@link Action} object) which is + * associated with a particular keystroke. + * + * @param aKeyStroke The keystroke to retrieve the action of + * + * @return The action associated with the specified keystroke + * + * @deprecated Use {@link #getActionMap()} + */ + public ActionListener getActionForKeyStroke(KeyStroke ks) + { + Object cmd = getInputMap().get(ks); + if (cmd != null) + { + if (cmd instanceof ActionListenerProxy) + return (ActionListenerProxy) cmd; + else if (cmd instanceof String) + return getActionMap().get(cmd); + } + return null; + } + + /** + * A hook for subclasses which want to customize event processing. + */ + protected void processComponentKeyEvent(KeyEvent e) + { + } + + /** + * Override the default key dispatch system from Component to hook into + * the swing {@link InputMap} / {@link ActionMap} system. + * + * See <a + * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html"> + * this report</a> for more details, it's somewhat complex. + */ + protected void processKeyEvent(KeyEvent e) + { + // let the AWT event processing send KeyEvents to registered listeners + super.processKeyEvent(e); + processComponentKeyEvent(e); + + // FIXME: this needs to be elaborated significantly, to do all the + // focus / ancestor / window searching for the various binding modes. + if (! e.isConsumed() && + processKeyBinding(KeyStroke.getKeyStrokeForEvent(e), + e, WHEN_FOCUSED, e.getID() == KeyEvent.KEY_PRESSED)) + e.consume(); + } + + protected boolean processKeyBinding(KeyStroke ks, + KeyEvent e, + int condition, + boolean pressed) + { + if (isEnabled()) + { + Action act = null; + InputMap map = getInputMap(condition); + if (map != null) + { + Object cmd = map.get(ks); + if (cmd != null) + { + if (cmd instanceof ActionListenerProxy) + act = (Action) cmd; + else + act = (Action) getActionMap().get(cmd); + } + } + if (act != null && act.isEnabled()) + return SwingUtilities.notifyAction(act, ks, e, this, e.getModifiers()); + } + return false; + } + + /** + * Remove a keyboard action registry. + * + * @param stroke The keystroke to unregister + * + * @see #registerKeyboardAction + * @see #getConditionForKeystroke + * @see #resetKeyboardActiond + */ + public void unregisterKeyboardAction(KeyStroke aKeyStroke) + { + // FIXME: Must be implemented. + } + + + /** + * Reset all keyboard action registries. + * + * @see #registerKeyboardAction + * @see #unregisterKeyboardAction + * @see #getConditionForKeystroke + */ + public void resetKeyboardActions() + { + if (inputMap_whenFocused != null) + inputMap_whenFocused.clear(); + if (inputMap_whenAncestorOfFocused != null) + inputMap_whenAncestorOfFocused.clear(); + if (inputMap_whenInFocusedWindow != null) + inputMap_whenInFocusedWindow.clear(); + if (actionMap != null) + actionMap.clear(); + } + + /** + * Mark the described region of this component as dirty in the current + * {@link RepaintManager}. This will queue an asynchronous repaint using + * the system painting thread in the near future. + * + * @param tm ignored + * @param x coordinate of the region to mark as dirty + * @param y coordinate of the region to mark as dirty + * @param width dimension of the region to mark as dirty + * @param height dimension of the region to mark as dirty + */ + public void repaint(long tm, int x, int y, int width, int height) + { + Rectangle dirty = new Rectangle(x, y, width, height); + Rectangle vis = getVisibleRect(); + dirty = dirty.intersection(vis); + RepaintManager.currentManager(this).addDirtyRegion(this, dirty.x, dirty.y, + dirty.width, + dirty.height); + } + + /** + * Mark the described region of this component as dirty in the current + * {@link RepaintManager}. This will queue an asynchronous repaint using + * the system painting thread in the near future. + * + * @param r The rectangle to mark as dirty + */ + public void repaint(Rectangle r) + { + repaint((long) 0, (int) r.getX(), (int) r.getY(), (int) r.getWidth(), + (int) r.getHeight()); + } + + /** + * Request focus on the default component of this component's {@link + * FocusTraversalPolicy}. + * + * @return The result of {@link #requestFocus} + * + * @deprecated Use {@link #requestFocus()} on the default component provided + * from the {@link FocusTraversalPolicy} instead. + */ + public boolean requestDefaultFocus() + { + return false; + } + + /** + * Queue a an invalidation and revalidation of this component, using + * {@link RepaintManager#addInvalidComponent}. + */ + public void revalidate() + { + invalidate(); + RepaintManager.currentManager(this).addInvalidComponent(this); + } + + /** + * Calls <code>scrollRectToVisible</code> on the component's parent. + * Components which can service this call should override. + * + * @param r The rectangle to make visible + */ + public void scrollRectToVisible(Rectangle r) + { + Component p = getParent(); + if (p instanceof JComponent) + ((JComponent) p).scrollRectToVisible(r); + } + + /** + * Set the value of the {@link #alignmentX} property. + * + * @param a The new value of the property + */ + public void setAlignmentX(float a) + { + alignmentX = a; + } + + /** + * Set the value of the {@link #alignmentY} property. + * + * @param a The new value of the property + */ + public void setAlignmentY(float a) + { + alignmentY = a; + } + + /** + * Set the value of the {@link #autoscrolls} property. + * + * @param a The new value of the property + */ + public void setAutoscrolls(boolean a) + { + autoscrolls = a; + } + + /** + * Set the value of the {@link #debugGraphicsOptions} property. + * + * @param debugOptions The new value of the property + */ + public void setDebugGraphicsOptions(int debugOptions) + { + debugGraphicsOptions = debugOptions; + } + + /** + * Set the value of the {@link #doubleBuffered} property. + * + * @param db The new value of the property + */ + public void setDoubleBuffered(boolean db) + { + doubleBuffered = db; + } + + /** + * Set the value of the {@link #enabled} property. + * + * @param enable The new value of the property + */ + public void setEnabled(boolean enable) + { + boolean oldEnabled = isEnabled(); + super.setEnabled(enable); + firePropertyChange("enabled", oldEnabled, enable); + } + + /** + * Set the value of the {@link #font} property. + * + * @param f The new value of the property + */ + public void setFont(Font f) + { + super.setFont(f); + } + + /** + * Set the value of the {@link #background} property. + * + * @param bg The new value of the property + */ + public void setBackground(Color bg) + { + super.setBackground(bg); + } + + /** + * Set the value of the {@link #foreground} property. + * + * @param fg The new value of the property + */ + public void setForeground(Color fg) + { + super.setForeground(fg); + } + + /** + * Set the value of the {@link #maximumSize} property. + * + * @param max The new value of the property + */ + public void setMaximumSize(Dimension max) + { + Dimension oldMaximumSize = maximumSize; + maximumSize = max; + firePropertyChange("maximumSize", oldMaximumSize, maximumSize); + } + + /** + * Set the value of the {@link #minimumSize} property. + * + * @param min The new value of the property + */ + public void setMinimumSize(Dimension min) + { + Dimension oldMinimumSize = minimumSize; + minimumSize = min; + firePropertyChange("minimumSize", oldMinimumSize, minimumSize); + } + + /** + * Set the value of the {@link #preferredSize} property. + * + * @param pref The new value of the property + */ + public void setPreferredSize(Dimension pref) + { + Dimension oldPreferredSize = preferredSize; + preferredSize = pref; + firePropertyChange("preferredSize", oldPreferredSize, preferredSize); + } + + /** + * Set the specified component to be the next component in the + * focus cycle, overriding the {@link FocusTraversalPolicy} for + * this component. + * + * @param aComponent The component to set as the next focusable + * + * @deprecated Use FocusTraversalPolicy instead + */ + public void setNextFocusableComponent(Component aComponent) + { + } + + /** + * Set the value of the {@link #requestFocusEnabled} property. + * + * @param e The new value of the property + */ + public void setRequestFocusEnabled(boolean e) + { + requestFocusEnabled = e; + } + + /** + * Get the value of the {@link #transferHandler} property. + * + * @return The current value of the property + * + * @see ComponentUI#setTransferHandler + */ + + public TransferHandler getTransferHandler() + { + return transferHandler; + } + + /** + * Set the value of the {@link #transferHandler} property. + * + * @param newHandler The new value of the property + * + * @see ComponentUI#getTransferHandler + */ + + public void setTransferHandler(TransferHandler newHandler) + { + if (transferHandler == newHandler) + return; + + TransferHandler oldHandler = transferHandler; + transferHandler = newHandler; + firePropertyChange("transferHandler", oldHandler, newHandler); + } + + /** + * Set the value of the {@link #opaque} property. + * + * @param isOpaque The new value of the property + * + * @see ComponentUI#update + */ + public void setOpaque(boolean isOpaque) + { + boolean oldOpaque = opaque; + opaque = isOpaque; + firePropertyChange("opaque", oldOpaque, opaque); + } + + /** + * Set the value of the visible property. + * + * @param v The new value of the property + */ + public void setVisible(boolean v) + { + super.setVisible(v); + } + + /** + * Call {@link paint}. + * + * @param g The graphics context to paint into + */ + public void update(Graphics g) + { + paint(g); + } + + /** + * Get the value of the UIClassID property. This property should be a key + * in the {@link UIDefaults} table managed by {@link UIManager}, the + * value of which is the name of a class to load for the component's + * {@link ui} property. + * + * @return A "symbolic" name which will map to a class to use for the + * component's UI, such as <code>"ComponentUI"</code> + * + * @see #setUI + * @see #updateUI + */ + public String getUIClassID() + { + return "ComponentUI"; + } + + /** + * Install a new UI delegate as the component's {@link ui} property. In + * the process, this will call {@link ComponentUI.uninstallUI} on any + * existing value for the {@link ui} property, and {@link + * ComponentUI.installUI} on the new UI delegate. + * + * @param newUI The new UI delegate to install + * + * @see #updateUI + * @see #getUIClassID + */ + protected void setUI(ComponentUI newUI) + { + if (ui != null) + ui.uninstallUI(this); + + ComponentUI oldUI = ui; + ui = newUI; + + if (ui != null) + ui.installUI(this); + + firePropertyChange("UI", oldUI, newUI); + + } + + /** + * This method should be overridden in subclasses. In JComponent, the + * method does nothing. In subclasses, it should a UI delegate + * (corresponding to the symbolic name returned from {@link + * getUIClassID}) from the {@link UIManager}, and calls {@link setUI} + * with the new delegate. + */ + public void updateUI() + { + System.out.println("update UI not overwritten in class: " + this); + } + + public static Locale getDefaultLocale() + { + return defaultLocale; + } + + public static void setDefaultLocale(Locale l) + { + defaultLocale = l; + } + + /** + * Returns the currently set input verifier for this component. + * + * @return the input verifier, or <code>null</code> if none + */ + public InputVerifier getInputVerifier() + { + return inputVerifier; + } + + /** + * Sets the input verifier to use by this component. + * + * @param verifier the input verifier, or <code>null</code> + */ + public void setInputVerifier(InputVerifier verifier) + { + InputVerifier oldVerifier = inputVerifier; + inputVerifier = verifier; + firePropertyChange("inputVerifier", oldVerifier, verifier); + } + + /** + * @since 1.3 + */ + public boolean getVerifyInputWhenFocusTarget() + { + return verifyInputWhenFocusTarget; + } + + /** + * @since 1.3 + */ + public void setVerifyInputWhenFocusTarget(boolean verifyInputWhenFocusTarget) + { + if (this.verifyInputWhenFocusTarget == verifyInputWhenFocusTarget) + return; + + this.verifyInputWhenFocusTarget = verifyInputWhenFocusTarget; + firePropertyChange("verifyInputWhenFocusTarget", + ! verifyInputWhenFocusTarget, + verifyInputWhenFocusTarget); + } + + /** + * Requests that this component gets the input focus if the + * requestFocusEnabled property is set to <code>true</code>. + * This also means that this component's top-level window becomes + * the focused window, if that is not already the case. + * + * The preconditions that have to be met to become a focus owner is that + * the component must be displayable, visible and focusable. + * + * Note that this signals only a request for becoming focused. There are + * situations in which it is not possible to get the focus. So developers + * should not assume that the component has the focus until it receives + * a {@link java.awt.event.FocusEvent} with a value of + * {@link java.awt.event.FocusEvent.FOCUS_GAINED}. + * + * @see {@link Component#requestFocus()} + */ + public void requestFocus() + { + if (isRequestFocusEnabled()) + super.requestFocus(); + } + + /** + * This method is overridden to make it public so that it can be used + * by look and feel implementations. + * + * You should not use this method directly. Instead you are strongly + * encouraged to call {@link #requestFocus} or {@link #requestFocusInWindow} + * instead. + * + * @param temporary if the focus change is temporary + * + * @return <code>false</code> if the focus change request will definitly + * fail, <code>true</code> if it will likely succeed + * + * @see {@link Component#requestFocus(boolean)} + * + * @since 1.4 + */ + public boolean requestFocus(boolean temporary) + { + return super.requestFocus(temporary); + } + + /** + * Requests that this component gets the input focus if the top level + * window that contains this component has the focus and the + * requestFocusEnabled property is set to <code>true</code>. + * + * The preconditions that have to be met to become a focus owner is that + * the component must be displayable, visible and focusable. + * + * Note that this signals only a request for becoming focused. There are + * situations in which it is not possible to get the focus. So developers + * should not assume that the component has the focus until it receives + * a {@link java.awt.event.FocusEvent} with a value of + * {@link java.awt.event.FocusEvent.FOCUS_GAINED}. + * + * @return <code>false</code> if the focus change request will definitly + * fail, <code>true</code> if it will likely succeed + * + * @see {@link Component#requestFocusInWindow()} + */ + public boolean requestFocusInWindow() + { + if (isRequestFocusEnabled()) + return super.requestFocusInWindow(); + else + return false; + } + + /** + * This method is overridden to make it public so that it can be used + * by look and feel implementations. + * + * You should not use this method directly. Instead you are strongly + * encouraged to call {@link #requestFocus} or {@link #requestFocusInWindow} + * instead. + * + * @param temporary if the focus change is temporary + * + * @return <code>false</code> if the focus change request will definitly + * fail, <code>true</code> if it will likely succeed + * + * @see {@link Component#requestFocus(boolean)} + * + * @since 1.4 + */ + public boolean requestFocusInWindow(boolean temporary) + { + return super.requestFocusInWindow(temporary); + } + + /** + * Receives notification if this component is added to a parent component. + * + * Notification is sent to all registered AncestorListeners about the + * new parent. + * + * This method sets up ActionListeners for all registered KeyStrokes of + * this component in the chain of parent components. + * + * A PropertyChange event is fired to indicate that the ancestor property + * has changed. + * + * This method is used internally and should not be used in applications. + */ + public void addNotify() + { + super.addNotify(); + + // let parents inherit the keybord mapping + InputMap input = getInputMap(); + ActionMap actions = getActionMap(); + + Container parent = getParent(); + while ((parent != null) && (parent instanceof JComponent)) + { + JComponent jParent = (JComponent) parent; + InputMap parentInput = jParent.getInputMap(); + ActionMap parentAction = jParent.getActionMap(); + + KeyStroke[] ikeys = input.keys(); + for (int i = 0; i < ikeys.length; i++) + { + Object o = input.get(ikeys[i]); + parentInput.put(ikeys[i], o); + } + + Object[] akeys = actions.keys(); + for (int i = 0; i < akeys.length; i++) + { + Action a = actions.get(akeys[i]); + parentAction.put(akeys[i], a); + } + + parent = jParent.getParent(); + } + + // notify ancestor listeners + AncestorListener[] ls = getAncestorListeners(); + AncestorEvent ev = new AncestorEvent(this, AncestorEvent.ANCESTOR_ADDED, + this, parent); + for (int i = 0; i < ls.length; i++) + { + ls[i].ancestorAdded(ev); + } + + // fire property change event for 'ancestor' + firePropertyChange("ancestor", null, parent); + } + + /** + * Receives notification that this component no longer has a parent. + * + * This method sends an AncestorEvent to all registered AncestorListeners, + * notifying them that the parent is gone. + * + * The keybord actions of this component are removed from the parent and + * its ancestors. + * + * A PropertyChangeEvent is fired to indicate that the 'ancestor' property + * has changed. + * + * This method is called before the component is actually removed from + * its parent, so the parent is still visible through {@link #getParent}. + */ + public void removeNotify() + { + super.removeNotify(); + + // let parents inherit the keybord mapping + InputMap input = getInputMap(); + ActionMap actions = getActionMap(); + + Container parent = getParent(); + while ((parent != null) && (parent instanceof JComponent)) + { + JComponent jParent = (JComponent) parent; + InputMap parentInput = jParent.getInputMap(); + ActionMap parentAction = jParent.getActionMap(); + + KeyStroke[] ikeys = input.allKeys(); + for (int i = 0; i < ikeys.length; i++) + { + parentInput.remove(ikeys[i]); + } + + Object[] akeys = actions.allKeys(); + for (int i = 0; i < akeys.length; i++) + { + parentAction.remove(akeys[i]); + } + + parent = jParent.getParent(); + } + + // notify ancestor listeners + AncestorListener[] ls = getAncestorListeners(); + AncestorEvent ev = new AncestorEvent(this, AncestorEvent.ANCESTOR_ADDED, + this, parent); + for (int i = 0; i < ls.length; i++) + { + ls[i].ancestorAdded(ev); + } + + // fire property change event for 'ancestor' + firePropertyChange("ancestor", parent, null); + } + + /** + * Returns <code>true</code> if the coordinates (x, y) lie within + * the bounds of this component and <code>false</code> otherwise. + * x and y are relative to the coordinate space of the component. + * + * @param x the X coordinate of the point to check + * @param y the Y coordinate of the point to check + * + * @return <code>true</code> if the specified point lies within the bounds + * of this component, <code>false</code> otherwise + */ + public boolean contains(int x, int y) + { + if (ui == null) + return super.contains(x, y); + else + return ui.contains(this, x, y); + } + + /** + * Disables this component. + * + * @deprecated replaced by {@link #setEnabled(boolean)} + */ + public void disable() + { + super.disable(); + } + + /** + * Enables this component. + * + * @deprecated replaced by {@link #setEnabled(boolean)} + */ + public void enable() + { + super.enable(); + } + + /** + * Returns the Graphics context for this component. This can be used + * to draw on a component. + * + * @return the Graphics context for this component + */ + public Graphics getGraphics() + { + return super.getGraphics(); + } + + /** + * Returns the X coordinate of the upper left corner of this component. + * Prefer this method over {@link #getBounds} or {@link #getLocation} + * because it does not cause any heap allocation. + * + * @return the X coordinate of the upper left corner of the component + */ + public int getX() + { + return super.getX(); + } + + /** + * Returns the Y coordinate of the upper left corner of this component. + * Prefer this method over {@link #getBounds} or {@link #getLocation} + * because it does not cause any heap allocation. + * + * @return the Y coordinate of the upper left corner of the component + */ + public int getY() + { + return super.getY(); + } + + /** + * Returns the height of this component. Prefer this method over + * {@link #getBounds} or {@link #getSize} because it does not cause + * any heap allocation. + * + * @return the height of the component + */ + public int getHeight() + { + return super.getHeight(); + } + + /** + * Returns the width of this component. Prefer this method over + * {@link #getBounds} or {@link #getSize} because it does not cause + * any heap allocation. + * + * @return the width of the component + */ + public int getWidth() + { + return super.getWidth(); + } + + /** + * Return all <code>PropertyChangeListener</code> objects registered. + * + * @return The set of <code>PropertyChangeListener</code> objects + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + if (changeSupport == null) + return new PropertyChangeListener[0]; + else + return changeSupport.getPropertyChangeListeners(); + } + + /** + * Prints this component to the given Graphics context. A call to this + * method results in calls to the methods {@link #printComponent}, + * {@link #printBorder} and {@link printChildren} in this order. + * + * Double buffering is temporarily turned off so the painting goes directly + * to the supplied Graphics context. + * + * @param g the Graphics context to print onto + */ + public void print(Graphics g) + { + boolean doubleBufferState = isDoubleBuffered(); + setDoubleBuffered(false); + printComponent(g); + printBorder(g); + printChildren(g); + setDoubleBuffered(doubleBufferState); + } + + /** + * Prints this component to the given Graphics context. This invokes + * {@link #print}. + * + * @param g the Graphics context to print onto + */ + public void printAll(Graphics g) + { + print(g); + } + + /** + * Prints this component to the specified Graphics context. The default + * behaviour is to invoke {@link #paintComponent}. Override this + * if you want special behaviour for printing. + * + * @param g the Graphics context to print onto + * + * @since 1.3 + */ + public void printComponent(Graphics g) + { + paintComponent(g); + } + + /** + * Print this component's children to the specified Graphics context. + * The default behaviour is to invoke {@link #paintChildren}. Override this + * if you want special behaviour for printing. + * + * @param g the Graphics context to print onto + * + * @since 1.3 + */ + public void printChildren(Graphics g) + { + paintChildren(g); + } + + /** + * Print this component's border to the specified Graphics context. + * The default behaviour is to invoke {@link #paintBorder}. Override this + * if you want special behaviour for printing. + * + * @param g the Graphics context to print onto + * + * @since 1.3 + */ + public void printBorder(Graphics g) + { + paintBorder(g); + } + + /** + * Processes mouse motion event, like dragging and moving. + * + * @param ev the MouseEvent describing the mouse motion + */ + protected void processMouseMotionEvent(MouseEvent ev) + { + super.processMouseMotionEvent(ev); + } + + /** + * Moves and resizes the component. + * + * @param x the new horizontal location + * @param y the new vertial location + * @param w the new width + * @param h the new height + */ + public void reshape(int x, int y, int w, int h) + { + super.reshape(x, y, w, h); + } +} diff --git a/libjava/classpath/javax/swing/JDesktopPane.java b/libjava/classpath/javax/swing/JDesktopPane.java new file mode 100644 index 00000000000..ff512114e93 --- /dev/null +++ b/libjava/classpath/javax/swing/JDesktopPane.java @@ -0,0 +1,331 @@ +/* JDesktopPane.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.beans.PropertyVetoException; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.plaf.DesktopPaneUI; + +/** + * JDesktopPane is a container (usually for JInternalFrames) that simulates a + * desktop. Typically, the user will create JInternalFrames and place thme in + * a JDesktopPane. The user can then interact with JInternalFrames like they + * usually would with JFrames. The actions (minimize, maximize, close, etc) + * are done by using a DesktopManager that is associated with the + * JDesktopPane. + */ +public class JDesktopPane extends JLayeredPane implements Accessible +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = 766333777224038726L; + + /** + * This specifies that when dragged, a JInternalFrame should be completely + * visible. + * + * @specnote final since 1.5.0. + */ + public static final int LIVE_DRAG_MODE = 0; + + /** + * This specifies that when dragged, a JInternalFrame should only be visible + * as an outline. + * + * @specnote final since 1.5.0. + */ + public static final int OUTLINE_DRAG_MODE = 1; + + /** The selected frame in the JDesktopPane. */ + private transient JInternalFrame selectedFrame; + + /** The JDesktopManager to use for acting on JInternalFrames. */ + transient DesktopManager desktopManager; + + /** The drag mode used by the JDesktopPane. */ + private transient int dragMode = LIVE_DRAG_MODE; + + /** + * AccessibleJDesktopPane + */ + protected class AccessibleJDesktopPane extends AccessibleJComponent + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = 6079388927946077570L; + + /** + * Constructor AccessibleJDesktopPane + */ + protected AccessibleJDesktopPane() + { + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.DESKTOP_PANE; + } + } + + /** + * Creates a new JDesktopPane object. + */ + public JDesktopPane() + { + setLayout(null); + updateUI(); + } + + /** + * This method returns the UI used with the JDesktopPane. + * + * @return The UI used with the JDesktopPane. + */ + public DesktopPaneUI getUI() + { + return (DesktopPaneUI) ui; + } + + /** + * This method sets the UI used with the JDesktopPane. + * + * @param ui The UI to use with the JDesktopPane. + */ + public void setUI(DesktopPaneUI ui) + { + super.setUI(ui); + } + + /** + * This method sets the drag mode to use with the JDesktopPane. + * + * @param mode The drag mode to use. + * + * @throws IllegalArgumentException If the drag mode given is not + * LIVE_DRAG_MODE or OUTLINE_DRAG_MODE. + */ + public void setDragMode(int mode) + { + if ((mode != LIVE_DRAG_MODE) && (mode != OUTLINE_DRAG_MODE)) + throw new IllegalArgumentException("Drag mode not valid."); + + // FIXME: Unsupported mode. + if (mode == OUTLINE_DRAG_MODE) + // throw new IllegalArgumentException("Outline drag modes are + // unsupported."); + mode = LIVE_DRAG_MODE; + + dragMode = mode; + } + + /** + * This method returns the drag mode used with the JDesktopPane. + * + * @return The drag mode used with the JDesktopPane. + */ + public int getDragMode() + { + return dragMode; + } + + /** + * This method returns the DesktopManager used with the JDesktopPane. + * + * @return The DesktopManager to use with the JDesktopPane. + */ + public DesktopManager getDesktopManager() + { + return desktopManager; + } + + /** + * This method sets the DesktopManager to use with the JDesktopPane. + * + * @param manager The DesktopManager to use with the JDesktopPane. + */ + public void setDesktopManager(DesktopManager manager) + { + desktopManager = manager; + } + + /** + * This method restores the UI used with the JDesktopPane to the default. + */ + public void updateUI() + { + setUI((DesktopPaneUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns a String identifier that allows the UIManager to know + * which class will act as JDesktopPane's UI. + * + * @return A String identifier for the UI class to use. + */ + public String getUIClassID() + { + return "DesktopPaneUI"; + } + + /** + * This method returns all JInternalFrames that are in the JDesktopPane. + * + * @return All JInternalFrames that are in the JDesktopPane. + */ + public JInternalFrame[] getAllFrames() + { + return getFramesFromComponents(getComponents()); + } + + /** + * This method returns the currently selected frame in the JDesktopPane. + * + * @return The currently selected frame in the JDesktopPane. + */ + public JInternalFrame getSelectedFrame() + { + return selectedFrame; + } + + /** + * This method sets the selected frame in the JDesktopPane. + * + * @param frame The selected frame in the JDesktopPane. + */ + public void setSelectedFrame(JInternalFrame frame) + { + if (selectedFrame != null) + { + try + { + selectedFrame.setSelected(false); + } + catch (PropertyVetoException e) + { + } + } + selectedFrame = null; + + try + { + if (frame != null) + frame.setSelected(true); + + selectedFrame = frame; + } + catch (PropertyVetoException e) + { + } + } + + /** + * This method returns all the JInternalFrames in the given layer. + * + * @param layer The layer to grab frames in. + * + * @return All JInternalFrames in the given layer. + */ + public JInternalFrame[] getAllFramesInLayer(int layer) + { + return getFramesFromComponents(getComponentsInLayer(layer)); + } + + /** + * This method always returns true to indicate that it is not transparent. + * + * @return true. + */ + public boolean isOpaque() + { + return true; + } + + /** + * This method returns a String that describes the JDesktopPane. + * + * @return A String that describes the JDesktopPane. + */ + protected String paramString() + { + return "JDesktopPane"; + } + + /** + * This method returns all the JInternalFrames in the given Component array. + * + * @param components An array to search for JInternalFrames in. + * + * @return An array of JInternalFrames found in the Component array. + */ + private static JInternalFrame[] getFramesFromComponents(Component[] components) + { + int count = 0; + + for (int i = 0; i < components.length; i++) + if (components[i] instanceof JInternalFrame) + count++; + + JInternalFrame[] value = new JInternalFrame[count]; + for (int i = 0, j = 0; i < components.length && j != count; i++) + if (components[i] instanceof JInternalFrame) + value[j++] = (JInternalFrame) components[i]; + return value; + } + + /** + * getAccessibleContext + * + * @return AccessibleContext + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJDesktopPane(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JDialog.java b/libjava/classpath/javax/swing/JDialog.java new file mode 100644 index 00000000000..83865f836f3 --- /dev/null +++ b/libjava/classpath/javax/swing/JDialog.java @@ -0,0 +1,588 @@ +/* JDialog.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.IllegalComponentStateException; +import java.awt.LayoutManager; +import java.awt.event.WindowEvent; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; + +/** + * Unlike JComponent derivatives, JDialog inherits from java.awt.Dialog. But + * also lets a look-and-feel component to its work. + * + * @author Ronald Veldema (rveldema_AT_cs.vu.nl) + */ +public class JDialog extends Dialog implements Accessible, WindowConstants, + RootPaneContainer +{ + private static final long serialVersionUID = -864070866424508218L; + + /** DOCUMENT ME! */ + protected AccessibleContext accessibleContext; + + /** The single RootPane in the Dialog. */ + protected JRootPane rootPane; + + /** + * Whether checking is enabled on the RootPane. + * + * @specnote Should be false to comply with J2SE 5.0 + */ + protected boolean rootPaneCheckingEnabled = false; + + /** The default action taken when closed. */ + private int close_action = HIDE_ON_CLOSE; + + /** Whether JDialogs are decorated by the Look and Feel. */ + private static boolean decorated; + + /** + * Whether we're in the init stage or not. + * If so, adds and layouts are for top-level, otherwise they're for the + * content pane + */ + private boolean initStageDone = false; + + /* Creates a new non-modal JDialog with no title + * using a shared Frame as the owner. + */ + public JDialog() + { + this(SwingUtilities.getOwnerFrame(), "", false, null); + } + + /** + * Creates a new non-modal JDialog with no title + * using the given owner. + * + * @param owner The owner of the JDialog. + */ + public JDialog(Dialog owner) + { + this(owner, "", false, null); + } + + /** + * Creates a new JDialog with no title using the + * given modal setting and owner. + * + * @param owner The owner of the JDialog. + * @param modal Whether the JDialog is modal. + */ + public JDialog(Dialog owner, boolean modal) + { + this(owner, "", modal, null); + } + + /** + * Creates a new non-modal JDialog using the + * given title and owner. + * + * @param owner The owner of the JDialog. + * @param title The title of the JDialog. + */ + public JDialog(Dialog owner, String title) + { + this(owner, title, false, null); + } + + /** + * Creates a new JDialog using the given modal + * settings, title, and owner. + * + * @param owner The owner of the JDialog. + * @param title The title of the JDialog. + * @param modal Whether the JDialog is modal. + */ + public JDialog(Dialog owner, String title, boolean modal) + { + this(owner, title, modal, null); + } + + /** + * Creates a new JDialog using the given modal + * settings, title, owner and graphics configuration. + * + * @param owner The owner of the JDialog. + * @param title The title of the JDialog. + * @param modal Whether the JDialog is modal. + * @param gc The Graphics Configuration to use. + */ + public JDialog(Dialog owner, String title, boolean modal, + GraphicsConfiguration gc) + { + super(owner, title, modal, gc); + dialogInit(); + } + + /** + * Creates a new non-modal JDialog with no title + * using the given owner. + * + * @param owner The owner of the JDialog. + */ + public JDialog(Frame owner) + { + this(owner, "", false, null); + } + + /** + * Creates a new JDialog with no title using the + * given modal setting and owner. + * + * @param owner The owner of the JDialog. + * @param modal Whether the JDialog is modal. + */ + public JDialog(Frame owner, boolean modal) + { + this(owner, "", modal, null); + } + + /** + * Creates a new non-modal JDialog using the + * given title and owner. + * + * @param owner The owner of the JDialog. + * @param title The title of the JDialog. + */ + public JDialog(Frame owner, String title) + { + this(owner, title, false, null); + } + + /** + * Creates a new JDialog using the given modal + * settings, title, and owner. + * + * @param owner The owner of the JDialog. + * @param title The title of the JDialog. + * @param modal Whether the JDialog is modal. + */ + public JDialog(Frame owner, String title, boolean modal) + { + this(owner, title, modal, null); + } + + /** + * Creates a new JDialog using the given modal + * settings, title, owner and graphics configuration. + * + * @param owner The owner of the JDialog. + * @param title The title of the JDialog. + * @param modal Whether the JDialog is modal. + * @param gc The Graphics Configuration to use. + */ + public JDialog(Frame owner, String title, boolean modal, + GraphicsConfiguration gc) + { + super((owner == null) ? SwingUtilities.getOwnerFrame() : owner, + title, modal, gc); + dialogInit(); + } + + /** + * This method is called to initialize the + * JDialog. It sets the layout used, the locale, + * and creates the RootPane. + */ + protected void dialogInit() + { + // FIXME: Do a check on GraphicsEnvironment.isHeadless() + setLocale(JComponent.getDefaultLocale()); + getRootPane(); // Will do set/create. + invalidate(); + // Now that initStageDone is true, adds and layouts apply to contentPane, + // not top-level. + initStageDone = true; + } + + /** + * This method returns whether JDialogs will have their + * window decorations provided by the Look and Feel. + * + * @return Whether the window decorations are Look and Feel provided. + */ + public static boolean isDefaultLookAndFeelDecorated() + { + return decorated; + } + + /** + * This method sets whether JDialogs will have their + * window decorations provided by the Look and Feel. + * + * @param defaultLookAndFeelDecorated Whether the window + * decorations are Look and Feel provided. + */ + public static void setDefaultLookAndFeelDecorated(boolean defaultLookAndFeelDecorated) + { + decorated = defaultLookAndFeelDecorated; + } + + /** + * This method returns the preferred size of + * the JDialog. + * + * @return The preferred size. + */ + public Dimension getPreferredSize() + { + Dimension d = super.getPreferredSize(); + return d; + } + + /** + * This method returns the JMenuBar used + * in this JDialog. + * + * @return The JMenuBar in the JDialog. + */ + public JMenuBar getJMenuBar() + { + return getRootPane().getJMenuBar(); + } + + /** + * This method sets the JMenuBar used + * in this JDialog. + * + * @param menubar The JMenuBar to use. + */ + public void setJMenuBar(JMenuBar menubar) + { + getRootPane().setJMenuBar(menubar); + } + + /** + * This method sets the LayoutManager used in the JDialog. + * This method will throw an Error if rootPaneChecking is + * enabled. + * + * @param manager The LayoutManager to use. + */ + public void setLayout(LayoutManager manager) + { + // Check if we're in initialization stage. If so, call super.setLayout + // otherwise, valid calls go to the content pane. + if (initStageDone) + { + if (isRootPaneCheckingEnabled()) + throw new Error("Cannot set top-level layout. Use" + + " getConentPane().setLayout instead."); + getContentPane().setLayout(manager); + } + else + super.setLayout(manager); + } + + /** + * This method sets the JLayeredPane used in the JDialog. + * If the given JLayeredPane is null, then this method + * will throw an Error. + * + * @param layeredPane The JLayeredPane to use. + */ + public void setLayeredPane(JLayeredPane layeredPane) + { + if (layeredPane == null) + throw new IllegalComponentStateException("layeredPane cannot be null."); + getRootPane().setLayeredPane(layeredPane); + } + + /** + * This method returns the JLayeredPane used with this JDialog. + * + * @return The JLayeredPane used with this JDialog. + */ + public JLayeredPane getLayeredPane() + { + return getRootPane().getLayeredPane(); + } + + /** + * This method returns the JRootPane used with this JDialog. + * + * @return The JRootPane used with this JDialog. + */ + public JRootPane getRootPane() + { + if (rootPane == null) + setRootPane(createRootPane()); + return rootPane; + } + + /** + * This method sets the JRootPane used with this JDialog. + * + * @param root The JRootPane to use. + */ + protected void setRootPane(JRootPane root) + { + if (rootPane != null) + remove(rootPane); + + rootPane = root; + rootPane.show(); + add(rootPane); + } + + /** + * This method creates a new JRootPane. + * + * @return A new JRootPane. + */ + protected JRootPane createRootPane() + { + return new JRootPane(); + } + + /** + * This method returns the ContentPane + * in the JRootPane. + * + * @return The ContentPane in the JRootPane. + */ + public Container getContentPane() + { + return getRootPane().getContentPane(); + } + + /** + * This method sets the ContentPane to use with this + * JDialog. If the ContentPane given is null, this method + * will throw an exception. + * + * @param contentPane The ContentPane to use with the JDialog. + */ + public void setContentPane(Container contentPane) + { + if (contentPane == null) + throw new IllegalComponentStateException("contentPane cannot be null."); + getRootPane().setContentPane(contentPane); + } + + /** + * This method returns the GlassPane for this JDialog. + * + * @return The GlassPane for this JDialog. + */ + public Component getGlassPane() + { + return getRootPane().getGlassPane(); + } + + /** + * This method sets the GlassPane for this JDialog. + * + * @param glassPane The GlassPane for this JDialog. + */ + public void setGlassPane(Component glassPane) + { + getRootPane().setGlassPane(glassPane); + } + + /** + * This method is called when a component is added to the + * the JDialog. Calling this method with rootPaneCheckingEnabled + * will cause an Error to be thrown. + * + * @param comp The component to add. + * @param constraints The constraints. + * @param index The position of the component. + */ + protected void addImpl(Component comp, Object constraints, int index) + { + // If we're adding in the initialization stage use super.add. + // Otherwise pass the add onto the content pane. + if (!initStageDone) + super.addImpl(comp, constraints, index); + else + { + if (isRootPaneCheckingEnabled()) + throw new Error("Do not add directly to JDialog." + + " Use getContentPane().add instead."); + getContentPane().add(comp, constraints, index); + } + } + + /** + * This method removes a component from the JDialog. + * + * @param comp The component to remove. + */ + public void remove(Component comp) + { + // If we're removing the root pane, use super.remove. Otherwise + // pass it on to the content pane instead. + if (comp == rootPane) + super.remove(rootPane); + else + getContentPane().remove(comp); + } + + /** + * This method returns whether rootPane checking is enabled. + * + * @return Whether rootPane checking is enabled. + */ + protected boolean isRootPaneCheckingEnabled() + { + return rootPaneCheckingEnabled; + } + + /** + * This method sets whether rootPane checking is enabled. + * + * @param enabled Whether rootPane checking is enabled. + */ + protected void setRootPaneCheckingEnabled(boolean enabled) + { + rootPaneCheckingEnabled = enabled; + } + + /** + * This method simply calls paint and returns. + * + * @param g The Graphics object to paint with. + */ + public void update(Graphics g) + { + paint(g); + } + + + /** + * This method handles window events. This allows the JDialog + * to honour its default close operation. + * + * @param e The WindowEvent. + */ + protected void processWindowEvent(WindowEvent e) + { + // System.out.println("PROCESS_WIN_EV-1: " + e); + super.processWindowEvent(e); + // System.out.println("PROCESS_WIN_EV-2: " + e); + switch (e.getID()) + { + case WindowEvent.WINDOW_CLOSING: + { + switch (getDefaultCloseOperation()) + { + case DISPOSE_ON_CLOSE: + { + dispose(); + break; + } + case HIDE_ON_CLOSE: + { + setVisible(false); + break; + } + case DO_NOTHING_ON_CLOSE: + break; + } + break; + } + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_OPENED: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_DEICONIFIED: + case WindowEvent.WINDOW_ACTIVATED: + case WindowEvent.WINDOW_DEACTIVATED: + break; + } + } + + /** + * This method sets the action to take + * when the JDialog is closed. + * + * @param operation The action to take. + */ + public void setDefaultCloseOperation(int operation) + { + /* Reference implementation allows invalid operations + to be specified. If so, getDefaultCloseOperation + must return the invalid code, and the behaviour + defaults to DO_NOTHING_ON_CLOSE. processWindowEvent + above handles this */ + close_action = operation; + } + + /** + * This method returns the action taken when + * the JDialog is closed. + * + * @return The action to take. + */ + public int getDefaultCloseOperation() + { + return close_action; + } + + /** + * This method returns a String describing the JDialog. + * + * @return A String describing the JDialog. + */ + protected String paramString() + { + return "JDialog"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + return null; + } +} diff --git a/libjava/classpath/javax/swing/JEditorPane.java b/libjava/classpath/javax/swing/JEditorPane.java new file mode 100644 index 00000000000..63c79ffdf12 --- /dev/null +++ b/libjava/classpath/javax/swing/JEditorPane.java @@ -0,0 +1,333 @@ +/* JEditorPane.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Dimension; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.accessibility.AccessibleContext; +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.EditorKit; +import javax.swing.text.JTextComponent; + + +public class JEditorPane extends JTextComponent +{ + private static final long serialVersionUID = 3140472492599046285L; + + private URL page; + private EditorKit editorKit; + + boolean focus_root; + + public JEditorPane() + { + setEditorKit(createDefaultEditorKit()); + } + + public JEditorPane(String url) throws IOException + { + this(new URL(url)); + } + + public JEditorPane(String type, String text) + { + setEditorKit(createEditorKitForContentType(type)); + setText(text); + } + + public JEditorPane(URL url) throws IOException + { + this(); + setPage(url); + } + + protected EditorKit createDefaultEditorKit() + { + return new DefaultEditorKit(); + } + + public static EditorKit createEditorKitForContentType(String type) + { + return new DefaultEditorKit(); + } + + /** + * Sends a given <code>HyperlinkEvent</code> to all registered listeners. + * + * @param event the event to send + */ + public void fireHyperlinkUpdate(HyperlinkEvent event) + { + HyperlinkListener[] listeners = getHyperlinkListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].hyperlinkUpdate(event); + } + + public AccessibleContext getAccessibleContext() + { + return null; + } + + public final String getContentType() + { + return getEditorKit().getContentType(); + } + + /** + * Returns the EditorKit. If there is no EditorKit set this method + * calls createDefaultEditorKit() and setEditorKit() first. + */ + public EditorKit getEditorKit() + { + if (editorKit == null) + setEditorKit(createDefaultEditorKit()); + return editorKit; + } + + public static String getEditorKitClassNameForContentType(String type) + { + return "text/plain"; + } + + public EditorKit getEditorKitForContentType(String type) + { + return editorKit; + } + + /** + * Returns the preferred size for the JEditorPane. + */ + public Dimension getPreferredSize() + { + return super.getPreferredSize(); + } + + public boolean getScrollableTracksViewportHeight() + { + return false; + } + + public boolean getScrollableTracksViewportWidth() + { + return false; + } + + public URL getPage() + { + return page; + } + + protected InputStream getStream(URL page) + throws IOException + { + return page.openStream(); + } + + public String getText() + { + return super.getText(); + } + + public String getUIClassID() + { + return "EditorPaneUI"; + } + + public boolean isFocusCycleRoot() + { + return focus_root; + } + + protected String paramString() + { + return "JEditorPane"; + } + + /** + * This method initializes from a stream. + */ + public void read(InputStream in, Object desc) + throws IOException + { + } + + /** + * Establishes the default bindings of type to classname. + */ + public static void registerEditorKitForContentType(String type, + String classname) + { + } + + /** + * Establishes the default bindings of type to classname. + */ + public static void registerEditorKitForContentType(String type, + String classname, + ClassLoader loader) + { + } + + /** + * Replaces the currently selected content with new content represented + * by the given string. + */ + public void replaceSelection(String content) + { + } + + /** + * Scrolls the view to the given reference location (that is, the value + * returned by the UL.getRef method for the URL being displayed). + */ + public void scrollToReference(String reference) + { + } + + public final void setContentType(String type) + { + if (editorKit != null + && editorKit.getContentType().equals(type)) + return; + + EditorKit kit = getEditorKitForContentType(type); + + if (kit != null) + setEditorKit(kit); + } + + public void setEditorKit(EditorKit newValue) + { + if (editorKit == newValue) + return; + + if (editorKit != null) + editorKit.deinstall(this); + + EditorKit oldValue = editorKit; + editorKit = newValue; + + if (editorKit != null) + { + editorKit.install(this); + setDocument(editorKit.createDefaultDocument()); + } + + firePropertyChange("editorKit", oldValue, newValue); + invalidate(); + repaint(); + } + + public void setEditorKitForContentType(String type, EditorKit k) + { + // FIXME: editorKitCache.put(type, kit); + } + + /** + * Sets the current URL being displayed. + */ + public void setPage(String url) throws IOException + { + setPage(new URL(url)); + } + + /** + * Sets the current URL being displayed. + */ + public void setPage(URL page) throws IOException + { + if (page == null) + throw new IOException("invalid url"); + + try + { + this.page = page; + getEditorKit().read(page.openStream(), getDocument(), 0); + } + catch (BadLocationException e) + { + // Ignored. '0' is always a valid offset. + } + } + + public void setText(String t) + { + super.setText(t); + } + + /** + * Add a <code>HyperlinkListener</code> object to this editor pane. + * + * @param listener the listener to add + */ + public void addHyperlinkListener(HyperlinkListener listener) + { + listenerList.add(HyperlinkListener.class, listener); + } + + /** + * Removes a <code>HyperlinkListener</code> object to this editor pane. + * + * @param listener the listener to remove + */ + public void removeHyperlinkListener(HyperlinkListener listener) + { + listenerList.remove(HyperlinkListener.class, listener); + } + + /** + * Returns all added <code>HyperlinkListener</code> objects. + * + * @return array of listeners + * + * @since 1.4 + */ + public HyperlinkListener[] getHyperlinkListeners() + { + return (HyperlinkListener[]) getListeners(HyperlinkListener.class); + } +} diff --git a/libjava/classpath/javax/swing/JFileChooser.java b/libjava/classpath/javax/swing/JFileChooser.java new file mode 100644 index 00000000000..17292fa4f61 --- /dev/null +++ b/libjava/classpath/javax/swing/JFileChooser.java @@ -0,0 +1,1190 @@ +/* JFileChooser.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Frame; +import java.awt.HeadlessException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.util.ArrayList; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.JDialog; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileSystemView; +import javax.swing.filechooser.FileView; +import javax.swing.plaf.FileChooserUI; + + +/** + * DOCUMENT ME! + */ +public class JFileChooser extends JComponent implements Accessible +{ + private static final long serialVersionUID = 3162921138695327837L; + + /** DOCUMENT ME! */ + public static final int OPEN_DIALOG = 0; + + /** DOCUMENT ME! */ + public static final int SAVE_DIALOG = 1; + + /** DOCUMENT ME! */ + public static final int CUSTOM_DIALOG = 2; + + /** DOCUMENT ME! */ + public static final int CANCEL_OPTION = 1; + + /** DOCUMENT ME! */ + public static final int APPROVE_OPTION = 0; + + /** DOCUMENT ME! */ + public static final int ERROR_OPTION = -1; + + /** DOCUMENT ME! */ + public static final int FILES_ONLY = 0; + + /** DOCUMENT ME! */ + public static final int DIRECTORIES_ONLY = 1; + + /** DOCUMENT ME! */ + public static final int FILES_AND_DIRECTORIES = 2; + + /** DOCUMENT ME! */ + public static final String CANCEL_SELECTION = "CancelSelection"; + + /** DOCUMENT ME! */ + public static final String APPROVE_SELECTION = "ApproveSelection"; + + /** DOCUMENT ME! */ + public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY = + "ApproveButtonTextChangedProperty"; + + /** DOCUMENT ME! */ + public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY = + "ApproveButtonToolTipTextChangedProperty"; + + /** DOCUMENT ME! */ + public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY = + "ApproveButtonMnemonicChangedProperty"; + + /** DOCUMENT ME! */ + public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY = + "ControlButtonsAreShownChangedProperty"; + + /** DOCUMENT ME! */ + public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged"; + + /** DOCUMENT ME! */ + public static final String SELECTED_FILE_CHANGED_PROPERTY = + "SelectedFileChangedProperty"; + + /** DOCUMENT ME! */ + public static final String SELECTED_FILES_CHANGED_PROPERTY = + "SelectedFilesChangedProperty"; + + /** DOCUMENT ME! */ + public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = + "MultiSelectionEnabledChangedProperty"; + + /** DOCUMENT ME! */ + public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY = + "FileSystemViewChanged"; + + /** DOCUMENT ME! */ + public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged"; + + /** DOCUMENT ME! */ + public static final String FILE_HIDING_CHANGED_PROPERTY = + "FileHidingChanged"; + + /** DOCUMENT ME! */ + public static final String FILE_FILTER_CHANGED_PROPERTY = + "fileFilterChanged"; + + /** DOCUMENT ME! */ + public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY = + "fileSelectionChanged"; + + /** DOCUMENT ME! */ + public static final String ACCESSORY_CHANGED_PROPERTY = + "AccessoryChangedProperty"; + + /** DOCUMENT ME! */ + public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY = + "acceptAllFileFilterUsedChanged"; + + /** DOCUMENT ME! */ + public static final String DIALOG_TITLE_CHANGED_PROPERTY = + "DialogTitleChangedProperty"; + + /** DOCUMENT ME! */ + public static final String DIALOG_TYPE_CHANGED_PROPERTY = + "DialogTypeChangedProperty"; + + /** DOCUMENT ME! */ + public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY = + "ChoosableFileFilterChangedProperty"; + + /** DOCUMENT ME! */ + protected AccessibleContext accessibleContext; + + /** DOCUMENT ME! */ + private FileSystemView fsv; + + /** DOCUMENT ME! */ + private JComponent accessory; + + /** DOCUMENT ME! */ + private int approveButtonMnemonic = 0; + + /** DOCUMENT ME! */ + private String approveButtonText; + + /** DOCUMENT ME! */ + private String approveButtonToolTipText; + + /** DOCUMENT ME! */ + private ArrayList choosableFilters = new ArrayList(); + + /** DOCUMENT ME! */ + private boolean isAcceptAll = true; + + /** DOCUMENT ME! */ + private String dialogTitle; + + /** DOCUMENT ME! */ + private int dialogType = OPEN_DIALOG; + + /** DOCUMENT ME! */ + private int retval = ERROR_OPTION; + + /** DOCUMENT ME! */ + private boolean multiSelection = false; + + /** DOCUMENT ME! */ + private boolean fileHiding = true; + + /** DOCUMENT ME! */ + private int fileSelectionMode = FILES_AND_DIRECTORIES; + + /** DOCUMENT ME! */ + private FileView fv = null; + + /** DOCUMENT ME! */ + private boolean controlButtonsShown = true; + + /** DOCUMENT ME! */ + private File currentDir = null; + + /** DOCUMENT ME! */ + private FileFilter currentFilter = null; + + /** DOCUMENT ME! */ + private File[] selectedFiles; + + /** DOCUMENT ME! */ + private File selectedFile; + + /** + * Creates a new JFileChooser object. + */ + public JFileChooser() + { + setup(null); + setCurrentDirectory(null); + } + + /** + * Creates a new JFileChooser object. + * + * @param currentDirectoryPath DOCUMENT ME! + */ + public JFileChooser(String currentDirectoryPath) + { + setup(null); + setCurrentDirectory(fsv.createFileObject(currentDirectoryPath)); + } + + /** + * Creates a new JFileChooser object with the specified directory and + * FileSystemView. + * + * @param currentDirectoryPath the directory that should initially be + * shown the filechooser + * @param fsv the FileSystemView object to use + */ + public JFileChooser(String currentDirectoryPath, FileSystemView fsv) + { + setup(fsv); + setCurrentDirectory(fsv.createFileObject(currentDirectoryPath)); + } + + /** + * Creates a new JFileChooser object. + * + * @param currentDirectory DOCUMENT ME! + */ + public JFileChooser(File currentDirectory) + { + setup(null); + setCurrentDirectory(currentDirectory); + } + + /** + * Creates a new JFileChooser object. + * + * @param fsv DOCUMENT ME! + */ + public JFileChooser(FileSystemView fsv) + { + setup(fsv); + setCurrentDirectory(null); + } + + /** + * Creates a new JFileChooser object. + * + * @param currentDirectory DOCUMENT ME! + * @param fsv DOCUMENT ME! + */ + public JFileChooser(File currentDirectory, FileSystemView fsv) + { + setup(fsv); + setCurrentDirectory(currentDirectory); + } + + /** + * DOCUMENT ME! + * + * @param view DOCUMENT ME! + */ + protected void setup(FileSystemView view) + { + if (view == null) + view = FileSystemView.getFileSystemView(); + setFileSystemView(view); + updateUI(); + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + public void setDragEnabled(boolean b) + { + // FIXME: Implement + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean getDragEnabled() + { + // FIXME: Implement + return false; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File getSelectedFile() + { + return selectedFile; + } + + /** + * DOCUMENT ME! + * + * @param file DOCUMENT ME! + */ + public void setSelectedFile(File file) + { + if (selectedFile != file) + { + File old = selectedFile; + selectedFile = file; + firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, old, selectedFile); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File[] getSelectedFiles() + { + if (selectedFiles != null) + return selectedFiles; + if (selectedFile != null) + return new File[] { selectedFile }; + return null; + } + + /** + * DOCUMENT ME! + * + * @param selectedFiles DOCUMENT ME! + */ + public void setSelectedFiles(File[] selectedFiles) + { + if (this.selectedFiles != selectedFiles) + { + File[] old = this.selectedFiles; + this.selectedFiles = selectedFiles; + firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, old, selectedFiles); + } + + if (selectedFiles != null) + setSelectedFile(selectedFiles[0]); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File getCurrentDirectory() + { + return currentDir; + } + + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + */ + public void setCurrentDirectory(File dir) + { + if (currentDir != dir || dir == null) + { + if (dir == null) + dir = fsv.getDefaultDirectory(); + + File old = currentDir; + currentDir = dir; + firePropertyChange(DIRECTORY_CHANGED_PROPERTY, old, currentDir); + } + } + + /** + * DOCUMENT ME! + */ + public void changeToParentDirectory() + { + setCurrentDirectory(fsv.getParentDirectory(currentDir)); + } + + /** + * DOCUMENT ME! + */ + public void rescanCurrentDirectory() + { + getUI().rescanCurrentDirectory(this); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + */ + public void ensureFileIsVisible(File f) + { + getUI().ensureFileIsVisible(this, f); + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws HeadlessException DOCUMENT ME! + */ + public int showOpenDialog(Component parent) throws HeadlessException + { + JDialog d = createDialog(parent); + + // FIXME: Remove when we get ancestor property + d.setTitle("Open"); + setDialogType(OPEN_DIALOG); + + retval = ERROR_OPTION; + + d.pack(); + d.show(); + return retval; + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws HeadlessException DOCUMENT ME! + */ + public int showSaveDialog(Component parent) throws HeadlessException + { + JDialog d = createDialog(parent); + setDialogType(SAVE_DIALOG); + + retval = ERROR_OPTION; + + d.pack(); + d.show(); + return retval; + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * @param approveButtonText DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws HeadlessException DOCUMENT ME! + */ + public int showDialog(Component parent, String approveButtonText) + throws HeadlessException + { + JDialog d = createDialog(parent); + setApproveButtonText(approveButtonText); + setDialogType(CUSTOM_DIALOG); + + retval = ERROR_OPTION; + + d.pack(); + d.show(); + return retval; + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws HeadlessException DOCUMENT ME! + */ + protected JDialog createDialog(Component parent) throws HeadlessException + { + Frame toUse = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent); + if (toUse == null) + toUse = SwingUtilities.getOwnerFrame(); + + JDialog dialog = new JDialog(toUse); + setSelectedFile(null); + dialog.getContentPane().add(this); + dialog.setModal(true); + dialog.invalidate(); + dialog.repaint(); + + return dialog; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean getControlButtonsAreShown() + { + return controlButtonsShown; + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + public void setControlButtonsAreShown(boolean b) + { + if (controlButtonsShown != b) + { + controlButtonsShown = b; + firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, + ! controlButtonsShown, controlButtonsShown); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getDialogType() + { + return dialogType; + } + + /** + * DOCUMENT ME! + * + * @param dialogType DOCUMENT ME! + */ + public void setDialogType(int dialogType) + { + if (dialogType != OPEN_DIALOG && dialogType != SAVE_DIALOG + && dialogType != CUSTOM_DIALOG) + throw new IllegalArgumentException("Choose allowable dialogType."); + + if (this.dialogType != dialogType) + { + int old = this.dialogType; + this.dialogType = dialogType; + firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, old, this.dialogType); + } + } + + /** + * DOCUMENT ME! + * + * @param dialogTitle DOCUMENT ME! + */ + public void setDialogTitle(String dialogTitle) + { + if (this.dialogTitle != dialogTitle) + { + String old = this.dialogTitle; + this.dialogTitle = dialogTitle; + firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, old, this.dialogTitle); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getDialogTitle() + { + return dialogTitle; + } + + /** + * DOCUMENT ME! + * + * @param toolTipText DOCUMENT ME! + */ + public void setApproveButtonToolTipText(String toolTipText) + { + if (approveButtonToolTipText != toolTipText) + { + String oldText = approveButtonToolTipText; + approveButtonToolTipText = toolTipText; + firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, + oldText, approveButtonToolTipText); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getApproveButtonToolTipText() + { + return approveButtonToolTipText; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getApproveButtonMnemonic() + { + return approveButtonMnemonic; + } + + /** + * DOCUMENT ME! + * + * @param mnemonic DOCUMENT ME! + */ + public void setApproveButtonMnemonic(int mnemonic) + { + if (approveButtonMnemonic != mnemonic) + { + int oldMnemonic = approveButtonMnemonic; + approveButtonMnemonic = mnemonic; + firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, + oldMnemonic, approveButtonMnemonic); + } + } + + /** + * DOCUMENT ME! + * + * @param mnemonic DOCUMENT ME! + */ + public void setApproveButtonMnemonic(char mnemonic) + { + setApproveButtonMnemonic((int) Character.toUpperCase(mnemonic)); + } + + /** + * DOCUMENT ME! + * + * @param approveButtonText DOCUMENT ME! + */ + public void setApproveButtonText(String approveButtonText) + { + if (this.approveButtonText != approveButtonText) + { + String oldText = this.approveButtonText; + this.approveButtonText = approveButtonText; + firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldText, + this.approveButtonText); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getApproveButtonText() + { + return approveButtonText; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileFilter[] getChoosableFileFilters() + { + return (FileFilter[]) choosableFilters.toArray(new FileFilter[0]); + } + + /** + * DOCUMENT ME! + * + * @param filter DOCUMENT ME! + */ + public void addChoosableFileFilter(FileFilter filter) + { + FileFilter[] old = getChoosableFileFilters(); + choosableFilters.add(filter); + FileFilter[] newFilters = getChoosableFileFilters(); + firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, newFilters); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean removeChoosableFileFilter(FileFilter f) + { + FileFilter[] old = getChoosableFileFilters(); + if (! choosableFilters.remove(f)) + return false; + FileFilter[] newFilters = getChoosableFileFilters(); + firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, newFilters); + return true; + } + + /** + * DOCUMENT ME! + */ + public void resetChoosableFileFilters() + { + choosableFilters.clear(); + choosableFilters.add(getUI().getAcceptAllFileFilter(this)); + setFileFilter((FileFilter) choosableFilters.get(0)); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileFilter getAcceptAllFileFilter() + { + return getUI().getAcceptAllFileFilter(this); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isAcceptAllFileFilterUsed() + { + return isAcceptAll; + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + public void setAcceptAllFileFilterUsed(boolean b) + { + if (isAcceptAll != b) + { + isAcceptAll = b; + firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, + ! isAcceptAll, isAcceptAll); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JComponent getAccessory() + { + return accessory; + } + + /** + * DOCUMENT ME! + * + * @param newAccessory DOCUMENT ME! + */ + public void setAccessory(JComponent newAccessory) + { + if (accessory != newAccessory) + { + JComponent old = accessory; + accessory = newAccessory; + firePropertyChange(ACCESSORY_CHANGED_PROPERTY, old, accessory); + } + } + + /** + * DOCUMENT ME! + * + * @param mode DOCUMENT ME! + */ + public void setFileSelectionMode(int mode) + { + if (mode != FILES_ONLY && mode != DIRECTORIES_ONLY + && mode != FILES_AND_DIRECTORIES) + throw new IllegalArgumentException("Choose a correct file selection mode."); + if (fileSelectionMode != mode) + { + int old = fileSelectionMode; + fileSelectionMode = mode; + firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, old, + fileSelectionMode); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getFileSelectionMode() + { + return fileSelectionMode; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isFileSelectionEnabled() + { + return (fileSelectionMode == FILES_ONLY + || fileSelectionMode == FILES_AND_DIRECTORIES); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isDirectorySelectionEnabled() + { + return (fileSelectionMode == DIRECTORIES_ONLY + || fileSelectionMode == FILES_AND_DIRECTORIES); + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + public void setMultiSelectionEnabled(boolean b) + { + if (multiSelection != b) + { + multiSelection = b; + firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, + ! multiSelection, multiSelection); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isMultiSelectionEnabled() + { + return multiSelection; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isFileHidingEnabled() + { + return fileHiding; + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + public void setFileHidingEnabled(boolean b) + { + if (fileHiding != b) + { + fileHiding = b; + firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, ! fileHiding, + fileHiding); + } + } + + /** + * DOCUMENT ME! + * + * @param filter DOCUMENT ME! + */ + public void setFileFilter(FileFilter filter) + { + if (currentFilter != filter) + { + FileFilter old = currentFilter; + currentFilter = filter; + firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, old, currentFilter); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileFilter getFileFilter() + { + return currentFilter; + } + + /** + * DOCUMENT ME! + * + * @param fileView DOCUMENT ME! + */ + public void setFileView(FileView fileView) + { + if (fv != fileView) + { + FileView old = fv; + fv = fileView; + firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, old, fv); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileView getFileView() + { + return fv; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + private FileView getInternalFileView() + { + if (fv == null) + return getUI().getFileView(this); + return fv; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getName(File f) + { + return getInternalFileView().getName(f); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getDescription(File f) + { + return getInternalFileView().getDescription(f); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getTypeDescription(File f) + { + return getInternalFileView().getTypeDescription(f); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Icon getIcon(File f) + { + return getInternalFileView().getIcon(f); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isTraversable(File f) + { + return getFileSystemView().isTraversable(f).booleanValue(); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean accept(File f) + { + if (f == null) + return false; + return getFileFilter().accept(f); + } + + /** + * DOCUMENT ME! + * + * @param fsv DOCUMENT ME! + */ + public void setFileSystemView(FileSystemView fsv) + { + if (this.fsv != fsv) + { + FileSystemView old = this.fsv; + this.fsv = fsv; + firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, old, this.fsv); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileSystemView getFileSystemView() + { + return fsv; + } + + /** + * DOCUMENT ME! + */ + public void approveSelection() + { + retval = APPROVE_OPTION; + fireActionPerformed(APPROVE_SELECTION); + } + + /** + * DOCUMENT ME! + */ + public void cancelSelection() + { + retval = CANCEL_OPTION; + fireActionPerformed(CANCEL_SELECTION); + } + + /** + * DOCUMENT ME! + * + * @param l DOCUMENT ME! + */ + public void addActionListener(ActionListener l) + { + listenerList.add(ActionListener.class, l); + } + + /** + * DOCUMENT ME! + * + * @param l DOCUMENT ME! + */ + public void removeActionListener(ActionListener l) + { + try + { + listenerList.remove(ActionListener.class, l); + } + catch (IllegalArgumentException e) + { + e.printStackTrace(); + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public ActionListener[] getActionListeners() + { + return (ActionListener[]) getListeners(ActionListener.class); + } + + /** + * DOCUMENT ME! + * + * @param command DOCUMENT ME! + */ + protected void fireActionPerformed(String command) + { + ActionListener[] list = getActionListeners(); + ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, + command); + + for (int i = 0; i < list.length; i++) + list[i].actionPerformed(event); + } + + /** + * DOCUMENT ME! + */ + public void updateUI() + { + setUI((FileChooserUI) UIManager.getUI(this)); + revalidate(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getUIClassID() + { + return "FileChooserUI"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileChooserUI getUI() + { + return (FileChooserUI) ui; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected String paramString() + { + return "JFileChooser"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + return null; + } +} diff --git a/libjava/classpath/javax/swing/JFormattedTextField.java b/libjava/classpath/javax/swing/JFormattedTextField.java new file mode 100644 index 00000000000..f8230f69fb3 --- /dev/null +++ b/libjava/classpath/javax/swing/JFormattedTextField.java @@ -0,0 +1,347 @@ +/* JFormattedTextField.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.event.FocusEvent; +import java.io.Serializable; +import java.text.Format; +import java.text.ParseException; +import java.util.Date; + +import javax.swing.text.DateFormatter; +import javax.swing.text.DefaultFormatter; +import javax.swing.text.Document; +import javax.swing.text.DocumentFilter; +import javax.swing.text.NavigationFilter; + +/** + * @author Michael Koch + * @since 1.4 + */ +public class JFormattedTextField extends JTextField +{ + private static final long serialVersionUID = 5464657870110180632L; + + public abstract static class AbstractFormatter implements Serializable + { + private static final long serialVersionUID = -5193212041738979680L; + + private JFormattedTextField textField; + + public AbstractFormatter () + { + //Do nothing here. + } + + protected Object clone () + throws CloneNotSupportedException + { + throw new InternalError ("not implemented"); + } + + protected Action[] getActions () + { + return textField.getActions(); + } + + protected DocumentFilter getDocumentFilter () + { + throw new InternalError ("not implemented"); + } + + protected JFormattedTextField getFormattedTextField () + { + return textField; + } + + protected NavigationFilter getNavigationFilter () + { + return textField.getNavigationFilter(); + } + + public void install(JFormattedTextField textField) + { + if (this.textField != null) + uninstall(); + + this.textField = textField; + } + + public void uninstall () + { + this.textField = null; + } + + protected void invalidEdit () + { + textField.invalidEdit(); + } + + protected void setEditValid (boolean valid) + { + textField.editValid = valid; + } + + public abstract Object stringToValue (String text) + throws ParseException; + + public abstract String valueToString (Object value) + throws ParseException; + } + + public abstract static class AbstractFormatterFactory + { + public AbstractFormatterFactory () + { + // Do nothing here. + } + + public abstract AbstractFormatter getFormatter (JFormattedTextField tf); + } + + static class FormatterFactoryWrapper extends AbstractFormatterFactory + { + AbstractFormatter formatter; + + public FormatterFactoryWrapper(AbstractFormatter formatter) + { + this.formatter = formatter; + } + + public AbstractFormatter getFormatter(JFormattedTextField tf) + { + return formatter; + } + } + + public static final int COMMIT = 0; + public static final int COMMIT_OR_REVERT = 1; + public static final int REVERT = 2; + public static final int PERSIST = 3; + + private Object value; + private int focusLostBehavior = COMMIT_OR_REVERT; + private AbstractFormatterFactory formatterFactory; + // Package-private to avoid an accessor method. + boolean editValid = true; + + public JFormattedTextField () + { + this((AbstractFormatterFactory) null, null); + } + + public JFormattedTextField (Format format) + { + throw new InternalError ("not implemented"); + } + + public JFormattedTextField (AbstractFormatter formatter) + { + this(new FormatterFactoryWrapper(formatter), null); + } + + public JFormattedTextField (AbstractFormatterFactory factory) + { + this(factory, null); + } + + public JFormattedTextField (AbstractFormatterFactory factory, Object value) + { + this.formatterFactory = factory; + this.value = value; + } + + public JFormattedTextField (Object value) + { + this.value = value; + } + + public void commitEdit () + throws ParseException + { + throw new InternalError ("not implemented"); + } + + public Action[] getActions () + { + // FIXME: Add JFormattedTextField specific actions + return super.getActions(); + } + + public int getFocusLostBehavior() + { + return focusLostBehavior; + } + + public AbstractFormatter getFormatter () + { + if (formatterFactory == null) + return null; + + return formatterFactory.getFormatter(this); + } + + public AbstractFormatterFactory getFormatterFactory () + { + return formatterFactory; + } + + public String getUIClassID () + { + return "FormattedTextFieldUI"; + } + + public Object getValue () + { + return value; + } + + protected void invalidEdit () + { + UIManager.getLookAndFeel().provideErrorFeedback(this); + } + + public boolean isEditValid () + { + return editValid; + } + + protected void processFocusEvent (FocusEvent evt) + { + // it's safe to simply call super for now, until it gets clear + // what this method is supposed to do + // throw new InternalError ("not implemented"); + super.processFocusEvent(evt); + } + + public void setDocument(Document newDocument) + { + Document oldDocument = getDocument(); + + if (oldDocument == newDocument) + return; + + super.setDocument(newDocument); + } + + public void setFocusLostBehavior(int behavior) + { + if (behavior != COMMIT + && behavior != COMMIT_OR_REVERT + && behavior != PERSIST + && behavior != REVERT) + throw new IllegalArgumentException("invalid behavior"); + + this.focusLostBehavior = behavior; + } + + protected void setFormatter (AbstractFormatter formatter) + { + AbstractFormatter oldFormatter = null; + + if (formatterFactory != null) + oldFormatter = formatterFactory.getFormatter(this); + + if (oldFormatter == formatter) + return; + + setFormatterFactory(new FormatterFactoryWrapper(formatter)); + firePropertyChange("formatter", oldFormatter, formatter); + } + + public void setFormatterFactory (AbstractFormatterFactory factory) + { + if (formatterFactory == factory) + return; + + AbstractFormatterFactory oldFactory = formatterFactory; + formatterFactory = factory; + firePropertyChange("formatterFactory", oldFactory, factory); + } + + public void setValue (Object newValue) + { + if (value == newValue) + return; + + // format value + AbstractFormatter formatter = createFormatter(newValue); + try + { + setText(formatter.valueToString(newValue)); + } + catch (ParseException ex) + { + // TODO: what should we do with this? + } + + Object oldValue = value; + value = newValue; + firePropertyChange("value", oldValue, newValue); + } + + /** + * A helper method that attempts to create a formatter that is suitable + * to format objects of the type like <code>value</code>. + * + * If <code>formatterFactory</code> is not null and the returned formatter + * is also not <code>null</code> then this formatter is used. Otherwise we + * try to create one based on the type of <code>value</code>. + * + * @param value an object which should be formatted by the formatter + * + * @return a formatter able to format objects of the class of + * <code>value</code> + */ + AbstractFormatter createFormatter(Object value) + { + AbstractFormatter formatter = null; + if (formatterFactory != null + && formatterFactory.getFormatter(this) != null) + formatter = formatterFactory.getFormatter(this); + else + { + if (value instanceof Date) + formatter = new DateFormatter(); + else + formatter = new DefaultFormatter(); + } + return formatter; + } +} diff --git a/libjava/classpath/javax/swing/JFrame.java b/libjava/classpath/javax/swing/JFrame.java new file mode 100644 index 00000000000..d8b10d5e36d --- /dev/null +++ b/libjava/classpath/javax/swing/JFrame.java @@ -0,0 +1,349 @@ +/* JFrame.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.AWTEvent; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.LayoutManager; +import java.awt.event.KeyEvent; +import java.awt.event.WindowEvent; + +import javax.accessibility.AccessibleContext; + +/** + * Unlike JComponent derivatives, JFrame inherits from + * java.awt.Frame. But also lets a look-and-feel component to its work. + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class JFrame extends Frame + implements WindowConstants, RootPaneContainer +{ + private static final long serialVersionUID = -3362141868504252139L; + private static boolean defaultLookAndFeelDecorated; + private int close_action = HIDE_ON_CLOSE; + protected AccessibleContext accessibleContext; + protected JRootPane rootPane; + + /** + * @specnote rootPaneCheckingEnabled is false to comply with J2SE 5.0 + */ + protected boolean rootPaneCheckingEnabled = false; + + /** + * Tells us if we're in the initialization stage. + * If so, adds go to top-level Container, otherwise they go + * to the content pane for this container. + */ + private boolean initStageDone = false; + + public JFrame() + { + super("JFrame"); + frameInit(); + } + + public JFrame(String title) + { + super(title); + frameInit(); + } + + /** + * Creates a new JFrame in the specified {@link GraphicsConfiguration} + * and with an empty title. + * + * @param gc the <code>GraphicsConfiguration</code> that is used for + * the new <code>JFrame</code> + * + * @see Frame(GraphicsConfiguration) + */ + public JFrame(GraphicsConfiguration gc) + { + super(gc); + frameInit(); + } + + /** + * Creates a new JFrame in the specified {@link GraphicsConfiguration} + * and with the specified title. + * + * @param title the title for the new <code>JFrame</code> + * @param gc the <code>GraphicsConfiguration</code> that is used for + * the new <code>JFrame</code> + * + * @see Frame(String, GraphicsConfiguration) + */ + public JFrame(String title, GraphicsConfiguration gc) + { + super(title, gc); + frameInit(); + } + + protected void frameInit() + { + super.setLayout(new BorderLayout(1, 1)); + enableEvents(AWTEvent.WINDOW_EVENT_MASK); + getRootPane(); // will do set/create + // We're now done the init stage. + initStageDone = true; + } + + public Dimension getPreferredSize() + { + return super.getPreferredSize(); + } + + public JMenuBar getJMenuBar() + { + return getRootPane().getJMenuBar(); + } + + public void setJMenuBar(JMenuBar menubar) + { + getRootPane().setJMenuBar(menubar); + } + + public void setLayout(LayoutManager manager) + { + // Check if we're in initialization stage. If so, call super.setLayout + // otherwise, valid calls go to the content pane. + if (initStageDone) + { + if (isRootPaneCheckingEnabled()) + throw new Error("Cannot set layout. Use getContentPane().setLayout()" + + " instead."); + getContentPane().setLayout(manager); + } + else + super.setLayout(manager); + } + + public void setLayeredPane(JLayeredPane layeredPane) + { + getRootPane().setLayeredPane(layeredPane); + } + + public JLayeredPane getLayeredPane() + { + return getRootPane().getLayeredPane(); + } + + public JRootPane getRootPane() + { + if (rootPane == null) + setRootPane(createRootPane()); + return rootPane; + } + + protected void setRootPane(JRootPane root) + { + if (rootPane != null) + remove(rootPane); + + rootPane = root; + add(rootPane, BorderLayout.CENTER); + } + + protected JRootPane createRootPane() + { + return new JRootPane(); + } + + public Container getContentPane() + { + return getRootPane().getContentPane(); + } + + public void setContentPane(Container contentPane) + { + getRootPane().setContentPane(contentPane); + } + + public Component getGlassPane() + { + return getRootPane().getGlassPane(); + } + + public void setGlassPane(Component glassPane) + { + getRootPane().setGlassPane(glassPane); + } + + protected void addImpl(Component comp, Object constraints, int index) + { + // If we're adding in the initialization stage use super.add. + // Otherwise pass the add onto the content pane. + if (!initStageDone) + super.addImpl(comp, constraints, index); + else + { + if (isRootPaneCheckingEnabled()) + throw new Error("rootPaneChecking is enabled - adding components " + + "disallowed."); + getContentPane().add(comp,constraints,index); + } + } + + public void remove(Component comp) + { + // If we're removing the root pane, use super.remove. Otherwise + // pass it on to the content pane instead. + if (comp==rootPane) + super.remove(rootPane); + else + getContentPane().remove(comp); + } + + protected boolean isRootPaneCheckingEnabled() + { + return rootPaneCheckingEnabled; + } + + protected void setRootPaneCheckingEnabled(boolean enabled) + { + rootPaneCheckingEnabled = enabled; + } + + public void update(Graphics g) + { + paint(g); + } + + protected void processKeyEvent(KeyEvent e) + { + super.processKeyEvent(e); + } + + public static void setDefaultLookAndFeelDecorated(boolean decorated) + { + defaultLookAndFeelDecorated = decorated; + } + + public static boolean isDefaultLookAndFeelDecorated() + { + return defaultLookAndFeelDecorated; + } + + public AccessibleContext getAccessibleContext() + { + return accessibleContext; + } + + public int getDefaultCloseOperation() + { + return close_action; + } + + protected String paramString() + { + return "JFrame"; + } + + protected void processWindowEvent(WindowEvent e) + { + super.processWindowEvent(e); + switch (e.getID()) + { + case WindowEvent.WINDOW_CLOSING: + { + switch (close_action) + { + case EXIT_ON_CLOSE: + { + System.exit(0); + break; + } + case DISPOSE_ON_CLOSE: + { + dispose(); + break; + } + case HIDE_ON_CLOSE: + { + setVisible(false); + break; + } + case DO_NOTHING_ON_CLOSE: + break; + } + break; + } + case WindowEvent.WINDOW_CLOSED: + case WindowEvent.WINDOW_OPENED: + case WindowEvent.WINDOW_ICONIFIED: + case WindowEvent.WINDOW_DEICONIFIED: + case WindowEvent.WINDOW_ACTIVATED: + case WindowEvent.WINDOW_DEACTIVATED: + break; + } + } + + /** + * Defines what happens when this frame is closed. Can be one off + * <code>EXIT_ON_CLOSE</code>, + * <code>DISPOSE_ON_CLOSE</code>, + * <code>HIDE_ON_CLOSE</code> or + * <code>DO_NOTHING_ON_CLOSE</code>. + * The default is <code>HIDE_ON_CLOSE</code>. + * When <code>EXIT_ON_CLOSE</code> is specified this method calls + * <code>SecurityManager.checkExit(0)</code> which might throw a + * <code>SecurityException</code>. When the specified operation is + * not one of the above a <code>IllegalArgumentException</code> is + * thrown. + */ + public void setDefaultCloseOperation(int operation) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null && operation == EXIT_ON_CLOSE) + sm.checkExit(0); + + if (operation != EXIT_ON_CLOSE && operation != DISPOSE_ON_CLOSE + && operation != HIDE_ON_CLOSE && operation != DO_NOTHING_ON_CLOSE) + throw new IllegalArgumentException("defaultCloseOperation must be EXIT_ON_CLOSE, HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or DO_NOTHING_ON_CLOSE"); + + close_action = operation; + } +} diff --git a/libjava/classpath/javax/swing/JInternalFrame.java b/libjava/classpath/javax/swing/JInternalFrame.java new file mode 100644 index 00000000000..b504aaaa5e3 --- /dev/null +++ b/libjava/classpath/javax/swing/JInternalFrame.java @@ -0,0 +1,1754 @@ +/* JInternalFrame.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.KeyboardFocusManager; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.beans.PropertyVetoException; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleValue; +import javax.swing.event.InternalFrameEvent; +import javax.swing.event.InternalFrameListener; +import javax.swing.plaf.DesktopIconUI; +import javax.swing.plaf.InternalFrameUI; + +/** + * This class implements a Swing widget that looks and acts like a native + * frame. The frame can be dragged, resized, closed, etc. Typically, + * JInternalFrames are placed in JDesktopPanes. The actions that the + * JInternalFrame performs (maximizing, minimizing, etc.) are performed by a + * DesktopManager. As with regular frames, components are added by calling + * frame.getContentPane().add. + */ +public class JInternalFrame extends JComponent implements Accessible, + WindowConstants, + RootPaneContainer +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = -5425177187760785402L; + + /** + * DOCUMENT ME! + */ + protected class AccessibleJInternalFrame extends AccessibleJComponent + implements AccessibleValue + { + private static final long serialVersionUID = 5931936924175476797L; + + /** + * Creates a new AccessibleJInternalFrame object. + */ + protected AccessibleJInternalFrame() + { + super(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getAccessibleName() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getMaximumAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param n DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean setCurrentAccessibleValue(Number n) + { + return false; + } + } + + /** + * This class represents the JInternalFrame while it is iconified. + */ + public static class JDesktopIcon extends JComponent implements Accessible + { + /** + * DOCUMENT ME! + */ + protected class AccessibleJDesktopIcon extends AccessibleJComponent + implements AccessibleValue + { + private static final long serialVersionUID = 5035560458941637802L; + + /** + * Creates a new AccessibleJDesktopIcon object. + */ + protected AccessibleJDesktopIcon() + { + super(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getMaximumAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param n DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean setCurrentAccessibleValue(Number n) + { + return false; + } + } + + private static final long serialVersionUID = 4672973344731387687L; + + /** The JInternalFrame this DesktopIcon represents. */ + JInternalFrame frame; + + /** + * Creates a new JDesktopIcon object for representing the given frame. + * + * @param f The JInternalFrame to represent. + */ + public JDesktopIcon(JInternalFrame f) + { + frame = f; + updateUI(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJDesktopIcon(); + return accessibleContext; + } + + /** + * This method returns the JDesktopPane this JDesktopIcon is in. + * + * @return The JDesktopPane this JDesktopIcon is in. + */ + public JDesktopPane getDesktopPane() + { + JDesktopPane p = (JDesktopPane) SwingUtilities.getAncestorOfClass(JDesktopPane.class, + this); + return p; + } + + /** + * This method returns the JInternalFrame this JDesktopIcon represents. + * + * @return The JInternalFrame this JDesktopIcon represents. + */ + public JInternalFrame getInternalFrame() + { + return frame; + } + + /** + * This method returns the UI that is responsible for the JDesktopIcon. + * + * @return The UI that is responsible for the JDesktopIcon. + */ + public DesktopIconUI getUI() + { + return (DesktopIconUI) ui; + } + + /** + * This method returns the String identifier that is used to determine + * which class is used for JDesktopIcon's UI. + * + * @return A String identifier for the UI class. + */ + public String getUIClassID() + { + return "DesktopIconUI"; + } + + /** + * This method sets the JInternalFrame that this JDesktopIcon represents. + * + * @param f The JInternalFrame that this JDesktopIcon represents. + */ + public void setInternalFrame(JInternalFrame f) + { + frame = f; + } + + /** + * This method sets the UI used for this JDesktopIcon. + * + * @param ui The UI to use. + */ + public void setUI(DesktopIconUI ui) + { + super.setUI(ui); + } + + /** + * This method restores the UI property to the defaults. + */ + public void updateUI() + { + setUI((DesktopIconUI) UIManager.getUI(this)); + } + } + + /** + * The property fired in a PropertyChangeEvent when the contentPane property + * changes. + */ + public static final String CONTENT_PANE_PROPERTY = "contentPane"; + + /** + * The property fired in a PropertyChangeEvent when the frameIcon property + * changes. + */ + public static final String FRAME_ICON_PROPERTY = "frameIcon"; + + /** + * The property fired in a PropertyChangeEvent when the glassPane property + * changes. + */ + public static final String GLASS_PANE_PROPERTY = "glassPane"; + + /** + * The property fired in a PropertyChangeEvent when the closed property + * changes. + */ + public static final String IS_CLOSED_PROPERTY = "closed"; + + /** + * The property fired in a PropertyChangeEvent when the icon property + * changes. + */ + public static final String IS_ICON_PROPERTY = "icon"; + + /** + * The property fired in a PropertyChangeEvent when the maximum property + * changes. + */ + public static final String IS_MAXIMUM_PROPERTY = "maximum"; + + /** + * The property fired in a PropertyChangeEvent when the selected property + * changes. + */ + public static final String IS_SELECTED_PROPERTY = "selected"; + + /** + * The property fired in a PropertyChangeEvent when the layeredPane property + * changes. + */ + public static final String LAYERED_PANE_PROPERTY = "layeredPane"; + + /** + * The property fired in a PropertyChangeEvent when the jMenuBar property + * changes. + */ + public static final String MENU_BAR_PROPERTY = "JMenuBar"; + + /** + * The property fired in a PropertyChangeEvent when the rootPane property + * changes. + */ + public static final String ROOT_PANE_PROPERTY = "rootPane"; + + /** + * The property fired in a PropertyChangeEvent when the title property + * changes. + */ + public static final String TITLE_PROPERTY = "title"; + + /** Whether the JInternalFrame is closable. */ + protected boolean closable; + + /** Whether the JInternalFrame can be iconified. */ + protected boolean iconable; + + /** Whether the JInternalFrame is closed. */ + protected boolean isClosed; + + /** Whether the JInternalFrame has been iconified. */ + protected boolean isIcon; + + /** Whether the JInternalFrame has been maximized. */ + protected boolean isMaximum; + + /** Whether the JInternalFrame is the active frame. */ + protected boolean isSelected; + + /** Whether the JInternalFrame can be maximized. */ + protected boolean maximizable; + + /** + * Whether the JInternalFrame has rootPaneChecking enabled. + * + * @specnote Should be false to comply with J2SE 5.0 + */ + protected boolean rootPaneCheckingEnabled = false; + + /** + * Tells us if we're in the initialization stage. + * If so, adds go to top-level Container, otherwise they go + * to the content pane for this container. + */ + private boolean initStageDone = false; + + /** Whether the JInternalFrame is resizable. */ + protected boolean resizable; + + /** + * The JDesktopIcon that represents the JInternalFrame while it is + * iconified. + */ + protected JDesktopIcon desktopIcon; + + /** The icon used in the JMenuBar in the TitlePane. */ + protected Icon frameIcon; + + /** The rootPane of the JInternalFrame. */ + protected JRootPane rootPane; + + /** The title on the TitlePane of the JInternalFrame. */ + protected String title; + + /** The bounds of the JInternalFrame before it was maximized. */ + private transient Rectangle storedBounds; + + /** The Component that receives focus by default. */ + private transient Component defaultFocus; + + /** The default close action taken, */ + private transient int defaultCloseOperation = DISPOSE_ON_CLOSE; + + /** Whether the JInternalFrame has become visible for the very first time. */ + private transient boolean isFirstTimeVisible = true; + + /** + * Whether the JInternalFrame is in the transition from being a maximized + * frame back to a regular sized frame. + */ + private transient boolean maxTransition = false; + + /** DOCUMENT ME! */ + private transient boolean wasIcon = false; + + /** + * Creates a new JInternalFrame object that has no title, and is + * non-resizable, non-maximizable, non-iconifiable, and non-closable. + */ + public JInternalFrame() + { + this(null, false, false, false, false); + } + + /** + * Creates a new JInternalFrame object with the given title and is + * non-resizable, non-maximizable, non-iconifiable, and non-closable. + * + * @param title The title displayed in the JInternalFrame. + */ + public JInternalFrame(String title) + { + this(title, false, false, false, false); + } + + /** + * Creates a new JInternalFrame object with the given title and resizable + * properties. The JInternalFrame is non-maximizable, non-iconifiable, and + * non-closable. + * + * @param title The title displayed in the JInternalFrame. + * @param resizable Whether the JInternalFrame is resizable. + */ + public JInternalFrame(String title, boolean resizable) + { + this(title, resizable, false, false, false); + } + + /** + * Creates a new JInternalFrame object with the given title, resizable, and + * closable properties. The JInternalFrame is non-maximizable and + * non-iconifiable. + * + * @param title The title displayed in the JInternalFrame. + * @param resizable Whether the JInternalFrame is resizable. + * @param closable Whether the JInternalFrame is closable. + */ + public JInternalFrame(String title, boolean resizable, boolean closable) + { + this(title, resizable, closable, false, false); + } + + /** + * Creates a new JInternalFrame object with the given title, resizable, + * closable and maximizable properties. The JInternalFrame is + * non-iconifiable. + * + * @param title The title displayed in the JInternalFrame. + * @param resizable Whether the JInternalFrame is resizable. + * @param closable Whether the JInternalFrame is closable. + * @param maximizable Whether the JInternalFrame is maximizable. + */ + public JInternalFrame(String title, boolean resizable, boolean closable, + boolean maximizable) + { + this(title, resizable, closable, maximizable, false); + } + + /** + * Creates a new JInternalFrame object with the given title, resizable, + * closable, maximizable and iconifiable properties. + * + * @param title The title displayed in the JInternalFrame. + * @param resizable Whether the JInternalFrame is resizable. + * @param closable Whether the JInternalFrame is closable. + * @param maximizable Whether the JInternalFrame is maximizable. + * @param iconifiable Whether the JInternalFrame is iconifiable. + */ + public JInternalFrame(String title, boolean resizable, boolean closable, + boolean maximizable, boolean iconifiable) + { + this.title = title; + this.resizable = resizable; + this.closable = closable; + this.maximizable = maximizable; + this.iconable = iconifiable; + storedBounds = new Rectangle(); + setRootPane(createRootPane()); + updateUI(); + initStageDone = true; // Done the init stage, now adds go to content pane. + } + + /** + * This method adds Components to this Container. For JInternalFrames, + * instead of calling add directly on the JInternalFrame, it should be + * called with JInternalFrame.getContentPane().add. If root pane checking + * is enabled, calling this method will cause an exception to be thrown. + * + * @param comp The Component to add. + * @param constraints The constraints on the Component added. + * @param index The position to place the Component. + * + * @throws Error DOCUMENT ME! + */ + protected void addImpl(Component comp, Object constraints, int index) + { + // If we're in the initialization stage use super.add. Here we add the + // rootPane as well as the title bar and other stuff. + // Otherwise pass the add onto the content pane. + if (!initStageDone) + super.addImpl(comp,constraints, index); + else + { + if (isRootPaneCheckingEnabled()) + throw new Error("Do not use add() on JInternalFrame directly. Use " + + "getContentPane().add() instead"); + getContentPane().add(comp, constraints, index); + } + } + + /** + * This method adds an InternalFrameListener to this JInternalFrame. + * + * @param l The listener to add. + */ + public void addInternalFrameListener(InternalFrameListener l) + { + listenerList.add(InternalFrameListener.class, l); + } + + /** + * This method is used to create a root pane for the JInternalFrame. This + * method is called by the constructors. + * + * @return A root pane for the JInternalFrame to use. + */ + protected JRootPane createRootPane() + { + return new JRootPane(); + } + + /** + * This method makes this JInternalFrame invisible, unselected and closed. + * If this JInternalFrame is not closed already, it will fire an + * INTERNAL_FRAME_CLoSED event. This method is similar to setClosed but it + * doesn't give vetoable listeners a chance to veto and it will not fire an + * INTERNAL_FRAME_CLOSING event. + */ + public void dispose() + { + hide(); + JDesktopPane pane = getDesktopPane(); + if (pane != null) + pane.setSelectedFrame(null); + else + { + try + { + setSelected(false); + } + catch (PropertyVetoException e) + { + // Do nothing if they don't want to be unselected. + } + } + isClosed = true; + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); + removeNotify(); + } + + /** + * This method is used for closing this JInternalFrame. It fires an + * INTERNAL_FRAME_CLOSING event and then performs the action specified by + * the default close operation. + */ + public void doDefaultCloseAction() + { + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); + switch (getDefaultCloseOperation()) + { + case HIDE_ON_CLOSE: + hide(); + break; + case DISPOSE_ON_CLOSE: + dispose(); + break; + } + } + + /** + * This method fires an InternalFrameEvent to the listeners. + * + * @param id The type of event being fired. See InternalFrameEvent. + */ + protected void fireInternalFrameEvent(int id) + { + Object[] ifListeners = listenerList.getListenerList(); + InternalFrameEvent evt = new InternalFrameEvent(this, id); + switch (id) + { + case InternalFrameEvent.INTERNAL_FRAME_CLOSING: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]) + .internalFrameClosing(evt); + } + break; + case InternalFrameEvent.INTERNAL_FRAME_ACTIVATED: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]) + .internalFrameActivated(evt); + } + break; + case InternalFrameEvent.INTERNAL_FRAME_CLOSED: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]).internalFrameClosed(evt); + } + break; + case InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]) + .internalFrameDeactivated(evt); + } + break; + case InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]) + .internalFrameDeiconified(evt); + } + break; + case InternalFrameEvent.INTERNAL_FRAME_ICONIFIED: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]) + .internalFrameIconified(evt); + } + break; + case InternalFrameEvent.INTERNAL_FRAME_OPENED: + for (int i = ifListeners.length - 2; i >= 0; i -= 2) + { + if (ifListeners[i] == InternalFrameListener.class) + ((InternalFrameListener) ifListeners[i + 1]).internalFrameOpened(evt); + } + break; + } + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJInternalFrame(); + return accessibleContext; + } + + /** + * This method returns the Content Pane for this JInternalFrame. + * + * @return The Content Pane for this JInternalFrame. + */ + public Container getContentPane() + { + return getRootPane().getContentPane(); + } + + /** + * This method returns the default action taken when this JInternalFrame is + * closed. + * + * @return The default action taken when this JInternalFrame is closed. + */ + public int getDefaultCloseOperation() + { + return defaultCloseOperation; + } + + /** + * This method returns the JDesktopIcon that represents this JInternalFrame + * while it is iconified. + * + * @return The JDesktopIcon that represents this JInternalFrame while it is + * iconified. + */ + public JDesktopIcon getDesktopIcon() + { + if (desktopIcon == null) + desktopIcon = new JDesktopIcon(this); + return desktopIcon; + } + + /** + * This method searches this JInternalFrame ancestors for an instance of + * JDesktopPane. If one is found, it is returned. If none is found, then it + * will search the JDesktopIcon for a JDesktopPane. + * + * @return The JDesktopPane that this JInternalFrame belongs to. + */ + public JDesktopPane getDesktopPane() + { + JDesktopPane value = (JDesktopPane) SwingUtilities.getAncestorOfClass(JDesktopPane.class, + this); + if (value == null && desktopIcon != null) + value = desktopIcon.getDesktopPane(); + return value; + } + + /** + * This method returns null because this must always be the root of a focus + * traversal. + * + * @return always null + * + * @since 1.4 + */ + public final Container getFocusCycleRootAncestor() + { + // as defined. + return null; + } + + /** + * This method returns the child Component that will receive focus if this + * JInternalFrame is selected. + * + * @return The child Component that will receive focus. + */ + public Component getFocusOwner() + { + if (isSelected()) + { + Component focus = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + if (SwingUtilities.isDescendingFrom(focus, this)) + { + defaultFocus = focus; + return focus; + } + } + return null; + } + + /** + * This method returns the Frame Icon (the icon used in the JInternalFrame + * TitlePane and iconified frame). + * + * @return The Frame Icon. + */ + public Icon getFrameIcon() + { + return frameIcon; + } + + /** + * This method returns the Glass Pane used with this JInternalFrame. + * + * @return The Glass Pane used with this JInternalFrame. + */ + public Component getGlassPane() + { + return getRootPane().getGlassPane(); + } + + /** + * This method returns an array of InternalFrameListeners that are listening + * to this JInternalFrame. + * + * @return An array of InternalFrameListeners that are listening to this + * JInternalFrame. + */ + public InternalFrameListener[] getInternalFrameListeners() + { + return (InternalFrameListener[]) listenerList.getListeners(InternalFrameListener.class); + } + + /** + * This method returns the JMenuBar for this JInternalFrame. + * + * @return The JMenuBar for this JInternalFrame. + */ + public JMenuBar getJMenuBar() + { + return getRootPane().getJMenuBar(); + } + + /** + * This method returns the layer that this JInternalFrame resides in. + * + * @return The layer that this JInternalFrame resides in. + */ + public int getLayer() + { + JDesktopPane pane = getDesktopPane(); + if (pane != null) + // The cast here forces the call to the instance method getLayer() + // instead of the static method (this would lead to infinite + // recursion). + return pane.getLayer((Component) this); + return -1; + } + + /** + * This method returns the LayeredPane for this JInternalFrame. + * + * @return The LayeredPane for this JInternalFrame. + */ + public JLayeredPane getLayeredPane() + { + return getRootPane().getLayeredPane(); + } + + /** + * This method is deprecated. This method returns the JMenuBar for this + * JInternalFrame. + * + * @return The JMenuBar for this JInternalFrame. + * + * @deprecated 1.0.3 + */ + public JMenuBar getMenuBar() + { + return getJMenuBar(); + } + + /** + * This method returns the child Component that will receive focus when the + * JInternalFrame is selected. If the JInternalFrame is selected, this + * method returns getFocusOwner(). Otherwise, it will return the child + * Component that most recently requested focus. If that is null, then the + * initial focus Component is returned. If that is null, then the default + * focus component is returned. + * + * @return The most recent focus owner. + */ + public Component getMostRecentFocusOwner() + { + if (isSelected()) + return getFocusOwner(); + else + return defaultFocus; + } + + /** + * This method returns the bounds of the JInternalFrame if it is not + * maximized. If it is maximized, it returns the bounds of the + * JInternalFrame before it was maximized (the bounds that it will be + * restored to). + * + * @return A Rectangle that contains this JInternalFrame's normal bounds (or + * just its bounds if it is not maximized). + */ + public Rectangle getNormalBounds() + { + if (! isMaximum() && ! maxTransition) + return getBounds(); + else + return storedBounds; + } + + /** + * This method returns the Root Pane for this JInternalFrame. + * + * @return The Root Pane for this JInternalFrame. + */ + public JRootPane getRootPane() + { + return rootPane; + } + + /** + * This method sets the title of the JInternalFrame. + * + * @return The String displayed in the TitlePane of this JInternalFrame. + */ + public String getTitle() + { + return title; + } + + /** + * This method returns the UI used to represent the JInternalFrame. + * + * @return The UI used to represent the JInternalFrame. + */ + public InternalFrameUI getUI() + { + return (InternalFrameUI) ui; + } + + /** + * This method returns a String identifier that is used to determine which + * class acts as the JInternalFrame's UI. + * + * @return A String identifier to determine a UI class. + */ + public String getUIClassID() + { + return "InternalFrameUI"; + } + + /** + * This method returns null. + * + * @return null. + */ + public final String getWarningString() + { + // as defined. + return null; + } + + /** + * This method deselects this JInternalFrame and hides it. + */ + public void hide() + { + JDesktopPane pane = getDesktopPane(); + if (pane != null) + pane.setSelectedFrame(null); + else + { + try + { + setSelected(false); + } + catch (PropertyVetoException e) + { + // Do nothing. + } + } + super.hide(); + } + + /** + * This method returns whether this JInternalFrame is closable. + * + * @return Whether this JInternalFrame is closable. + */ + public boolean isClosable() + { + return closable; + } + + /** + * This method returns whether this JInternalFrame has been closed. + * + * @return Whether this JInternalFrame is closed. + */ + public boolean isClosed() + { + return isClosed; + } + + /** + * This must always return true. + * + * @return always true + * + * @since 1.4 + */ + public final boolean isFocusCycleRoot() + { + return true; + } + + /** + * This method returns whether this JInternalFrame is currently iconified. + * + * @return Whether this JInternalFrame is currently iconified. + */ + public boolean isIcon() + { + return isIcon; + } + + /** + * This method returns whether the JInternalFrame can be iconified. + * + * @return Whether the JInternalFrame can be iconified. + */ + public boolean isIconifiable() + { + return iconable; + } + + /** + * This method returns whether this JInternalFrame can be maximized. + * + * @return Whether this JInternalFrame can be maximized. + */ + public boolean isMaximizable() + { + return maximizable; + } + + /** + * This method returns whether this JInternalFrame is currently maximized. + * + * @return Whether this JInternalFrame is maximized. + */ + public boolean isMaximum() + { + return isMaximum; + } + + /** + * This method returns whether this JInternalFrame is resizable. + * + * @return Whether this JInternalFrame is resizable. + */ + public boolean isResizable() + { + return resizable; + } + + /** + * This method returns whether root pane checking is enabled. If root pane + * checking is enabled, then calls to addImpl and setLayout will throw + * exceptions. + * + * @return Whether root pane checking is enabled. + */ + protected boolean isRootPaneCheckingEnabled() + { + return rootPaneCheckingEnabled; + } + + /** + * This method returns whether this JInternalFrame is selected. + * + * @return Whether this JInternalFrame is selected. + */ + public boolean isSelected() + { + return isSelected; + } + + /** + * A helper method that moves this JInternalFrame to the back if the parent + * is a JLayeredPane. + */ + public void moveToBack() + { + if (getParent() instanceof JLayeredPane) + ((JLayeredPane) getParent()).moveToBack(this); + } + + /** + * A helper method that moves this JInternalFrame to the front if the parent + * is a JLayeredPane. + */ + public void moveToFront() + { + if (getParent() instanceof JLayeredPane) + ((JLayeredPane) getParent()).moveToFront(this); + } + + /** + * This method causes the children of this JInternalFrame to be laid out. + * Before it begins, if this JInternalFrame is an icon, then it will be + * deiconified. If it is maximized, then it will be restored. If either + * operation fails, then this method will return. + */ + public void pack() + { + try + { + if (isIcon()) + setIcon(false); + else if (isMaximum()) + setMaximum(false); + } + catch (PropertyVetoException e) + { + // Do nothing if they don't want to be restored first. + } + setSize(getPreferredSize()); + } + + /** + * This method is overridden to allow for speedier painting while this + * JInternalFramme is being dragged. + * + * @param g The Graphics object to paint with. + */ + protected void paintComponent(Graphics g) + { + super.paintComponent(g); + } + + /** + * This method returns a String describing this JInternalFrame. + * + * @return A String describing this JInternalFrame. + */ + protected String paramString() + { + return "JInternalFrame"; + } + + /** + * This method removes the given Component from the Container. + * + * @param comp The Component to remove. + */ + public void remove(Component comp) + { + // If we're removing the root pane, use super.remove. Otherwise + // pass it on to the content pane instead. + if (comp==rootPane) + super.remove(comp); + else + getContentPane().remove(comp); + } + + /** + * This method removes an InternalFrameListener from this JInternalFrame. + * + * @param l The listener to remove. + */ + public void removeInternalFrameListener(InternalFrameListener l) + { + listenerList.remove(InternalFrameListener.class, l); + } + + /** + * This method resizes and positions this JInternalFrame. It also forces a + * relayout of the Container. + * + * @param x The x position of this JInternalFrame. + * @param y The y position of this JInternalFrame. + * @param width The width of this JInternalFrame. + * @param height The height of this JInternalFrame. + */ + public void reshape(int x, int y, int width, int height) + { + super.reshape(x, y, width, height); + invalidate(); + doLayout(); + } + + /** + * This method gives focus to the last child Component that had focus. This + * is used by the UI when this JInternalFrame is activated. + */ + public void restoreSubcomponentFocus() + { + Component c = getMostRecentFocusOwner(); + if (c != null) + c.requestFocus(); + } + + /** + * This method sets whether this JInternalFrame can be closed. + * + * @param b Whether this JInternalFrame can be closed. + */ + public void setClosable(boolean b) + { + closable = b; + } + + /** + * This method closes the JInternalFrame if the given boolean is true. If it + * is false, then the result of this method is unspecified. If the + * JInternalFrame is closed, this method does nothing. This method will + * first fire an INTERNAL_FRAME_CLOSING event and give a chance for veto + * listeners to cancel the close. If no listener vetoes the change, the + * closed property is set to true and the JInternalFrame is hidden and + * unselected. The method will finish by firing an INTERNAL_FRAME_CLOSED + * event. + * + * @param b Whether the JInternalFrame will be closed. + * + * @throws PropertyVetoException If a VetoableChangeListener vetoes the change. + */ + public void setClosed(boolean b) throws PropertyVetoException + { + if (b && ! isClosed()) + { + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); + fireVetoableChange(IS_CLOSED_PROPERTY, false, true); + + isClosed = b; + + firePropertyChange(IS_CLOSED_PROPERTY, false, true); + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); + } + } + + /** + * This method sets the Container to be used as a Content Pane for this + * JInternalFrame. + * + * @param c The Container to use as a Content Pane. + */ + public void setContentPane(Container c) + { + if (c != getContentPane()) + { + Container old = getContentPane(); + getRootPane().setContentPane(c); + firePropertyChange(CONTENT_PANE_PROPERTY, old, c); + } + } + + /** + * This method sets the action taken when this JInternalFrame is closed. + * + * @param operation One of DO_NOTHING_ON_CLOSE, HIDE_ON_CLOSE or + * DISPOSE_ON_CLOSE. + * + * @throws Error If the given operation is not one of the allowed modes. + */ + public void setDefaultCloseOperation(int operation) + { + /* Reference implementation allows invalid operations to be specified. + In that case, behaviour defaults to DO_NOTHING_ON_CLOSE. + processWindowEvent handles the behaviour. getDefaultCloseOperation + must return the invalid operator code. */ + defaultCloseOperation = operation; + } + + /** + * This method sets the JDesktopIcon that represents this JInternalFrame + * while it is iconified. + * + * @param d The JDesktopIcon that represents this JInternalFrame while it is + * iconified. + */ + public void setDesktopIcon(JDesktopIcon d) + { + d.setInternalFrame(this); + desktopIcon = d; + } + + /** + * This method does nothing because this must be the root of a focus + * traversal cycle. + * + * @param focusCycleRoot Not used. + */ + public final void setFocusCycleRoot(boolean focusCycleRoot) + { + // Do nothing + } + + /** + * This method sets the Icon to be used in two places. The first is icon + * that is painted at the top left corner of the JInternalFrame when it is + * not iconified (clicking on that icon will activate the TitlePane + * JMenuBar). When the JInternalFrame is iconified, it will be the icon + * displayed in the JDesktopIcon. If no icon is set, the JInternalFrame + * will use a Look and Feel default. + * + * @param icon The Icon used in the TitlePane JMenuBar and iconified frames. + */ + public void setFrameIcon(Icon icon) + { + if (icon != frameIcon) + { + Icon old = frameIcon; + frameIcon = icon; + firePropertyChange(FRAME_ICON_PROPERTY, old, frameIcon); + } + } + + /** + * This method sets the Glass Pane used with this JInternalFrame. + * + * @param glass The Glass Pane to use with this JInternalFrame. + */ + public void setGlassPane(Component glass) + { + if (glass != getGlassPane()) + { + Component old = getGlassPane(); + getRootPane().setGlassPane(glass); + firePropertyChange(GLASS_PANE_PROPERTY, old, glass); + } + } + + /** + * This method iconifies or deiconifies this JInternalFrame given the + * boolean argument. If the JInternalFrame becomes iconified, it will fire + * an INTERNAL_FRAME_ICONIFIED event. If the JInternalFrame becomes + * deiconified, it will fire anINTERNAL_FRAME_DEICONIFIED event. + * + * @param b Whether this JInternalFrame is to be iconified or deiconified. + * + * @throws PropertyVetoException DOCUMENT ME! + */ + public void setIcon(boolean b) throws PropertyVetoException + { + if (b != isIcon()) + { + fireVetoableChange(IS_ICON_PROPERTY, b, isIcon); + + isIcon = b; + + firePropertyChange(IS_ICON_PROPERTY, ! isIcon, isIcon); + if (b) + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ICONIFIED); + else + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED); + } + } + + /** + * This method sets whether the JInternalFrame can be iconified. (This means + * that the JInternalFrame can be turned into an icon if minimized). + * + * @param b Whether the JInternalFrame can be iconified. + */ + public void setIconifiable(boolean b) + { + iconable = b; + } + + /** + * This method sets the JMenuBar to be used with this JInternalFrame. + * + * @param b The JMenuBar to be used with this JInternalFrame. + */ + public void setJMenuBar(JMenuBar b) + { + getRootPane().setJMenuBar(b); + } + + /** + * A helper method that set the layer that this JInternalFrame resides in. + * Using this version of the method means that the user should not set it + * to values that are already defined in JLayeredPane. If predefined values + * are to be used, the user should use the setLayer(Integer) version. + * + * @param layer The layer to place this JInternalFrame in. + */ + public void setLayer(int layer) + { + setLayer(new Integer(layer)); + } + + /** + * A helper method that sets the layer that this JInternalFrame resides in. + * Calling this version of the method should use layer values that are + * already defined in JLayeredPane. + * + * @param layer The layer to place this JInternalFrame in. + */ + public void setLayer(Integer layer) + { + JDesktopPane p = getDesktopPane(); + if (p != null) + { + int pos = p.getPosition(this); + p.setLayer(this, layer.intValue(), pos); + } + } + + /** + * This method sets the JLayeredPane to use with this JInternalFrame. + * + * @param layered The JLayeredPane to use as a layeredPane. + */ + public void setLayeredPane(JLayeredPane layered) + { + if (layered != getLayeredPane()) + { + JLayeredPane old = getLayeredPane(); + getRootPane().setLayeredPane(layered); + firePropertyChange(LAYERED_PANE_PROPERTY, old, layered); + } + } + + /** + * This method sets whether the JInternalFrame can be maximized. + * + * @param b Whether this JInternalFrame can be maximized. + */ + public void setMaximizable(boolean b) + { + maximizable = b; + } + + /** + * This method sets the Layout Manager used in the JInternalFrame. SetLayout + * should not be called on the JInternalFrame directly. Instead, it should + * be called with JInternalFrame.getContentPane().setLayout. Calls to this + * method with root pane checking enabled will cause exceptions to be + * thrown. + * + * @param manager The Layout Manager to be used with the JInternalFrame. + * + * @throws Error If rootPaneChecking is enabled. + */ + public void setLayout(LayoutManager manager) + { + // Check if we're in initialization stage. If so, call super.setLayout + // otherwise, valid calls go to the content pane. + if (initStageDone) + { + if (isRootPaneCheckingEnabled()) + throw new Error("Cannot set layout. Use getContentPane().setLayout()" + + " instead."); + getContentPane().setLayout(manager); + } + else + super.setLayout(manager); + } + + /** + * This method sets the JInternalFrame to maximized (if the given argument + * is true) or restores the JInternalFrame to its normal bounds otherwise. + * + * @param b Whether this JInteralFrame will be maximized or restored. + * + * @throws PropertyVetoException If a VetoableChangeListener vetoes the change. + */ + public void setMaximum(boolean b) throws PropertyVetoException + { + if (b != isMaximum()) + { + fireVetoableChange(IS_MAXIMUM_PROPERTY, b, isMaximum); + isMaximum = b; + if (b) + setNormalBounds(getBounds()); + maxTransition = ! b; + firePropertyChange(IS_MAXIMUM_PROPERTY, ! isMaximum, isMaximum); + maxTransition = false; + } + } + + /** + * This method is deprecated. This method sets the JMenuBar used with this + * JInternalFrame. + * + * @param m The JMenuBar to use with this JInternalFrame. + * + * @deprecated 1.0.3 + */ + public void setMenuBar(JMenuBar m) + { + setJMenuBar(m); + } + + /** + * This method sets the bounds that this JInternalFrame will be restored to. + * + * @param r The bounds that this JInternalFrame will be restored to. + */ + public void setNormalBounds(Rectangle r) + { + storedBounds.setBounds(r.x, r.y, r.width, r.height); + } + + /** + * This method sets whether the JInternalFrame can be resized by a user + * action (like dragging at the frame borders). + * + * @param b Whether this JInternalFramer can be resized. + */ + public void setResizable(boolean b) + { + resizable = b; + } + + /** + * This method sets the Root Pane for this JInternalFrame. + * + * @param root The Root Pane for this JInternalFrame. + */ + protected void setRootPane(JRootPane root) + { + if (rootPane != null) + remove(rootPane); + + rootPane = root; + add(root); + } + + /** + * This method sets whether root pane checking is enabled. If root pane + * checking is enabled, then calls to addImpl and setLayout will throw + * exceptions. + * + * @param enabled Whether root pane checking is enabled. + */ + protected void setRootPaneCheckingEnabled(boolean enabled) + { + rootPaneCheckingEnabled = enabled; + } + + /** + * This method sets whether this JInternalFrame is the selected frame in the + * JDesktopPane (or other container). When selected, a JInternalFrame will + * have focus and paint its TitlePane differently (usually a different + * colour). If this method selects the frame, this JInternalFrame will fire + * an INTERNAL_FRAME_ACTIVATED event. If it deselects this frame, it will + * fire an INTERNAL_FRAME_DEACTIVATED event. + * + * @param selected Whether this JInternalFrame will become selected or + * deselected. + * + * @throws PropertyVetoException If a VetoableChangeListener vetoes the change. + */ + public void setSelected(boolean selected) throws PropertyVetoException + { + if (selected != isSelected()) + { + fireVetoableChange(IS_SELECTED_PROPERTY, selected, isSelected); + + if (! selected) + defaultFocus = getMostRecentFocusOwner(); + + isSelected = selected; + + if (selected) + restoreSubcomponentFocus(); + + firePropertyChange(IS_SELECTED_PROPERTY, ! isSelected, isSelected); + + if (isSelected) + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ACTIVATED); + else + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED); + } + } + + /** + * This method sets the title displayed in the TitlePane of this + * JInternalFrame. + * + * @param title The title displayed. + */ + public void setTitle(String title) + { + if (title == null && this.title == null) + return; + if (title == null || this.title == null || ! this.title.equals(title)) + { + String old = title; + this.title = title; + firePropertyChange(TITLE_PROPERTY, old, this.title); + } + } + + /** + * This method displays the JInternalFrame. If it is not visible, this + * method will bring this JInternalFrame to the front, make it visible and + * select it. If this is the first time this JInternalFrame is made + * visible, an INTERNAL_FRAME_OPENED event will be fired. + */ + public void show() + { + if (! isVisible()) + { + moveToFront(); + super.show(); + + JDesktopPane pane = getDesktopPane(); + if (pane != null) + pane.setSelectedFrame(this); + else + { + try + { + setSelected(true); + } + catch (PropertyVetoException e) + { + // Do nothing. if they don't want to be selected. + } + } + if (isFirstTimeVisible) + { + isFirstTimeVisible = false; + fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED); + } + } + } + + /** + * This method is used to set the UI responsible for the JInternalFrame. + * + * @param ui The UI responsible for the JInternalFrame. + */ + public void setUI(InternalFrameUI ui) + { + super.setUI(ui); + } + + /** + * This method causes the JInternalFrame to be brough to back in the + * z-order. + */ + public void toBack() + { + moveToBack(); + } + + /** + * This method causes the JInternalFrame to be brought to front in the + * z-order. + */ + public void toFront() + { + moveToFront(); + } + + /** + * This method resets the UI to the Look and Feel defaults. + */ + public void updateUI() + { + setUI((InternalFrameUI) UIManager.getUI(this)); + } + + /** + * This helper method allows JInternalFrames to signal that they were + * iconned for the first time. + * + * @param b Whether the JInternalFrame was iconned. + * @param ID The identifier of the property change event to fire if the + * JInternalFrame is iconned for the first time. + */ + void setWasIcon(boolean b, String ID) + { + if (b && ! wasIcon) + { + wasIcon = b; + firePropertyChange(ID, ! b, b); + } + } + + /** + * This helper method returns whether the JInternalFrame has been iconned + * once already. + * + * @return Whether the JInternalFrame has been iconned once already. + */ + boolean getWasIcon() + { + return wasIcon; + } + + /** + * This method is a convenience method to fire vetoable property changes. + * + * @param name The identifier of the property change. + * @param oldValue The old value. + * @param newValue The new value. + * + * @throws PropertyVetoException Fired if a vetoable change listener vetoes + * the change. + */ + private void fireVetoableChange(String name, boolean oldValue, + boolean newValue) + throws PropertyVetoException + { + super.fireVetoableChange(name, Boolean.valueOf(oldValue), Boolean.valueOf(newValue)); + } +} diff --git a/libjava/classpath/javax/swing/JLabel.java b/libjava/classpath/javax/swing/JLabel.java new file mode 100644 index 00000000000..088f7d69345 --- /dev/null +++ b/libjava/classpath/javax/swing/JLabel.java @@ -0,0 +1,647 @@ +/* JLabel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Font; +import java.awt.Image; +import java.awt.event.KeyEvent; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.plaf.LabelUI; + +/** + * A swing widget that displays a text message and/or an icon. + */ +public class JLabel extends JComponent implements Accessible, SwingConstants +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = 5496508283662221534L; + + /** + * The Component the label will give focus to when its mnemonic is + * activated. + */ + protected Component labelFor; + + /** The label's text. */ + private transient String text; + + /** Where the label will be positioned horizontally. */ + private transient int horizontalAlignment = LEADING; + + /** Where the label text will be placed horizontally relative to the icon. */ + private transient int horizontalTextPosition = TRAILING; + + /** Where the label will be positioned vertically. */ + private transient int verticalAlignment = CENTER; + + /** Where the label text will be place vertically relative to the icon. */ + private transient int verticalTextPosition = CENTER; + + /** The icon painted when the label is enabled. */ + private transient Icon icon; + + /** The icon painted when the label is disabled. */ + private transient Icon disabledIcon; + + /** The label's mnemnonic key. */ + private transient int displayedMnemonic = KeyEvent.VK_UNDEFINED; + + /** The index of the menemonic character in the text. */ + private transient int displayedMnemonicIndex = -1; + + /** The gap between the icon and the text. */ + private transient int iconTextGap = 4; + + /** + * Creates a new vertically centered, horizontally on the leading edge + * JLabel object with text and no icon. + */ + public JLabel() + { + this(null, null, LEADING); + } + + /** + * Creates a new vertically and horizontally centered + * JLabel object with no text and the given icon. + * + * @param image The icon to use with the label. + */ + public JLabel(Icon image) + { + this(null, image, CENTER); + } + + /** + * Creates a new vertically centered JLabel object with no text and the + * given icon and horizontal alignment. By default, the text is TRAILING + * the image. + * + * @param image The icon to use with the label. + * @param horizontalAlignment The horizontal alignment of the label. + */ + public JLabel(Icon image, int horizontalAlignment) + { + this(null, image, horizontalAlignment); + } + + /** + * Creates a new horizontally leading and vertically centered JLabel + * object with no icon and the given text. + * + * @param text The text to use with the label. + */ + public JLabel(String text) + { + this(text, null, LEADING); + } + + /** + * Creates a new vertically centered JLabel object with no icon and the + * given text and horizontal alignment. + * + * @param text The text to use with the label. + * @param horizontalAlignment The horizontal alignment of the label. + */ + public JLabel(String text, int horizontalAlignment) + { + this(text, null, horizontalAlignment); + } + + /** + * Creates a new vertically centered JLabel object with the given text, + * icon, and horizontal alignment. + * + * @param text The text to use with the label. + * @param icon The icon to use with the label. + * @param horizontalAlignment The horizontal alignment of the label. + */ + public JLabel(String text, Icon icon, int horizontalAlignment) + { + this.text = text; + this.icon = icon; + this.horizontalAlignment = horizontalAlignment; + updateUI(); + } + + /** + * This method returns the label's UI delegate. + * + * @return The label's UI delegate. + */ + public LabelUI getUI() + { + return (LabelUI) ui; + } + + /** + * This method sets the label's UI delegate. + * + * @param ui The label's UI delegate. + */ + public void setUI(LabelUI ui) + { + super.setUI(ui); + } + + /** + * This method resets the label's UI delegate to the default UI for the + * current look and feel. + */ + public void updateUI() + { + setUI((LabelUI) UIManager.getUI(this)); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for this label. + * + * @return The UIClass identifier. "LabelUI" + */ + public String getUIClassID() + { + return "LabelUI"; + } + + /** + * This method is used primarily for debugging purposes and returns a string + * that can be used to represent this label. + * + * @return A string to represent this label. + */ + protected String paramString() + { + return "JLabel"; + } + + /** + * This method returns the label text. + * + * @return The label text. + */ + public String getText() + { + return text; + } + + /** + * This method changes the "text" property. The given text will be painted + * in the label. + * + * @param newText The label's text. + */ + public void setText(String newText) + { + if (text != newText) + { + String oldText = text; + text = newText; + firePropertyChange("text", oldText, newText); + + if (text != null && text.length() <= displayedMnemonicIndex) + setDisplayedMnemonicIndex(text.length() - 1); + } + } + + /** + * This method returns the active icon. The active icon is painted when the + * label is enabled. + * + * @return The active icon. + */ + public Icon getIcon() + { + return icon; + } + + /** + * This method changes the "icon" property. This icon (the active icon) will + * be the one displayed when the label is enabled. + * + * @param newIcon The active icon. + */ + public void setIcon(Icon newIcon) + { + if (icon != newIcon) + { + Icon oldIcon = icon; + icon = newIcon; + firePropertyChange("icon", oldIcon, newIcon); + } + } + + /** + * This method returns the disabled icon. The disabled icon is painted when + * the label is disabled. If the disabled icon is null and the active icon + * is an ImageIcon, this method returns a grayed version of the icon. The + * grayed version of the icon becomes the disabledIcon. + * + * @return The disabled icon. + */ + public Icon getDisabledIcon() + { + if (disabledIcon == null && icon instanceof ImageIcon) + disabledIcon = new ImageIcon(GrayFilter.createDisabledImage(((ImageIcon) icon) + .getImage())); + + return disabledIcon; + } + + /** + * This method changes the "disabledIcon" property. This icon (the disabled + * icon) will be the one displayed when the label is disabled. + * + * @param newIcon The disabled icon. + */ + public void setDisabledIcon(Icon newIcon) + { + if (disabledIcon != newIcon) + { + Icon oldIcon = disabledIcon; + disabledIcon = newIcon; + firePropertyChange("disabledIcon", oldIcon, newIcon); + } + } + + /** + * This method sets the keycode that will be the label's mnemonic. If the + * label is used as a label for another component, the label will give + * focus to that component when the mnemonic is activated. + * + * @param mnemonic The keycode to use for the mnemonic. + */ + public void setDisplayedMnemonic(int mnemonic) + { + if (displayedMnemonic != mnemonic) + { + firePropertyChange("displayedMnemonic", + displayedMnemonic, mnemonic); + displayedMnemonic = mnemonic; + + if (text != null) + setDisplayedMnemonicIndex(text.toUpperCase().indexOf(mnemonic)); + } + } + + /** + * This method sets the character that will be the mnemonic used. If the + * label is used as a label for another component, the label will give + * focus to that component when the mnemonic is activated. + * + * @param mnemonic The character to use for the mnemonic. + */ + public void setDisplayedMnemonic(char mnemonic) + { + setDisplayedMnemonic((int) Character.toUpperCase(mnemonic)); + } + + /** + * This method returns the keycode that is used for the label's mnemonic. + * + * @return The keycode that is used for the label's mnemonic. + */ + public int getDisplayedMnemonic() + { + return (int) displayedMnemonic; + } + + /** + * This method sets which character in the text will be the underlined + * character. If the given index is -1, then this indicates that there is + * no mnemonic. If the index is less than -1 or if the index is equal to + * the length, this method will throw an IllegalArgumentException. + * + * @param newIndex The index of the character to underline. + * + * @throws IllegalArgumentException If index less than -1 or index equals + * length. + */ + public void setDisplayedMnemonicIndex(int newIndex) + throws IllegalArgumentException + { + if (newIndex < -1 || (text != null && newIndex >= text.length())) + throw new IllegalArgumentException(); + + if (newIndex == -1 + || text == null + || text.charAt(newIndex) != displayedMnemonic) + newIndex = -1; + + if (newIndex != displayedMnemonicIndex) + { + int oldIndex = displayedMnemonicIndex; + displayedMnemonicIndex = newIndex; + firePropertyChange("displayedMnemonicIndex", + oldIndex, newIndex); + } + } + + /** + * This method returns which character in the text will be the underlined + * character. + * + * @return The index of the character that will be underlined. + */ + public int getDisplayedMnemonicIndex() + { + return displayedMnemonicIndex; + } + + /** + * This method ensures that the key is valid as a horizontal alignment. + * Valid keys are: LEFT, CENTER, RIGHT, LEADING, TRAILING + * + * @param key The key to check. + * @param message The message of the exception to be thrown if the key is + * invalid. + * + * @return The key if it's valid. + * + * @throws IllegalArgumentException If the key is invalid. + */ + protected int checkHorizontalKey(int key, String message) + { + if (key != LEFT && key != CENTER && key != RIGHT && key != LEADING + && key != TRAILING) + throw new IllegalArgumentException(message); + else + return key; + } + + /** + * This method ensures that the key is valid as a vertical alignment. Valid + * keys are: TOP, CENTER, and BOTTOM. + * + * @param key The key to check. + * @param message The message of the exception to be thrown if the key is + * invalid. + * + * @return The key if it's valid. + * + * @throws IllegalArgumentException If the key is invalid. + */ + protected int checkVerticalKey(int key, String message) + { + if (key != TOP && key != BOTTOM && key != CENTER) + throw new IllegalArgumentException(message); + else + return key; + } + + /** + * This method returns the gap between the icon and the text. + * + * @return The gap between the icon and the text. + */ + public int getIconTextGap() + { + return iconTextGap; + } + + /** + * This method changes the "iconTextGap" property. The iconTextGap + * determines how much space there is between the icon and the text. + * + * @param newGap The gap between the icon and the text. + */ + public void setIconTextGap(int newGap) + { + if (iconTextGap != newGap) + { + firePropertyChange("iconTextGap", iconTextGap, newGap); + iconTextGap = newGap; + } + } + + /** + * This method returns the vertical alignment of the label. + * + * @return The vertical alignment of the label. + */ + public int getVerticalAlignment() + { + return verticalAlignment; + } + + /** + * This method changes the "verticalAlignment" property of the label. The + * vertical alignment determines how where the label will be placed + * vertically. If the alignment is not valid, it will default to the + * center. + * + * @param alignment The vertical alignment of the label. + */ + public void setVerticalAlignment(int alignment) + { + if (alignment == verticalAlignment) + return; + + int oldAlignment = verticalAlignment; + verticalAlignment = checkVerticalKey(alignment, "verticalAlignment"); + firePropertyChange("verticalAlignment", oldAlignment, verticalAlignment); + } + + /** + * This method returns the horziontal alignment of the label. + * + * @return The horizontal alignment of the label. + */ + public int getHorizontalAlignment() + { + return horizontalAlignment; + } + + /** + * This method changes the "horizontalAlignment" property. The horizontal + * alignment determines where the label will be placed horizontally. + * + * @param alignment The horizontal alignment of the label. + */ + public void setHorizontalAlignment(int alignment) + { + if (horizontalAlignment == alignment) + return; + + int oldAlignment = horizontalAlignment; + horizontalAlignment = checkHorizontalKey(alignment, "horizontalAlignment"); + firePropertyChange("horizontalAlignment", oldAlignment, + horizontalAlignment); + } + + /** + * This method returns the vertical text position of the label. + * + * @return The vertical text position of the label. + */ + public int getVerticalTextPosition() + { + return verticalTextPosition; + } + + /** + * This method changes the "verticalTextPosition" property of the label. The + * vertical text position determines where the text will be placed + * vertically relative to the icon. + * + * @param textPosition The vertical text position. + */ + public void setVerticalTextPosition(int textPosition) + { + if (textPosition != verticalTextPosition) + { + int oldPos = verticalTextPosition; + verticalTextPosition = checkVerticalKey(textPosition, + "verticalTextPosition"); + firePropertyChange("verticalTextPosition", oldPos, + verticalTextPosition); + } + } + + /** + * This method returns the horizontal text position of the label. + * + * @return The horizontal text position. + */ + public int getHorizontalTextPosition() + { + return horizontalTextPosition; + } + + /** + * This method changes the "horizontalTextPosition" property of the label. + * The horizontal text position determines where the text will be placed + * horizontally relative to the icon. + * + * @param textPosition The horizontal text position. + */ + public void setHorizontalTextPosition(int textPosition) + { + if (textPosition != horizontalTextPosition) + { + int oldPos = horizontalTextPosition; + horizontalTextPosition = checkHorizontalKey(textPosition, + "horizontalTextPosition"); + firePropertyChange("horizontalTextPosition", oldPos, + horizontalTextPosition); + } + } + + /** + * This method simply returns false if the current icon image (current icon + * will depend on whether the label is enabled) is not equal to the passed + * in image. + * + * @param img The image to check. + * @param infoflags The bitwise inclusive OR of ABORT, ALLBITS, ERROR, + * FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, and WIDTH + * @param x The x position + * @param y The y position + * @param w The width + * @param h The height + * + * @return Whether the current icon image is equal to the image given. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, + int h) + { + Icon currIcon = isEnabled() ? icon : disabledIcon; + + // XXX: Is this the correct way to check for image equality? + if (currIcon != null && currIcon instanceof ImageIcon) + return (((ImageIcon) currIcon).getImage() == img); + + return false; + } + + /** + * This method returns the component that the label gives focus to when the + * mnemonic is activated. + * + * @return The component that gets focus when the label's mnemonic is + * activated. + */ + public Component getLabelFor() + { + return labelFor; + } + + /** + * This method changes the "labelFor" property. The component that the label + * is acting as a label for will request focus when the label's mnemonic + * is activated. + * + * @param c The component that gets focus when the label's mnemonic is + * activated. + */ + public void setLabelFor(Component c) + { + if (c != labelFor) + { + Component oldLabelFor = labelFor; + labelFor = c; + firePropertyChange("labelFor", oldLabelFor, labelFor); + } + } + + /** + * This method overrides setFont so that we can call for a repaint after the + * font is changed. + * + * @param f The font for this label. + */ + public void setFont(Font f) + { + super.setFont(f); + repaint(); + } + + /** + * DOCUMENT ME! + * + * @return + */ + public AccessibleContext getAccessibleContext() + { + return null; + } +} diff --git a/libjava/classpath/javax/swing/JLayeredPane.java b/libjava/classpath/javax/swing/JLayeredPane.java new file mode 100644 index 00000000000..c9a4fd40413 --- /dev/null +++ b/libjava/classpath/javax/swing/JLayeredPane.java @@ -0,0 +1,622 @@ +/* JLayeredPane.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +import javax.accessibility.Accessible; + +/** + * <p>The "Layered Pane" is a container which divides its children into 6 (or + * more) disjoint sets. the pre-defined sets are:</p> + * + * <ul> + * <li>"Frame Content"</li> + * <li>"Default"</li> + * <li>"Palette"</li> + * <li>"Modal"</li> + * <li>"Popup"</li> + * <li>"Drag"</li> + * </ul> + * + * <p>A child is in exactly one of these layers at any time, though there may + * be other layers if someone creates them.</p> + * + * <p>The purpose of this class is to translate this view of "layers" into a + * contiguous array of components: the one held in our ancestor, + * {@link java.awt.Container}.</p> + * + * <p>There is a precise set of words we will use to refer to numbers within + * this class:</p> + * + * <dl> + * <dt>Component Index:</dt> + * <dd>An offset into the <code>component</code> array held in our ancestor, + * {@link java.awt.Container}, from <code>[0 .. component.length)</code>. The drawing + * rule with indices is that 0 is drawn last.</dd> + * + * <dt>Layer Number:</dt> + * <dd>A general <code>int</code> specifying a layer within this component. Negative + * numbers are drawn first, then layer 0, then positive numbered layers, in + * ascending order.</dd> + * + * <dt>Position:</dt> + * <dd>An offset into a layer's "logical drawing order". Layer position 0 + * is drawn last. Layer position -1 is a synonym for the first layer + * position (the logical "bottom").</dd> + * </dl> + * + * <p><b>Note:</b> the layer numbering order is the <em>reverse</em> of the + * component indexing and position order</p> + * + * @author Graydon Hoare (graydon@redhat.com) + */ +public class JLayeredPane extends JComponent implements Accessible +{ + private static final long serialVersionUID = 5534920399324590459L; + + public static final String LAYER_PROPERTY = "layeredContainerLayer"; + + public static Integer FRAME_CONTENT_LAYER = new Integer (-30000); + + public static Integer DEFAULT_LAYER = new Integer (0); + public static Integer PALETTE_LAYER = new Integer (100); + public static Integer MODAL_LAYER = new Integer (200); + public static Integer POPUP_LAYER = new Integer (300); + public static Integer DRAG_LAYER = new Integer (400); + + TreeMap layers; // Layer Number (Integer) -> Layer Size (Integer) + Hashtable componentToLayer; // Component -> Layer Number (Integer) + + public JLayeredPane() + { + layers = new TreeMap (); + componentToLayer = new Hashtable (); + } + + + /** + * Looks up the layer a child component is currently assigned to. + * + * @param c the component to look up. + * @return the layer the component is currently assigned to, in this container. + * @throws IllegalArgumentException if the component is not a child of this container. + */ + public int getLayer(Component c) + { + Component myComp = c; + while(! componentToLayer.containsKey(myComp)) + { + myComp = myComp.getParent(); + if (myComp == null) + break; + } + if (myComp == null) + throw new IllegalArgumentException + ("component is not in this JLayeredPane"); + Integer layerObj = (Integer) componentToLayer.get(myComp); + return layerObj.intValue(); + } + + /** + * Looks up the layer of <code>comp</code> in the component's nearest + * JLayeredPane ancestor. If <code>comp</code> is not contained + * in a JLayeredPane, the value 0 (default layer) is returned. + * + * @param comp the component for which the layer is looked up + * + * @return the layer of <code>comp</code> in its nearest JLayeredPane + * ancestor + */ + public static int getLayer(JComponent comp) + { + JLayeredPane lp = (JLayeredPane) SwingUtilities.getAncestorOfClass + (JLayeredPane.class, comp); + if (lp == null) + return 0; + else + // The cast here forces the call to the instance method getLayer() + // instead of the static method (this would lead to infinite + // recursion). + return lp.getLayer((Component) comp); + } + + /** + * Returns the first JLayeredPane that contains the Component + * <code>comp</code> or <code>null</code> if <code>comp</code> is + * not contained in a JLayeredPane. + * + * @param comp the component for which we are searching the JLayeredPane + * ancestor + * + * @return the first JLayeredPane that contains the Component + * <code>comp</code> or <code>null</code> if <code>comp</code> is + * not contained in a JLayeredPane + */ + public static JLayeredPane getLayeredPaneAbove(Component comp) + { + JLayeredPane lp = (JLayeredPane) SwingUtilities.getAncestorOfClass + (JLayeredPane.class, comp); + return lp; + } + + /** + * <p>Returns a pair of ints representing a half-open interval + * <code>[top, bottom)</code>, which is the range of component indices + * the provided layer number corresponds to.</p> + * + * <p>Note that "bottom" is <em>not</em> included in the interval of + * component indices in this layer: a layer with 0 elements in it has + * <code>ret[0] == ret[1]</code>.</p> + * + * @param layer the layer to look up. + * @return the half-open range of indices this layer spans. + * @throws IllegalArgumentException if layer does not refer to an active layer + * in this container. + */ + private int[] layerToRange (Integer layer) + { + int[] ret = new int[2]; + ret[1] = getComponents ().length; + Iterator i = layers.entrySet ().iterator (); + while (i.hasNext()) + { + Map.Entry pair = (Map.Entry) i.next(); + Integer layerNum = (Integer) pair.getKey (); + Integer layerSz = (Integer) pair.getValue (); + if (layerNum.intValue() == layer.intValue()) + { + ret[0] = ret[1] - layerSz.intValue (); + return ret; + } + else + { + ret[1] -= layerSz.intValue (); + } + } + // should have found the layer during iteration + throw new IllegalArgumentException (); + } + + /** + * Increments the recorded size of a given layer. + * + * @param layer the layer number to increment. + * @see #incrLayer() + */ + private void incrLayer(Integer layer) + { + int sz = 1; + if (layers.containsKey (layer)) + sz += ((Integer)(layers.get (layer))).intValue (); + layers.put (layer, new Integer(sz)); + } + + /** + * Decrements the recorded size of a given layer. + * + * @param layer the layer number to decrement. + * @see #decrLayer() + */ + private void decrLayer(Integer layer) + { + int sz = 0; + if (layers.containsKey (layer)) + sz = ((Integer)(layers.get (layer))).intValue () - 1; + layers.put (layer, new Integer(sz)); + } + + /** + * Return the greatest layer number currently in use, in this container. + * This number may legally be positive <em>or</em> negative. + * + * @return the least layer number. + * @see #lowestLayer() + */ + public int highestLayer() + { + if (layers.size() == 0) + return 0; + return ((Integer)(layers.lastKey ())).intValue (); + } + + /** + * Return the least layer number currently in use, in this container. + * This number may legally be positive <em>or</em> negative. + * + * @return the least layer number. + * @see #highestLayer() + */ + public int lowestLayer() + { + if (layers.size() == 0) + return 0; + return ((Integer)(layers.firstKey ())).intValue (); + } + + /** + * Moves a component to the "front" of its layer. The "front" is a + * synonym for position 0, which is also the last position drawn in each + * layer, so is usually the component which occludes the most other + * components in its layer. + * + * @param c the component to move to the front of its layer. + * @throws IllegalArgumentException if the component is not a child of + * this container. + * @see #moveToBack() + */ + public void moveToFront(Component c) + { + setPosition (c, 0); + } + + /** + * <p>Moves a component to the "back" of its layer. The "back" is a + * synonym for position N-1 (also known as position -1), where N is the + * size of the layer.</p> + * + * <p>The "back" of a layer is the first position drawn, so the component at + * the "back" is usually the component which is occluded by the most + * other components in its layer.</p> + * + * @param c the component to move to the back of its layer. + * @throws IllegalArgumentException if the component is not a child of + * this container. + * @see #moveToFront() + */ + public void moveToBack(Component c) + { + setPosition (c, -1); + } + + /** + * Return the position of a component within its layer. Positions are assigned + * from the "front" (position 0) to the "back" (position N-1), and drawn from + * the back towards the front. + * + * @param c the component to get the position of. + * @throws IllegalArgumentException if the component is not a child of + * this container. + * @see #setPosition() + */ + public int getPosition(Component c) + { + int layer = getLayer (c); + int[] range = layerToRange(new Integer(layer)); + int top = range[0]; + int bot = range[1]; + Component[] comps = getComponents (); + for (int i = top; i < bot; ++i) + { + if (comps[i] == c) + return i - top; + } + // should have found it + throw new IllegalArgumentException (); + } + + /** + * Change the position of a component within its layer. Positions are assigned + * from the "front" (position 0) to the "back" (position N-1), and drawn from + * the back towards the front. + * + * @param c the component to change the position of. + * @param position the position to assign the component to. + * @throws IllegalArgumentException if the component is not a child of + * this container. + * @see #getPosition() + */ + public void setPosition(Component c, int position) + { + int layer = getLayer (c); + int[] range = layerToRange(new Integer(layer)); + if (range[0] == range[1]) + throw new IllegalArgumentException (); + + int top = range[0]; + int bot = range[1]; + if (position == -1) + position = (bot - top) - 1; + int targ = Math.min(top + position, bot-1); + int curr = -1; + + Component[] comps = getComponents(); + for (int i = top; i < bot; ++i) + { + if (comps[i] == c) + { + curr = i; + break; + } + } + if (curr == -1) + // should have found it + throw new IllegalArgumentException(); + + super.swapComponents (curr, targ); + revalidate(); + repaint(); + } + + /** + * Return an array of all components within a layer of this + * container. Components are ordered front-to-back, with the "front" + * element (which draws last) at position 0 of the returned array. + * + * @param layer the layer to return components from. + * @return the components in the layer. + */ + public Component[] getComponentsInLayer(int layer) + { + int[] range = layerToRange (getObjectForLayer (layer)); + if (range[0] == range[1]) + return new Component[0]; + else + { + Component[] comps = getComponents (); + int sz = range[1] - range[0]; + Component[] nc = new Component[sz]; + for (int i = 0; i < sz; ++i) + nc[i] = comps[range[0] + i]; + return nc; + } + } + + /** + * Return the number of components within a layer of this + * container. + * + * @param layer the layer count components in. + * @return the number of components in the layer. + */ + public int getComponentCountInLayer(int layer) + { + int[] range = layerToRange (getObjectForLayer (layer)); + if (range[0] == range[1]) + return 0; + else + return (range[1] - range[0]); + } + + /** + * Return a hashtable mapping child components of this container to + * Integer objects representing the component's layer assignments. + */ + protected Hashtable getComponentToLayer() + { + return componentToLayer; + } + + /** + * Return the index of a component within the underlying (contiguous) + * array of children. This is a "raw" number which does not represent the + * child's position in a layer, but rather its position in the logical + * drawing order of all children of the container. + * + * @param c the component to look up. + * @return the external index of the component. + * @throws IllegalArgumentException if the component is not a child of + * this container. + */ + public int getIndexOf(Component c) + { + int layer = getLayer (c); + int[] range = layerToRange(new Integer(layer)); + Component[] comps = getComponents(); + for (int i = range[0]; i < range[1]; ++i) + { + if (comps[i] == c) + return i; + } + // should have found the component during iteration + throw new IllegalArgumentException (); + } + + /** + * Return an Integer object which holds the same int value as the + * parameter. This is strictly an optimization to minimize the number of + * identical Integer objects which we allocate. + * + * @param layer the layer number as an int. + * @return the layer number as an Integer, possibly shared. + */ + protected Integer getObjectForLayer(int layer) + { + switch (layer) + { + case -30000: + return FRAME_CONTENT_LAYER; + + case 0: + return DEFAULT_LAYER; + + case 100: + return PALETTE_LAYER; + + case 200: + return MODAL_LAYER; + + case 300: + return POPUP_LAYER; + + case 400: + return DRAG_LAYER; + + default: + break; + } + + return new Integer(layer); + } + + /** + * Computes an index at which to request the superclass {@link + * java.awt.Container} inserts a component, given an abstract layer and + * position number. + * + * @param layer the layer in which to insert a component. + * @param position the position in the layer at which to insert a component. + * @return the index at which to insert the component. + */ + protected int insertIndexForLayer(int layer, int position) + { + + Integer lobj = getObjectForLayer (layer); + if (! layers.containsKey(lobj)) + layers.put (lobj, new Integer (0)); + int[] range = layerToRange (lobj); + if (range[0] == range[1]) + return range[0]; + + int top = range[0]; + int bot = range[1]; + + if (position == -1 || position > (bot - top)) + return bot; + else + return top + position; + } + + /** + * Removes a child from this container. The child is specified by + * index. After removal, the child no longer occupies a layer. + * + * @param index the index of the child component to remove. + */ + public void remove (int index) + { + Component c = getComponent (index); + int layer = getLayer (c); + decrLayer (new Integer(layer)); + componentToLayer.remove (c); + super.remove (index); + revalidate(); + repaint(); + } + + /** + * Removes a child from this container. The child is specified directly. + * After removal, the child no longer occupies a layer. + * + * @param comp the child to remove. + */ + public void remove (Component comp) + { + remove (getIndexOf (comp)); + } + + /** + * <p>Set the layer property for a component, within this container. The + * component will be implicitly mapped to the bottom-most position in the + * layer, but only if added <em>after</em> calling this method.</p> + * + * <p>Read that carefully: this method should be called <em>before</em> the + * component is added to the container.</p> + * + * @param c the component to set the layer property for. + * @param layer the layer number to assign to the component. + */ + public void setLayer(Component c, int layer) + { + componentToLayer.put (c, getObjectForLayer (layer)); + } + + /** + * Set the layer and position of a component, within this container. + * + * @param c the child component to set the layer property for. + * @param layer the layer number to assign to the component. + * @param position the position number to assign to the component. + */ + public void setLayer(Component c, + int layer, + int position) + { + remove(c); + add(c, getObjectForLayer (layer)); + setPosition(c, position); + revalidate(); + repaint(); + } + + /** + * Overrides the default implementation from {@link java.awt.Container} + * such that <code>layerConstraint</code> is interpreted as an {@link + * Integer}, specifying the layer to which the component will be added + * (at the bottom position). + * + * @param comp the component to add. + * @param layerConstraint an integer specifying the layer to add the component to. + * @param index an ignored parameter, for compatibility. + */ + protected void addImpl(Component comp, Object layerConstraint, int index) + { + Integer layer; + if (layerConstraint != null && layerConstraint instanceof Integer) + layer = (Integer) layerConstraint; + else if (componentToLayer.containsKey (comp)) + layer = (Integer) componentToLayer.remove (comp); + else + layer = DEFAULT_LAYER; + + int newIdx = insertIndexForLayer(layer.intValue (), index); + + componentToLayer.put (comp, layer); + incrLayer (layer); + + super.addImpl(comp, null, newIdx); + revalidate(); + repaint(); + } + + /** + * Sets the layer property for a JComponent. + * + * @param component the component for which to set the layer + * @param layer the layer property to set + */ + public static void putLayer(JComponent component, int layer) + { + getLayeredPaneAbove(component).setLayer(component, layer); + } +} diff --git a/libjava/classpath/javax/swing/JList.java b/libjava/classpath/javax/swing/JList.java new file mode 100644 index 00000000000..fb8d18b8565 --- /dev/null +++ b/libjava/classpath/javax/swing/JList.java @@ -0,0 +1,1416 @@ +/* JList.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Color; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.plaf.ListUI; +import javax.swing.text.Position; + +/** + * <p>This class is a facade over three separate objects: {@link + * javax.swing.ListModel}, {@link javax.swing.ListSelectionModel} and + * {@link javax.swing.plaf.ListUI}. The facade represents a unified "list" + * concept, with independently replacable (possibly client-provided) models + * for its contents and its current selection. In addition, each element in + * the list is rendered via a strategy class {@link + * javax.swing.ListCellRenderer}.</p> + * + * <p>Lists have many properties, some of which are stored in this class + * while others are delegated to the list's model or selection. The + * following properties are available:</p> + * + * <table> + * <tr><th>Property </th><th>Stored in</th><th>Bound?</th></tr> + * <tr><td>accessibleContext </td><td>list </td><td>no </td></tr> + * <tr><td>anchorSelectionIndex </td><td>selection</td><td>no </td></tr> + * <tr><td>cellRenderer </td><td>list </td><td>yes </td></tr> + * <tr><td>dragEnabled </td><td>list </td><td>no </td></tr> + * <tr><td>firstVisibleIndex </td><td>list </td><td>no </td></tr> + * <tr><td>fixedCellHeight </td><td>list </td><td>yes </td></tr> + * <tr><td>fixedCellWidth </td><td>list </td><td>yes </td></tr> + * <tr><td>lastVisibleIndex </td><td>list </td><td>no </td></tr> + * <tr><td>layoutOrientation </td><td>list </td><td>yes </td></tr> + * <tr><td>leadSelectionIndex </td><td>selection</td><td>no </td></tr> + * <tr><td>maxSelectionIndex </td><td>selection</td><td>no </td></tr> + * <tr><td>minSelectionIndex </td><td>selection</td><td>no </td></tr> + * <tr><td>model </td><td>list </td><td>yes </td></tr> + * <tr><td>opaque </td><td>list </td><td>no </td></tr> + * <tr><td>preferredScrollableViewportSize</td><td>list </td><td>no </td></tr> + * <tr><td>prototypeCellValue </td><td>list </td><td>yes </td></tr> + * <tr><td>scrollableTracksViewportHeight </td><td>list </td><td>no </td></tr> + * <tr><td>scrollableTracksViewportWidth </td><td>list </td><td>no </td></tr> + * <tr><td>selectedIndex </td><td>selection</td><td>no </td></tr> + * <tr><td>selectedIndices </td><td>selection</td><td>no </td></tr> + * <tr><td>selectedValue </td><td>model </td><td>no </td></tr> + * <tr><td>selectedValues </td><td>model </td><td>no </td></tr> + * <tr><td>selectionBackground </td><td>list </td><td>yes </td></tr> + * <tr><td>selectionEmpty </td><td>selection</td><td>no </td></tr> + * <tr><td>selectionForeground </td><td>list </td><td>yes </td></tr> + * <tr><td>selectionMode </td><td>selection</td><td>no </td></tr> + * <tr><td>selectionModel </td><td>list </td><td>yes </td></tr> + * <tr><td>UI </td><td>list </td><td>yes </td></tr> + * <tr><td>UIClassID </td><td>list </td><td>no </td></tr> + * <tr><td>valueIsAdjusting </td><td>list </td><td>no </td></tr> + * <tr><td>visibleRowCount </td><td>list </td><td>no </td></tr> + * </table> + * + * @author Graydon Hoare (graydon@redhat.com) + */ + +public class JList extends JComponent implements Accessible, Scrollable +{ + private static final long serialVersionUID = 4406629526391098046L; + + /** + * Constant value used in "layoutOrientation" property. This value means + * that cells are laid out in a single vertical column. This is the default. + */ + public static final int VERTICAL = 0; + + /** + * Constant value used in "layoutOrientation" property. This value means + * that cells are laid out in multiple columns "newspaper style", filling + * vertically first, then horizontally. + */ + public static final int VERTICAL_WRAP = 1; + + /** + * Constant value used in "layoutOrientation" property. This value means + * that cells are laid out in multiple columns "newspaper style", + * filling horizontally first, then vertically. + */ + public static final int HORIZONTAL_WRAP = 2; + + /** + * This property indicates whether "drag and drop" functions are enabled + * on the list. + */ + boolean dragEnabled; + + /** This property provides a strategy for rendering cells in the list. */ + ListCellRenderer cellRenderer; + + /** + * This property indicates an fixed width to assign to all cells in the + * list. If its value is <code>-1</code>, no width has been + * assigned. This value can be set explicitly, or implicitly by setting + * the {@link #prototypeCellValue} property. + */ + int fixedCellWidth; + + /** + * This property indicates an fixed height to assign to all cells in the + * list. If its value is <code>-1</code>, no height has been + * assigned. This value can be set explicitly, or implicitly by setting + * the {@link #prototypeCellValue} property. + */ + int fixedCellHeight; + + /** + * This property holds the current layout orientation of the list, which + * is one of the integer constants {@link #VERTICAL}, {@link + * #VERTICAL_WRAP}, or {@link #HORIZONTAL_WRAP}. + */ + int layoutOrientation; + + /** This property holds the data elements displayed by the list. */ + ListModel model; + + /** + * <p>This property holds a reference to a "prototype" data value -- + * typically a String -- which is used to calculate the {@link + * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the + * {@link #cellRenderer} property to acquire a component to render the + * prototype.</p> + * + * <p>It is important that you <em>not</em> set this value to a + * component. It has to be a <em>data value</em> such as the objects you + * would find in the list's model. Setting it to a component will have + * undefined (and undesirable) affects. </p> + */ + Object prototypeCellValue; + + /** + * This property specifies a foreground color for the selected cells in + * the list. When {@link ListCellRenderer.getListCellRendererComponent} + * is called with a selected cell object, the component returned will + * have its "foreground" set to this color. + */ + Color selectionBackground; + + /** + * This property specifies a background color for the selected cells in + * the list. When {@link ListCellRenderer.getListCellRendererComponent} + * is called with a selected cell object, the component returned will + * have its "background" property set to this color. + */ + Color selectionForeground; + + /** + * This property holds a description of which data elements in the {@link + * #model} property should be considered "selected", when displaying and + * interacting with the list. + */ + ListSelectionModel selectionModel; + + + /** + * This property indicates that the list's selection is currently + * "adjusting" -- perhaps due to a user actively dragging the mouse over + * multiple list elements -- and is therefore likely to change again in + * the near future. A {@link ListSelectionListener} might choose to delay + * updating its view of the list's selection until this property is + * false, meaning that the adjustment has completed. + */ + boolean valueIsAdjusting; + + /** + * This property indicates a <em>preference</em> for the number of rows + * displayed in the list, and will scale the + * {@link #preferredScrollableViewportSize} property accordingly. The actual + * number of displayed rows, when the list is placed in a real {@link + * Viewport} or other component, may be greater or less than this number. + */ + int visibleRowCount; + + /** + * Fire a {@link ListSelectionEvent} to all the registered ListSelectionListeners. + */ + protected void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting) + { + ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting); + ListSelectionListener listeners[] = getListSelectionListeners(); + for (int i = 0; i < listeners.length; ++i) + { + listeners[i].valueChanged(evt); + } + } + + /** + * This private listener propagates {@link ListSelectionEvent} events + * from the list's "selectionModel" property to the list's {@link + * ListSelectionListener} listeners. It also listens to {@link + * ListDataEvent} events from the list's {@link #model} property. If this + * class receives either type of event, it triggers repainting of the + * list. + */ + private class ListListener + implements ListSelectionListener, ListDataListener + { + // ListDataListener events + public void contentsChanged(ListDataEvent event) + { + JList.this.revalidate(); + JList.this.repaint(); + } + public void intervalAdded(ListDataEvent event) + { + JList.this.revalidate(); + JList.this.repaint(); + } + public void intervalRemoved(ListDataEvent event) + { + JList.this.revalidate(); + JList.this.repaint(); + } + // ListSelectionListener events + public void valueChanged(ListSelectionEvent event) + { + JList.this.fireSelectionValueChanged(event.getFirstIndex(), + event.getLastIndex(), + event.getValueIsAdjusting()); + JList.this.repaint(); + } + }; + + /** + * Shared ListListener instance, subscribed to both the current {@link + * #model} and {@link #selectionModel} properties of the list. + */ + ListListener listListener; + + + /** + * Creates a new JList object. + */ + public JList() + { + init(); + } + + /** + * Creates a new JList object. + * + * @param listData Initial data to populate the list with + */ + public JList(Object[] listData) + { + init(); + setListData(listData); + } + + /** + * Creates a new JList object. + * + * @param listData Initial data to populate the list with + */ + public JList(Vector listData) + { + init(); + setListData(listData); + } + + /** + * Creates a new JList object. + * + * @param listData Initial data to populate the list with + */ + public JList(ListModel listData) + { + init(); + setModel(listData); + } + + void init() + { + dragEnabled = false; + fixedCellHeight = -1; + fixedCellWidth = -1; + layoutOrientation = VERTICAL; + opaque = true; + valueIsAdjusting = false; + visibleRowCount = 8; + + cellRenderer = new DefaultListCellRenderer(); + listListener = new ListListener(); + + setModel(new DefaultListModel()); + setSelectionModel(createSelectionModel()); + + updateUI(); + } + + /** + * Creates the default <code>ListSelectionModel</code>. + * + * @return the <code>ListSelectionModel</code> + */ + protected ListSelectionModel createSelectionModel() + { + return new DefaultListSelectionModel(); + } + + /** + * Gets the value of the {@link #fixedCellHeight} property. This property + * may be <code>-1</code> to indicate that no cell height has been + * set. This property is also set implicitly when the + * {@link #prototypeCellValue} property is set. + * + * @return The current value of the property + * + * @see #fixedCellHeight + * @see #setFixedCellHeight + * @see #setPrototypeCellValue + */ + public int getFixedCellHeight() + { + return fixedCellHeight; + } + + /** + * Sets the value of the {@link #fixedCellHeight} property. This property + * may be <code>-1</code> to indicate that no cell height has been + * set. This property is also set implicitly when the {@link + * #prototypeCellValue} property is set, but setting it explicitly + * overrides the height computed from {@link #prototypeCellValue}. + * + * @see #getFixedCellHeight + * @see #getPrototypeCellValue + */ + public void setFixedCellHeight(int h) + { + if (fixedCellHeight == h) + return; + + int old = fixedCellHeight; + fixedCellHeight = h; + firePropertyChange("fixedCellWidth", old, h); + } + + + /** + * Gets the value of the {@link #fixedCellWidth} property. This property + * may be <code>-1</code> to indicate that no cell width has been + * set. This property is also set implicitly when the {@link + * #prototypeCellValue} property is set. + * + * @return The current value of the property + * + * @see #setFixedCellWidth + * @see #setPrototypeCellValue + */ + public int getFixedCellWidth() + { + return fixedCellWidth; + } + + /** + * Sets the value of the {@link #fixedCellWidth} property. This property + * may be <code>-1</code> to indicate that no cell width has been + * set. This property is also set implicitly when the {@link + * #prototypeCellValue} property is set, but setting it explicitly + * overrides the width computed from {@link #prototypeCellValue}. + * + * @see #getFixedCellHeight + * @see #getPrototypeCellValue + */ + public void setFixedCellWidth(int w) + { + if (fixedCellWidth == w) + return; + + int old = fixedCellWidth; + fixedCellWidth = w; + firePropertyChange("fixedCellWidth", old, w); + } + + /** + * Gets the value of the {@link #visibleRowCount} property. + * + * @return the current value of the property. + */ + + public int getVisibleRowCount() + { + return visibleRowCount; + } + + /** + * Sets the value of the {@link #visibleRowCount} property. + * + * @param visibleRowCount The new property value + */ + public void setVisibleRowCount(int vc) + { + visibleRowCount = vc; + revalidate(); + repaint(); + } + + /** + * Adds a {@link ListSelectionListener} to the listener list for this + * list. The listener will be called back with a {@link + * ListSelectionEvent} any time the list's {@link #selectionModel} + * property changes. The source of such events will be the JList, + * not the selection model. + * + * @param listener The new listener to add + */ + public void addListSelectionListener(ListSelectionListener listener) + { + listenerList.add (ListSelectionListener.class, listener); + } + + /** + * Removes a {@link ListSelectionListener} from the listener list for + * this list. The listener will no longer be called when the list's + * {@link #selectionModel} changes. + * + * @param listener The listener to remove + */ + public void removeListSelectionListener(ListSelectionListener listener) + { + listenerList.remove(ListSelectionListener.class, listener); + } + + /** + * Returns an array of all ListSelectionListeners subscribed to this + * list. + * + * @return The current subscribed listeners + * + * @since 1.4 + */ + public ListSelectionListener[] getListSelectionListeners() + { + return (ListSelectionListener[]) getListeners(ListSelectionListener.class); + } + + public int getSelectionMode() + { + return selectionModel.getSelectionMode(); + } + + /** + * Sets the list's "selectionMode" property, which simply mirrors the + * same property on the list's {@link #selectionModel} property. This + * property should be one of the integer constants + * <code>SINGLE_SELECTION</code>, <code>SINGLE_INTERVAL_SELECTION</code>, + * or <code>MULTIPLE_INTERVAL_SELECTION</code> from the {@link + * ListSelectionModel} interface. + * + * @param a The new selection mode + */ + public void setSelectionMode(int a) + { + selectionModel.setSelectionMode(a); + } + + /** + * Adds the interval <code>[a,a]</code> to the set of selections managed + * by this list's {@link #selectionModel} property. Depending on the + * selection mode, this may cause existing selections to become invalid, + * or may simply expand the set of selections. + * + * @param a A number in the half-open range <code>[0, x)</code> where + * <code>x = getModel.getSize()</code>, indicating the index of an + * element in the list to select. + * + * @see #setSelectionMode + * @see #selectionModel + */ + public void setSelectedIndex(int a) + { + selectionModel.setSelectionInterval(a, a); + } + + /** + * For each element <code>a[i]</code> of the provided array + * <code>a</code>, calls {@link #setSelectedIndex} on <code>a[i]</code>. + * + * @see #setSelectionMode + * @see #selectionModel + */ + public void setSelectedIndices(int [] a) + { + for (int i = 0; i < a.length; ++i) + setSelectedIndex(a[i]); + } + + /** + * Returns the minimum index of an element in the list which is currently + * selected. + * + * @return A number in the half-open range <code>[0, x)</code> where + * <code>x = getModel.getSize()</code>, indicating the minimum index of + * an element in the list for which the element is selected, or + * <code>-1</code> if no elements are selected + */ + public int getSelectedIndex() + { + return selectionModel.getMinSelectionIndex(); + } + + /** + * Returns <code>true</code> if the model's selection is empty, otherwise + * <code>false</code>. + * + * @return The return value of {@link ListSelectionModel#isSelectionEmpty} + */ + public boolean isSelectionEmpty() + { + return selectionModel.isSelectionEmpty(); + } + + /** + * Returns the list index of the upper left or upper right corner of the + * {@link #visibleRect} property, depending on the {@link + * #componentOrientation} property. + * + * @return The index of the first visible list cell, or <code>-1</code> + * if none is visible. + */ + public int getFirstVisibleIndex() + { + ComponentOrientation or = getComponentOrientation(); + Rectangle r = getVisibleRect(); + if (or == ComponentOrientation.RIGHT_TO_LEFT) + r.translate((int) r.getWidth(), 0); + return getUI().locationToIndex(this, r.getLocation()); + } + + + /** + * Returns index of the cell to which specified location is closest to + * @param location for which to look for in the list + * + * @return index of the cell to which specified location is closest to. + */ + public int locationToIndex(Point location) { + return getUI().locationToIndex(this, location); + } + + /** + * Returns location of the cell located at the specified index in the list. + * @param index of the cell for which location will be determined + * + * @return location of the cell located at the specified index in the list. + */ + public Point indexToLocation(int index){ + //FIXME: Need to implement. + return null; + } + + /** + * Returns the list index of the lower right or lower left corner of the + * {@link #visibleRect} property, depending on the {@link + * #componentOrientation} property. + * + * @return The index of the first visible list cell, or <code>-1</code> + * if none is visible. + */ + public int getLastVisibleIndex() + { + ComponentOrientation or = getComponentOrientation(); + Rectangle r = getVisibleRect(); + r.translate(0, (int) r.getHeight()); + if (or == ComponentOrientation.LEFT_TO_RIGHT) + r.translate((int) r.getWidth(), 0); + return getUI().locationToIndex(this, r.getLocation()); + } + + /** + * Returns the indices of values in the {@link #model} property which are + * selected. + * + * @return An array of model indices, each of which is selected according + * to the {@link #selection} property + */ + public int[] getSelectedIndices() + { + int lo, hi, n, i, j; + if (selectionModel.isSelectionEmpty()) + return new int[0]; + lo = selectionModel.getMinSelectionIndex(); + hi = selectionModel.getMaxSelectionIndex(); + n = 0; + for (i = lo; i <= hi; ++i) + if (selectionModel.isSelectedIndex(i)) + n++; + int [] v = new int[n]; + j = 0; + for (i = lo; i < hi; ++i) + if (selectionModel.isSelectedIndex(i)) + v[j++] = i; + return v; + } + + /** + * Indicates whether the list element at a given index value is + * currently selected. + * + * @param a The index to check + * @return <code>true</code> if <code>a</code> is the index of a selected + * list element + */ + public boolean isSelectedIndex(int a) + { + return selectionModel.isSelectedIndex(a); + } + + /** + * Returns the first value in the list's {@link #model} property which is + * selected, according to the list's {@link #selectionModel} property. + * This is equivalent to calling + * <code>getModel()getElementAt(getSelectedIndex())</code>, with a check + * for the special index value of <code>-1</code> which returns null + * <code>null</code>. + * + * @return The first selected element, or <code>null</code> if no element + * is selected. + * + * @see getSelectedValues + */ + public Object getSelectedValue() + { + int index = getSelectedIndex(); + if (index == -1) + return null; + return getModel().getElementAt(index); + } + + /** + * Returns all the values in the list's {@link #model} property which + * are selected, according to the list's {@link #selectionModel} property. + * + * @return An array containing all the selected values + * + * @see getSelectedValue + */ + public Object[] getSelectedValues() + { + int [] idx = getSelectedIndices(); + Object [] v = new Object[idx.length]; + for (int i = 0; i < idx.length; ++i) + v[i] = getModel().getElementAt(i); + return v; + } + + /** + * Gets the value of the {@link #selectionBackground} property. + * + * @return The current value of the property + */ + public Color getSelectionBackground() + { + return selectionBackground; + } + + /** + * Sets the value of the {@link #selectionBackground} property. + * + * @param c The new value of the property + */ + public void setSelectionBackground(Color c) + { + if (selectionBackground == c) + return; + + Color old = selectionBackground; + selectionBackground = c; + firePropertyChange("selectionBackground", old, c); + repaint(); + } + + /** + * Gets the value of the {@link #selectionForeground} property. + * + * @return The current value of the property + */ + public Color getSelectionForeground() + { + return selectionForeground; + } + + /** + * Sets the value of the {@link #selectionForeground} property. + * + * @param c The new value of the property + */ + public void setSelectionForeground(Color c) + { + if (selectionForeground == c) + return; + + Color old = selectionForeground; + selectionForeground = c; + firePropertyChange("selectionForeground", old, c); + } + + /** + * Sets the selection to cover only the specified value, if it + * exists in the model. + * + * @param obj The object to select + * @param scroll Whether to scroll the list to make the newly selected + * value visible + * + * @see #ensureIndexIsVisible + */ + + public void setSelectedValue(Object obj, boolean scroll) + { + for (int i = 0; i < model.getSize(); ++i) + { + if (model.getElementAt(i).equals(obj)) + { + setSelectedIndex(i); + if (scroll) + ensureIndexIsVisible(i); + break; + } + } + } + + /** + * Scrolls this list to make the specified cell visible. This + * only works if the list is contained within a viewport. + * + * @param i The list index to make visible + * + * @see JComponent#scrollRectToVisible + */ + public void ensureIndexIsVisible(int i) + { + scrollRectToVisible(getUI().getCellBounds(this, i, i)); + } + + /** + * Sets the {@link #model} property of the list to a new anonymous + * {@link AbstractListModel} subclass which accesses the provided Object + * array directly. + * + * @param listData The object array to build a new list model on + * @see #setModel + */ + public void setListData(final Object[] listData) + { + setModel(new AbstractListModel() + { + public int getSize() + { + return listData.length; + } + + public Object getElementAt(int i) + { + return listData[i]; + } + }); + } + + /** + * Sets the {@link #model} property of the list to a new anonymous {@link + * AbstractListModel} subclass which accesses the provided vector + * directly. + * + * @param listData The object array to build a new list model on + * @see #setModel + */ + public void setListData(final Vector listData) + { + setModel(new AbstractListModel() + { + public int getSize() + { + return listData.size(); + } + + public Object getElementAt(int i) + { + return listData.elementAt(i); + } + }); + } + + /** + * Gets the value of the {@link #cellRenderer} property. + * + * @return The current value of the property + */ + public ListCellRenderer getCellRenderer() + { + return cellRenderer; + } + + /** + * Sets the value of the {@link #celLRenderer} property. + * + * @param renderer The new property value + */ + public void setCellRenderer(ListCellRenderer renderer) + { + if (cellRenderer == renderer) + return; + + ListCellRenderer old = cellRenderer; + cellRenderer = renderer; + firePropertyChange("cellRenderer", old, renderer); + revalidate(); + repaint(); + } + + /** + * Gets the value of the {@link #model} property. + * + * @return The current value of the property + */ + public ListModel getModel() + { + return model; + } + + /** + * Sets the value of the {@link #model} property. The list's {@link + * #listListener} is unsubscribed from the existing model, if it exists, + * and re-subscribed to the new model. + * + * @param model The new property value + */ + public void setModel(ListModel model) + { + if (this.model == model) + return; + + if (this.model != null) + this.model.removeListDataListener(listListener); + + ListModel old = this.model; + this.model = model; + + if (this.model != null) + this.model.addListDataListener(listListener); + + firePropertyChange("model", old, model); + revalidate(); + repaint(); + } + + + public ListSelectionModel getSelectionModel() + { + return selectionModel; + } + + /** + * Sets the value of the {@link #selectionModel} property. The list's + * {@link #listListener} is unsubscribed from the existing selection + * model, if it exists, and re-subscribed to the new selection model. + * + * @param model The new property value + */ + public void setSelectionModel(ListSelectionModel model) + { + if (selectionModel == model) + return; + + if (selectionModel != null) + selectionModel.removeListSelectionListener(listListener); + + ListSelectionModel old = selectionModel; + selectionModel = model; + + if (selectionModel != null) + selectionModel.addListSelectionListener(listListener); + + firePropertyChange("selectionModel", old, model); + revalidate(); + repaint(); + } + + /** + * Gets the value of the UI property. + * + * @return The current property value + */ + public ListUI getUI() + { + return (ListUI) ui; + } + + /** + * Sets the value of the UI property. + * + * @param ui The new property value + */ + public void setUI(ListUI ui) + { + super.setUI(ui); + } + + /** + * Calls {@link #setUI} with the {@link ListUI} subclass + * returned from calling {@link UIManager#getUI}. + */ + public void updateUI() + { + setUI((ListUI) UIManager.getUI(this)); + } + + /** + * Return the class identifier for the list's UI property. This should + * be the constant string <code>"ListUI"</code>, and map to an + * appropriate UI class in the {@link UIManager}. + * + * @return The class identifier + */ + public String getUIClassID() + { + return "ListUI"; + } + + + /** + * Returns the current value of the {@link #prototypeCellValue} + * property. This property holds a reference to a "prototype" data value + * -- typically a String -- which is used to calculate the {@link + * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the + * {@link #cellRenderer} property to acquire a component to render the + * prototype. + * + * @return The current prototype cell value + * @see #setPrototypeCellValue + */ + public Object getPrototypeCellValue() + { + return prototypeCellValue; + } + + /** + * <p>Set the {@link #prototypeCellValue} property. This property holds a + * reference to a "prototype" data value -- typically a String -- which + * is used to calculate the {@link #fixedCellWidth} and {@link + * #fixedCellHeight} properties, using the {@link #cellRenderer} property + * to acquire a component to render the prototype.</p> + * + * <p>It is important that you <em>not</em> set this value to a + * component. It has to be a <em>data value</em> such as the objects you + * would find in the list's model. Setting it to a component will have + * undefined (and undesirable) affects. </p> + * + * @param obj The new prototype cell value + * @see #getPrototypeCellValue + */ + public void setPrototypeCellValue(Object obj) + { + if (prototypeCellValue == obj) + return; + + Object old = prototypeCellValue; + Component comp = getCellRenderer() + .getListCellRendererComponent(this, obj, 0, false, false); + Dimension d = comp.getPreferredSize(); + fixedCellWidth = d.width; + fixedCellHeight = d.height; + prototypeCellValue = obj; + firePropertyChange("prototypeCellValue", old, obj); + } + + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * Returns a size indicating how much space this list would like to + * consume, when contained in a scrollable viewport. This is part of the + * {@link Scrollable} interface, which interacts with {@link + * ScrollPaneLayout} and {@link Viewport} to define scrollable objects. + * + * @return The preferred size + */ + public Dimension getPreferredScrollableViewportSize() + { + + Dimension retVal = getPreferredSize(); + if (getLayoutOrientation() == VERTICAL) + { + if (fixedCellHeight != -1) + { + if (fixedCellWidth != -1) + { + int size = getModel().getSize(); + retVal = new Dimension(fixedCellWidth, size * fixedCellHeight); + } // TODO: add else clause (preferredSize is ok for now) + } // TODO: add else clause (preferredSize is ok for now) + } + return retVal; + } + + /** + * <p>Return the number of pixels the list must scroll in order to move a + * "unit" of the list into the provided visible rectangle. When the + * provided direction is positive, the call describes a "downwards" + * scroll, which will be exposing a cell at a <em>greater</em> index in + * the list than those elements currently showing. Then the provided + * direction is negative, the call describes an "upwards" scroll, which + * will be exposing a cell at a <em>lesser</em> index in the list than + * those elements currently showing.</p> + * + * <p>If the provided orientation is <code>HORIZONTAL</code>, the above + * comments refer to "rightwards" for positive direction, and "leftwards" + * for negative.</p> + * + * + * @param visibleRect The rectangle to scroll an element into + * @param orientation One of the numeric consants <code>VERTICAL</code> + * or <code>HORIZONTAL</code> + * @param direction An integer indicating the scroll direction: positive means + * forwards (down, right), negative means backwards (up, left) + * + * @return The scrollable unit increment, in pixels + */ + public int getScrollableUnitIncrement(Rectangle visibleRect, + int orientation, int direction) + { + ListUI lui = this.getUI(); + if (orientation == SwingConstants.VERTICAL) + { + if (direction > 0) + { + // Scrolling down + Point bottomLeft = new Point(visibleRect.x, + visibleRect.y + visibleRect.height); + int curIdx = lui.locationToIndex(this, bottomLeft); + Rectangle curBounds = lui.getCellBounds(this, curIdx, curIdx); + if (curBounds.y + curBounds.height == bottomLeft.y) + { + // we are at the exact bottom of the current cell, so we + // are being asked to scroll to the end of the next one + if (curIdx + 1 < model.getSize()) + { + // there *is* a next item in the list + Rectangle nxtBounds = lui.getCellBounds(this, curIdx + 1, curIdx + 1); + return nxtBounds.height; + } + else + { + // no next item, no advance possible + return 0; + } + } + else + { + // we are part way through an existing cell, so we are being + // asked to scroll to the bottom of it + return (curBounds.y + curBounds.height) - bottomLeft.y; + } + } + else + { + // scrolling up + Point topLeft = new Point(visibleRect.x, visibleRect.y); + int curIdx = lui.locationToIndex(this, topLeft); + Rectangle curBounds = lui.getCellBounds(this, curIdx, curIdx); + if (curBounds.y == topLeft.y) + { + // we are at the exact top of the current cell, so we + // are being asked to scroll to the top of the previous one + if (curIdx > 0) + { + // there *is* a previous item in the list + Rectangle nxtBounds = lui.getCellBounds(this, curIdx - 1, curIdx - 1); + return -nxtBounds.height; + } + else + { + // no previous item, no advance possible + return 0; + } + } + else + { + // we are part way through an existing cell, so we are being + // asked to scroll to the top of it + return curBounds.y - topLeft.y; + } + } + } + + // FIXME: handle horizontal scrolling (also wrapping?) + return 1; + } + + /** + * <p>Return the number of pixels the list must scroll in order to move a + * "block" of the list into the provided visible rectangle. When the + * provided direction is positive, the call describes a "downwards" + * scroll, which will be exposing a cell at a <em>greater</em> index in + * the list than those elements currently showing. Then the provided + * direction is negative, the call describes an "upwards" scroll, which + * will be exposing a cell at a <em>lesser</em> index in the list than + * those elements currently showing.</p> + * + * <p>If the provided orientation is <code>HORIZONTAL</code>, the above + * comments refer to "rightwards" for positive direction, and "leftwards" + * for negative.</p> + * + * + * @param visibleRect The rectangle to scroll an element into + * @param orientation One of the numeric consants <code>VERTICAL</code> + * or <code>HORIZONTAL</code> + * @param direction An integer indicating the scroll direction: positive means + * forwards (down, right), negative means backwards (up, left) + * + * @return The scrollable unit increment, in pixels + */ + public int getScrollableBlockIncrement(Rectangle visibleRect, + int orientation, int direction) + { + if (orientation == VERTICAL) + return visibleRect.height * direction; + else + return visibleRect.width * direction; + } + + /** + * Gets the value of the {@link #scrollableTracksViewportWidth} property. + * + * @return <code>true</code> if the viewport is larger (horizontally) + * than the list and the list should be expanded to fit the viewport; + * <code>false</code> if the viewport is smaller than the list and the + * list should scroll (horizontally) within the viewport + */ + public boolean getScrollableTracksViewportWidth() + { + Component parent = getParent(); + boolean retVal = false; + if (parent instanceof JViewport) + { + JViewport viewport = (JViewport) parent; + Dimension pref = getPreferredSize(); + if (viewport.getSize().width > pref.width) + retVal = true; + if ((getLayoutOrientation() == HORIZONTAL_WRAP) + && (getVisibleRowCount() <= 0)) + retVal = true; + } + return retVal; + } + + /** + * Gets the value of the {@link #scrollableTracksViewportWidth} property. + * + * @return <code>true</code> if the viewport is larger (vertically) + * than the list and the list should be expanded to fit the viewport; + * <code>false</code> if the viewport is smaller than the list and the + * list should scroll (vertically) within the viewport + */ + public boolean getScrollableTracksViewportHeight() + { + Component parent = getParent(); + boolean retVal = false; + if (parent instanceof JViewport) + { + JViewport viewport = (JViewport) parent; + Dimension pref = getPreferredSize(); + if (viewport.getSize().height > pref.height) + retVal = true; + if ((getLayoutOrientation() == VERTICAL_WRAP) + && (getVisibleRowCount() <= 0)) + retVal = true; + } + return retVal; + } + + public int getAnchorSelectionIndex() + { + return selectionModel.getAnchorSelectionIndex(); + } + + public int getLeadSelectionIndex() + { + return selectionModel.getLeadSelectionIndex(); + } + + public int getMinSelectionIndex() + { + return selectionModel.getMaxSelectionIndex(); + } + + public int getMaxSelectionIndex() + { + return selectionModel.getMaxSelectionIndex(); + } + + public void clearSelection() + { + selectionModel.clearSelection(); + } + + public void setSelectionInterval(int anchor, int lead) + { + selectionModel.setSelectionInterval(anchor, lead); + } + + public void addSelectionInterval(int anchor, int lead) + { + selectionModel.addSelectionInterval(anchor, lead); + } + + public void removeSelectionInterval(int index0, int index1) + { + selectionModel.removeSelectionInterval(index0, index1); + } + + /** + * Returns the value of the <code>valueIsAdjusting</code> property. + * + * @return the value + */ + public boolean getValueIsAdjusting() + { + return valueIsAdjusting; + } + + /** + * Sets the <code>valueIsAdjusting</code> property. + * + * @param isAdjusting the new value + */ + public void setValueIsAdjusting(boolean isAdjusting) + { + valueIsAdjusting = isAdjusting; + } + + /** + * Return the value of the <code>dragEnabled</code> property. + * + * @return the value + * + * @since 1.4 + */ + public boolean getDragEnabled() + { + return dragEnabled; + } + + /** + * Set the <code>dragEnabled</code> property. + * + * @param enabled new value + * + * @since 1.4 + */ + public void setDragEnabled(boolean enabled) + { + dragEnabled = enabled; + } + + /** + * Returns the layout orientation. + * + * @return the orientation, one of <code>JList.VERTICAL</code>, + * <code>JList.VERTICAL_WRAP</code> and <code>JList.HORIZONTAL_WRAP</code> + * + * @since 1.4 + */ + public int getLayoutOrientation() + { + return layoutOrientation; + } + + /** + * Sets the layout orientation. + * + * @param orientation the orientation to set, one of <code>JList.VERTICAL</code>, + * <code>JList.VERTICAL_WRAP</code> and <code>JList.HORIZONTAL_WRAP</code> + * + * @since 1.4 + */ + public void setLayoutOrientation(int orientation) + { + if (layoutOrientation == orientation) + return; + + int old = layoutOrientation; + layoutOrientation = orientation; + firePropertyChange("layoutOrientation", old, orientation); + } + + /** + * Returns the bounds of the rectangle that encloses both list cells + * with index0 and index1. + * + * @param index0 the index of the first cell + * @param index1 the index of the second cell + * + * @return the bounds of the rectangle that encloses both list cells + * with index0 and index1, <code>null</code> if one of the indices is + * not valid + */ + public Rectangle getCellBounds(int index0, int index1) + { + return ((ListUI) ui).getCellBounds(this, index0, index1); + } + + /** + * Returns the next list element (beginning from <code>startIndex</code> + * that starts with <code>prefix</code>. Searching is done in the direction + * specified by <code>bias</code>. + * + * @param prefix the prefix to search for in the cell values + * @param startIndex the index where to start searching from + * @param bias the search direction, either {@link Position.Bias.Forward} + * or {@link Position.Bias.Backward} + * + * @return the index of the found element or -1 if no such element has + * been found + * + * @throws IllegalArgumentException if prefix is <code>null</code> or + * startIndex is not valid + * + * @since 1.4 + */ + public int getNextMatch(String prefix, int startIndex, Position.Bias bias) + { + if (prefix == null) + throw new IllegalArgumentException("The argument 'prefix' must not be" + + " null."); + if (startIndex < 0) + throw new IllegalArgumentException("The argument 'startIndex' must not" + + " be less than zero."); + + int size = model.getSize(); + if (startIndex > model.getSize()) + throw new IllegalArgumentException("The argument 'startIndex' must not" + + " be greater than the number of" + + " elements in the ListModel."); + + int index = -1; + if (bias == Position.Bias.Forward) + { + for (int i = startIndex; i < size; i++) + { + String item = model.getElementAt(i).toString(); + if (item.startsWith(prefix)) + { + index = i; + break; + } + } + } + else + { + for (int i = startIndex; i >= 0; i--) + { + String item = model.getElementAt(i).toString(); + if (item.startsWith(prefix)) + { + index = i; + break; + } + } + } + return index; + } +} diff --git a/libjava/classpath/javax/swing/JMenu.java b/libjava/classpath/javax/swing/JMenu.java new file mode 100644 index 00000000000..8dcad8b77cd --- /dev/null +++ b/libjava/classpath/javax/swing/JMenu.java @@ -0,0 +1,915 @@ +/* JMenu.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; +import javax.swing.plaf.MenuItemUI; + +/** + * This class represents a menu that can be added to a menu bar or + * can be a submenu in some other menu. When JMenu is selected it + * displays JPopupMenu containing its menu items. + * + * <p> + * JMenu's fires MenuEvents when this menu's selection changes. If this menu + * is selected, then fireMenuSelectedEvent() is invoked. In case when menu is + * deselected or cancelled, then fireMenuDeselectedEvent() or + * fireMenuCancelledEvent() is invoked, respectivelly. + * </p> + */ +public class JMenu extends JMenuItem implements Accessible, MenuElement +{ + private static final long serialVersionUID = 4227225638931828014L; + + /** A Popup menu associated with this menu, which pops up when menu is selected */ + private JPopupMenu popupMenu = new JPopupMenu(); + + /** Whenever menu is selected or deselected the MenuEvent is fired to + menu's registered listeners. */ + private MenuEvent menuEvent = new MenuEvent(this); + + /*Amount of time, in milliseconds, that should pass before popupMenu + associated with this menu appears or disappers */ + private int delay; + + /* PopupListener */ + protected WinListener popupListener; + + /** Location at which popup menu associated with this menu will be + displayed */ + private Point menuLocation; + + /** + * Creates a new JMenu object. + */ + public JMenu() + { + super(); + } + + /** + * Creates a new <code>JMenu</code> with the specified label. + * + * @param text label for this menu + */ + public JMenu(String text) + { + super(text); + popupMenu.setInvoker(this); + } + + /** + * Creates a new <code>JMenu</code> object. + * + * @param action Action that is used to create menu item tha will be + * added to the menu. + */ + public JMenu(Action action) + { + super(action); + createActionChangeListener(this); + popupMenu.setInvoker(this); + } + + /** + * Creates a new <code>JMenu</code> with specified label and an option + * for this menu to be tear-off menu. + * + * @param text label for this menu + * @param tearoff true if this menu should be tear-off and false otherwise + */ + public JMenu(String text, boolean tearoff) + { + // FIXME: tearoff not implemented + this(text); + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + } + + /** + * Adds specified menu item to this menu + * + * @param item Menu item to add to this menu + * + * @return Menu item that was added + */ + public JMenuItem add(JMenuItem item) + { + return popupMenu.add(item); + } + + /** + * Adds specified component to this menu. + * + * @param component Component to add to this menu + * + * @return Component that was added + */ + public Component add(Component component) + { + popupMenu.insert(component, -1); + return component; + } + + /** + * Adds specified component to this menu at the given index + * + * @param component Component to add + * @param index Position of this menu item in the menu + * + * @return Component that was added + */ + public Component add(Component component, int index) + { + return popupMenu.add(component, index); + } + + /** + * Adds JMenuItem constructed with the specified label to this menu + * + * @param text label for the menu item that will be added + * + * @return Menu Item that was added to this menu + */ + public JMenuItem add(String text) + { + return popupMenu.add(text); + } + + /** + * Adds JMenuItem constructed using properties from specified action. + * + * @param action action to construct the menu item with + * + * @return Menu Item that was added to this menu + */ + public JMenuItem add(Action action) + { + return popupMenu.add(action); + } + + /** + * Removes given menu item from this menu. Nothing happens if + * this menu doesn't contain specified menu item. + * + * @param item Menu Item which needs to be removed + */ + public void remove(JMenuItem item) + { + popupMenu.remove(item); + } + + /** + * Removes component at the specified index from this menu + * + * @param index Position of the component that needs to be removed in the menu + */ + public void remove(int index) + { + popupMenu.remove(index); + } + + /** + * Removes given component from this menu. + * + * @param component Component to remove + */ + public void remove(Component component) + { + int index = popupMenu.getComponentIndex(component); + popupMenu.remove(index); + } + + /** + * Removes all menu items from the menu + */ + public void removeAll() + { + popupMenu.removeAll(); + } + + /** + * Creates JMenuItem with the specified text and inserts it in the + * at the specified index + * + * @param text label for the new menu item + * @param index index at which to insert newly created menu item. + */ + public void insert(String text, int index) + { + this.insert(new JMenuItem(text), index); + } + + /** + * Creates JMenuItem with the specified text and inserts it in the + * at the specified index. IllegalArgumentException is thrown + * if index is less than 0 + * + * @param item menu item to insert + * @param index index at which to insert menu item. + * @return Menu item that was added to the menu + */ + public JMenuItem insert(JMenuItem item, int index) + { + if (index < 0) + throw new IllegalArgumentException("index less than zero"); + + popupMenu.insert(item, index); + return item; + } + + /** + * Creates JMenuItem with the associated action and inserts it to the menu + * at the specified index. IllegalArgumentException is thrown + * if index is less than 0 + * + * @param action Action for the new menu item + * @param index index at which to insert newly created menu item. + * @return Menu item that was added to the menu + */ + public JMenuItem insert(Action action, int index) + { + JMenuItem item = new JMenuItem(action); + this.insert(item, index); + + return item; + } + + /** + * This method sets this menuItem's UI to the UIManager's default for the + * current look and feel. + */ + public void updateUI() + { + super.setUI((MenuItemUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the menu. + * + * @return The Look and Feel classID. "MenuUI" + */ + public String getUIClassID() + { + return "MenuUI"; + } + + /** + * Sets model for this menu. + * + * @param model model to set + */ + public void setModel(ButtonModel model) + { + super.setModel(model); + } + + /** + * Returns true if the menu is selected and false otherwise + * + * @return true if the menu is selected and false otherwise + */ + public boolean isSelected() + { + return super.isSelected(); + } + + /** + * A helper method to handle setSelected calls from both mouse events and + * direct calls to setSelected. Direct calls shouldn't expand the popup + * menu and should select the JMenu even if it is disabled. Mouse events + * only select the JMenu if it is enabled and should expand the popup menu + * associated with this JMenu. + * @param selected whether or not the JMenu was selected + * @param menuEnabled whether or not selecting the menu is "enabled". This + * is always true for direct calls, and is set to isEnabled() for mouse + * based calls. + * @param showMenu whether or not to show the popup menu + */ + private void setSelectedHelper(boolean selected, boolean menuEnabled, boolean showMenu) + { + // If menu is selected and enabled, activates the menu and + // displays associated popup. + if (selected && menuEnabled) + { + super.setArmed(true); + super.setSelected(true); + + // FIXME: The popup menu should be shown on the screen after certain + // number of seconds pass. The 'delay' property of this menu indicates + // this amount of seconds. 'delay' property is 0 by default. + if (isShowing()) + { + fireMenuSelected(); + + int x = 0; + int y = 0; + if (showMenu) + if (menuLocation == null) + { + // Calculate correct position of the popup. Note that location of the popup + // passed to show() should be relative to the popup's invoker + if (isTopLevelMenu()) + y = this.getHeight(); + else + x = this.getWidth(); + getPopupMenu().show(this, x, y); + } + else + { + getPopupMenu().show(this, menuLocation.x, menuLocation.y); + } + } + } + + else + { + super.setSelected(false); + super.setArmed(false); + fireMenuDeselected(); + popupMenu.setVisible(false); + } + } + + /** + * Changes this menu selected state if selected is true and false otherwise + * This method fires menuEvents to menu's registered listeners. + * + * @param selected true if the menu should be selected and false otherwise + */ + public void setSelected(boolean selected) + { + setSelectedHelper(selected, true, false); + } + + /** + * Checks if PopupMenu associated with this menu is visible + * + * @return true if the popup associated with this menu is currently visible + * on the screen and false otherwise. + */ + public boolean isPopupMenuVisible() + { + return popupMenu.isVisible(); + } + + /** + * Sets popup menu visibility + * + * @param popup true if popup should be visible and false otherwise + */ + public void setPopupMenuVisible(boolean popup) + { + if (getModel().isEnabled()) + popupMenu.setVisible(popup); + } + + /** + * Returns origin point of the popup menu + * + * @return Point containing + */ + protected Point getPopupMenuOrigin() + { + // if menu in the menu bar + if (isTopLevelMenu()) + return new Point(0, this.getHeight()); + + // if submenu + return new Point(this.getWidth(), 0); + } + + /** + * Returns delay property. + * + * @return delay property, indicating number of milliseconds before + * popup menu associated with the menu appears or disappears after + * menu was selected or deselected respectively + */ + public int getDelay() + { + return delay; + } + + /** + * Sets delay property for this menu. If given time for the delay + * property is negative, then IllegalArgumentException is thrown + * + * @param delay number of milliseconds before + * popup menu associated with the menu appears or disappears after + * menu was selected or deselected respectively + */ + public void setDelay(int delay) + { + if (delay < 0) + throw new IllegalArgumentException("delay less than 0"); + this.delay = delay; + } + + /** + * Sets location at which popup menu should be displayed + * The location given is relative to this menu item + * + * @param x x-coordinate of the menu location + * @param y y-coordinate of the menu location + */ + public void setMenuLocation(int x, int y) + { + menuLocation = new Point(x, y); + } + + /** + * Creates and returns JMenuItem associated with the given action + * + * @param action Action to use for creation of JMenuItem + * + * @return JMenuItem that was creted with given action + */ + protected JMenuItem createActionComponent(Action action) + { + return new JMenuItem(action); + } + + /** + * Creates ActionChangeListener to listen for PropertyChangeEvents occuring + * in the action that is associated with this menu + * + * @param item menu that contains action to listen to + * + * @return The PropertyChangeListener + */ + protected PropertyChangeListener createActionChangeListener(JMenuItem item) + { + return new ActionChangedListener(item); + } + + /** + * Adds separator to the end of the menu items in the menu. + */ + public void addSeparator() + { + getPopupMenu().addSeparator(); + } + + /** + * Inserts separator in the menu at the specified index. + * + * @param index Index at which separator should be inserted + */ + public void insertSeparator(int index) + { + if (index < 0) + throw new IllegalArgumentException("index less than 0"); + + getPopupMenu().insert(new JPopupMenu.Separator(), index); + } + + /** + * Returns menu item located at the specified index in the menu + * + * @param index Index at which to look for the menu item + * + * @return menu item located at the specified index in the menu + */ + public JMenuItem getItem(int index) + { + if (index < 0) + throw new IllegalArgumentException("index less than 0"); + + Component c = popupMenu.getComponentAtIndex(index); + + if (c instanceof JMenuItem) + return (JMenuItem) c; + else + return null; + } + + /** + * Returns number of items in the menu including separators. + * + * @return number of items in the menu + * + * @see #getMenuComponentCount() + */ + public int getItemCount() + { + return getMenuComponentCount(); + } + + /** + * Checks if this menu is a tear-off menu. + * + * @return true if this menu is a tear-off menu and false otherwise + */ + public boolean isTearOff() + { + // NOT YET IMPLEMENTED + return false; + } + + /** + * Returns number of menu components in this menu + * + * @return number of menu components in this menu + */ + public int getMenuComponentCount() + { + return popupMenu.getComponentCount(); + } + + /** + * Returns menu component located at the givent index + * in the menu + * + * @param index index at which to get the menu component in the menu + * + * @return Menu Component located in the menu at the specified index + */ + public Component getMenuComponent(int index) + { + return (Component) popupMenu.getComponentAtIndex(index); + } + + /** + * Return components belonging to this menu + * + * @return components belonging to this menu + */ + public Component[] getMenuComponents() + { + return popupMenu.getComponents(); + } + + /** + * Checks if this menu is a top level menu. The menu is top + * level menu if it is inside the menu bar. While if the menu + * inside some other menu, it is considered to be a pull-right menu. + * + * @return true if this menu is top level menu, and false otherwise + */ + public boolean isTopLevelMenu() + { + return getParent() instanceof JMenuBar; + } + + /** + * Checks if given component exists in this menu. The submenus of + * this menu are checked as well + * + * @param component Component to look for + * + * @return true if the given component exists in this menu, and false otherwise + */ + public boolean isMenuComponent(Component component) + { + return false; + } + + /** + * Returns popup menu associated with the menu. + * + * @return popup menu associated with the menu. + */ + public JPopupMenu getPopupMenu() + { + return popupMenu; + } + + /** + * Adds MenuListener to the menu + * + * @param listener MenuListener to add + */ + public void addMenuListener(MenuListener listener) + { + listenerList.add(MenuListener.class, listener); + } + + /** + * Removes MenuListener from the menu + * + * @param listener MenuListener to remove + */ + public void removeMenuListener(MenuListener listener) + { + listenerList.remove(MenuListener.class, listener); + } + + /** + * Returns all registered <code>MenuListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public MenuListener[] getMenuListeners() + { + return (MenuListener[]) listenerList.getListeners(MenuListener.class); + } + + /** + * This method fires MenuEvents to all menu's MenuListeners. In this case + * menuSelected() method of MenuListeners is called to indicated that the menu + * was selected. + */ + protected void fireMenuSelected() + { + MenuListener[] listeners = getMenuListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].menuSelected(menuEvent); + } + + /** + * This method fires MenuEvents to all menu's MenuListeners. In this case + * menuDeselected() method of MenuListeners is called to indicated that the menu + * was deselected. + */ + protected void fireMenuDeselected() + { + EventListener[] ll = listenerList.getListeners(MenuListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuListener) ll[i]).menuDeselected(menuEvent); + } + + /** + * This method fires MenuEvents to all menu's MenuListeners. In this case + * menuSelected() method of MenuListeners is called to indicated that the menu + * was cancelled. The menu is cancelled when it's popup menu is close without selection. + */ + protected void fireMenuCanceled() + { + EventListener[] ll = listenerList.getListeners(MenuListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuListener) ll[i]).menuCanceled(menuEvent); + } + + /** + * Creates WinListener that listens to the menu;s popup menu. + * + * @param popup JPopupMenu to listen to + * + * @return The WinListener + */ + protected WinListener createWinListener(JPopupMenu popup) + { + return new WinListener(popup); + } + + /** + * Method of the MenuElementInterface. It reacts to the selection + * changes in the menu. If this menu was selected, then it + * displayes popup menu associated with it and if this menu was + * deselected it hides the popup menu. + * + * @param changed true if the menu was selected and false otherwise + */ + public void menuSelectionChanged(boolean changed) + { + // if this menu selection is true, then activate this menu and + // display popup associated with this menu + setSelectedHelper(changed, isEnabled(), true); + } + + /** + * Method of MenuElement interface. Returns sub components of + * this menu. + * + * @return array containing popupMenu that is associated with this menu + */ + public MenuElement[] getSubElements() + { + return new MenuElement[] { popupMenu }; + } + + /** + * @return Returns reference to itself + */ + public Component getComponent() + { + return this; + } + + /** + * This method is overriden with empty implementation, s.t the + * accelerator couldn't be set for the menu. The mnemonic should + * be used for the menu instead. + * + * @param keystroke accelerator for this menu + */ + public void setAccelerator(KeyStroke keystroke) + { + throw new Error("setAccelerator() is not defined for JMenu. Use setMnemonic() instead."); + } + + /** + * This method process KeyEvent occuring when the menu is visible + * + * @param event The KeyEvent + */ + protected void processKeyEvent(KeyEvent event) + { + } + + /** + * Programatically performs click + * + * @param time Number of milliseconds for which this menu stays pressed + */ + public void doClick(int time) + { + getModel().setArmed(true); + getModel().setPressed(true); + try + { + java.lang.Thread.sleep(time); + } + catch (java.lang.InterruptedException e) + { + // probably harmless + } + + getModel().setPressed(false); + getModel().setArmed(false); + popupMenu.show(this, this.getWidth(), 0); + } + + /** + * A string that describes this JMenu. Normally only used + * for debugging. + * + * @return A string describing this JMenu + */ + protected String paramString() + { + return super.paramString(); + } + + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJMenu(); + + return accessibleContext; + } + + protected class AccessibleJMenu extends AccessibleJMenuItem + implements AccessibleSelection + { + private static final long serialVersionUID = -8131864021059524309L; + + protected AccessibleJMenu() + { + } + + public int getAccessibleChildrenCount() + { + return 0; + } + + public Accessible getAccessibleChild(int value0) + { + return null; + } + + public AccessibleSelection getAccessibleSelection() + { + return null; + } + + public Accessible getAccessibleSelection(int value0) + { + return null; + } + + public boolean isAccessibleChildSelected(int value0) + { + return false; + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU; + } + + public int getAccessibleSelectionCount() + { + return 0; + } + + public void addAccessibleSelection(int value0) + { + } + + public void removeAccessibleSelection(int value0) + { + } + + public void clearAccessibleSelection() + { + } + + public void selectAllAccessibleSelection() + { + } + } + + protected class WinListener extends WindowAdapter implements Serializable + { + JPopupMenu popupMenu; + private static final long serialVersionUID = -6415815570638474823L; + + public WinListener(JPopupMenu popup) + { + } + + public void windowClosing(WindowEvent event) + { + } + } + + /** + * This class listens to PropertyChangeEvents occuring in menu's action + */ + protected class ActionChangedListener implements PropertyChangeListener + { + /** menu item associated with the action */ + private JMenuItem menuItem; + + /** Creates new ActionChangedListener and adds it to menuItem's action */ + public ActionChangedListener(JMenuItem menuItem) + { + this.menuItem = menuItem; + + Action a = menuItem.getAction(); + if (a != null) + a.addPropertyChangeListener(this); + } + + /**This method is invoked when some change occures in menuItem's action*/ + public void propertyChange(PropertyChangeEvent evt) + { + // FIXME: Need to implement + } + } + +} diff --git a/libjava/classpath/javax/swing/JMenuBar.java b/libjava/classpath/javax/swing/JMenuBar.java new file mode 100644 index 00000000000..a464fff9bae --- /dev/null +++ b/libjava/classpath/javax/swing/JMenuBar.java @@ -0,0 +1,459 @@ +/* JMenuBar.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.plaf.MenuBarUI; + +/** + * JMenuBar is a container for menu's. For a menu bar to be seen on the + * screen, at least one menu should be added to it. Just like adding + * components to container, one can use add() to add menu's to the menu bar. + * Menu's will be displayed in the menu bar in the order they were added. + * The JMenuBar uses selectionModel to keep track of selected menu index. + * JMenuBar's selectionModel will fire ChangeEvents to its registered + * listeners when the selected index changes. + */ +public class JMenuBar extends JComponent implements Accessible, MenuElement +{ + private static final long serialVersionUID = -8191026883931977036L; + + /** JMenuBar's model. It keeps track of selected menu's index */ + private transient SingleSelectionModel selectionModel; + + /* borderPainted property indicating if the menuBar's border will be painted*/ + private boolean borderPainted; + + /* margin between menu bar's border and its menues*/ + private Insets margin; + + /** + * Creates a new JMenuBar object. + */ + public JMenuBar() + { + selectionModel = new DefaultSingleSelectionModel(); + borderPainted = true; + updateUI(); + } + + /** + * Adds menu to the menu bar + * + * @param c menu to add + * + * @return reference to the added menu + */ + public JMenu add(JMenu c) + { + c.setAlignmentX(Component.LEFT_ALIGNMENT); + super.add(c); + return c; + } + + /** + * This method overrides addNotify() in the Container to register + * this menu bar with the current keyboard manager. + */ + public void addNotify() + { + // FIXME: Should register this menu bar with the keyboard manager + super.addNotify(); + } + + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * Returns reference to this menu bar + * + * @return reference to this menu bar + */ + public Component getComponent() + { + return this; + } + + /** + * Returns component at the specified index. + * + * @param i index of the component to get + * + * @return component at the specified index. Null is returned if + * component at the specified index doesn't exist. + * @deprecated Replaced by getComponent(int) + */ + public Component getComponentAtIndex(int i) + { + return getComponent(i); + } + + /** + * Returns index of the specified component + * + * @param c Component to search for + * + * @return index of the specified component. -1 is returned if + * specified component doesnt' exist in the menu bar. + */ + public int getComponentIndex(Component c) + { + Component[] comps = getComponents(); + + int index = -1; + + for (int i = 0; i < comps.length; i++) + { + if (comps[i].equals(c)) + { + index = i; + break; + } + } + + return index; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JMenu getHelpMenu() + { + return null; + } + + /** + * Returns margin betweeen menu bar's border and its menues + * + * @return margin between menu bar's border and its menues + */ + public Insets getMargin() + { + if (margin == null) + return new Insets(0, 0, 0, 0); + else + return margin; + } + + /** + * Return menu at the specified index. If component at the + * specified index is not a menu, then null is returned. + * + * @param index index to look for the menu + * + * @return menu at specified index, or null if menu doesn't exist + * at the specified index. + */ + public JMenu getMenu(int index) + { + if (getComponentAtIndex(index) instanceof JMenu) + return (JMenu) getComponentAtIndex(index); + else + return null; + } + + /** + * Returns number of menu's in this menu bar + * + * @return number of menu's in this menu bar + */ + public int getMenuCount() + { + return getComponentCount(); + } + + /** + * Returns selection model for this menu bar. SelectionModel + * keeps track of the selected menu in the menu bar. Whenever + * selected property of selectionModel changes, the ChangeEvent + * will be fired its ChangeListeners. + * + * @return selection model for this menu bar. + */ + public SingleSelectionModel getSelectionModel() + { + return selectionModel; + } + + /** + * Method of MenuElement interface. It returns subcomponents + * of the menu bar, which are all the menues that it contains. + * + * @return MenuElement[] array containing menues in this menu bar + */ + public MenuElement[] getSubElements() + { + MenuElement[] subElements = new MenuElement[getComponentCount()]; + + for (int i = 0; i < getComponentCount(); i++) + subElements[i] = (MenuElement) getMenu(i); + + return subElements; + } + + /** + * Set the "UI" property of the menu bar, which is a look and feel class + * responsible for handling the menuBar's input events and painting it. + * + * @return The current "UI" property + */ + public MenuBarUI getUI() + { + return (MenuBarUI) ui; + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the menu bar. + * + * @return The Look and Feel classID. "MenuItemUI" + */ + public String getUIClassID() + { + return "MenuBarUI"; + } + + /** + * Returns true if menu bar paints its border and false otherwise + * + * @return true if menu bar paints its border and false otherwise + */ + public boolean isBorderPainted() + { + return borderPainted; + } + + /** + * Returns true if some menu in menu bar is selected. + * + * @return true if some menu in menu bar is selected and false otherwise + */ + public boolean isSelected() + { + return selectionModel.isSelected(); + } + + /** + * This method does nothing by default. This method is need for the + * MenuElement interface to be implemented. + * + * @param isIncluded true if menuBar is included in the selection + * and false otherwise + */ + public void menuSelectionChanged(boolean isIncluded) + { + // Do nothing - needed for implementation of MenuElement interface + } + + /** + * Paints border of the menu bar, if its borderPainted property is set to + * true. + * + * @param g The graphics context with which to paint the border + */ + protected void paintBorder(Graphics g) + { + if (borderPainted) + getBorder().paintBorder(this, g, 0, 0, getSize(null).width, + getSize(null).height); + } + + /** + * A string that describes this JMenuBar. Normally only used + * for debugging. + * + * @return A string describing this JMenuBar + */ + protected String paramString() + { + StringBuffer sb = new StringBuffer(); + sb.append(super.paramString()); + sb.append(",margin="); + if (getMargin() != null) + sb.append(getMargin()); + sb.append(",paintBorder=").append(isBorderPainted()); + return sb.toString(); + } + + /** + * Process key events forwarded from MenuSelectionManager. This method + * doesn't do anything. It is here to conform to the MenuElement interface. + * + * @param event event forwarded from MenuSelectionManager + * @param path path to the menu element from which event was generated + * @param manager MenuSelectionManager for the current menu hierarchy + * + */ + public void processKeyEvent(KeyEvent e, MenuElement[] path, + MenuSelectionManager manager) + { + // Do nothing - needed for implementation of MenuElement interface + } + + /** + * Process mouse events forwarded from MenuSelectionManager. This method + * doesn't do anything. It is here to conform to the MenuElement interface. + * + * @param event event forwarded from MenuSelectionManager + * @param path path to the menu element from which event was generated + * @param manager MenuSelectionManager for the current menu hierarchy + * + */ + public void processMouseEvent(MouseEvent event, MenuElement[] path, + MenuSelectionManager manager) + { + // Do nothing - needed for implementation of MenuElement interface + } + + /** + * This method overrides removeNotify() in the Container to + * unregister this menu bar from the current keyboard manager. + */ + public void removeNotify() + { + // Must unregister this menu bar with the current keyboard manager. + super.removeNotify(); + } + + /** + * Sets painting status of the border. If 'b' is true then menu bar's + * border will be painted, and it will not be painted otherwise. + * + * @param b indicates if menu bar's border should be painted. + */ + public void setBorderPainted(boolean b) + { + if (b != borderPainted) + { + boolean old = borderPainted; + borderPainted = b; + firePropertyChange("borderPainted", old, b); + revalidate(); + repaint(); + } + } + + /** + * Sets help menu for this menu bar + * + * @param menu help menu + */ + public void setHelpMenu(JMenu menu) + { + } + + /** + * Sets the menu bar's "margin" bound property, which represents + * distance between the menubar's border and its menus. + * icon. When marging property is modified, PropertyChangeEvent will + * be fired to menuBar's PropertyChangeListener's. + * + * @param m distance between the menubar's border and its menus. + * + */ + public void setMargin(Insets m) + { + if (m != margin) + { + Insets oldMargin = margin; + margin = m; + firePropertyChange("margin", oldMargin, margin); + } + } + + /** + * Changes menu bar's selection to the specified menu. + * This method updates selected index of menu bar's selection model, + * which results in a model firing change event. + * + * @param sel menu to select + */ + public void setSelected(Component sel) + { + int index = getComponentIndex(sel); + selectionModel.setSelectedIndex(index); + } + + /** + * Sets menuBar's selection model to the one specified + * + * @param model SingleSelectionModel that needs to be set for this menu bar + */ + public void setSelectionModel(SingleSelectionModel model) + { + if (selectionModel != model) + { + SingleSelectionModel oldModel = selectionModel; + selectionModel = model; + firePropertyChange("model", oldModel, selectionModel); + } + } + + /** + * Set the "UI" property of the menu bar, which is a look and feel class + * responsible for handling menuBar's input events and painting it. + * + * @param ui The new "UI" property + */ + public void setUI(MenuBarUI ui) + { + super.setUI(ui); + } + + /** + * Set the "UI" property to a class constructed, via the {@link + * UIManager}, from the current look and feel. + */ + public void updateUI() + { + setUI((MenuBarUI) UIManager.getUI(this)); + invalidate(); + } +} diff --git a/libjava/classpath/javax/swing/JMenuItem.java b/libjava/classpath/javax/swing/JMenuItem.java new file mode 100644 index 00000000000..069b7bc86f8 --- /dev/null +++ b/libjava/classpath/javax/swing/JMenuItem.java @@ -0,0 +1,677 @@ +/* JMenuItem.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MenuDragMouseEvent; +import javax.swing.event.MenuDragMouseListener; +import javax.swing.event.MenuKeyEvent; +import javax.swing.event.MenuKeyListener; +import javax.swing.plaf.MenuItemUI; + +/** + * JMenuItem represents element in the menu. It inherits most of + * its functionality from AbstractButton, however its behavior somewhat + * varies from it. JMenuItem fire different kinds of events. + * PropertyChangeEvents are fired when menuItems properties are modified; + * ChangeEvents are fired when menuItem's state changes and actionEvents are + * fired when menu item is selected. In addition to this events menuItem also + * fire MenuDragMouseEvent and MenuKeyEvents when mouse is dragged over + * the menu item or associated key with menu item is invoked respectively. + */ +public class JMenuItem extends AbstractButton implements Accessible, + MenuElement +{ + private static final long serialVersionUID = -1681004643499461044L; + + /** Combination of keyboard keys that can be used to activate this menu item */ + private KeyStroke accelerator; + + /** + * Creates a new JMenuItem object. + */ + public JMenuItem() + { + super(); + } + + /** + * Creates a new JMenuItem with the given icon. + * + * @param icon Icon that will be displayed on the menu item + */ + public JMenuItem(Icon icon) + { + // FIXME: The requestedFocusEnabled property should + // be set to false, when only icon is set for menu item. + super(); + init(null, icon); + } + + /** + * Creates a new JMenuItem with the given label. + * + * @param text label for the menu item + */ + public JMenuItem(String text) + { + this(text, null); + } + + /** + * Creates a new JMenuItem associated with the specified action. + * + * @param action action for this menu item + */ + public JMenuItem(Action action) + { + super(); + super.setAction(action); + } + + /** + * Creates a new JMenuItem with specified text and icon. + * Text is displayed to the left of icon by default. + * + * @param text label for this menu item + * @param icon icon that will be displayed on this menu item + */ + public JMenuItem(String text, Icon icon) + { + super(); + init(text, icon); + } + + /** + * Creates a new JMenuItem object. + * + * @param text label for this menu item + * @param mnemonic - Single key that can be used with a + * look-and-feel meta key to activate this menu item. However + * menu item should be visible on the screen when mnemonic is used. + */ + public JMenuItem(String text, int mnemonic) + { + this(text, null); + setMnemonic(mnemonic); + } + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + } + + /** + * Initializes this menu item + * + * @param text label for this menu item + * @param icon icon to be displayed for this menu item + */ + protected void init(String text, Icon icon) + { + super.init(text, icon); + setModel(new DefaultButtonModel()); + + // Initializes properties for this menu item, that are different + // from Abstract button properties. + /* NOTE: According to java specifications paint_border should be set to false, + since menu item should not have a border. However running few java programs + it seems that menu items and menues can have a border. Commenting + out statement below for now. */ + //borderPainted = false; + focusPainted = false; + horizontalAlignment = JButton.LEFT; + horizontalTextPosition = JButton.LEFT; + } + + /** + * Set the "UI" property of the menu item, which is a look and feel class + * responsible for handling menuItem's input events and painting it. + * + * @param ui The new "UI" property + */ + public void setUI(MenuItemUI ui) + { + super.setUI(ui); + } + + /** + * This method sets this menuItem's UI to the UIManager's default for the + * current look and feel. + */ + public void updateUI() + { + MenuItemUI mi = ((MenuItemUI) UIManager.getUI(this)); + setUI(mi); + invalidate(); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the menuItem. + * + * @return The Look and Feel classID. "MenuItemUI" + */ + public String getUIClassID() + { + return "MenuItemUI"; + } + + /** + * Returns true if button's model is armed and false otherwise. The + * button model is armed if menu item has focus or it is selected. + * + * @return $boolean$ true if button's model is armed and false otherwise + */ + public boolean isArmed() + { + return getModel().isArmed(); + } + + /** + * Sets menuItem's "ARMED" property + * + * @param armed DOCUMENT ME! + */ + public void setArmed(boolean armed) + { + getModel().setArmed(armed); + } + + /** + * Enable or disable menu item. When menu item is disabled, + * its text and icon are grayed out if they exist. + * + * @param enabled if true enable menu item, and disable otherwise. + */ + public void setEnabled(boolean enabled) + { + super.setEnabled(enabled); + } + + /** + * Return accelerator for this menu item. + * + * @return $KeyStroke$ accelerator for this menu item. + */ + public KeyStroke getAccelerator() + { + return accelerator; + } + + /** + * Sets accelerator for this menu item. + * + * @param keystroke accelerator for this menu item. + */ + public void setAccelerator(KeyStroke keystroke) + { + this.accelerator = keystroke; + } + + /** + * Configures menu items' properties from properties of the specified action. + * This method overrides configurePropertiesFromAction from AbstractButton + * to also set accelerator property. + * + * @param action action to configure properties from + */ + protected void configurePropertiesFromAction(Action action) + { + super.configurePropertiesFromAction(action); + + if (! (this instanceof JMenu) && action != null) + setAccelerator((KeyStroke) (action.getValue(Action.ACCELERATOR_KEY))); + } + + /** + * Creates PropertyChangeListener to listen for the changes in action + * properties. + * + * @param action action to listen to for property changes + * + * @return $PropertyChangeListener$ Listener that listens to changes in + * action properties. + */ + protected PropertyChangeListener createActionPropertyChangeListener(Action action) + { + return new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent e) + { + Action act = (Action) (e.getSource()); + configurePropertiesFromAction(act); + } + }; + } + + /** + * Process mouse events forwarded from MenuSelectionManager. + * + * @param event event forwarded from MenuSelectionManager + * @param path path to the menu element from which event was generated + * @param manager MenuSelectionManager for the current menu hierarchy + */ + public void processMouseEvent(MouseEvent event, MenuElement[] path, + MenuSelectionManager manager) + { + // Fire MenuDragMouseEvents if mouse is being dragged. + boolean dragged + = (event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0; + if (dragged) + processMenuDragMouseEvent(createMenuDragMouseEvent(event, path, manager)); + + switch (event.getID()) + { + case MouseEvent.MOUSE_CLICKED: + break; + case MouseEvent.MOUSE_ENTERED: + if (isRolloverEnabled()) + model.setRollover(true); + break; + case MouseEvent.MOUSE_EXITED: + if (isRolloverEnabled()) + model.setRollover(false); + + // for JMenu last element on the path is its popupMenu. + // JMenu shouldn't me disarmed. + if (! (path[path.length - 1] instanceof JPopupMenu) && ! dragged) + setArmed(false); + break; + case MouseEvent.MOUSE_PRESSED: + if ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) + { + model.setArmed(true); + model.setPressed(true); + } + break; + case MouseEvent.MOUSE_RELEASED: + break; + case MouseEvent.MOUSE_MOVED: + break; + case MouseEvent.MOUSE_DRAGGED: + break; + } + } + + /** + * Creates MenuDragMouseEvent. + * + * @param event MouseEvent that occured while mouse was pressed. + * @param path Path the the menu element where the dragging event was + * originated + * @param manager MenuSelectionManager for the current menu hierarchy. + * + * @return new MenuDragMouseEvent + */ + private MenuDragMouseEvent createMenuDragMouseEvent(MouseEvent event, + MenuElement[] path, + MenuSelectionManager manager) + { + return new MenuDragMouseEvent((Component) event.getSource(), + event.getID(), event.getWhen(), + event.getModifiers(), event.getX(), + event.getY(), event.getClickCount(), + event.isPopupTrigger(), path, manager); + } + + /** + * Process key events forwarded from MenuSelectionManager. + * + * @param event event forwarded from MenuSelectionManager + * @param path path to the menu element from which event was generated + * @param manager MenuSelectionManager for the current menu hierarchy + */ + public void processKeyEvent(KeyEvent event, MenuElement[] path, + MenuSelectionManager manager) + { + // Need to implement. + } + + /** + * This method fires MenuDragMouseEvents to registered listeners. + * Different types of MenuDragMouseEvents are fired depending + * on the observed mouse event. + * + * @param event Mouse + */ + public void processMenuDragMouseEvent(MenuDragMouseEvent event) + { + switch (event.getID()) + { + case MouseEvent.MOUSE_ENTERED: + fireMenuDragMouseEntered(event); + break; + case MouseEvent.MOUSE_EXITED: + fireMenuDragMouseExited(event); + break; + case MouseEvent.MOUSE_DRAGGED: + fireMenuDragMouseDragged(event); + break; + case MouseEvent.MOUSE_RELEASED: + fireMenuDragMouseReleased(event); + break; + } + } + + /** + * This method fires MenuKeyEvent to registered listeners. + * Different types of MenuKeyEvents are fired depending + * on the observed key event. + * + * @param event DOCUMENT ME! + */ + public void processMenuKeyEvent(MenuKeyEvent event) + { + // Need to implement. + } + + /** + * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. + * + * @param event The event signifying that mouse entered menuItem while it was dragged + */ + protected void fireMenuDragMouseEntered(MenuDragMouseEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuDragMouseListener) ll[i]).menuDragMouseEntered(event); + } + + /** + * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. + * + * @param event The event signifying that mouse has exited menu item, while it was dragged + */ + protected void fireMenuDragMouseExited(MenuDragMouseEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuDragMouseListener) ll[i]).menuDragMouseExited(event); + } + + /** + * Fires MenuDragMouseEvent to all of the menuItem's MouseInputListeners. + * + * @param event The event signifying that mouse is being dragged over the menuItem + */ + protected void fireMenuDragMouseDragged(MenuDragMouseEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuDragMouseListener) ll[i]).menuDragMouseDragged(event); + } + + /** + * This method fires a MenuDragMouseEvent to all the MenuItem's MouseInputListeners. + * + * @param event The event signifying that mouse was released while it was dragged over the menuItem + */ + protected void fireMenuDragMouseReleased(MenuDragMouseEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuDragMouseListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuDragMouseListener) ll[i]).menuDragMouseReleased(event); + } + + /** + * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. + * + * @param event The event signifying that key associated with this menu was pressed + */ + protected void fireMenuKeyPressed(MenuKeyEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuKeyListener) ll[i]).menuKeyPressed(event); + } + + /** + * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. + * + * @param event The event signifying that key associated with this menu was released + */ + protected void fireMenuKeyReleased(MenuKeyEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuKeyListener) ll[i]).menuKeyTyped(event); + } + + /** + * This method fires a MenuKeyEvent to all the MenuItem's MenuKeyListeners. + * + * @param event The event signifying that key associated with this menu was typed. + * The key is typed when it was pressed and then released + */ + protected void fireMenuKeyTyped(MenuKeyEvent event) + { + EventListener[] ll = listenerList.getListeners(MenuKeyListener.class); + + for (int i = 0; i < ll.length; i++) + ((MenuKeyListener) ll[i]).menuKeyTyped(event); + } + + /** + * Method of the MenuElement interface. + * This method is invoked by MenuSelectionManager when selection of + * this menu item has changed. If this menu item was selected then + * arm it's model, and disarm the model otherwise. The menu item + * is considered to be selected, and thus highlighted when its model + * is armed. + * + * @param changed indicates selection status of this menu item. If changed is + * true then menu item is selected and deselected otherwise. + */ + public void menuSelectionChanged(boolean changed) + { + Component parent = this.getParent(); + if (changed) + { + model.setArmed(true); + + if (parent != null && parent instanceof JPopupMenu) + ((JPopupMenu) parent).setSelected(this); + } + else + { + model.setArmed(false); + + if (parent != null && parent instanceof JPopupMenu) + ((JPopupMenu) parent).getSelectionModel().clearSelection(); + } + } + + /** + * Method of the MenuElement interface. + * + * @return $MenuElement[]$ Returns array of sub-components for this menu + * item. By default menuItem doesn't have any subcomponents and so + * empty array is returned instead. + */ + public MenuElement[] getSubElements() + { + return new MenuElement[0]; + } + + /** + * Returns reference to the component that will paint this menu item. + * + * @return $Component$ Component that will paint this menu item. + * Simply returns reference to this menu item. + */ + public Component getComponent() + { + return this; + } + + /** + * Adds a MenuDragMouseListener to this menu item. When mouse + * is dragged over the menu item the MenuDragMouseEvents will be + * fired, and these listeners will be called. + * + * @param listener The new listener to add + */ + public void addMenuDragMouseListener(MenuDragMouseListener listener) + { + listenerList.add(MenuDragMouseListener.class, listener); + } + + /** + * Removes a MenuDragMouseListener from the menuItem's listener list. + * + * @param listener The listener to remove + */ + public void removeMenuDragMouseListener(MenuDragMouseListener listener) + { + listenerList.remove(MenuDragMouseListener.class, listener); + } + + /** + * Returns all added MenuDragMouseListener objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public MenuDragMouseListener[] getMenuDragMouseListeners() + { + return (MenuDragMouseListener[]) listenerList.getListeners(MenuDragMouseListener.class); + } + + /** + * Adds an MenuKeyListener to this menu item. This listener will be + * invoked when MenuKeyEvents will be fired by this menu item. + * + * @param listener The new listener to add + */ + public void addMenuKeyListener(MenuKeyListener listener) + { + listenerList.add(MenuKeyListener.class, listener); + } + + /** + * Removes an MenuKeyListener from the menuItem's listener list. + * + * @param listener The listener to remove + */ + public void removeMenuKeyListener(MenuKeyListener listener) + { + listenerList.remove(MenuKeyListener.class, listener); + } + + /** + * Returns all added MenuKeyListener objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public MenuKeyListener[] getMenuKeyListeners() + { + return (MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class); + } + + /** + * A string that describes this JMenuItem. Normally only used + * for debugging. + * + * @return A string describing this JMenuItem + */ + protected String paramString() + { + return super.paramString(); + } + + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJMenuItem(); + + return accessibleContext; + } + + protected class AccessibleJMenuItem extends AccessibleAbstractButton + implements ChangeListener + { + private static final long serialVersionUID = 6748924232082076534L; + + /** + * Creates a new AccessibleJMenuItem object. + */ + AccessibleJMenuItem() + { + //super(component); + } + + public void stateChanged(ChangeEvent event) + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.MENU_ITEM; + } + } +} diff --git a/libjava/classpath/javax/swing/JOptionPane.java b/libjava/classpath/javax/swing/JOptionPane.java new file mode 100644 index 00000000000..88fa993be00 --- /dev/null +++ b/libjava/classpath/javax/swing/JOptionPane.java @@ -0,0 +1,1547 @@ +/* JOptionPane.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.event.InternalFrameAdapter; +import javax.swing.event.InternalFrameEvent; +import javax.swing.plaf.OptionPaneUI; + +/** + * This class creates different types of JDialogs and JInternalFrames that can + * ask users for input or pass on information. JOptionPane can be used by + * calling one of the show static methods or by creating an instance of + * JOptionPane and calling createDialog or createInternalFrame. + */ +public class JOptionPane extends JComponent implements Accessible +{ + /** + * DOCUMENT ME! + */ + protected class AccessibleJOptionPane extends JComponent.AccessibleJComponent + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = 686071432213084821L; + + /** + * Creates a new AccessibleJOptionPane object. + */ + protected AccessibleJOptionPane() + { + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + } + + /** DOCUMENT ME! */ + private static final long serialVersionUID = 5231143276678566796L; + + /** The value returned when cancel option is selected. */ + public static final int CANCEL_OPTION = 2; + + /** The value returned when the dialog is closed without a selection. */ + public static final int CLOSED_OPTION = -1; + + /** An option used in confirmation dialog methods. */ + public static final int DEFAULT_OPTION = -1; + + /** The value returned when the no option is selected. */ + public static final int NO_OPTION = 1; + + /** An option used in confirmation dialog methods. */ + public static final int OK_CANCEL_OPTION = 2; + + /** The value returned when the ok option is selected. */ + public static final int OK_OPTION = 0; + + /** An option used in confirmation dialog methods. */ + public static final int YES_NO_CANCEL_OPTION = 1; + + /** An option used in confirmation dialog methods. */ + public static final int YES_NO_OPTION = 0; + + /** The value returned when the yes option is selected. */ + public static final int YES_OPTION = 0; + + /** Identifier for the error message type. */ + public static final int ERROR_MESSAGE = 0; + + /** Identifier for the information message type. */ + public static final int INFORMATION_MESSAGE = 1; + + /** Identifier for the plain message type. */ + public static final int PLAIN_MESSAGE = -1; + + /** Identifier for the question message type. */ + public static final int QUESTION_MESSAGE = 3; + + /** Identifier for the warning message type. */ + public static final int WARNING_MESSAGE = 2; + + /** + * The identifier for the propertyChangeEvent when the icon property + * changes. + */ + public static final String ICON_PROPERTY = "icon"; + + /** + * The identifier for the propertyChangeEvent when the initialSelectionValue + * property changes. + */ + public static final String INITIAL_SELECTION_VALUE_PROPERTY = "initialSelectionValue"; + + /** + * The identifier for the propertyChangeEvent when the initialValue property + * changes. + */ + public static final String INITIAL_VALUE_PROPERTY = "initialValue"; + + /** + * The identifier for the propertyChangeEvent when the inputValue property + * changes. + */ + public static final String INPUT_VALUE_PROPERTY = "inputValue"; + + /** + * The identifier for the propertyChangeEvent when the message property + * changes. + */ + public static final String MESSAGE_PROPERTY = "message"; + + /** + * The identifier for the propertyChangeEvent when the messageType property + * changes. + */ + public static final String MESSAGE_TYPE_PROPERTY = "messageType"; + + /** + * The identifier for the propertyChangeEvent when the optionType property + * changes. + */ + public static final String OPTION_TYPE_PROPERTY = "optionType"; + + /** + * The identifier for the propertyChangeEvent when the options property + * changes. + */ + public static final String OPTIONS_PROPERTY = "options"; + + /** + * The identifier for the propertyChangeEvent when the selectionValues + * property changes. + */ + public static final String SELECTION_VALUES_PROPERTY = "selectionValues"; + + /** + * The identifier for the propertyChangeEvent when the value property + * changes. + */ + public static final String VALUE_PROPERTY = "value"; + + /** + * The identifier for the propertyChangeEvent when the wantsInput property + * changes. + */ + public static final String WANTS_INPUT_PROPERTY = "wantsInput"; + + /** The value returned when the inputValue is uninitialized. */ + public static Object UNINITIALIZED_VALUE = "uninitializedValue"; + + /** The icon displayed in the dialog/internal frame. */ + protected Icon icon; + + /** The initial selected value in the input component. */ + protected Object initialSelectionValue; + + /** The object that is initially selected for options. */ + protected Object initialValue; + + /** The value the user inputs. */ + protected Object inputValue = UNINITIALIZED_VALUE; + + /** The message displayed in the dialog/internal frame. */ + protected Object message; + + /** The type of message displayed. */ + protected int messageType = PLAIN_MESSAGE; + + /** + * The options (usually buttons) aligned at the bottom for the user to + * select. + */ + protected Object[] options; + + /** The type of options to display. */ + protected int optionType = DEFAULT_OPTION; + + /** The input values the user can select. */ + protected Object[] selectionValues; + + /** The value returned by selecting an option. */ + protected Object value = UNINITIALIZED_VALUE; + + /** Whether the Dialog/InternalFrame needs input. */ + protected boolean wantsInput; + + /** The common frame used when no parent is provided. */ + private static Frame privFrame = SwingUtilities.getOwnerFrame(); + + /** + * Creates a new JOptionPane object using a message of "JOptionPane + * message", using the PLAIN_MESSAGE type and DEFAULT_OPTION. + */ + public JOptionPane() + { + this("JOptionPane message", PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null); + } + + /** + * Creates a new JOptionPane object using the given message using the + * PLAIN_MESSAGE type and DEFAULT_OPTION. + * + * @param message The message to display. + */ + public JOptionPane(Object message) + { + this(message, PLAIN_MESSAGE, DEFAULT_OPTION, null, null, null); + } + + /** + * Creates a new JOptionPane object using the given message and messageType + * and DEFAULT_OPTION. + * + * @param message The message to display. + * @param messageType The type of message. + */ + public JOptionPane(Object message, int messageType) + { + this(message, messageType, DEFAULT_OPTION, null, null, null); + } + + /** + * Creates a new JOptionPane object using the given message, messageType and + * optionType. + * + * @param message The message to display. + * @param messageType The type of message. + * @param optionType The type of options. + */ + public JOptionPane(Object message, int messageType, int optionType) + { + this(message, messageType, optionType, null, null, null); + } + + /** + * Creates a new JOptionPane object using the given message, messageType, + * optionType and icon. + * + * @param message The message to display. + * @param messageType The type of message. + * @param optionType The type of options. + * @param icon The icon to display. + */ + public JOptionPane(Object message, int messageType, int optionType, Icon icon) + { + this(message, messageType, optionType, icon, null, null); + } + + /** + * Creates a new JOptionPane object using the given message, messageType, + * optionType, icon and options. + * + * @param message The message to display. + * @param messageType The type of message. + * @param optionType The type of options. + * @param icon The icon to display. + * @param options The options given. + */ + public JOptionPane(Object message, int messageType, int optionType, + Icon icon, Object[] options) + { + this(message, messageType, optionType, icon, options, null); + } + + /** + * Creates a new JOptionPane object using the given message, messageType, + * optionType, icon, options and initialValue. The initialValue will be + * focused initially. + * + * @param message The message to display. + * @param messageType The type of message. + * @param optionType The type of options. + * @param icon The icon to display. + * @param options The options given. + * @param initialValue The component to focus on initially. + * + * @throws IllegalArgumentException If the messageType or optionType are not + * legal values. + */ + public JOptionPane(Object message, int messageType, int optionType, + Icon icon, Object[] options, Object initialValue) + { + this.message = message; + if (! validMessageType(messageType)) + throw new IllegalArgumentException("Message Type not legal value."); + this.messageType = messageType; + if (! validOptionType(optionType)) + throw new IllegalArgumentException("Option Type not legal value."); + this.optionType = optionType; + this.icon = icon; + this.options = options; + this.initialValue = initialValue; + + setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + updateUI(); + invalidate(); + repaint(); + } + + /** + * This method creates a new JDialog that is either centered around the + * parent's frame or centered on the screen (if the parent is null). The + * JDialog will not be resizable and will be modal. Once the JDialog is + * disposed, the inputValue and value properties will be set by the + * optionPane. + * + * @param parentComponent The parent of the Dialog. + * @param title The title in the bar of the JDialog. + * + * @return A new JDialog based on the JOptionPane configuration. + */ + public JDialog createDialog(Component parentComponent, String title) + { + Frame toUse = getFrameForComponent(parentComponent); + if (toUse == null) + toUse = getRootFrame(); + + JDialog dialog = new JDialog(toUse, title); + inputValue = UNINITIALIZED_VALUE; + value = UNINITIALIZED_VALUE; + + // FIXME: This dialog should be centered on the parent + // or at the center of the screen (if the parent is null) + // Need getGraphicsConfiguration to return non-null in + // order for that to work so we know how large the + // screen is. + dialog.getContentPane().add(this); + dialog.setModal(true); + dialog.setResizable(false); + dialog.invalidate(); + dialog.repaint(); + + return dialog; + } + + /** + * This method creates a new JInternalFrame that is in the JDesktopPane + * which contains the parentComponent given. If no suitable JDesktopPane + * can be found from the parentComponent given, a RuntimeException will be + * thrown. + * + * @param parentComponent The parent to find a JDesktopPane from. + * @param title The title of the JInternalFrame. + * + * @return A new JInternalFrame based on the JOptionPane configuration. + * + * @throws RuntimeException If no suitable JDesktopPane is found. + */ + public JInternalFrame createInternalFrame(Component parentComponent, + String title) + throws RuntimeException + { + JDesktopPane toUse = getDesktopPaneForComponent(parentComponent); + if (toUse == null) + throw new RuntimeException("parentComponent does not have a valid parent"); + + JInternalFrame frame = new JInternalFrame(title); + + inputValue = UNINITIALIZED_VALUE; + value = UNINITIALIZED_VALUE; + + frame.setClosable(true); + toUse.add(frame); + + // FIXME: JLayeredPane broken? See bug # 16576 + // frame.setLayer(JLayeredPane.MODAL_LAYER); + return frame; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJOptionPane(); + return accessibleContext; + } + + /** + * This method returns the JDesktopPane for the given parentComponent or + * null if none can be found. + * + * @param parentComponent The component to look in. + * + * @return The JDesktopPane for the given component or null if none can be + * found. + */ + public static JDesktopPane getDesktopPaneForComponent(Component parentComponent) + { + return (JDesktopPane) SwingUtilities.getAncestorOfClass(JDesktopPane.class, + parentComponent); + } + + /** + * This method returns the Frame for the given parentComponent or null if + * none can be found. + * + * @param parentComponent The component to look in. + * + * @return The Frame for the given component or null if none can be found. + */ + public static Frame getFrameForComponent(Component parentComponent) + { + return (Frame) SwingUtilities.getAncestorOfClass(Frame.class, + parentComponent); + } + + /** + * This method returns the icon displayed. + * + * @return The icon displayed. + */ + public Icon getIcon() + { + return icon; + } + + /** + * This method returns the value initially selected from the list of values + * the user can input. + * + * @return The initial selection value. + */ + public Object getInitialSelectionValue() + { + return initialSelectionValue; + } + + /** + * This method returns the value that is focused from the list of options. + * + * @return The initial value from options. + */ + public Object getInitialValue() + { + return initialValue; + } + + /** + * This method returns the value that the user input. + * + * @return The user's input value. + */ + public Object getInputValue() + { + return inputValue; + } + + /** + * This method returns the maximum characters per line. By default, this is + * Integer.MAX_VALUE. + * + * @return The maximum characters per line. + */ + public int getMaxCharactersPerLineCount() + { + return Integer.MAX_VALUE; + } + + /** + * This method returns the message displayed. + * + * @return The message displayed. + */ + public Object getMessage() + { + return message; + } + + /** + * This method returns the message type. + * + * @return The message type. + */ + public int getMessageType() + { + return messageType; + } + + /** + * This method returns the options. + * + * @return The options. + */ + public Object[] getOptions() + { + return options; + } + + /** + * This method returns the option type. + * + * @return The option type. + */ + public int getOptionType() + { + return optionType; + } + + /** + * This method returns the Frame used by JOptionPane dialog's that have no + * parent. + * + * @return The Frame used by dialogs that have no parent. + */ + public static Frame getRootFrame() + { + return privFrame; + } + + /** + * This method returns the selection values. + * + * @return The selection values. + */ + public Object[] getSelectionValues() + { + return selectionValues; + } + + /** + * This method returns the UI used by the JOptionPane. + * + * @return The UI used by the JOptionPane. + */ + public OptionPaneUI getUI() + { + return (OptionPaneUI) ui; + } + + /** + * This method returns an identifier to determine which UI class will act as + * the UI. + * + * @return The UI identifier. + */ + public String getUIClassID() + { + return "OptionPaneUI"; + } + + /** + * This method returns the value that the user selected out of options. + * + * @return The value that the user selected out of options. + */ + public Object getValue() + { + return value; + } + + /** + * This method returns whether this JOptionPane wants input. + * + * @return Whether this JOptionPane wants input. + */ + public boolean getWantsInput() + { + return wantsInput; + } + + /** + * This method returns a String that describes this JOptionPane. + * + * @return A String that describes this JOptionPane. + */ + protected String paramString() + { + return "JOptionPane"; + } + + /** + * This method requests focus for the initial value. + */ + public void selectInitialValue() + { + if (ui != null) + ((OptionPaneUI) ui).selectInitialValue(this); + } + + /** + * This method changes the icon property. + * + * @param newIcon The new icon to use. + */ + public void setIcon(Icon newIcon) + { + if (icon != newIcon) + { + Icon old = icon; + icon = newIcon; + firePropertyChange(ICON_PROPERTY, old, icon); + } + } + + /** + * This method changes the initial selection property. + * + * @param newValue The new initial selection. + */ + public void setInitialSelectionValue(Object newValue) + { + if (initialSelectionValue != newValue) + { + Object old = initialSelectionValue; + initialSelectionValue = newValue; + firePropertyChange(INITIAL_SELECTION_VALUE_PROPERTY, old, + initialSelectionValue); + } + } + + /** + * This method changes the initial value property. + * + * @param newValue The new initial value. + */ + public void setInitialValue(Object newValue) + { + if (initialValue != newValue) + { + Object old = initialValue; + initialValue = newValue; + firePropertyChange(INITIAL_VALUE_PROPERTY, old, initialValue); + } + } + + /** + * This method changes the inputValue property. + * + * @param newValue The new inputValue. + */ + public void setInputValue(Object newValue) + { + if (inputValue != newValue) + { + Object old = inputValue; + inputValue = newValue; + firePropertyChange(INPUT_VALUE_PROPERTY, old, inputValue); + } + } + + /** + * This method changes the message property. + * + * @param newMessage The new message. + */ + public void setMessage(Object newMessage) + { + if (message != newMessage) + { + Object old = message; + message = newMessage; + firePropertyChange(MESSAGE_PROPERTY, old, message); + } + } + + /** + * This method changes the messageType property. + * + * @param newType The new messageType. + * + * @throws IllegalArgumentException If the messageType is not valid. + */ + public void setMessageType(int newType) + { + if (! validMessageType(newType)) + throw new IllegalArgumentException("Message Type not legal value."); + if (newType != messageType) + { + int old = messageType; + messageType = newType; + firePropertyChange(MESSAGE_TYPE_PROPERTY, old, messageType); + } + } + + /** + * This method changes the options property. + * + * @param newOptions The new options. + */ + public void setOptions(Object[] newOptions) + { + if (options != newOptions) + { + Object[] old = options; + options = newOptions; + firePropertyChange(OPTIONS_PROPERTY, old, options); + } + } + + /** + * This method changes the optionType property. + * + * @param newType The new optionType. + * + * @throws IllegalArgumentException If the optionType is not valid. + */ + public void setOptionType(int newType) + { + if (! validOptionType(newType)) + throw new IllegalArgumentException("Option Type not legal value."); + if (newType != optionType) + { + int old = optionType; + optionType = newType; + firePropertyChange(OPTION_TYPE_PROPERTY, old, optionType); + } + } + + /** + * This method changes the Frame used for JOptionPane dialogs that have no + * parent. + * + * @param newRootFrame The Frame to use for dialogs that have no parent. + */ + public static void setRootFrame(Frame newRootFrame) + { + privFrame = newRootFrame; + } + + /** + * This method changes the selectionValues property. + * + * @param newValues The new selectionValues. + */ + public void setSelectionValues(Object[] newValues) + { + if (newValues != selectionValues) + { + if (newValues != null) + wantsInput = true; + Object[] old = selectionValues; + selectionValues = newValues; + firePropertyChange(SELECTION_VALUES_PROPERTY, old, selectionValues); + } + } + + /** + * This method sets the UI used with the JOptionPane. + * + * @param ui The UI used with the JOptionPane. + */ + public void setUI(OptionPaneUI ui) + { + super.setUI(ui); + } + + /** + * This method sets the value has been selected out of options. + * + * @param newValue The value that has been selected out of options. + */ + public void setValue(Object newValue) + { + if (value != newValue) + { + Object old = value; + value = newValue; + firePropertyChange(VALUE_PROPERTY, old, value); + } + } + + /** + * This method changes the wantsInput property. + * + * @param newValue Whether this JOptionPane requires input. + */ + public void setWantsInput(boolean newValue) + { + if (wantsInput != newValue) + { + boolean old = wantsInput; + wantsInput = newValue; + firePropertyChange(WANTS_INPUT_PROPERTY, old, wantsInput); + } + } + + /** + * This method shows a confirmation dialog with the title "Select an Option" + * and displays the given message. The parent frame will be the same as the + * parent frame of the given parentComponent. This method returns the + * option chosen by the user. + * + * @param parentComponent The parentComponent to find a frame in. + * @param message The message to display. + * + * @return The option that was selected. + */ + public static int showConfirmDialog(Component parentComponent, Object message) + { + JOptionPane pane = new JOptionPane(message); + JDialog dialog = pane.createDialog(parentComponent, "Select an Option"); + + dialog.pack(); + dialog.show(); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows a confirmation dialog with the given message, + * optionType and title. The frame that owns the dialog will be the same + * frame that holds the given parentComponent. This method returns the + * option that was chosen. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param optionType The optionType. + * + * @return The option that was chosen. + */ + public static int showConfirmDialog(Component parentComponent, + Object message, String title, + int optionType) + { + JOptionPane pane = new JOptionPane(message, PLAIN_MESSAGE, optionType); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows a confirmation dialog with the given message, title, + * messageType and optionType. The frame owner will be the same frame as + * the one that holds the given parentComponent. This method returns the + * option selected by the user. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param optionType The optionType. + * @param messageType The messageType. + * + * @return The selected option. + */ + public static int showConfirmDialog(Component parentComponent, + Object message, String title, + int optionType, int messageType) + { + JOptionPane pane = new JOptionPane(message, messageType, optionType); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows a confirmation dialog with the given message, title, + * optionType, messageType and icon. The frame owner will be the same as + * the one that holds the given parentComponent. This method returns the + * option selected by the user. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param optionType The optionType. + * @param messageType The messsageType. + * @param icon The icon displayed. + * + * @return The selected option. + */ + public static int showConfirmDialog(Component parentComponent, + Object message, String title, + int optionType, int messageType, + Icon icon) + { + JOptionPane pane = new JOptionPane(message, messageType, optionType, icon); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method will show a QUESTION_MESSAGE input dialog with the given + * message. No selectionValues is set so the Look and Feel will usually + * give the user a TextField to fill out. The frame owner will be the same + * frame that holds the given parentComponent. This method will return the + * value entered by the user. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * + * @return The value entered by the user. + */ + public static String showInputDialog(Component parentComponent, + Object message) + { + JOptionPane pane = new JOptionPane(message, QUESTION_MESSAGE); + pane.setWantsInput(true); + JDialog dialog = pane.createDialog(parentComponent, null); + dialog.pack(); + dialog.show(); + + return (String) pane.getInputValue(); + } + + /** + * This method will show a QUESTION_MESSAGE type input dialog with the given + * message and initialSelectionValue. Since there is no selectionValues + * set, the Look and Feel will usually give a TextField to fill out. The + * frame owner will be the same as the one that holds the given + * parentComponent. This method will return the value entered by the user. + * + * @param parentComponent The component to find a frame in. + * @param message The message to display. + * @param initialSelectionValue The initially selected value. + * + * @return The value the user input. + */ + public static String showInputDialog(Component parentComponent, + Object message, + Object initialSelectionValue) + { + JOptionPane pane = new JOptionPane(message, QUESTION_MESSAGE); + pane.setInitialSelectionValue(initialSelectionValue); + pane.setWantsInput(true); + JDialog dialog = pane.createDialog(parentComponent, null); + dialog.pack(); + dialog.show(); + + return (String) pane.getInputValue(); + } + + /** + * This method displays a new input dialog with the given message, title and + * messageType. Since no selectionValues value is given, the Look and Feel + * will usually give the user a TextField to input data to. This method + * returns the value the user inputs. + * + * @param parentComponent The component to find a frame in. + * @param message The message to display. + * @param title The title of the dialog. + * @param messageType The messageType. + * + * @return The value the user input. + */ + public static String showInputDialog(Component parentComponent, + Object message, String title, + int messageType) + { + JOptionPane pane = new JOptionPane(message, messageType); + pane.setWantsInput(true); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + + return (String) pane.getInputValue(); + } + + /** + * This method shows an input dialog with the given message, title, + * messageType, icon, selectionValues, and initialSelectionValue. This + * method returns the value that the user selects. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param messageType The messageType. + * @param icon The icon displayed. + * @param selectionValues The list of values to select from. + * @param initialSelectionValue The initially selected value. + * + * @return The user selected value. + */ + public static Object showInputDialog(Component parentComponent, + Object message, String title, + int messageType, Icon icon, + Object[] selectionValues, + Object initialSelectionValue) + { + JOptionPane pane = new JOptionPane(message, messageType); + pane.setWantsInput(true); + pane.setIcon(icon); + pane.setSelectionValues(selectionValues); + pane.setInitialSelectionValue(initialSelectionValue); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + + return (String) pane.getInputValue(); + } + + /** + * This method shows a QUESTION_MESSAGE type input dialog. Since no + * selectionValues is set, the Look and Feel will usually give the user a + * TextField to input data to. This method returns the value the user + * inputs. + * + * @param message The message to display. + * + * @return The user selected value. + */ + public static String showInputDialog(Object message) + { + JOptionPane pane = new JOptionPane(message, QUESTION_MESSAGE); + pane.setWantsInput(true); + JDialog dialog = pane.createDialog(null, null); + dialog.pack(); + dialog.show(); + + return (String) pane.getInputValue(); + } + + /** + * This method shows a QUESTION_MESSAGE type input dialog. Since no + * selectionValues is set, the Look and Feel will usually give the user a + * TextField to input data to. The input component will be initialized with + * the initialSelectionValue. This method returns the value the user + * inputs. + * + * @param message The message to display. + * @param initialSelectionValue The initialSelectionValue. + * + * @return The user selected value. + */ + public static String showInputDialog(Object message, + Object initialSelectionValue) + { + JOptionPane pane = new JOptionPane(message, QUESTION_MESSAGE); + pane.setWantsInput(true); + pane.setInitialSelectionValue(initialSelectionValue); + JDialog dialog = pane.createDialog(null, null); + dialog.pack(); + dialog.show(); + + return (String) pane.getInputValue(); + } + + /** + * This method shows an internal confirmation dialog with the given message. + * The internal frame dialog will be placed in the first JDesktopPane + * ancestor of the given parentComponent. This method will return the value + * selected. + * + * @param parentComponent The parent to find a JDesktopPane in. + * @param message The message to display. + * + * @return The value selected. + */ + public static int showInternalConfirmDialog(Component parentComponent, + Object message) + { + JOptionPane pane = new JOptionPane(message); + JInternalFrame frame = pane.createInternalFrame(parentComponent, null); + + startModal(frame, pane); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows an internal confirmation dialog with the given message, + * optionType and title. The internal frame dialog will be placed in the + * first JDesktopPane ancestor of the given parentComponent. This method + * will return the selected value. + * + * @param parentComponent The parent to find a JDesktopPane in. + * @param message The message to display. + * @param title The title to display. + * @param optionType The option type. + * + * @return The selected value. + */ + public static int showInternalConfirmDialog(Component parentComponent, + Object message, String title, + int optionType) + { + JOptionPane pane = new JOptionPane(message, PLAIN_MESSAGE, optionType); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows an internal confirmation dialog with the given message, + * title, optionTypes and icon for the given message type. The internal + * confirmation dialog will be placed in the first instance of + * JDesktopPane ancestor of the given parentComponent. + * + * @param parentComponent The component to find a JDesktopPane in. + * @param message The message to display. + * @param title The title of the dialog. + * @param optionType The option type. + * @param messageType The message type. + * + * @return The selected value. + */ + public static int showInternalConfirmDialog(Component parentComponent, + Object message, String title, + int optionType, int messageType) + { + JOptionPane pane = new JOptionPane(message, messageType, optionType); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows an internal confirmation dialog with the given message, + * title, option type, message type, and icon. The internal frame dialog + * will be placed in the first JDesktopPane ancestor that is found in the + * given parentComponent. This method returns the selected value. + * + * @param parentComponent The parent to find a JDesktopPane in. + * @param message The message to display. + * @param title The title to display. + * @param optionType The option type. + * @param messageType The message type. + * @param icon The icon to display. + * + * @return The selected value. + */ + public static int showInternalConfirmDialog(Component parentComponent, + Object message, String title, + int optionType, int messageType, + Icon icon) + { + JOptionPane pane = new JOptionPane(message, messageType, optionType, icon); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows an internal input dialog with the given message. The + * internal frame dialog will be placed in the first JDesktopPane ancestor + * of the given parent component. This method returns the value input by + * the user. + * + * @param parentComponent The parent to find a JDesktopPane in. + * @param message The message to display. + * + * @return The user selected value. + */ + public static String showInternalInputDialog(Component parentComponent, + Object message) + { + JOptionPane pane = new JOptionPane(message); + pane.setWantsInput(true); + JInternalFrame frame = pane.createInternalFrame(parentComponent, null); + + startModal(frame, pane); + + return (String) pane.getInputValue(); + } + + /** + * This method shows an internal input dialog with the given message, title + * and message type. The internal input dialog will be placed in the first + * JDesktopPane ancestor found in the given parent component. This method + * will return the input value given by the user. + * + * @param parentComponent The component to find a JDesktopPane in. + * @param message The message to display. + * @param title The title to display. + * @param messageType The message type. + * + * @return The user input value. + */ + public static String showInternalInputDialog(Component parentComponent, + Object message, String title, + int messageType) + { + JOptionPane pane = new JOptionPane(message, messageType); + pane.setWantsInput(true); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + + return (String) pane.getInputValue(); + } + + /** + * This method shows an internal input dialog with the given message, title + * message type, icon, selection value list and initial selection value. + * The internal frame dialog will be placed in the first JDesktopPane + * ancestor found in the given parent component. This method returns the + * input value from the user. + * + * @param parentComponent The parent to find a JDesktopPane in. + * @param message The message to display. + * @param title The title to display. + * @param messageType The message type. + * @param icon The icon to display. + * @param selectionValues The selection value list. + * @param initialSelectionValue The initial selection value. + * + * @return The user input value. + */ + public static Object showInternalInputDialog(Component parentComponent, + Object message, String title, + int messageType, Icon icon, + Object[] selectionValues, + Object initialSelectionValue) + { + JOptionPane pane = new JOptionPane(message, messageType); + pane.setWantsInput(true); + pane.setIcon(icon); + pane.setSelectionValues(selectionValues); + pane.setInitialSelectionValue(initialSelectionValue); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + + return (String) pane.getInputValue(); + } + + /** + * This method shows an internal message dialog with the given message. The + * internal frame dialog will be placed in the first JDesktopPane ancestor + * found in the given parent component. + * + * @param parentComponent The component to find a JDesktopPane in. + * @param message The message to display. + */ + public static void showInternalMessageDialog(Component parentComponent, + Object message) + { + JOptionPane pane = new JOptionPane(message); + JInternalFrame frame = pane.createInternalFrame(parentComponent, null); + + startModal(frame, pane); + } + + /** + * This method shows an internal message dialog with the given message, + * title and message type. The internal message dialog is placed in the + * first JDesktopPane ancestor found in the given parent component. + * + * @param parentComponent The parent component to find a JDesktopPane in. + * @param message The message to display. + * @param title The title to display. + * @param messageType The message type. + */ + public static void showInternalMessageDialog(Component parentComponent, + Object message, String title, + int messageType) + { + JOptionPane pane = new JOptionPane(message, messageType); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + } + + /** + * This method shows an internal message dialog with the given message, + * title, message type and icon. The internal message dialog is placed in + * the first JDesktopPane ancestor found in the given parent component. + * + * @param parentComponent The component to find a JDesktopPane in. + * @param message The message to display. + * @param title The title to display. + * @param messageType The message type. + * @param icon The icon to display. + */ + public static void showInternalMessageDialog(Component parentComponent, + Object message, String title, + int messageType, Icon icon) + { + JOptionPane pane = new JOptionPane(message, messageType); + pane.setIcon(icon); + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + } + + /** + * This method displays an internal option dialog with the given message, + * title, option type, message type, icon, option list, and initial option + * value. The internal option dialog is placed in the first JDesktopPane + * ancestor found in the parent component. This method returns the option + * selected. + * + * @param parentComponent The parent to find a JDesktopPane in. + * @param message The message displayed. + * @param title The title displayed. + * @param optionType The option type. + * @param messageType The message type. + * @param icon The icon to display. + * @param options The array of options. + * @param initialValue The initial value selected. + * + * @return The option that was selected. + */ + public static int showInternalOptionDialog(Component parentComponent, + Object message, String title, + int optionType, int messageType, + Icon icon, Object[] options, + Object initialValue) + { + JOptionPane pane = new JOptionPane(message, messageType, optionType, icon, + options, initialValue); + + JInternalFrame frame = pane.createInternalFrame(parentComponent, title); + + startModal(frame, pane); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method shows an INFORMATION_MESSAGE type message dialog. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + */ + public static void showMessageDialog(Component parentComponent, + Object message) + { + JOptionPane pane = new JOptionPane(message, INFORMATION_MESSAGE); + JDialog dialog = pane.createDialog(parentComponent, null); + dialog.pack(); + dialog.show(); + } + + /** + * This method shows a message dialog with the given message, title and + * messageType. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param messageType The messageType. + */ + public static void showMessageDialog(Component parentComponent, + Object message, String title, + int messageType) + { + JOptionPane pane = new JOptionPane(message, messageType); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + } + + /** + * This method shows a message dialog with the given message, title, + * messageType and icon. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param messageType The messageType. + * @param icon The icon displayed. + */ + public static void showMessageDialog(Component parentComponent, + Object message, String title, + int messageType, Icon icon) + { + JOptionPane pane = new JOptionPane(message, messageType); + pane.setIcon(icon); + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + } + + /** + * This method shows an option dialog with the given message, title, + * optionType, messageType, icon, options and initialValue. This method + * returns the option that was selected. + * + * @param parentComponent The component to find a frame in. + * @param message The message displayed. + * @param title The title of the dialog. + * @param optionType The optionType. + * @param messageType The messageType. + * @param icon The icon displayed. + * @param options The options to choose from. + * @param initialValue The initial value. + * + * @return The selected option. + */ + public static int showOptionDialog(Component parentComponent, + Object message, String title, + int optionType, int messageType, + Icon icon, Object[] options, + Object initialValue) + { + JOptionPane pane = new JOptionPane(message, messageType, optionType, icon, + options, initialValue); + + JDialog dialog = pane.createDialog(parentComponent, title); + dialog.pack(); + dialog.show(); + + return ((Integer) pane.getValue()).intValue(); + } + + /** + * This method resets the UI to the Look and Feel default. + */ + public void updateUI() + { + setUI((OptionPaneUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns true if the key is a valid messageType. + * + * @param key The key to check. + * + * @return True if key is valid. + */ + private boolean validMessageType(int key) + { + switch (key) + { + case ERROR_MESSAGE: + case INFORMATION_MESSAGE: + case PLAIN_MESSAGE: + case QUESTION_MESSAGE: + case WARNING_MESSAGE: + return true; + } + return false; + } + + /** + * This method returns true if the key is a valid optionType. + * + * @param key The key to check. + * + * @return True if key is valid. + */ + private boolean validOptionType(int key) + { + switch (key) + { + case DEFAULT_OPTION: + case OK_CANCEL_OPTION: + case YES_NO_CANCEL_OPTION: + case YES_NO_OPTION: + return true; + } + return false; + } + + /** + * This helper method makes the JInternalFrame wait until it is notified by + * an InternalFrameClosing event. This method also adds the given + * JOptionPane to the JInternalFrame and sizes it according to the + * JInternalFrame's preferred size. + * + * @param f The JInternalFrame to make modal. + * @param pane The JOptionPane to add to the JInternalFrame. + */ + private static void startModal(JInternalFrame f, JOptionPane pane) + { + f.getContentPane().add(pane); + f.pack(); + f.show(); + + Dimension pref = f.getPreferredSize(); + f.setBounds(0, 0, pref.width, pref.height); + + synchronized (f) + { + final JInternalFrame tmp = f; + tmp.toFront(); + + f.addInternalFrameListener(new InternalFrameAdapter() + { + public void internalFrameClosed(InternalFrameEvent e) + { + synchronized (tmp) + { + tmp.removeInternalFrameListener(this); + tmp.notifyAll(); + } + } + }); + try + { + while (! f.isClosed()) + f.wait(); + } + catch (InterruptedException ignored) + { + } + } + } +} diff --git a/libjava/classpath/javax/swing/JPanel.java b/libjava/classpath/javax/swing/JPanel.java new file mode 100644 index 00000000000..c7f7c448331 --- /dev/null +++ b/libjava/classpath/javax/swing/JPanel.java @@ -0,0 +1,114 @@ +/* JPanel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.FlowLayout; +import java.awt.LayoutManager; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.plaf.PanelUI; + +/** + * An instance of JPanel can be added to a panel, frame etc + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class JPanel extends JComponent implements Accessible +{ + public JPanel() + { + this(new FlowLayout(), + true); + } + + public JPanel(boolean double_buffered) + { + this(new FlowLayout(), + double_buffered); + } + + public JPanel(LayoutManager layout) + { + this(layout, + true); + } + + + public JPanel(LayoutManager layout, + boolean isDoubleBuffered) + { + if (layout == null) + { + System.err.println("NO LAYOUT SET !!!"); + layout = new FlowLayout(); + } + setLayout(layout); + setOpaque(true); + + updateUI(); + } + + public String getUIClassID() + { return "PanelUI"; } + + + public void setUI(PanelUI ui) { + super.setUI(ui); + } + + public PanelUI getUI() { + return (PanelUI)ui; + } + + public void updateUI() { + setUI((PanelUI)UIManager.getUI(this)); + } + + + public AccessibleContext getAccessibleContext() + { + return null; + } + + protected String paramString() + { + return "JPanel"; + } +} diff --git a/libjava/classpath/javax/swing/JPasswordField.java b/libjava/classpath/javax/swing/JPasswordField.java new file mode 100644 index 00000000000..f9df10217c8 --- /dev/null +++ b/libjava/classpath/javax/swing/JPasswordField.java @@ -0,0 +1,270 @@ +/* JPasswordField.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.IOException; +import java.io.ObjectOutputStream; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +/** + * class JPasswordField + * + * @author Andrew Selkirk + * @version 1.0 + */ +public class JPasswordField extends JTextField +{ + /** + * AccessibleJPasswordField + */ + protected class AccessibleJPasswordField extends AccessibleJTextField + { + private static final long serialVersionUID = -8477039424200681086L; + + /** + * Constructor AccessibleJPasswordField + */ + protected AccessibleJPasswordField() + { + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PASSWORD_TEXT; + } + } + + /** + * echoChar. Default is 0. + */ + private char echoChar = 0; + + /** + * Creates a <code>JPasswordField</code> object. + */ + public JPasswordField() + { + this(null, null, 0); + } + + /** + * Creates a <code>JPasswordField</code> object. + * + * @param text the initial text + */ + public JPasswordField(String text) + { + this(null, text, 0); + } + + /** + * Creates a <code>JPasswordField</code> object. + * + * @param columns the number of columns + */ + public JPasswordField(int columns) + { + this(null, null, columns); + } + + /** + * Creates a <code>JPasswordField</code> object. + * + * @param text the initial text + * @param columns the number of columns + */ + public JPasswordField(String text, int columns) + { + this(null, text, columns); + } + + /** + * Creates a <code>JPasswordField</code> object. + * + * @param document the document to use + * @param text the initial text + * @param columns the number of columns + */ + public JPasswordField(Document document, String text, int columns) + { + super(document, text, columns); + } + + /** + * writeObject + * + * @param stream the stream to write to + * + * @exception IOException if an error occurs + */ + private void writeObject(ObjectOutputStream stream) throws IOException + { + // TODO: Implement me. + } + + /** + * Returns the <code>UIClassID</code> + * + * @return the string "PasswordFieldUI" + */ + public String getUIClassID() + { + return "PasswordFieldUI"; + } + + /** + * getEchoChar + * + * @return the echo char + */ + public char getEchoChar() + { + return echoChar; + } + + /** + * setEchoChar + * + * @param echo the echo char + */ + public void setEchoChar(char echo) + { + this.echoChar = echo; + } + + /** + * echoCharIsSet + * + * @return <code>true</code> if the echo char is set, + * <code>false</code> otherwise. + */ + public boolean echoCharIsSet() + { + return echoChar == 0; + } + + /** + * Copies the selected text into the clipboard. This operation is not + * allowed in a password input field. + */ + public void copy() + { + UIManager.getLookAndFeel().provideErrorFeedback(this); + } + + /** + * Cuts the selected text and puts it into the clipboard. This operation + * is not allowed in a password input field. + */ + public void cut() + { + UIManager.getLookAndFeel().provideErrorFeedback(this); + } + + /** + * getText + * + * @return String + * + * @deprecated + */ + public String getText() + { + return null; // TODO + } + + /** + * getText + * + * @param offset TODO + * @param length TODO + * + * @return String + * + * @exception BadLocationException TODO + * + * @deprecated + */ + public String getText(int offset, int length) throws BadLocationException + { + return null; // TODO + } + + /** + * getPassword + * + * @return char[] + */ + public char[] getPassword() + { + return new char[0]; // TODO + } + + /** + * paramString + * + * @return String + */ + protected String paramString() + { + return null; // TODO + } + + /** + * getAccessibleContext + * + * @return the <code>AccessibleContext</code> object + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJPasswordField(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JPopupMenu.java b/libjava/classpath/javax/swing/JPopupMenu.java new file mode 100644 index 00000000000..a0a735965c5 --- /dev/null +++ b/libjava/classpath/javax/swing/JPopupMenu.java @@ -0,0 +1,1071 @@ +/* JPopupMenu.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.Insets; +import java.awt.Panel; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.EventListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import javax.swing.plaf.PopupMenuUI; + +/** + * JPopupMenu is a container that is used to display popup menu's menu + * items. By default JPopupMenu is a lightweight container, however if it + * is the case that JPopupMenu's bounds are outside of main window, then + * heawyweight container will be used to display menu items. It is also + * possible to change JPopupMenu's default behavior and set JPopupMenu + * to always use heavyweight container. + * + * JPopupMenu can be displayed anywhere; it is a floating free popup menu. + * However before JPopupMenu is diplayed, its invoker property should be set. + * JPopupMenu's invoker is a component relative to which popup menu is + * displayed. + * + * JPopupMenu fires PopupMenuEvents to its registered listeners. Whenever + * JPopupMenu becomes visible on the screen then PopupMenuEvent indicating + * that popup menu became visible will be fired. In the case when + * JPopupMenu becomes invisible or cancelled without selection, then + * popupMenuBecomeInvisible() or popupMenuCancelled() methods of + * PopupMenuListeners will be invoked. + * + * JPopupMenu also fires PropertyChangeEvents when its bound properties + * change.In addittion to inheritted bound properties, JPopupMenu has + * 'visible' bound property. When JPopupMenu becomes visible/invisible on + * the screen it fires PropertyChangeEvents to its registered + * PropertyChangeListeners. + */ +public class JPopupMenu extends JComponent implements Accessible, MenuElement +{ + private static final long serialVersionUID = -8336996630009646009L; + + /* indicates if popup's menu border should be painted*/ + private boolean borderPainted = true; + + /** Flag indicating whether lightweight, mediumweight or heavyweight popup + is used to display menu items. + + These are the possible cases: + + 1. if DefaultLightWeightPopupEnabled true + (i) use lightweight container if popup feets inside top-level window + (ii) only use heavyweight container (JWindow) if popup doesn't fit. + + 2. if DefaultLightWeightPopupEnabled false + (i) if popup fits, use awt.Panel (mediumWeight) + (ii) if popup doesn't fit, use JWindow (heavyWeight) + */ + private static boolean DefaultLightWeightPopupEnabled = true; + + /* Component that invokes popup menu. */ + transient Component invoker; + + /* Label for this popup menu. It is not used in most of the look and feel themes. */ + private String label; + + /*Amount of space between menuItem's in JPopupMenu and JPopupMenu's border */ + private Insets margin; + + /** Indicates whether ligthWeight container can be used to display popup + menu. This flag is the same as DefaultLightWeightPopupEnabled, but setting + this flag can change popup menu after creation of the object */ + private boolean lightWeightPopupEnabled; + + /** SelectionModel that keeps track of menu selection. */ + private SingleSelectionModel selectionModel; + + /* Popup that is used to display JPopupMenu */ + private transient Popup popup; + + /* Location of the popup */ + private Point popupLocation; + + /* Field indicating if popup menu is visible or not */ + private boolean visible = false; + + /** + * Creates a new JPopupMenu object. + */ + public JPopupMenu() + { + this(null); + } + + /** + * Creates a new JPopupMenu with specified label + * + * @param label Label for popup menu. + */ + public JPopupMenu(String label) + { + lightWeightPopupEnabled = getDefaultLightWeightPopupEnabled(); + setLabel(label); + setSelectionModel(new DefaultSingleSelectionModel()); + super.setVisible(false); + updateUI(); + } + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + } + + /** + * Adds given menu item to the popup menu + * + * @param item menu item to add to the popup menu + * + * @return menu item that was added to the popup menu + */ + public JMenuItem add(JMenuItem item) + { + this.insert(item, -1); + return item; + } + + /** + * Constructs menu item with a specified label and adds it to + * popup menu + * + * @param text label for the menu item to be added + * + * @return constructed menu item that was added to the popup menu + */ + public JMenuItem add(String text) + { + JMenuItem item = new JMenuItem(text); + return add(item); + } + + /** + * Constructs menu item associated with the specified action + * and adds it to the popup menu + * + * @param action Action for the new menu item + * + * @return menu item that was added to the menu + */ + public JMenuItem add(Action action) + { + JMenuItem item = createActionComponent(action); + + if (action != null) + action.addPropertyChangeListener(createActionChangeListener(item)); + + return add(item); + } + + /** + * Revomes component at the given index from the menu. + * + * @param index index of the component that will be removed in the menu + */ + public void remove(int index) + { + super.remove(index); + + GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 100.0; + constraints.weighty = 100.0; + + Component[] items = getComponents(); + for (int i = index; i < items.length; i++) + { + constraints.gridy = i; + super.add(items[i], constraints, i); + } + } + + /** + * Create menu item associated with the given action + * and inserts it into the popup menu at the specified index + * + * @param action Action for the new menu item + * @param index index in the popup menu at which to insert new menu item. + */ + public void insert(Action action, int index) + { + JMenuItem item = new JMenuItem(action); + this.insert(item, index); + } + + /** + * Insert given component to the popup menu at the + * specified index + * + * @param component Component to insert + * @param index Index at which to insert given component + */ + public void insert(Component component, int index) + { + GridBagConstraints constraints = new GridBagConstraints(); + constraints.fill = GridBagConstraints.BOTH; + constraints.weightx = 100.0; + constraints.weighty = 100.0; + + constraints.gridy = index; + super.add(component, constraints, index); + + // need to change constraints for the components that were moved by 1 + // due to the insertion + if (index != -1) + { + Component[] items = getComponents(); + + for (int i = index + 1; i < items.length; i++) + { + constraints.gridy = i; + super.add(items[i], constraints, i); + } + } + } + + /** + * Returns flag indicating if newly created JPopupMenu will use + * heavyweight or lightweight container to display its menu items + * + * @return true if JPopupMenu will use lightweight container to display + * menu items by default, and false otherwise. + */ + public static boolean getDefaultLightWeightPopupEnabled() + { + return DefaultLightWeightPopupEnabled; + } + + /** + * Sets whether JPopupMenu should use ligthWeight container to + * display it menu items by default + * + * @param enabled true if JPopupMenu should use lightweight container + * for displaying its menu items, and false otherwise. + */ + public static void setDefaultLightWeightPopupEnabled(boolean enabled) + { + DefaultLightWeightPopupEnabled = enabled; + } + + /** + * This method returns the UI used to display the JPopupMenu. + * + * @return The UI used to display the JPopupMenu. + */ + public PopupMenuUI getUI() + { + return (PopupMenuUI) ui; + } + + /** + * Set the "UI" property of the menu item, which is a look and feel class + * responsible for handling popupMenu's input events and painting it. + * + * @param ui The new "UI" property + */ + public void setUI(PopupMenuUI ui) + { + super.setUI(ui); + } + + /** + * This method sets this menuItem's UI to the UIManager's default for the + * current look and feel. + */ + public void updateUI() + { + setUI((PopupMenuUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the menuItem. + * + * @return The Look and Feel classID. "PopupMenuUI" + */ + public String getUIClassID() + { + return "PopupMenuUI"; + } + + /** + * Returns selectionModel used by this popup menu to keep + * track of the selection. + * + * @return popup menu's selection model + */ + public SingleSelectionModel getSelectionModel() + { + return selectionModel; + } + + /** + * Sets selection model for this popup menu + * + * @param model new selection model of this popup menu + */ + public void setSelectionModel(SingleSelectionModel model) + { + selectionModel = model; + } + + /** + * Creates new menu item associated with a given action. + * + * @param action Action used to create new menu item + * + * @return new created menu item associated with a given action. + */ + protected JMenuItem createActionComponent(Action action) + { + return new JMenuItem(action); + } + + /** + * Creates PropertyChangeListener that listens to PropertyChangeEvents + * occuring in the Action associated with given menu item in this popup menu. + * + * @param item MenuItem + * + * @return The PropertyChangeListener + */ + protected PropertyChangeListener createActionChangeListener(JMenuItem item) + { + return new ActionChangeListener(); + } + + /** + * Returns true if this popup menu will display its menu item in + * a lightweight container and false otherwise. + * + * @return true if this popup menu will display its menu items + * in a lightweight container and false otherwise. + */ + public boolean isLightWeightPopupEnabled() + { + return lightWeightPopupEnabled; + } + + /** + * DOCUMENT ME! + * + * @param enabled DOCUMENT ME! + */ + public void setLightWeightPopupEnabled(boolean enabled) + { + lightWeightPopupEnabled = enabled; + } + + /** + * Returns label for this popup menu + * + * @return label for this popup menu + */ + public String getLabel() + { + return label; + } + + /** + * Sets label for this popup menu. This method fires PropertyChangeEvent + * when the label property is changed. Please note that most + * of the Look & Feel will ignore this property. + * + * @param label label for this popup menu + */ + public void setLabel(String label) + { + if (label != this.label) + { + String oldLabel = this.label; + this.label = label; + firePropertyChange("label", oldLabel, label); + } + } + + /** + * Adds separator to this popup menu + */ + public void addSeparator() + { + // insert separator at the end of the list of menu items + this.insert(new Separator(), -1); + } + + /** + * Adds popupMenuListener to listen for PopupMenuEvents fired + * by the JPopupMenu + * + * @param listener PopupMenuListener to add to JPopupMenu + */ + public void addPopupMenuListener(PopupMenuListener listener) + { + listenerList.add(PopupMenuListener.class, listener); + } + + /** + * Removes PopupMenuListener from JPopupMenu's list of listeners + * + * @param listener PopupMenuListener which needs to be removed + */ + public void removePopupMenuListener(PopupMenuListener listener) + { + listenerList.remove(PopupMenuListener.class, listener); + } + + /** + * Returns array of PopupMenuListeners that are listening to JPopupMenu + * + * @return Array of PopupMenuListeners that are listening to JPopupMenu + */ + public PopupMenuListener[] getPopupMenuListeners() + { + return ((PopupMenuListener[]) listenerList.getListeners(PopupMenuListener.class)); + } + + /** + * This method calls popupMenuWillBecomeVisible() of popup menu's + * PopupMenuListeners. This method is invoked just before popup menu + * will appear on the screen. + */ + protected void firePopupMenuWillBecomeVisible() + { + EventListener[] ll = listenerList.getListeners(PopupMenuListener.class); + + for (int i = 0; i < ll.length; i++) + ((PopupMenuListener) ll[i]).popupMenuWillBecomeVisible(new PopupMenuEvent(this)); + } + + /** + * This method calls popupMenuWillBecomeInvisible() of popup + * menu's PopupMenuListeners. This method is invoked just before popup + * menu will disappear from the screen + */ + protected void firePopupMenuWillBecomeInvisible() + { + EventListener[] ll = listenerList.getListeners(PopupMenuListener.class); + + for (int i = 0; i < ll.length; i++) + ((PopupMenuListener) ll[i]).popupMenuWillBecomeInvisible(new PopupMenuEvent(this)); + } + + /** + * This method calls popupMenuCanceled() of popup menu's PopupMenuListeners. + * This method is invoked just before popup menu is cancelled. This happens + * when popup menu is closed without selecting any of its menu items. This + * usually happens when the top-level window is resized or moved. + */ + protected void firePopupMenuCanceled() + { + EventListener[] ll = listenerList.getListeners(PopupMenuListener.class); + + for (int i = 0; i < ll.length; i++) + ((PopupMenuListener) ll[i]).popupMenuCanceled(new PopupMenuEvent(this)); + } + + /** + * This methods sets popup menu's size to its' preferred size. If the + * popup menu's size is previously set it will be ignored. + */ + public void pack() + { + super.setSize(null); + } + + /** + * Return visibility of the popup menu + * + * @return true if popup menu is visible on the screen and false otherwise. + */ + public boolean isVisible() + { + return visible; + } + + /** + * Sets visibility property of this popup menu. If the property is + * set to true then popup menu will be dispayed and popup menu will + * hide itself if visible property is set to false. + * + * @param visible true if popup menu will become visible and false otherwise. + */ + public void setVisible(boolean visible) + { + if (visible == isVisible()) + return; + + boolean old = isVisible(); + this.visible = visible; + if (old != isVisible()) + { + firePropertyChange("visible", old, isVisible()); + if (visible) + { + firePopupMenuWillBecomeVisible(); + Container rootContainer = (Container) SwingUtilities.getRoot(invoker); + + boolean fit = true; + Dimension size; + + // Determine the size of the popup menu + if (this.getSize().width == 0 && this.getSize().width == 0) + size = this.getPreferredSize(); + else + size = this.getSize(); + + if ((size.width > (rootContainer.getWidth() - popupLocation.x)) + || (size.height > (rootContainer.getHeight() - popupLocation.y))) + fit = false; + if (lightWeightPopupEnabled && fit) + popup = new LightWeightPopup(this); + else + { + if (fit) + popup = new MediumWeightPopup(this); + else + popup = new HeavyWeightPopup(this); + } + if (popup instanceof LightWeightPopup + || popup instanceof MediumWeightPopup) + { + JLayeredPane layeredPane; + layeredPane = SwingUtilities.getRootPane(invoker) + .getLayeredPane(); + Point p = new Point(popupLocation.x, popupLocation.y); + SwingUtilities.convertPointFromScreen(p, layeredPane); + popup.show(p.x, p.y, size.width, size.height); + } + else + { + // Subtract insets of the top-level container if popup menu's + // top-left corner is inside it. + Insets insets = rootContainer.getInsets(); + popup.show(popupLocation.x - insets.left, + popupLocation.y - insets.top, size.width, + size.height); + } + } + else + { + firePopupMenuWillBecomeInvisible(); + popup.hide(); + } + } + } + + /** + * Sets location of the popup menu. + * + * @param x X coordinate of the popup menu's location + * @param y Y coordinate of the popup menu's location + */ + public void setLocation(int x, int y) + { + if (popupLocation == null) + popupLocation = new Point(); + + popupLocation.x = x; + popupLocation.y = y; + } + + /** + * Returns popup menu's invoker. + * + * @return popup menu's invoker + */ + public Component getInvoker() + { + return invoker; + } + + /** + * Sets popup menu's invoker. + * + * @param component The new invoker of this popup menu + */ + public void setInvoker(Component component) + { + invoker = component; + } + + /** + * This method displays JPopupMenu on the screen at the specified + * location. Note that x and y coordinates given to this method + * should be expressed in terms of the popup menus' invoker. + * + * @param component Invoker for this popup menu + * @param x x-coordinate of the popup menu relative to the specified invoker + * @param y y-coordiate of the popup menu relative to the specified invoker + */ + public void show(Component component, int x, int y) + { + setInvoker(component); + Point p = new Point(x, y); + SwingUtilities.convertPointToScreen(p, component); + setLocation(p.x, p.y); + setVisible(true); + } + + /** + * Returns component located at the specified index in the popup menu + * + * @param index index of the component to return + * + * @return component located at the specified index in the popup menu + * + * @deprecated Replaced by getComponent(int) + */ + public Component getComponentAtIndex(int index) + { + return getComponent(index); + } + + /** + * Returns index of the specified component in the popup menu + * + * @param component Component to look for + * + * @return index of the specified component in the popup menu + */ + public int getComponentIndex(Component component) + { + Component[] items = getComponents(); + + for (int i = 0; i < items.length; i++) + { + if (items[i].equals(component)) + return i; + } + + return -1; + } + + /** + * Sets size of the popup + * + * @param size Dimensions representing new size of the popup menu + */ + public void setPopupSize(Dimension size) + { + super.setSize(size); + } + + /** + * Sets size of the popup menu + * + * @param width width for the new size + * @param height height for the new size + */ + public void setPopupSize(int width, int height) + { + super.setSize(width, height); + } + + /** + * Selects specified component in this popup menu. + * + * @param selected component to select + */ + public void setSelected(Component selected) + { + int index = getComponentIndex(selected); + selectionModel.setSelectedIndex(index); + } + + /** + * Checks if this popup menu paints its border. + * + * @return true if this popup menu paints its border and false otherwise. + */ + public boolean isBorderPainted() + { + return borderPainted; + } + + /** + * Sets if the border of the popup menu should be + * painter or not. + * + * @param painted true if the border should be painted and false otherwise + */ + public void setBorderPainted(boolean painted) + { + borderPainted = painted; + } + + /** + * Returns margin for this popup menu. + * + * @return margin for this popup menu. + */ + public Insets getMargin() + { + return margin; + } + + /** + * A string that describes this JPopupMenu. Normally only used + * for debugging. + * + * @return A string describing this JMenuItem + */ + protected String paramString() + { + StringBuffer sb = new StringBuffer(); + sb.append(super.paramString()); + sb.append(",label="); + if (getLabel() != null) + sb.append(getLabel()); + sb.append(",lightWeightPopupEnabled=").append(isLightWeightPopupEnabled()); + sb.append(",margin="); + if (getMargin() != null) + sb.append(margin); + sb.append(",paintBorder=").append(isBorderPainted()); + return sb.toString(); + } + + /** + * Process mouse events forwarded from MenuSelectionManager. This method + * doesn't do anything. It is here to conform to the MenuElement interface. + * + * @param event event forwarded from MenuSelectionManager + * @param path path to the menu element from which event was generated + * @param manager MenuSelectionManager for the current menu hierarchy + */ + public void processMouseEvent(MouseEvent event, MenuElement[] path, + MenuSelectionManager manager) + { + // Empty Implementation. This method is needed for the implementation + // of MenuElement interface + } + + /** + * Process key events forwarded from MenuSelectionManager. This method + * doesn't do anything. It is here to conform to the MenuElement interface. + * + * @param event event forwarded from MenuSelectionManager + * @param path path to the menu element from which event was generated + * @param manager MenuSelectionManager for the current menu hierarchy + * + */ + public void processKeyEvent(KeyEvent event, MenuElement[] path, + MenuSelectionManager manager) + { + // Empty Implementation. This method is needed for the implementation + // of MenuElement interface + } + + /** + * Method of MenuElement Interface. It is invoked when + * popupMenu's selection has changed + * + * @param changed true if this popupMenu is part of current menu + * hierarchy and false otherwise. + */ + public void menuSelectionChanged(boolean changed) + { + if (! changed) + setVisible(false); + } + + /** + * Return subcomonents of this popup menu. This method returns only + * components that implement the <code>MenuElement</code> interface. + * + * @return array of menu items belonging to this popup menu + */ + public MenuElement[] getSubElements() + { + Component[] items = getComponents(); + ArrayList subElements = new ArrayList(); + + for (int i = 0; i < items.length; i++) + if (items[i] instanceof MenuElement) + subElements.add(items[i]); + + return (MenuElement[]) + subElements.toArray(new MenuElement[subElements.size()]); + } + + /** + * Method of the MenuElement interface. Returns reference to itself. + * + * @return Returns reference to itself + */ + public Component getComponent() + { + return this; + } + + /** + * Checks if observing mouse event should trigger popup + * menu to show on the screen. + * + * @param event MouseEvent to check + * + * @return true if the observing mouse event is popup trigger and false otherwise + */ + public boolean isPopupTrigger(MouseEvent event) + { + return ((PopupMenuUI) getUI()).isPopupTrigger(event); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJPopupMenu(); + + return accessibleContext; + } + + /** + * This interface is used to display menu items of the JPopupMenu + */ + private interface Popup + { + /** + * Displays container on the screen + * + * @param x x-coordinate of popup menu's location on the screen + * @param y y-coordinate of popup menu's location on the screen + * @param width width of the container that is used to display menu + * item's for popup menu + * @param height height of the container that is used to display menu + * item's for popup menu + */ + void show(int x, int y, int width, int height); + + /** + * Hides container used to display popup menu item's from the screen + */ + void hide(); + } + + /** + * This class represents Popup menu that uses light weight container + * to display its contents. + */ + private class LightWeightPopup extends Container implements Popup + { + /** + * Creates a new LightWeightPopup menu + * + * @param c Container containing menu items + */ + private Component c; + + public LightWeightPopup(Container c) + { + this.c = c; + } + + /** + * Displayes lightweight container with menu items to the screen + * + * @param x x-coordinate of lightweight container on the screen + * @param y y-coordinate of lightweight container on the screen + * @param width width of the lightweight container + * @param height height of the lightweight container + */ + public void show(int x, int y, int width, int height) + { + JLayeredPane layeredPane; + layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); + c.setBounds(x, y, width, height); + layeredPane.add(c, JLayeredPane.POPUP_LAYER, 0); + } + + /** + * Hides lightweight container from the screen + */ + public void hide() + { + // FIXME: Right now the lightweight container is removed from JLayered + // pane. It is probably would be better in order to improve performance + // to make the container invisible instead of removing it everytime. + JLayeredPane layeredPane; + layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); + int index = layeredPane.getIndexOf(c); + layeredPane.remove(index); + } + } + + /** + * MediumWeightPopup is an AWT Panel with JPopupMenu's menu items. + * It is used to display JPopupMenu's menu items on the screen + */ + private class MediumWeightPopup extends Panel implements Popup + { + /** + * Creates a new MediumWeightPopup object. + * + * @param c Container with JPopupMenu's menu items + */ + public MediumWeightPopup(Container c) + { + this.add(c); + } + + /** + * Displays AWT Panel with its components on the screen + * + * @param x x-coordinate of the upper-left corner of the panel's + * @param y y-coordinate of the upper-left corner of the panel's + * @param width width of the panel + * @param height height of the panel + */ + public void show(int x, int y, int width, int height) + { + JLayeredPane layeredPane; + layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); + layeredPane.add(this, JLayeredPane.POPUP_LAYER, 0); + this.setBounds(x, y, width, height); + } + + /** + * Hides This panel from the screen + */ + public void hide() + { + // FIXME: Right now the lightweight container is removed from JLayered + // pane. It is probably would be better in order to improve performance + // to make the container invisible instead of removing it everytime. + JLayeredPane layeredPane; + layeredPane = SwingUtilities.getRootPane(invoker).getLayeredPane(); + int index = layeredPane.getIndexOf(this); + layeredPane.remove(index); + } + } + + /** + * HeavyWeightPopup is JWindow that is used to display JPopupMenu menu item's + * on the screen + */ + private class HeavyWeightPopup extends JWindow implements Popup + { + /** + * Creates a new HeavyWeightPopup object. + * + * @param c Container containing menu items + */ + public HeavyWeightPopup(Container c) + { + this.setContentPane(c); + } + + /** + * Displays JWindow container JPopupMenu's menu items to the screen + * + * @param x x-coordinate of JWindow containing menu items + * @param y y-coordinate of JWindow containing menu items + * @param width width of the JWindow + * @param height height of the JWindow + */ + public void show(int x, int y, int width, int height) + { + this.setBounds(x, y, width, height); + this.show(); + } + } + + /** + * This is the separator that can be used in popup menu. + */ + public static class Separator extends JSeparator + { + public Separator() + { + } + + public String getUIClassID() + { + return "PopupMenuSeparatorUI"; + } + } + + protected class AccessibleJPopupMenu extends AccessibleJComponent + { + private static final long serialVersionUID = 7423261328879849768L; + + protected AccessibleJPopupMenu() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.POPUP_MENU; + } + } + + /* This class resizes popup menu and repaints popup menu appropriately if one + of item's action has changed */ + protected class ActionChangeListener implements PropertyChangeListener + { + public void propertyChange(PropertyChangeEvent evt) + { + JPopupMenu.this.revalidate(); + JPopupMenu.this.repaint(); + } + } +} diff --git a/libjava/classpath/javax/swing/JProgressBar.java b/libjava/classpath/javax/swing/JProgressBar.java new file mode 100644 index 00000000000..1b8fcea4672 --- /dev/null +++ b/libjava/classpath/javax/swing/JProgressBar.java @@ -0,0 +1,661 @@ +/* JProgressBar.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Graphics; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; +import javax.swing.border.Border; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ProgressBarUI; + +/** + * The ProgressBar is a widget that displays in two modes. In + * determinate mode, it displays fills a percentage of its bar + * based on its current value. In indeterminate mode, it creates + * box and bounces it between its bounds. + * + * <p> + * JProgressBars have the following properties: + * </p> + * + * <table> + * <tr><th> Property </th><th> Stored in </th><th> Bound? </th></tr> + * <tr><td> borderPainted </td><td> progressBar </td><td> yes </td></tr> + * <tr><td> changeListeners </td><td> progressBar </td><td> no </td></tr> + * <tr><td> indeterminate </td><td> progressBar </td><td> yes </td></tr> + * <tr><td> maximum </td><td> model </td><td> no </td></tr> + * <tr><td> minimum </td><td> model </td><td> no </td></tr> + * <tr><td> model </td><td> progressBar </td><td> no </td></tr> + * <tr><td> orientation </td><td> progressBar </td><td> yes </td></tr> + * <tr><td> percentComplete </td><td> progressBar </td><td> no </td></tr> + * <tr><td> string </td><td> progressBar </td><td> yes </td></tr> + * <tr><td> stringPainted </td><td> progressBar </td><td> yes </td></tr> + * <tr><td> value </td><td> model </td><td> no </td></tr> + * </table> + */ +public class JProgressBar extends JComponent implements SwingConstants, + Accessible +{ + /** + * AccessibleJProgressBar + */ + protected class AccessibleJProgressBar extends AccessibleJComponent + implements AccessibleValue + { + private static final long serialVersionUID = -2938130009392721813L; + + /** + * Constructor AccessibleJProgressBar + */ + protected AccessibleJProgressBar() + { + } + + /** + * getAccessibleStateSet + * + * @return AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PROGRESS_BAR; + } + + /** + * getAccessibleValue + * + * @return AccessibleValue + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * getCurrentAccessibleValue + * + * @return Number + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * setCurrentAccessibleValue + * + * @param value0 TODO + * + * @return boolean + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * getMinimumAccessibleValue + * + * @return Number + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * getMaximumAccessibleValue + * + * @return Number + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + private static final long serialVersionUID = 1980046021813598781L; + + /** Whether the ProgressBar is determinate. */ + private transient boolean indeterminate = false; + + /** The orientation of the ProgressBar */ + protected int orientation = HORIZONTAL; + + /** Whether borders should be painted. */ + protected boolean paintBorder = true; + + /** The model describing this ProgressBar. */ + protected BoundedRangeModel model; + + /** The string that is displayed by the ProgressBar. */ + protected String progressString; + + /** Whether the string should be painted. */ + protected boolean paintString = false; + + /** The static changeEvent passed to all ChangeListeners. */ + protected transient ChangeEvent changeEvent; + + /** The ChangeListener that listens to the model. */ + protected ChangeListener changeListener; + + /** + * Creates a new horizontally oriented JProgressBar object + * with a minimum of 0 and a maximum of 100. + */ + public JProgressBar() + { + this(HORIZONTAL, 0, 100); + } + + /** + * Creates a new JProgressBar object with a minimum of 0, + * a maximum of 100, and the given orientation. + * + * @param orientation The orientation of the JProgressBar. + * + * @throws IllegalArgumentException if <code>orientation</code> is not either + * {@link #HORIZONTAL} or {@link #VERTICAL}. + */ + public JProgressBar(int orientation) + { + this(orientation, 0, 100); + } + + /** + * Creates a new horizontally oriented JProgressBar object + * with the given minimum and maximum. + * + * @param minimum The minimum of the JProgressBar. + * @param maximum The maximum of the JProgressBar. + */ + public JProgressBar(int minimum, int maximum) + { + this(HORIZONTAL, minimum, maximum); + } + + /** + * Creates a new JProgressBar object with the given minimum, + * maximum, and orientation. + * + * @param minimum The minimum of the JProgressBar. + * @param maximum The maximum of the JProgressBar. + * @param orientation The orientation of the JProgressBar. + * + * @throws IllegalArgumentException if <code>orientation</code> is not either + * {@link #HORIZONTAL} or {@link #VERTICAL}. + */ + public JProgressBar(int orientation, int minimum, int maximum) + { + model = new DefaultBoundedRangeModel(minimum, 0, minimum, maximum); + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + " is not a legal orientation"); + this.orientation = orientation; + changeListener = createChangeListener(); + model.addChangeListener(changeListener); + updateUI(); + } + + /** + * Creates a new horizontally oriented JProgressBar object + * with the given model. + * + * @param model The model to be used with the JProgressBar. + */ + public JProgressBar(BoundedRangeModel model) + { + this.model = model; + changeListener = createChangeListener(); + model.addChangeListener(changeListener); + updateUI(); + } + + /** + * This method returns the current value of the JProgressBar. + * + * @return The current value of the JProgressBar. + */ + public int getValue() + { + return model.getValue(); + } + + /** + * This method sets the value of the JProgressBar. + * + * @param value The value of the JProgressBar. + */ + public void setValue(int value) + { + model.setValue(value); + } + + /** + * This method paints the border of the JProgressBar + * + * @param graphics The graphics object to paint with. + */ + protected void paintBorder(Graphics graphics) + { + Border border = getBorder(); + if (paintBorder && border != null) + border.paintBorder(this, graphics, 0, 0, + getWidth(), + getHeight()); + } + + /** + * This method returns the orientation of the JProgressBar. + * + * @return The orientation of the JProgressBar. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method changes the orientation property. The orientation of the + * JProgressBar can be either horizontal or vertical. + * + * @param orientation The orientation of the JProgressBar. + */ + public void setOrientation(int orientation) + { + if (orientation != VERTICAL && orientation != HORIZONTAL) + throw new IllegalArgumentException("orientation must be one of VERTICAL or HORIZONTAL"); + if (this.orientation != orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange("orientation", oldOrientation, + this.orientation); + } + } + + /** + * This method returns whether the progressString will be painted. + * + * @return Whether the string is painted. + */ + public boolean isStringPainted() + { + return paintString; + } + + /** + * This method changes the stringPainted property. + * + * @param painted Whether the string is painted. + */ + public void setStringPainted(boolean painted) + { + if (paintString != painted) + { + boolean oldPainted = paintString; + paintString = painted; + firePropertyChange("stringPainted", oldPainted, + paintString); + } + } + + /** + * This method returns the string that is painted if the + * stringPainted property is set to true. If there is no + * string set, it will return a string containing the + * JProgressBar's value as a percent. + * + * @return The string that is painted. + */ + public String getString() + { + if (progressString != null) + return progressString; + else + return (int) (getPercentComplete() * 100) + "%"; + } + + /** + * This method changes the string property. The string + * given will be the one painted. If you want to + * revert to the default string given, set the + * string to null. + * + * @param string The string to be painted. + */ + public void setString(String string) + { + if (((string == null || progressString == null) && + string != progressString) || (string != null && + ! string.equals(progressString))) + { + String oldString = progressString; + progressString = string; + firePropertyChange("string", oldString, progressString); + } + } + + /** + * This method returns the percent of the bar + * that is "complete". (This is the amount value / (max - min)). + * + * @return DOCUMENT ME! + */ + public double getPercentComplete() + { + if (getMaximum() == getMinimum()) + return 1.0; + else + return (double) (model.getValue() - model.getMinimum()) / (model + .getMaximum() + - model.getMinimum()); + } + + /** + * This method returns whether the border is painted. + * + * @return Whether the border is painted. + */ + public boolean isBorderPainted() + { + return paintBorder; + } + + /** + * This method changes the borderPainted property. + * + * @param painted Whether the border is painted. + */ + public void setBorderPainted(boolean painted) + { + if (painted != paintBorder) + { + boolean oldPainted = paintBorder; + paintBorder = painted; + firePropertyChange("borderPainted", oldPainted, + paintBorder); + } + } + + /** + * This method returns the JProgressBar's UI delegate. + * + * @return This JProgressBar's UI delegate. + */ + public ProgressBarUI getUI() + { + return (ProgressBarUI) ui; + } + + /** + * This method changes the UI property for this JProgressBar. + * + * @param ui The new UI delegate. + */ + public void setUI(ProgressBarUI ui) + { + super.setUI(ui); + } + + /** + * This method reverts the UI delegate for this JProgressBar + * to the default for this Look and Feel. + */ + public void updateUI() + { + setUI((ProgressBarUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns the identifier to allow the UIManager + * to pick the correct class to act as the UI for + * this JProgressBar. + * + * @return The UIClassID: "ProgressBarUI". + */ + public String getUIClassID() + { + return "ProgressBarUI"; + } + + /** + * This method returns a ChangeListener that gets registered + * model. By default, the ChangeListener, propagates the + * ChangeEvents to the ChangeListeners of the JProgressBar. + * + * @return A new ChangeListener. + */ + protected ChangeListener createChangeListener() + { + return new ChangeListener() + { + public void stateChanged(ChangeEvent ce) + { + fireStateChanged(); + } + }; + } + + /** + * This method adds a ChangeListener to this JProgressBar. + * + * @param listener The ChangeListener to add to this JProgressBar. + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * This method removes a ChangeListener from this JProgressBar. + * + * @param listener The ChangeListener to remove from this JProgressBar. + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * This method returns an array of all ChangeListeners listening to this + * progress bar. + * + * @return An array of ChangeListeners listening to this progress bar. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * This method is called when the JProgressBar receives a ChangeEvent + * from its model. This simply propagates the event (changing the source + * to the JProgressBar) to the JProgressBar's listeners. + */ + protected void fireStateChanged() + { + Object[] changeListeners = listenerList.getListenerList(); + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + for (int i = changeListeners.length - 2; i >= 0; i -= 2) + { + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + } + } + + /** + * This method returns the model used with this JProgressBar. + * + * @return The model used with this JProgressBar. + */ + public BoundedRangeModel getModel() + { + return model; + } + + /** + * This method changes the model property for this JProgressBar. + * + * @param model The model to use with this JProgressBar. + */ + public void setModel(BoundedRangeModel model) + { + if (model != this.model) + { + this.model.removeChangeListener(changeListener); + this.model = model; + this.model.addChangeListener(changeListener); + fireStateChanged(); + } + } + + /** + * This method returns the minimum value of this JProgressBar. + * + * @return The minimum value of this JProgressBar. + */ + public int getMinimum() + { + return model.getMinimum(); + } + + /** + * This method sets the minimum value of this JProgressBar. + * + * @param minimum The minimum value of this JProgressBar. + */ + public void setMinimum(int minimum) + { + model.setMinimum(minimum); + } + + /** + * This method returns the maximum value of this JProgressBar. + * + * @return The maximum value of this JProgressBar. + */ + public int getMaximum() + { + return model.getMaximum(); + } + + /** + * This method sets the maximum value of this JProgressBar. + * + * @param maximum The maximum value of this JProgressBar. + */ + public void setMaximum(int maximum) + { + model.setMaximum(maximum); + } + + /** + * This method returns a string that can be used to + * describe this JProgressBar. This method is usually + * only used for debugging purposes. + * + * @return A string that describes this JProgressBar. + */ + protected String paramString() + { + return "JProgressBar"; + } + + /** + * This method changes the indeterminate property. If the + * JProgressBar is determinate, it paints a percentage + * of the bar described by its value. If it is indeterminate, + * it simply bounces a box between the ends of the bar; the + * value of the JProgressBar is ignored. + * + * @param newValue Whether the JProgressBar is indeterminate. + */ + public void setIndeterminate(boolean newValue) + { + if (indeterminate != newValue) + { + boolean olddeter = indeterminate; + indeterminate = newValue; + firePropertyChange("indeterminate", olddeter, + indeterminate); + } + } + + /** + * This method returns whether the JProgressBar is indeterminate. + * + * @return Whether this JProgressBar is indeterminate. + */ + public boolean isIndeterminate() + { + return indeterminate; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJProgressBar(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JRadioButton.java b/libjava/classpath/javax/swing/JRadioButton.java new file mode 100644 index 00000000000..66f5902e899 --- /dev/null +++ b/libjava/classpath/javax/swing/JRadioButton.java @@ -0,0 +1,259 @@ +/* JRadioButton.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.plaf.ButtonUI; + +/** + * The <code>JRadioButton</code> component provides a visually selectable + * button with mutually exclusive behaviour within a <code>ButtonGroup</code>. + * A series of radio buttons can be used to provide options to the user, + * where the user can only select one of the available options. The state + * of the button is provided by the superclass, <code>JToggleButton</code>. + * <code>JRadioButton</code> adds the additional behaviour, that if two + * or more radio buttons are grouped together, the selection of one implies + * the deselection of the other buttons within the group. + * <p> + * + * Buttons are grouped by adding each instance to a <code>ButtonGroup</code>. + * The existence of such a grouping is not reflected visually, so other means + * should be used to denote this. For instance, the grouped buttons can be placed + * within the same panel, possibly with an appropriate border to denote + * the connection between the components. + * + * @author Michael Koch (konqueror@gmx.de) + * @author Graydon Hoare (graydon@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see JToggleButton + * @see ButtonGroup + * @since 1.2 + */ +public class JRadioButton extends JToggleButton +{ + /** + * Compatible with Sun's JDK. + */ + private static final long serialVersionUID = 7751949583255506856L; + + /** + * This class provides accessibility support for the toggle button. + */ + protected class AccessibleJRadioButton + extends AccessibleJToggleButton + { + private static final long serialVersionUID = 4850967637026120674L; + + /** + * Constructor for the accessible toggle button. + */ + protected AccessibleJRadioButton() + { + /* Call the superclass to register for events */ + super(); + } + + /** + * Returns the accessible role for the toggle button. + * + * @return An instance of <code>AccessibleRole</code>, describing + * the role of the toggle button. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.RADIO_BUTTON; + } + + } + + /** + * Constructs an unselected radio button with no text or icon. + */ + public JRadioButton() + { + this(null, null, false); + } + + /** + * Constructs a radio button using the labelling, state + * and icon specified by the supplied action. + * + * @param a the action to use to define the properties of the button. + */ + public JRadioButton(Action a) + { + this(); + setAction(a); + } + + /** + * Constructs an unselected radio button with the supplied icon + * and no text. + * + * @param icon the icon to use. + */ + public JRadioButton(Icon icon) + { + this(null, icon, false); + } + + /** + * Constructs a radio button with the supplied icon and state. + * + * @param icon the icon to use. + * @param selected if true, the radio button is initially in the + * selected state. Otherwise, the button is unselected. + */ + public JRadioButton(Icon icon, boolean selected) + { + this(null, icon, selected); + } + + /** + * Constructs an unselected radio button using the supplied text + * and no icon. + * + * @param text the text to use. + */ + public JRadioButton(String text) + { + this(text, null, false); + } + + /** + * Constructs a radio button with the supplied text and state. + * + * @param text the text to use. + * @param selected if true, the radio button is initially in the + * selected state. Otherwise, the button is unselected. + */ + public JRadioButton(String text, boolean selected) + { + this(text, null, selected); + } + + /** + * Constructs an unselected radio button with the supplied text + * and icon. + * + * @param text the text to use. + * @param icon the icon to use. + */ + public JRadioButton(String text, Icon icon) + { + this(text, icon, false); + } + + /** + * Constructs a radio button with the supplied text, icon and state. + * + * @param text the text to use. + * @param icon the icon to use. + * @param selected if true, the radio button is initially in the + * selected state. Otherwise, the button is unselected. + */ + public JRadioButton(String text, Icon icon, boolean selected) + { + super(text, icon, selected); + borderPainted = false; + contentAreaFilled = false; + } + + /** + * Returns the accessible context for this <code>JRadioButton</code>, + * in the form of an instance of <code>AccessibleJRadioButton</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + { + /* Create the context */ + accessibleContext = new AccessibleJRadioButton(); + } + return accessibleContext; + } + + /** + * Returns a string specifying the name of the Look and Feel UI class + * that renders this component. + * + * @return the Look and Feel UI class for <code>JRadioButton</code>s + * as a <code>String</code>. + */ + public String getUIClassID() + { + return "RadioButtonUI"; + } + + /** + * Returns a string representation of this component for debugging use. + * Users should not depend on anything as regards the content or formatting + * of this string, except for the fact that the returned string may never be + * null (only empty). + * + * @return the component in <code>String</code> form for debugging. + */ + protected String paramString() + { + return super.paramString(); + } + + /** + * This method resets the radio button's UI delegate to the default UI for + * the current look and feel. + */ + public void updateUI() + { + /* + I can't see any difference between this and the superclass one, + but Sun reimplements it... there is no RadioButtonUI class for it + to be cast to. + */ + setUI((ButtonUI) UIManager.getUI(this)); + } + +} + + + diff --git a/libjava/classpath/javax/swing/JRadioButtonMenuItem.java b/libjava/classpath/javax/swing/JRadioButtonMenuItem.java new file mode 100644 index 00000000000..76a8fef640a --- /dev/null +++ b/libjava/classpath/javax/swing/JRadioButtonMenuItem.java @@ -0,0 +1,212 @@ +/* JRadioButtonMenuItem.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.IOException; +import java.io.ObjectOutputStream; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; + +/** + * This class represents JRadioButtonMenuItem. Its behaviour is very similar + * to JRadioButton. Just like JRadioButton, user can check and uncheck this + * menu item by clicking on it. JRadioButtonMenuItem uses ToggleButtonModel + * to keep track of its selection. If the JRadioButtonMenuItem is included in + * the button group, then only one JRadioButtonMenuItem can be selected at + * one time. + */ +public class JRadioButtonMenuItem extends JMenuItem implements Accessible +{ + private static final long serialVersionUID = 8482658191548521743L; + + /** name for the UI delegate for this radio button menu item. */ + private static final String uiClassID = "RadioButtonMenuItemUI"; + + /** + * Creates a new JRadioButtonMenuItem object. + */ + public JRadioButtonMenuItem() + { + this(null, null); + } + + /** + * Creates a new JRadioButtonMenuItem with specified icon + * + * @param icon Icon to be used for this menu item + */ + public JRadioButtonMenuItem(Icon icon) + { + this(null, icon); + } + + /** + * Creates a new JRadioButtonMenuItem with specified label + * + * @param text Label for this menu item + */ + public JRadioButtonMenuItem(String text) + { + this(text, null); + } + + /** + * Creates a new JRadioButtonMenuItem using specified action + * + * @param action Action for this menu item + */ + public JRadioButtonMenuItem(Action action) + { + this(); + setAction(action); + } + + /** + * Creates a new JRadioButtonMenuItem with specified label and icon + * + * @param text Label for this menu item + * @param icon Icon for this menu item + */ + public JRadioButtonMenuItem(String text, Icon icon) + { + this(text, icon, false); + } + + /** + * Creates a new JRadioButtonMenuItem with specified label + * and marked selected if 'selected' is true. + * + * @param text Text for this menu item + * @param selected Selected state of this menu item + */ + public JRadioButtonMenuItem(String text, boolean selected) + { + this(text, null, selected); + } + + /** + * Creates a new JRadioButtonMenuItem with specified icon + * and given selected state + * + * @param icon Icon for this menu item + * @param selected Selected state for this menu item + */ + public JRadioButtonMenuItem(Icon icon, boolean selected) + { + this(null, icon, selected); + } + + /** + * Creates a new JRadioButtonMenuItem with specified label, + * icon and selected state. + * + * @param text Label for this menu item + * @param icon Icon to be use for this menu item + * @param selected selected state of this menu item + */ + public JRadioButtonMenuItem(String text, Icon icon, boolean selected) + { + super(text, icon); + setModel(new JToggleButton.ToggleButtonModel()); + model.setSelected(selected); + } + + private void writeObject(ObjectOutputStream stream) throws IOException + { + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the menuItem. + * + * @return The Look and Feel classID. "JRadioButtonMenuItemUI" + */ + public String getUIClassID() + { + return uiClassID; + } + + /** + * This method overrides JComponent.requestFocus with an empty + * implementation, since JRadioButtonMenuItems should not + * receve focus in general. + */ + public void requestFocus() + { + // Should do nothing here + } + + /** + * A string that describes this JRadioButtonMenuItem. Normally only used + * for debugging. + * + * @return A string describing this JRadioButtonMenuItem + */ + protected String paramString() + { + return "JRadioButtonMenuItem"; + } + + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJRadioButtonMenuItem(); + + return accessibleContext; + } + + protected class AccessibleJRadioButtonMenuItem extends AccessibleJMenuItem + { + private static final long serialVersionUID = 4381471510145292179L; + + /** + * Creates a new AccessibleJRadioButtonMenuItem object. + */ + protected AccessibleJRadioButtonMenuItem() + { + } + + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.RADIO_BUTTON; + } + } +} diff --git a/libjava/classpath/javax/swing/JRootPane.java b/libjava/classpath/javax/swing/JRootPane.java new file mode 100644 index 00000000000..cb0bafd84e0 --- /dev/null +++ b/libjava/classpath/javax/swing/JRootPane.java @@ -0,0 +1,625 @@ +/* JRootPane.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.LayoutManager; +import java.awt.LayoutManager2; +import java.io.Serializable; + +import javax.accessibility.AccessibleRole; +import javax.swing.plaf.RootPaneUI; + +/** + * This class is where JComponents are added to. Unlike awt where you could + * just say frame.add(), with swing you need to say frame.getRootPane() + * (which delivers an instance of this class) and add your components to + * that. It is implemented by several 'layers' (pane() should be read as + * plane()) each on top of the others where you can add components to. + * (getContentPane(), getGlassPane(), getLayeredPane()) + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class JRootPane extends JComponent +{ + // The class used to obtain the accessible role for this object. + protected static class AccessibleJRootPane + { + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 1082432482784468088L; + + /** + * Creates a new <code>AccessibleJRootPane</code> object. + */ + protected AccessibleJRootPane() + { + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.ROOT_PANE; + } + } + + // Custom Layout Manager for JRootPane. It positions contentPane and + // menuBar withing its layeredPane. + protected class RootLayout implements LayoutManager2, Serializable + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = -4100116998559815027L; + + /** + * Creates a new <code>RootLayout</code> object. + */ + protected RootLayout() + { + } + + /** + * DOCUMENT ME! + * + * @param comp DOCUMENT ME! + * @param constraints DOCUMENT ME! + */ + public void addLayoutComponent(Component comp, Object constraints) + { + } + + /** + * DOCUMENT ME! + * + * @param name DOCUMENT ME! + * @param comp DOCUMENT ME! + */ + public void addLayoutComponent(String name, Component comp) + { + } + + /** + * DOCUMENT ME! + * + * @param target DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public float getLayoutAlignmentX(Container target) + { + return target.getAlignmentX(); + } + + /** + * DOCUMENT ME! + * + * @param target DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public float getLayoutAlignmentY(Container target) + { + return target.getAlignmentY(); + } + + /** + * DOCUMENT ME! + * + * @param target DOCUMENT ME! + */ + public void invalidateLayout(Container target) + { + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + */ + public void layoutContainer(Container c) + { + Dimension menuBarSize; + Dimension containerSize = c.getSize(null); + Dimension contentPaneSize = contentPane.getPreferredSize(); + + /* + if size of top-level window wasn't set then just set + contentPane and menuBar to its preferred sizes. + Otherwise, if the size of top-level window was specified then + set menuBar to its preferred size and make content pane + to fit into the remaining space + + + +-------------------------------+ + | JLayeredPane | + | +--------------------------+ | + | | menuBar | | + | +--------------------------+ | + | +--------------------------+ | + | |contentPane | | + | | | | + | | | | + | | | | + | +--------------------------+ | + +-------------------------------+ + + */ + if (containerSize.width == 0 && containerSize.height == 0) + { + if (menuBar != null) + { + int maxWidth; + menuBarSize = menuBar.getPreferredSize(); + maxWidth = Math.max(menuBarSize.width, contentPaneSize.width); + menuBar.setBounds(0, 0, maxWidth, menuBarSize.height); + glassPane.setBounds(0, menuBarSize.height, maxWidth, + contentPaneSize.height); + contentPane.setBounds(0, menuBarSize.height, maxWidth, + contentPaneSize.height); + layeredPane.setSize(maxWidth, + menuBarSize.height + contentPaneSize.height); + } + else + { + glassPane.setBounds(0, 0, contentPaneSize.width, + contentPaneSize.height); + contentPane.setBounds(0, 0, contentPaneSize.width, + contentPaneSize.height); + layeredPane.setSize(contentPaneSize.width, contentPaneSize.height); + } + } + else + { + if (menuBar != null) + { + menuBarSize = menuBar.getPreferredSize(); + if (menuBarSize.height > containerSize.height) + menuBarSize.height = containerSize.height; + menuBar.setBounds(0, 0, containerSize.width, menuBarSize.height); + int remainingHeight = containerSize.height - menuBarSize.height; + glassPane.setBounds(0, menuBarSize.height, containerSize.width, + containerSize.height - menuBarSize.height); + contentPane.setBounds(0, menuBarSize.height, + containerSize.width, + (containerSize.height - menuBarSize.height)); + } + else + { + glassPane.setBounds(0, 0, containerSize.width, + containerSize.height); + contentPane.setBounds(0, 0, containerSize.width, + containerSize.height); + } + + layeredPane.setSize(containerSize.width, containerSize.height); + } + } + + /** + * DOCUMENT ME! + * + * @param target DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension maximumLayoutSize(Container target) + { + return preferredLayoutSize(target); + } + + /** + * DOCUMENT ME! + * + * @param target DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension minimumLayoutSize(Container target) + { + return preferredLayoutSize(target); + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension preferredLayoutSize(Container c) + { + Dimension menuBarSize; + Dimension prefSize; + + Dimension containerSize = c.getSize(); + Dimension contentPaneSize = contentPane.getPreferredSize(); + + if (containerSize.width == 0 && containerSize.height == 0) + { + if (menuBar != null) + { + int maxWidth; + menuBarSize = menuBar.getPreferredSize(); + maxWidth = Math.max(menuBarSize.width, contentPaneSize.width); + prefSize = new Dimension(maxWidth, + contentPaneSize.height + + menuBarSize.height); + } + else + prefSize = contentPaneSize; + } + else + prefSize = c.getSize(); + + return prefSize; + } + + /** + * DOCUMENT ME! + * + * @param comp DOCUMENT ME! + */ + public void removeLayoutComponent(Component comp) + { + } + } + + /** DOCUMENT ME! */ + private static final long serialVersionUID = 8690748000348575668L; + + public static final int NONE = 0; + public static final int FRAME = 1; + public static final int PLAIN_DIALOG = 2; + public static final int INFORMATION_DIALOG = 3; + public static final int ERROR_DIALOG = 4; + public static final int COLOR_CHOOSER_DIALOG = 5; + public static final int FILE_CHOOSER_DIALOG = 6; + public static final int QUESTION_DIALOG = 7; + public static final int WARNING_DIALOG = 8; + + /** DOCUMENT ME! */ + protected Component glassPane; + + /** DOCUMENT ME! */ + protected JLayeredPane layeredPane; + + /** DOCUMENT ME! */ + protected JMenuBar menuBar; + + /** DOCUMENT ME! */ + protected Container contentPane; + + protected JButton defaultButton; + + /** + * @since 1.4 + */ + private int windowDecorationStyle = NONE; + + /** + * DOCUMENT ME! + * + * @param m DOCUMENT ME! + */ + public void setJMenuBar(JMenuBar m) + { + JLayeredPane jlPane = getLayeredPane(); + if (menuBar != null) + jlPane.remove(menuBar); + menuBar = m; + if (menuBar != null) + jlPane.add(menuBar, JLayeredPane.FRAME_CONTENT_LAYER); + } + + /** + * @deprecated Replaced by <code>setJMenuBar()</code> + */ + public void setMenuBar(JMenuBar m) + { + setJMenuBar(m); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JMenuBar getJMenuBar() + { + return menuBar; + } + + /** + * @deprecated Replaced by <code>getJMenuBar()</code> + */ + public JMenuBar getMenuBar() + { + return getJMenuBar(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isValidateRoot() + { + return true; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Container getContentPane() + { + if (contentPane == null) + setContentPane(createContentPane()); + return contentPane; + } + + /** + * DOCUMENT ME! + * + * @param p DOCUMENT ME! + */ + public void setContentPane(Container p) + { + contentPane = p; + getLayeredPane().add(contentPane, JLayeredPane.FRAME_CONTENT_LAYER); + } + + /** + * DOCUMENT ME! + * + * @param comp DOCUMENT ME! + * @param constraints DOCUMENT ME! + * @param index DOCUMENT ME! + */ + protected void addImpl(Component comp, Object constraints, int index) + { + super.addImpl(comp, constraints, index); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Component getGlassPane() + { + if (glassPane == null) + setGlassPane(createGlassPane()); + return glassPane; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + */ + public void setGlassPane(Component f) + { + if (glassPane != null) + remove(glassPane); + + glassPane = f; + + glassPane.setVisible(false); + add(glassPane, 0); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JLayeredPane getLayeredPane() + { + if (layeredPane == null) + setLayeredPane(createLayeredPane()); + return layeredPane; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + */ + public void setLayeredPane(JLayeredPane f) + { + if (layeredPane != null) + remove(layeredPane); + + layeredPane = f; + add(f, -1); + } + + /** + * Creates a new <code>JRootPane</code> object. + */ + public JRootPane() + { + setLayout(createRootLayout()); + getGlassPane(); + getLayeredPane(); + getContentPane(); + setDoubleBuffered(true); + updateUI(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected LayoutManager createRootLayout() + { + return new RootLayout(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected Container createContentPane() + { + JPanel p = new JPanel(); + p.setName(this.getName() + ".contentPane"); + p.setLayout(new BorderLayout()); + return p; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected Component createGlassPane() + { + JPanel p = new JPanel(); + p.setName(this.getName() + ".glassPane"); + p.setLayout(new BorderLayout()); + p.setVisible(false); + p.setOpaque(false); + return p; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected JLayeredPane createLayeredPane() + { + JLayeredPane l = new JLayeredPane(); + l.setLayout(null); + return l; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public RootPaneUI getUI() + { + return (RootPaneUI) ui; + } + + /** + * DOCUMENT ME! + * + * @param ui DOCUMENT ME! + */ + public void setUI(RootPaneUI ui) + { + super.setUI(ui); + } + + /** + * DOCUMENT ME! + */ + public void updateUI() + { + setUI((RootPaneUI) UIManager.getUI(this)); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getUIClassID() + { + return "RootPaneUI"; + } + + public JButton getDefaultButton() + { + return defaultButton; + } + + public void setDefaultButton(JButton newButton) + { + if (defaultButton == newButton) + return; + + JButton oldButton = defaultButton; + defaultButton = newButton; + firePropertyChange("defaultButton", oldButton, newButton); + } + + /** + * @since 1.4 + */ + public int getWindowDecorationStyle() + { + return windowDecorationStyle; + } + + /** + * @since 1.4 + */ + public void setWindowDecorationStyle(int style) + { + if (style != NONE + && style != FRAME + && style != INFORMATION_DIALOG + && style != ERROR_DIALOG + && style != COLOR_CHOOSER_DIALOG + && style != FILE_CHOOSER_DIALOG + && style != QUESTION_DIALOG + && style != WARNING_DIALOG) + throw new IllegalArgumentException("invalid style"); + + int oldStyle = windowDecorationStyle; + windowDecorationStyle = style; + firePropertyChange("windowDecorationStyle", oldStyle, style); + } +} diff --git a/libjava/classpath/javax/swing/JScrollBar.java b/libjava/classpath/javax/swing/JScrollBar.java new file mode 100644 index 00000000000..caed92cf60e --- /dev/null +++ b/libjava/classpath/javax/swing/JScrollBar.java @@ -0,0 +1,647 @@ +/* JScrollBar.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Adjustable; +import java.awt.Dimension; +import java.awt.event.AdjustmentEvent; +import java.awt.event.AdjustmentListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; +import javax.swing.plaf.ScrollBarUI; + +/** + * The JScrollBar. Two buttons control how the values that the + * scroll bar can take. You can also drag the thumb or click the track + * to move the scroll bar. Typically, the JScrollBar is used with + * other components to translate the value of the bar to the viewable + * contents of the other components. + */ +public class JScrollBar extends JComponent implements Adjustable, Accessible +{ + /** + * DOCUMENT ME! + */ + protected class AccessibleJScrollBar extends JComponent.AccessibleJComponent + implements AccessibleValue + { + private static final long serialVersionUID = -7758162392045586663L; + + /** + * Creates a new AccessibleJSlider object. + * + * @param value0 DOCUMENT ME! + */ + protected AccessibleJScrollBar() + { + super(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * setCurrentAccessibleValue + * + * @param value0 TODO + * + * @return boolean + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * getMinimumAccessibleValue + * + * @return Number + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * getMaximumAccessibleValue + * + * @return Number + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + private static final long serialVersionUID = -8195169869225066566L; + + /** How much the thumb moves when moving in a block. */ + protected int blockIncrement = 10; + + /** The model that holds the scroll bar's data. */ + protected BoundedRangeModel model; + + /** The orientation of the scroll bar. */ + protected int orientation = SwingConstants.VERTICAL; + + /** How much the thumb moves when moving in a unit. */ + protected int unitIncrement = 1; + + /** + * Creates a new horizontal JScrollBar object with a minimum + * of 0, a maxmium of 100, a value of 0 and an extent of 10. + */ + public JScrollBar() + { + this(SwingConstants.VERTICAL, 0, 10, 0, 100); + } + + /** + * Creates a new JScrollBar object with a minimum of 0, a + * maximum of 100, a value of 0, an extent of 10 and the given + * orientation. + * + * @param orientation The orientation of the JScrollBar. + */ + public JScrollBar(int orientation) + { + this(orientation, 0, 10, 0, 100); + } + + /** + * Creates a new JScrollBar object with the given orientation, + * value, min, max, and extent. + * + * @param orientation The orientation to use. + * @param value The value to use. + * @param extent The extent to use. + * @param min The minimum value of the scrollbar. + * @param max The maximum value of the scrollbar. + */ + public JScrollBar(int orientation, int value, int extent, int min, int max) + { + model = new DefaultBoundedRangeModel(value, extent, min, max); + if (orientation != SwingConstants.HORIZONTAL + && orientation != SwingConstants.VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); + this.orientation = orientation; + updateUI(); + } + + /** + * This method sets the UI of this scrollbar to + * the given UI. + * + * @param ui The UI to use with this scrollbar. + */ + public void setUI(ScrollBarUI ui) + { + super.setUI(ui); + } + + /** + * This method returns the UI that is being used + * with this scrollbar. + * + * @return The scrollbar's current UI. + */ + public ScrollBarUI getUI() + { + return (ScrollBarUI) ui; + } + + /** + * This method changes the UI to be the + * default for the current look and feel. + */ + public void updateUI() + { + setUI((ScrollBarUI) UIManager.getUI(this)); + invalidate(); + repaint(); + } + + /** + * This method returns an identifier to + * choose the correct UI delegate for the + * scrollbar. + * + * @return The identifer to choose the UI delegate; "ScrollBarUI" + */ + public String getUIClassID() + { + return "ScrollBarUI"; + } + + /** + * This method returns the orientation of the scrollbar. + * + * @return The orientation of the scrollbar. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method sets the orientation of the scrollbar. + * + * @param orientation The orientation of the scrollbar. + */ + public void setOrientation(int orientation) + { + if (orientation != SwingConstants.HORIZONTAL + && orientation != SwingConstants.VERTICAL) + throw new IllegalArgumentException("orientation must be one of HORIZONTAL or VERTICAL"); + if (orientation != this.orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange("orientation", oldOrientation, + this.orientation); + } + } + + /** + * This method returns the model being used with + * the scrollbar. + * + * @return The scrollbar's model. + */ + public BoundedRangeModel getModel() + { + return model; + } + + /** + * This method sets the model to use with + * the scrollbar. + * + * @param newModel The new model to use with the scrollbar. + */ + public void setModel(BoundedRangeModel newModel) + { + if (model != newModel) + { + BoundedRangeModel oldModel = model; + model = newModel; + firePropertyChange("model", oldModel, model); + } + } + + /** + * This method returns how much the scrollbar's value + * should change for a unit increment depending on the + * given direction. + * + * @param direction The direction to scroll in. + * + * @return The amount the scrollbar's value will change given the direction. + */ + public int getUnitIncrement(int direction) + { + return direction * unitIncrement; + } + + /** + * This method sets the unitIncrement property. + * + * @param unitIncrement The new unitIncrement. + */ + public void setUnitIncrement(int unitIncrement) + { + if (unitIncrement != this.unitIncrement) + { + int oldInc = this.unitIncrement; + this.unitIncrement = unitIncrement; + firePropertyChange("unitIncrement", oldInc, + this.unitIncrement); + } + } + + /** + * The method returns how much the scrollbar's value + * should change for a block increment depending on + * the given direction. + * + * @param direction The direction to scroll in. + * + * @return The amount the scrollbar's value will change given the direction. + */ + public int getBlockIncrement(int direction) + { + return direction * blockIncrement; + } + + /** + * This method sets the blockIncrement property. + * + * @param blockIncrement The new blockIncrement. + */ + public void setBlockIncrement(int blockIncrement) + { + if (blockIncrement != this.blockIncrement) + { + int oldInc = this.blockIncrement; + this.blockIncrement = blockIncrement; + firePropertyChange("blockIncrement", oldInc, + this.blockIncrement); + } + } + + /** + * This method returns the unitIncrement. + * + * @return The unitIncrement. + */ + public int getUnitIncrement() + { + return unitIncrement; + } + + /** + * This method returns the blockIncrement. + * + * @return The blockIncrement. + */ + public int getBlockIncrement() + { + return blockIncrement; + } + + /** + * This method returns the value of the scrollbar. + * + * @return The value of the scrollbar. + */ + public int getValue() + { + return model.getValue(); + } + + /** + * This method changes the value of the scrollbar. + * + * @param value The new value of the scrollbar. + */ + public void setValue(int value) + { + if (isEnabled() && value != getValue()) + { + model.setValue(value); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, value); + } + } + + /** + * This method returns the visible amount (AKA extent). + * The visible amount can be used by UI delegates to + * determine the size of the thumb. + * + * @return The visible amount (AKA extent). + */ + public int getVisibleAmount() + { + return model.getExtent(); + } + + /** + * This method sets the visible amount (AKA extent). + * + * @param extent The visible amount (AKA extent). + */ + public void setVisibleAmount(int extent) + { + if (extent != getVisibleAmount()) + { + model.setExtent(extent); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, extent); + } + } + + /** + * This method returns the minimum value of the scrollbar. + * + * @return The minimum value of the scrollbar. + */ + public int getMinimum() + { + return model.getMinimum(); + } + + /** + * This method sets the minimum value of the scrollbar. + * + * @param minimum The minimum value of the scrollbar. + */ + public void setMinimum(int minimum) + { + if (minimum != getMinimum()) + { + model.setMinimum(minimum); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, minimum); + } + } + + /** + * This method returns the maximum value of the scrollbar. + * + * @return The maximum value of the scrollbar. + */ + public int getMaximum() + { + return model.getMaximum(); + } + + /** + * This method sets the maximum value of the scrollbar. + * + * @param maximum The maximum value of the scrollbar. + */ + public void setMaximum(int maximum) + { + if (maximum != getMaximum()) + { + model.setMaximum(maximum); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, maximum); + } + } + + /** + * This method returns the model's isAjusting value. + * + * @return The model's isAdjusting value. + */ + public boolean getValueIsAdjusting() + { + return model.getValueIsAdjusting(); + } + + /** + * This method sets the model's isAdjusting value. + * + * @param b The new isAdjusting value. + */ + public void setValueIsAdjusting(boolean b) + { + model.setValueIsAdjusting(b); + } + + /** + * This method sets the value, extent, minimum and + * maximum. + * + * @param newValue The new value. + * @param newExtent The new extent. + * @param newMin The new minimum. + * @param newMax The new maximum. + */ + public void setValues(int newValue, int newExtent, int newMin, int newMax) + { + if (!isEnabled()) + newValue = model.getValue(); + // It seems to be that on any change the value is fired. + if (newValue != getValue() || newExtent != getVisibleAmount() || + newMin != getMinimum() || newMax != getMaximum()) + { + model.setRangeProperties(newValue, newExtent, newMin, newMax, + model.getValueIsAdjusting()); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, newValue); + } + } + + /** + * This method adds an AdjustmentListener to the scroll bar. + * + * @param listener The listener to add. + */ + public void addAdjustmentListener(AdjustmentListener listener) + { + listenerList.add(AdjustmentListener.class, listener); + } + + /** + * This method removes an AdjustmentListener from the scroll bar. + * + * @param listener The listener to remove. + */ + public void removeAdjustmentListener(AdjustmentListener listener) + { + listenerList.remove(AdjustmentListener.class, listener); + } + + /** + * This method returns an arry of all AdjustmentListeners listening to + * this scroll bar. + * + * @return An array of AdjustmentListeners listening to this scroll bar. + */ + public AdjustmentListener[] getAdjustmentListeners() + { + return (AdjustmentListener[]) listenerList.getListeners(AdjustmentListener.class); + } + + /** + * This method is called to fired AdjustmentEvents to the listeners + * of this scroll bar. All AdjustmentEvents that are fired + * will have an ID of ADJUSTMENT_VALUE_CHANGED and a type of + * TRACK. + * + * @param id The ID of the adjustment event. + * @param type The Type of change. + * @param value The new value for the property that was changed.. + */ + protected void fireAdjustmentValueChanged(int id, int type, int value) + { + Object[] adjustmentListeners = listenerList.getListenerList(); + AdjustmentEvent adjustmentEvent = new AdjustmentEvent(this, + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, + value); + for (int i = adjustmentListeners.length - 2; i >= 0; i -= 2) + { + if (adjustmentListeners[i] == AdjustmentListener.class) + ((AdjustmentListener) adjustmentListeners[i + 1]).adjustmentValueChanged(adjustmentEvent); + } + } + + /** + * This method returns the minimum size for this scroll bar. + * + * @return The minimum size. + */ + public Dimension getMinimumSize() + { + return ui.getMinimumSize(this); + } + + /** + * This method returns the maximum size for this scroll bar. + * + * @return The maximum size. + */ + public Dimension getMaximumSize() + { + return ui.getMaximumSize(this); + } + + /** + * This method overrides the setEnabled in JComponent. + * When the scroll bar is disabled, the knob cannot + * be moved. + * + * @param x Whether the scrollbar is enabled. + */ + public void setEnabled(boolean x) + { + // nothing special needs to be done here since we + // just check the enabled setting before changing the value. + super.setEnabled(x); + } + + /** + * A string that describes this JScrollBar. Normally only used + * for debugging. + * + * @return A string describing this JScrollBar. + */ + protected String paramString() + { + return "JScrollBar"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJScrollBar(); + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JScrollPane.java b/libjava/classpath/javax/swing/JScrollPane.java new file mode 100644 index 00000000000..377f05a88c2 --- /dev/null +++ b/libjava/classpath/javax/swing/JScrollPane.java @@ -0,0 +1,733 @@ +/* JScrollPane.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Rectangle; + +import javax.accessibility.Accessible; +import javax.swing.border.Border; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ScrollPaneUI; +import javax.swing.plaf.UIResource; + +/** + * A component that embeds another component and enables it to be scrolled + * both in horizontal and vertical direction. + * + * <table> + * <tr><th>Property </th><th>Stored in </th><th>Bound?</th></tr> + * <tr><td>columnHeader </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>columnHeaderView </td><td>columnHeader </td><td>no </td></tr> + * <tr><td>componentOrientation </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>horizontalScrollBar </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>horizontalScrollBarPolicy </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>layout </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>rowHeader </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>rowHeaderView </td><td>rowHeader </td><td>no </td></tr> + * <tr><td>validateRoot </td><td>scrollPane </td><td>no </td></tr> + * <tr><td>verticalScrollBar </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>verticalScrollBarPolicy </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>viewport </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>viewportBorder </td><td>scrollPane </td><td>yes </td></tr> + * <tr><td>viewportBorderBounds </td><td>scrollPane </td><td>no </td></tr> + * <tr><td>viewportView </td><td>viewport </td><td>no </td></tr> + * <tr><td>wheelScrollingEnabled </td><td>scrollPane </td><td>yes </td></tr> + * </table> + */ +public class JScrollPane + extends JComponent + implements Accessible, ScrollPaneConstants +{ + private static final long serialVersionUID = 5203525440012340014L; + + protected JViewport columnHeader; + protected JViewport rowHeader; + + protected Component lowerLeft; + protected Component lowerRight; + protected Component upperLeft; + protected Component upperRight; + + protected JScrollBar horizontalScrollBar; + protected int horizontalScrollBarPolicy; + protected JScrollBar verticalScrollBar; + protected int verticalScrollBarPolicy; + + protected JViewport viewport; + + Border viewportBorder; + boolean wheelScrollingEnabled; + ChangeListener scrollListener; + + public JViewport getColumnHeader() + { + return columnHeader; + } + + public Component getCorner(String key) { + if (getComponentOrientation() + == ComponentOrientation.LEFT_TO_RIGHT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_LEFT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_RIGHT_CORNER; + } + else if (getComponentOrientation() + == ComponentOrientation.RIGHT_TO_LEFT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_RIGHT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_LEFT_CORNER; + } + + if (key == LOWER_RIGHT_CORNER) + return lowerRight; + else if (key == UPPER_RIGHT_CORNER) + return upperRight; + else if (key == LOWER_LEFT_CORNER) + return lowerLeft; + else if (key == UPPER_LEFT_CORNER) + return upperLeft; + return null; + } + + public JScrollBar getHorizontalScrollBar() + { + return horizontalScrollBar; + } + + public int getHorizontalScrollBarPolicy() + { + return horizontalScrollBarPolicy; + } + + public JViewport getRowHeader() + { + return rowHeader; + } + + public JScrollBar getVerticalScrollBar() + { + return verticalScrollBar; + } + + public int getVerticalScrollBarPolicy() + { + return verticalScrollBarPolicy; + } + + public JViewport getViewport() + { + return viewport; + } + + public Border getViewportBorder() + { + return viewportBorder; + } + + public Rectangle getViewportBorderBounds() + { + if (viewportBorder == null) + { + if (getViewport() == null) + return new Rectangle(0,0,0,0); + else + return getViewport().getBounds(); + } + else + { + Insets i = viewportBorder.getBorderInsets(getViewport()); + if (getViewport() == null) + return new Rectangle(0,0, + i.left+i.right, i.top+i.bottom); + else + { + Rectangle b = getViewport().getBounds(); + return new Rectangle(b.x - i.left, + b.y - i.top, + b.width + i.left + i.right, + b.height + i.top + i.bottom); + } + } + } + + public boolean isWheelScrollingEnabled() + { + return wheelScrollingEnabled; + } + + + + private void sync() + { + LayoutManager m = super.getLayout(); + if (m != null && m instanceof ScrollPaneLayout) + { + ScrollPaneLayout sl = (ScrollPaneLayout) m; + sl.syncWithScrollPane(this); + } + } + + private void removeNonNull(Component c) + { + if (c != null) + remove(c); + } + + private void addNonNull(Component c) + { + if (c != null) + add(c); + } + + public void setComponentOrientation(ComponentOrientation co) + { + ComponentOrientation old = super.getComponentOrientation(); + super.setComponentOrientation(co); + firePropertyChange("componentOrientation", old, co); + sync(); + } + + public void setColumnHeader(JViewport h) + { + if (columnHeader == h) + return; + + JViewport old = columnHeader; + removeNonNull(old); + columnHeader = h; + addNonNull(h); + firePropertyChange("columnHeader", old, h); + sync(); + } + + public void setColumnHeaderView(Component c) + { + if (columnHeader == null) + setColumnHeader(createViewport()); + columnHeader.setView(c); + sync(); + } + + public void setCorner(String key, Component c) + { + if (getComponentOrientation() + == ComponentOrientation.LEFT_TO_RIGHT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_LEFT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_RIGHT_CORNER; + } + else if (getComponentOrientation() + == ComponentOrientation.RIGHT_TO_LEFT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_RIGHT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_LEFT_CORNER; + } + + if (key == LOWER_RIGHT_CORNER) + { + removeNonNull(lowerRight); + lowerRight = c; + addNonNull(c); + } + else if (key == UPPER_RIGHT_CORNER) + { + removeNonNull(upperRight); + upperRight = c; + addNonNull(c); + } + else if (key == LOWER_LEFT_CORNER) + { + removeNonNull(lowerLeft); + lowerLeft = c; + addNonNull(c); + } + else if (key == UPPER_LEFT_CORNER) + { + removeNonNull(upperLeft); + upperLeft = c; + addNonNull(c); + } + else + throw new IllegalArgumentException("unknown corner " + key); + sync(); + } + + public void setHorizontalScrollBar(JScrollBar h) + { + if (horizontalScrollBar == h) + return; + + JScrollBar old = horizontalScrollBar; + removeNonNull(old); + horizontalScrollBar = h; + addNonNull(h); + firePropertyChange("horizontalScrollBar", old, h); + sync(); + + if (old != null) + { + BoundedRangeModel model = old.getModel(); + if (model != null) + model.removeChangeListener(scrollListener); + } + if (h != null) + { + BoundedRangeModel model = h.getModel(); + if (model != null) + model.addChangeListener(scrollListener); + } + } + + public void setHorizontalScrollBarPolicy(int h) + { + if (horizontalScrollBarPolicy == h) + return; + + if (h != HORIZONTAL_SCROLLBAR_AS_NEEDED + && h != HORIZONTAL_SCROLLBAR_NEVER + && h != HORIZONTAL_SCROLLBAR_ALWAYS) + throw new IllegalArgumentException("unknown horizontal scrollbar policy"); + + int old = horizontalScrollBarPolicy; + horizontalScrollBarPolicy = h; + firePropertyChange("horizontalScrollBarPolicy", old, h); + sync(); + } + + public void setLayout(LayoutManager l) + { + LayoutManager old = super.getLayout(); + ScrollPaneLayout tmp = (ScrollPaneLayout) l; + super.setLayout(l); + tmp.syncWithScrollPane(this); + firePropertyChange("layout", old, l); + sync(); + } + + public void setRowHeader(JViewport v) + { + if (rowHeader == v) + return; + + JViewport old = rowHeader; + removeNonNull(old); + rowHeader = v; + addNonNull(v); + firePropertyChange("rowHeader", old, v); + sync(); + } + + public void setRowHeaderView(Component c) + { + if (rowHeader == null) + setRowHeader(createViewport()); + rowHeader.setView(c); + sync(); + } + + public void setVerticalScrollBar(JScrollBar v) + { + if (verticalScrollBar == v) + return; + + JScrollBar old = verticalScrollBar; + removeNonNull(old); + verticalScrollBar = v; + addNonNull(v); + firePropertyChange("verticalScrollBar", old, v); + sync(); + + if (old != null) + { + BoundedRangeModel model = old.getModel(); + if (model != null) + model.removeChangeListener(scrollListener); + } + if (v != null) + { + BoundedRangeModel model = v.getModel(); + if (model != null) + model.addChangeListener(scrollListener); + } + } + + public void setVerticalScrollBarPolicy(int v) + { + if (verticalScrollBarPolicy == v) + return; + + if (v != VERTICAL_SCROLLBAR_AS_NEEDED + && v != VERTICAL_SCROLLBAR_NEVER + && v != VERTICAL_SCROLLBAR_ALWAYS) + throw new IllegalArgumentException("unknown vertical scrollbar policy"); + + int old = verticalScrollBarPolicy; + verticalScrollBarPolicy = v; + firePropertyChange("verticalScrollBarPolicy", old, v); + sync(); + } + + public void setWheelScrollingEnabled(boolean b) + { + if (wheelScrollingEnabled == b) + return; + + boolean old = wheelScrollingEnabled; + wheelScrollingEnabled = b; + firePropertyChange("wheelScrollingEnabled", old, b); + sync(); + } + + public void setViewport(JViewport v) + { + if (viewport == v) + return; + + JViewport old = viewport; + removeNonNull(old); + if (old != null) + old.removeChangeListener(scrollListener); + viewport = v; + if (v != null) + v.addChangeListener(scrollListener); + addNonNull(v); + revalidate(); + repaint(); + firePropertyChange("viewport", old, v); + sync(); + } + + public void setViewportBorder(Border b) + { + if (viewportBorder == b) + return; + + Border old = viewportBorder; + viewportBorder = b; + firePropertyChange("viewportBorder", old, b); + sync(); + } + + public void setViewportView(Component view) + { + if (getViewport() == null) + { + setViewport(createViewport()); + } + + if (view != null) + { + getViewport().setView(view); + } + sync(); + } + + public boolean isValidateRoot() + { + return true; + } + + ChangeListener createScrollListener() + { + return new ChangeListener() + { + + public void stateChanged(ChangeEvent event) + { + JScrollBar vsb = JScrollPane.this.getVerticalScrollBar(); + JScrollBar hsb = JScrollPane.this.getHorizontalScrollBar(); + JViewport vp = JScrollPane.this.getViewport(); + + if (vp != null && event.getSource() == vp) + { + // if the viewport changed, we should update the VSB / HSB + // models according to the new vertical and horizontal sizes + + Rectangle vr = vp.getViewRect(); + Dimension vs = vp.getViewSize(); + if (vsb != null + && (vsb.getMinimum() != 0 + || vsb.getMaximum() != vs.height + || vsb.getValue() != vr.y + || vsb.getVisibleAmount() != vr.height)) + vsb.setValues(vr.y, vr.height, 0, vs.height); + + if (hsb != null + && (hsb.getMinimum() != 0 + || hsb.getMaximum() != vs.width + || hsb.getValue() != vr.width + || hsb.getVisibleAmount() != vr.height)) + hsb.setValues(vr.x, vr.width, 0, vs.width); + } + else + { + // otherwise we got a change update from either the VSB or + // HSB model, and we need to update the viewport positions of + // both the main viewport and any row or column headers to + // match. + + int xpos = 0; + int ypos = 0; + + if (vsb != null) + ypos = vsb.getValue(); + + if (hsb != null) + xpos = hsb.getValue(); + + Point pt = new Point(xpos, ypos); + + if (vp != null + && vp.getViewPosition() != pt) + vp.setViewPosition(pt); + + pt.x = 0; + + if (rowHeader != null + && rowHeader.getViewPosition() != pt) + rowHeader.setViewPosition(pt); + + pt.x = xpos; + pt.y = 0; + + if (columnHeader != null + && columnHeader.getViewPosition() != pt) + columnHeader.setViewPosition(pt); + + } + } + }; + } + + + /** + * Creates a new <code>JScrollPane</code> without a view. The scrollbar + * policy is set to {@link #VERTICAL_SCROLLBAR_AS_NEEDED} and + * {@link #HORIZONTAL_SCROLLBAR_AS_NEEDED}. + * + * @param view the component that is embedded inside the JScrollPane + */ + public JScrollPane() + { + this(null); + } + + /** + * Creates a new <code>JScrollPane</code> that embeds the specified + * <code>view</code> component, displaying vertical and horizontal scrollbars + * as needed. + * + * @param view the component that is embedded inside the JScrollPane + */ + public JScrollPane(Component view) + { + this(view, + VERTICAL_SCROLLBAR_AS_NEEDED, + HORIZONTAL_SCROLLBAR_AS_NEEDED); + } + + /** + * Creates a new <code>JScrollPane</code> without a view; The scrollbar + * policies are set to <code>vsbPolicy</code> and <code>hsbPolicy</code>. + * + * @param vsbPolicy the vertical scrollbar policy to set + * @param hsbPolicy the vertical scrollbar policy to set + * + * @see {@link ScrollPaneConstants#HORIZONTAL_SCROLLBAR_ALWAYS} + * @see {@link ScrollPaneConstants#HORIZONTAL_SCROLLBAR_AS_NEEDED} + * @see {@link ScrollPaneConstants#HORIZONTAL_SCROLLBAR_NEVER} + * @see {@link ScrollPaneConstants#VERTICAL_SCROLLBAR_ALWAYS} + * @see {@link ScrollPaneConstants#VERTICAL_SCROLLBAR_AS_NEEDED} + * @see {@link ScrollPaneConstants#VERTICAL_SCROLLBAR_NEVER} + */ + public JScrollPane(int vsbPolicy, int hsbPolicy) + { + this(null, vsbPolicy, hsbPolicy); + } + + /** + * Creates a new <code>JScrollPane</code> that embeds the specified + * <code>view</code> component; The scrollbar + * policies are set to <code>vsbPolicy</code> and <code>hsbPolicy</code>. + * + * @param vsbPolicy the vertical scrollbar policy to set + * @param hsbPolicy the vertical scrollbar policy to set + * + * @see {@link ScrollPaneConstants#HORIZONTAL_SCROLLBAR_ALWAYS} + * @see {@link ScrollPaneConstants#HORIZONTAL_SCROLLBAR_AS_NEEDED} + * @see {@link ScrollPaneConstants#HORIZONTAL_SCROLLBAR_NEVER} + * @see {@link ScrollPaneConstants#VERTICAL_SCROLLBAR_ALWAYS} + * @see {@link ScrollPaneConstants#VERTICAL_SCROLLBAR_AS_NEEDED} + * @see {@link ScrollPaneConstants#VERTICAL_SCROLLBAR_NEVER} + */ + public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) + { + scrollListener = createScrollListener(); + setVerticalScrollBarPolicy(vsbPolicy); + setVerticalScrollBar(createVerticalScrollBar()); + setHorizontalScrollBarPolicy(hsbPolicy); + setHorizontalScrollBar(createHorizontalScrollBar()); + viewport = createViewport(); + if (view != null) + getViewport().setView(view); + viewport.addChangeListener(scrollListener); + add(viewport,0); + setLayout(new ScrollPaneLayout()); + setOpaque(false); + updateUI(); + } + + + public JScrollBar createHorizontalScrollBar() + { + return new ScrollBar(SwingConstants.HORIZONTAL); + } + + public JScrollBar createVerticalScrollBar() + { + return new ScrollBar(SwingConstants.VERTICAL); + } + + protected JViewport createViewport() + { + return new JViewport(); + } + + public String getUIClassID() + { + return "ScrollPaneUI"; + } + + public void updateUI() + { + ScrollPaneUI b = (ScrollPaneUI)UIManager.getUI(this); + setUI(b); + } + + /** + * This method returns the scrollpane's UI delegate. + * + * @return The scrollpane's UI delegate. + */ + public ScrollPaneUI getUI() + { + return (ScrollPaneUI) ui; + } + + /** + * This method sets the scrollpane's UI delegate. + * + * @param ui The scrollpane's UI delegate. + */ + public void setUI(ScrollPaneUI ui) + { + super.setUI(ui); + } + + protected class ScrollBar + extends JScrollBar + implements UIResource + { + private static final long serialVersionUID = -42032395320987283L; + + public ScrollBar(int orientation) + { + super(orientation); + } + + public int getBlockIncrement(int direction) + { + Component view = JScrollPane.this.getViewport().getView(); + if (view == null || (! (view instanceof Scrollable))) + return super.getBlockIncrement(direction); + else + { + Scrollable s = (Scrollable) view; + return s.getScrollableBlockIncrement(JScrollPane.this.getViewport().getViewRect(), + this.getOrientation(), + direction); + } + } + + public int getUnitIncrement(int direction) + { + Component view = JScrollPane.this.getViewport().getView(); + if (view == null || (! (view instanceof Scrollable))) + return super.getUnitIncrement(direction); + else + { + Scrollable s = (Scrollable) view; + return s.getScrollableUnitIncrement(JScrollPane.this.getViewport().getViewRect(), + this.getOrientation(), + direction); + } + } + } +} diff --git a/libjava/classpath/javax/swing/JSeparator.java b/libjava/classpath/javax/swing/JSeparator.java new file mode 100644 index 00000000000..064c465b511 --- /dev/null +++ b/libjava/classpath/javax/swing/JSeparator.java @@ -0,0 +1,197 @@ +/* JSeparator.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.plaf.SeparatorUI; + + +/** + * The JSeparator. It is mostly used to divide/space out + * components. + */ +public class JSeparator extends JComponent implements SwingConstants, + Accessible +{ + /** + * AccessibleJSeparator + */ + protected class AccessibleJSeparator extends AccessibleJComponent + { + private static final long serialVersionUID = 916332890553201095L; + + /** + * Constructor AccessibleJSeparator + * + * @param component TODO + */ + protected AccessibleJSeparator() + { + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.SEPARATOR; + } + } + + private static final long serialVersionUID = 125301223445282357L; + + /** The orientation of the JSeparator. */ + private transient int orientation = HORIZONTAL; + + /** + * Creates a new horizontal JSeparator object. + */ + public JSeparator() + { + this(HORIZONTAL); + } + + /** + * Creates a new JSeparator object with the given orientation. + * + * @param orientation The orientation of the JSeparator. + */ + public JSeparator(int orientation) + { + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a valid orientation."); + this.orientation = orientation; + updateUI(); + } + + /** + * This method returns the UI delegate being + * used with the JSeparator. + * + * @return SeparatorUI The JSeparator's UI delegate. + */ + public SeparatorUI getUI() + { + return (SeparatorUI) ui; + } + + /** + * This method sets the UI delegate to use + * with the JSeparator. + * + * @param ui The UI delegate to use. + */ + public void setUI(SeparatorUI ui) + { + super.setUI(ui); + } + + /** + * This method resets the UI delegate to the + * default for the current look and feel. + */ + public void updateUI() + { + setUI((SeparatorUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns the identifier string + * that is used to determine the UI delegate + * from the current look and feel. + * + * @return String The identifier string for the UI. + */ + public String getUIClassID() + { + return "SeparatorUI"; + } + + /** + * This method returns the JSeparator's orientation. + * + * @return int The JSeparator's orientation. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method changes the JSeparator's orientation. + * + * @param orientation The JSeparator's orientation. + */ + public void setOrientation(int orientation) + { + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a valid orientation."); + this.orientation = orientation; + } + + /** + * This method returns a string desribing the JSeparator. + * Normally only used in debugging. + * + * @return String A string describing the JSeparator. + */ + protected String paramString() + { + return "JSeparator"; + } + + /** + * getAccessibleContext + * + * @return AccessibleContext + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJSeparator(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JSlider.java b/libjava/classpath/javax/swing/JSlider.java new file mode 100644 index 00000000000..7f995115d8f --- /dev/null +++ b/libjava/classpath/javax/swing/JSlider.java @@ -0,0 +1,907 @@ +/* JSlider.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Dimension; +import java.awt.MenuContainer; +import java.awt.image.ImageObserver; +import java.io.Serializable; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.Hashtable; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.SliderUI; + +/** + * The JSlider is a Swing component that allows selection of a value within a + * range by adjusting a thumb in a track. The values for the minimum, + * maximum, extent and value are stored in a {@link + * DefaultBoundedRangeModel}. + * + * <p> + * JSliders have the following properties: + * </p> + * + * <table> + * <tr><th> Property </th><th> Stored in </th><th> Bound? </th></tr> + * <tr><td> extent </td><td> model </td><td> no </td></tr> + * <tr><td> inverted </td><td> slider </td><td> yes </td></tr> + * <tr><td> labelTable </td><td> slider </td><td> yes </td></tr> + * <tr><td> majorTickSpacing </td><td> slider </td><td> yes </td></tr> + * <tr><td> maximum </td><td> model </td><td> no </td></tr> + * <tr><td> minimum </td><td> model </td><td> no </td></tr> + * <tr><td> minorTickSpacing </td><td> slider </td><td> yes </td></tr> + * <tr><td> model </td><td> slider </td><td> yes </td></tr> + * <tr><td> orientation </td><td> slider </td><td> yes </td></tr> + * <tr><td> paintLabels </td><td> slider </td><td> yes </td></tr> + * <tr><td> paintTicks </td><td> slider </td><td> yes </td></tr> + * <tr><td> snapToTicks </td><td> slider </td><td> no </td></tr> + * <tr><td> value </td><td> model </td><td> no </td></tr> + * <tr><td> valueIsAdjusting </td><td> model </td><td> no </td></tr> + * </table> + * + * <p> + * The various behavioral aspects of these properties follows: + * </p> + * + * <ul> + * <li> + * When non-bound properties stored in the slider change, the slider fires + * ChangeEvents to its ChangeListeners. + * </li> + * <li> + * When bound properties stored in the slider change, the slider fires + * PropertyChangeEvents to its PropertyChangeListeners + * </li> + * <li> + * If any of the model's properties change, it fires a ChangeEvent to its + * ChangeListeners, which include the slider. + * </li> + * <li> + * If the slider receives a ChangeEvent from its model, it will propagate the + * ChangeEvent to its ChangeListeners, with the ChangeEvent's "source" + * property set to refer to the slider, rather than the model. + * </li> + * </ul> + */ +public class JSlider extends JComponent implements SwingConstants, Accessible, + ImageObserver, + MenuContainer, Serializable +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = -1441275936141218479L; + + /** + * DOCUMENT ME! + */ + protected class AccessibleJSlider extends JComponent.AccessibleJComponent + implements AccessibleValue + { + private static final long serialVersionUID = -6301740148041106789L; + + /** + * Creates a new AccessibleJSlider object. + * + * @param value0 DOCUMENT ME! + */ + protected AccessibleJSlider() + { + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * setCurrentAccessibleValue + * + * @param value0 TODO + * + * @return boolean + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * getMinimumAccessibleValue + * + * @return Number + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * getMaximumAccessibleValue + * + * @return Number + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + /** Whether or not this slider paints its ticks. */ + private transient boolean paintTicks = false; + + /** Whether or not this slider paints its track. */ + private transient boolean paintTrack = true; + + /** Whether or not this slider paints its labels. */ + private transient boolean paintLabels = false; + + /** + * A dictionary of (Integer, Component) pairs where each Component is a + * JLabel and the Integer determines where the label will be painted. + */ + private transient Dictionary labelTable; + + /** The model used to describe the slider. */ + protected BoundedRangeModel sliderModel; + + /** The space between major ticks. */ + protected int majorTickSpacing; + + /** The space between minor ticks. */ + protected int minorTickSpacing; + + /** Whether the slider snaps its values to ticks. */ + protected boolean snapToTicks = true; + + /** The orientation of the slider. */ + protected int orientation = HORIZONTAL; + + /** Whether the slider is inverted. */ + private transient boolean isInverted; + + /** The ChangeListener that listens to the model. */ + protected ChangeListener changeListener; + + /** The ChangeEvent that is passed to all listeners of this slider. */ + protected transient ChangeEvent changeEvent; + + /** + * Creates a new horizontal JSlider object with a minimum of 0, a maximum of + * 100, and a value of 50. + */ + public JSlider() + { + this(HORIZONTAL, 0, 100, 50); + } + + /** + * Creates a new JSlider object with the given orientation and a minimum of + * 0, a maximum of 100, and a value of 50. + * + * @param orientation The orientation of the slider. + */ + public JSlider(int orientation) + { + this(orientation, 0, 100, 50); + } + + /** + * Creates a new horizontal JSlider object with the given maximum and + * minimum and a value that is halfway between the minimum and the + * maximum. + * + * @param minimum The minimum value of the JSlider. + * @param maximum The maximum value of the JSlider. + */ + public JSlider(int minimum, int maximum) + { + this(HORIZONTAL, minimum, maximum, (maximum + minimum) / 2); + } + + /** + * Creates a new horizontal JSlider object with the given minimum, maximum, + * and value. + * + * @param minimum The minimum value of the JSlider. + * @param maximum The maximum value of the JSlider. + * @param value The initial value of the JSlider. + */ + public JSlider(int minimum, int maximum, int value) + { + this(HORIZONTAL, minimum, maximum, value); + } + + /** + * Creates a new JSlider object with the given orientation, minimum, + * maximum, and value. + * + * @param orientation The orientation of the JSlider. + * @param minimum The minimum value of the JSlider. + * @param maximum The maximum value of the JSlider. + * @param value The initial value of the JSlider. + */ + public JSlider(int orientation, int minimum, int maximum, int value) + { + sliderModel = new DefaultBoundedRangeModel(value, 0, minimum, maximum); + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + " is not a legal orientation"); + this.orientation = orientation; + changeListener = createChangeListener(); + sliderModel.addChangeListener(changeListener); + updateUI(); + } + + /** + * Creates a new horizontal JSlider object with the given model. + * + * @param model The model the slider will be created with. + */ + public JSlider(BoundedRangeModel model) + { + if (model == null) + sliderModel = new DefaultBoundedRangeModel(50, 0, 0, 100); + else + sliderModel = model; + changeListener = createChangeListener(); + sliderModel.addChangeListener(changeListener); + updateUI(); + } + + /** + * This method returns the current value of the slider. + * + * @return The value of the slider stored in the model. + */ + public int getValue() + { + return sliderModel.getValue(); + } + + /** + * This method sets the value of the slider. + * + * @param value The slider's new value. + */ + public void setValue(int value) + { + sliderModel.setValue(value); + } + + /** + * This method returns the slider's UI delegate. + * + * @return The slider's UI delegate. + */ + public SliderUI getUI() + { + return (SliderUI) ui; + } + + /** + * This method sets the slider's UI delegate. + * + * @param ui A SliderUI object to use with this slider. + */ + public void setUI(SliderUI ui) + { + super.setUI(ui); + } + + /** + * This method sets this slider's UI to the UIManager's default for the + * current look and feel. + */ + public void updateUI() + { + setUI((SliderUI) UIManager.getUI(this)); + invalidate(); + repaint(); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the slider. + * + * @return The Look and Feel classID. "SliderUI" + */ + public String getUIClassID() + { + return "SliderUI"; + } + + /** + * Creates a ChangeListener for this Slider. + * + * @return A new ChangeListener. + */ + protected ChangeListener createChangeListener() + { + return new ChangeListener() + { + public void stateChanged(ChangeEvent ce) + { + // No need to trigger a repaint since the UI listens to the model + // as well. All we need to do is pass on the stateChanged event + // to our listeners. + fireStateChanged(); + } + }; + } + + /** + * This method registers a listener to this slider. The listener will be + * informed of new ChangeEvents. + * + * @param listener The listener to register. + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * This method removes a listener from this slider. + * + * @param listener The listener to remove. + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * This method is called whenever the model fires a ChangeEvent. It should + * propagate the ChangeEvent to its listeners with a new ChangeEvent that + * identifies the slider as the source. + */ + protected void fireStateChanged() + { + Object[] changeListeners = listenerList.getListenerList(); + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + for (int i = changeListeners.length - 2; i >= 0; i -= 2) + { + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + } + } + + /** + * This method returns an array of all ChangeListeners listening to this + * slider. + * + * @return An array of ChangeListeners listening to this slider. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * This method returns the model of the slider. + * + * @return The slider's model. + */ + public BoundedRangeModel getModel() + { + return sliderModel; + } + + /** + * This method changes the "model" property. It also needs to unregister + * any listeners to the old model and register any listeners to the new + * model. + * + * @param model The model to use with the slider. + */ + public void setModel(BoundedRangeModel model) + { + // I didn't do the null pointer check on purpose. + // If you try it with Sun's, it'll go ahead and set it to null + // and bork the next time it tries to access the model. + if (model != sliderModel) + { + BoundedRangeModel oldModel = sliderModel; + sliderModel = model; + oldModel.removeChangeListener(changeListener); + sliderModel.addChangeListener(changeListener); + firePropertyChange("model", oldModel, sliderModel); + } + } + + /** + * This method returns the minimum value of the slider. + * + * @return The minimum value of the slider. + */ + public int getMinimum() + { + return sliderModel.getMinimum(); + } + + /** + * This method sets the minimum value of the slider. + * + * @param minimum The minimum value of the slider. + */ + public void setMinimum(int minimum) + { + sliderModel.setMinimum(minimum); + } + + /** + * This method returns the maximum value of the slider. + * + * @return The maximum value of the slider. + */ + public int getMaximum() + { + return sliderModel.getMaximum(); + } + + /** + * This method sets the maximum value of the slider. + * + * @param maximum The maximum value of the slider. + */ + public void setMaximum(int maximum) + { + sliderModel.setMaximum(maximum); + } + + /** + * This method returns this slider's isAdjusting value which is true if the + * thumb is being dragged. + * + * @return The slider's isAdjusting value. + */ + public boolean getValueIsAdjusting() + { + return sliderModel.getValueIsAdjusting(); + } + + /** + * This method sets the isAdjusting value for the slider. + * + * @param adjusting The slider's isAdjusting value. + */ + public void setValueIsAdjusting(boolean adjusting) + { + sliderModel.setValueIsAdjusting(adjusting); + } + + /** + * This method returns the extent value for this slider. + * + * @return The extent value for this slider. + */ + public int getExtent() + { + return sliderModel.getExtent(); + } + + /** + * This method sets the extent value for this slider. + * + * @param extent The extent value for this slider. + */ + public void setExtent(int extent) + { + sliderModel.setExtent(extent); + } + + /** + * This method returns the slider orientation. + * + * @return The orientation of the slider. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method changes the "orientation" property of this slider. If the + * orientation is not VERTICAL or HORIZONTAL, this method does nothing. + * + * @param orientation The orientation of this slider. + */ + public void setOrientation(int orientation) + { + if (orientation != VERTICAL && orientation != HORIZONTAL) + throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL"); + if (orientation != this.orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange("orientation", oldOrientation, + this.orientation); + } + } + + /** + * This method returns the label table for this slider. + * + * @return The label table for this slider. + */ + public Dictionary getLabelTable() + { + return labelTable; + } + + /** + * This method changes the "labelTable" property of this slider. + * + * @param table The label table for this slider. + */ + public void setLabelTable(Dictionary table) + { + if (table != labelTable) + { + Dictionary oldTable = labelTable; + labelTable = table; + firePropertyChange("labelTable", oldTable, labelTable); + } + } + + /** + * This method is called to reset UI delegates for the labels in the + * labelTable to a default for the current look and feel. + */ + protected void updateLabelUIs() + { + if (labelTable == null) + return; + for (Enumeration list = labelTable.elements(); list.hasMoreElements();) + { + JLabel label = (JLabel) list.nextElement(); + label.updateUI(); + } + } + + /** + * Creates a hashtable of (Integer, JLabel) pairs that can be used as a + * label table for this slider. The labels will start from the sliders + * minimum and increase by the increment. Each label will have a text + * string indicating their integer value. + * + * @param increment The increment to between labels. + * + * @return A hashtable with the labels and their keys. + */ + public Hashtable createStandardLabels(int increment) + { + return createStandardLabels(increment, sliderModel.getMinimum()); + } + + /** + * Creates a hashtable of (Integer, JLabel) pairs that can be used as a + * label table for this slider. The labels will start from the given start + * value and increase by the increment. Each label will have a text string + * indicating their integer value. + * + * @param increment The increment to between labels. + * @param start The value to start from. + * + * @return A hashtable with the labels and their keys. + */ + public Hashtable createStandardLabels(int increment, int start) + { + Hashtable table = new Hashtable(); + JLabel label; + Dimension dim; + + int max = sliderModel.getMaximum(); + + for (int i = start; i <= max; i += increment) + { + label = new JLabel(String.valueOf(i)); + label.setVerticalAlignment(CENTER); + label.setHorizontalAlignment(CENTER); + + // Make sure these labels have the width and height + // they want. + dim = label.getPreferredSize(); + label.setBounds(label.getX(), label.getY(), + (int) dim.getWidth(), + (int) dim.getHeight()); + table.put(new Integer(i), label); + } + return table; + } + + /** + * This method returns whether the slider is inverted. Horizontal sliders + * that are not inverted will have the minimums on the left. If they are + * inverted, the minimums will be on the right. Vertical sliders that are + * not inverted will have the minimums at the bottom. If they are inverted, + * the minimums will be at the top. + * + * @return Whether this slider is inverted. + */ + public boolean getInverted() + { + return isInverted; + } + + /** + * This method changes the "inverted" property for this slider.Horizontal + * sliders that are not inverted will have the minimums on the left. If + * they are inverted, the minimums will be on the right. Vertical sliders + * that are not inverted will have the minimums at the bottom. If they are + * inverted, the minimums will be at the top. However, if the slider's + * componentOrientation is set to RIGHT_TO_LEFT, then everything gets + * reversed again. + * + * @param inverted Whether the slider should be inverted. + */ + public void setInverted(boolean inverted) + { + if (isInverted != inverted) + { + boolean oldInverted = isInverted; + isInverted = inverted; + firePropertyChange("inverted", oldInverted, isInverted); + } + } + + /** + * This method returns the amount of units between each major tick mark. + * + * @return The amount of units between each major tick mark. + */ + public int getMajorTickSpacing() + { + return majorTickSpacing; + } + + /** + * This method changes the "majorTickSpacing" property for this slider. The + * major tick spacing is the amount of units between each major tick mark. + * + * @param spacing The amount of units between each major tick mark. + */ + public void setMajorTickSpacing(int spacing) + { + if (majorTickSpacing != spacing) + { + int oldSpacing = majorTickSpacing; + majorTickSpacing = spacing; + firePropertyChange("majorTickSpacing", oldSpacing, + majorTickSpacing); + } + } + + /** + * This method returns the amount of units between each minor tick mark. + * + * @return The amount of units between each minor tick mark. + */ + public int getMinorTickSpacing() + { + return minorTickSpacing; + } + + /** + * This method changes the "minorTickSpacing" property for this slider. The + * minor tick spacing is the amount of units between each minor tick mark. + * + * @param spacing The amount of units between each minor tick mark. + */ + public void setMinorTickSpacing(int spacing) + { + if (minorTickSpacing != spacing) + { + int oldSpacing = minorTickSpacing; + minorTickSpacing = spacing; + firePropertyChange("minorTickSpacing", oldSpacing, + minorTickSpacing); + } + } + + /** + * This method returns whether this slider is snapping to ticks. Sliders + * that snap to ticks will automatically move the thumb to the nearest tick + * mark. + * + * @return Whether this slider snaps to ticks. + */ + public boolean getSnapToTicks() + { + return snapToTicks; + } + + /** + * This method sets whether this slider will snap to ticks. Sliders that + * snap to ticks will automatically move the thumb to the nearest tick + * mark. + * + * @param snap Whether this slider snaps to ticks. + */ + public void setSnapToTicks(boolean snap) + { + if (snap != snapToTicks) + { + snapToTicks = snap; + fireStateChanged(); + } + } + + /** + * This method returns whether the slider will paint its tick marks. In + * addition to setting this property to true, one of minor tick spacing or + * major tick spacing must be set to a value greater than 0 in order for + * ticks to be painted. + * + * @return Whether ticks will be painted. + */ + public boolean getPaintTicks() + { + return paintTicks; + } + + /** + * This method changes the "paintTicks" property for this slider. In + * addition to setting this property to true, one of minor tick spacing or + * major tick spacing must be set to a value greater than 0 in order for + * ticks to be painted. + * + * @param paint Whether ticks will be painted. + */ + public void setPaintTicks(boolean paint) + { + if (paint != paintTicks) + { + boolean oldPaintTicks = paintTicks; + paintTicks = paint; + firePropertyChange("paintTicks", oldPaintTicks, paintTicks); + } + } + + /** + * This method returns whether the track will be painted. + * + * @return Whether the track will be painted. + */ + public boolean getPaintTrack() + { + return paintTrack; + } + + /** + * This method sets whether the track will be painted. + * + * @param paint Whether the track will be painted. + */ + public void setPaintTrack(boolean paint) + { + paintTrack = paint; + } + + /** + * This method returns whether labels will be painted. + * + * @return Whether labels will be painted. + */ + public boolean getPaintLabels() + { + return paintLabels; + } + + /** + * This method changes the "paintLabels" property. + * + * @param paint Whether labels will be painted. + */ + public void setPaintLabels(boolean paint) + { + if (paint != paintLabels) + { + boolean oldPaintLabels = paintLabels; + paintLabels = paint; + firePropertyChange("paintLabels", oldPaintLabels, paintLabels); + } + } + + /** + * This method is used primarily for debugging purposes and returns a string + * that can be used to represent this slider. + * + * @return A string representing this slider. + */ + protected String paramString() + { + return "JSlider"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJSlider(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JSpinner.java b/libjava/classpath/javax/swing/JSpinner.java new file mode 100644 index 00000000000..96fe10f7268 --- /dev/null +++ b/libjava/classpath/javax/swing/JSpinner.java @@ -0,0 +1,622 @@ +/* JSpinner.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +import javax.swing.border.EtchedBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.SpinnerUI; +import javax.swing.text.DateFormatter; + +/** + * A JSpinner is a component which typically contains a numeric value and a + * way to manipulate the value. + * + * @author Ka-Hing Cheung + * + * @since 1.4 + */ +public class JSpinner extends JComponent +{ + /** + * DOCUMENT ME! + */ + public static class DefaultEditor extends JPanel implements ChangeListener, + PropertyChangeListener, + LayoutManager + { + private JSpinner spinner; + + /** The JFormattedTextField that backs the editor. */ + JFormattedTextField ftf; + + /** + * For compatability with Sun's JDK 1.4.2 rev. 5 + */ + private static final long serialVersionUID = -5317788736173368172L; + + /** + * Creates a new <code>DefaultEditor</code> object. + * + * @param spinner the <code>JSpinner</code> associated with this editor + */ + public DefaultEditor(JSpinner spinner) + { + super(); + setLayout(this); + this.spinner = spinner; + ftf = new JFormattedTextField(); + add(ftf); + ftf.setValue(spinner.getValue()); + spinner.addChangeListener(this); + } + + /** + * Returns the <code>JSpinner</code> object for this editor. + */ + public JSpinner getSpinner() + { + return spinner; + } + + /** + * DOCUMENT ME! + */ + public void commitEdit() + throws ParseException + { + } /* TODO */ + + /** + * DOCUMENT ME! + * + * @param spinner DOCUMENT ME! + */ + public void dismiss(JSpinner spinner) + { + spinner.removeChangeListener(this); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JFormattedTextField getTextField() + { + return ftf; + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + */ + public void layoutContainer(Container parent) + { + Insets insets = getInsets(); + Dimension size = getSize(); + ftf.setBounds(insets.left, insets.top, + size.width - insets.left - insets.right, + size.height - insets.top - insets.bottom); + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension minimumLayoutSize(Container parent) + { + Insets insets = getInsets(); + Dimension minSize = ftf.getMinimumSize(); + return new Dimension(minSize.width + insets.left + insets.right, + minSize.height + insets.top + insets.bottom); + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension preferredLayoutSize(Container parent) + { + Insets insets = getInsets(); + Dimension prefSize = ftf.getPreferredSize(); + return new Dimension(prefSize.width + insets.left + insets.right, + prefSize.height + insets.top + insets.bottom); + } + + /** + * DOCUMENT ME! + * + * @param event DOCUMENT ME! + */ + public void propertyChange(PropertyChangeEvent event) + { + } /* TODO */ + + /** + * DOCUMENT ME! + * + * @param event DOCUMENT ME! + */ + public void stateChanged(ChangeEvent event) + { + } /* TODO */ + + /* no-ops */ + public void removeLayoutComponent(Component child) + { + } + + /** + * DOCUMENT ME! + * + * @param name DOCUMENT ME! + * @param child DOCUMENT ME! + */ + public void addLayoutComponent(String name, Component child) + { + } + } + + /** + * DOCUMENT ME! + */ + public static class NumberEditor extends DefaultEditor + { + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 3791956183098282942L; + + /** + * Creates a new NumberEditor object. + * + * @param spinner DOCUMENT ME! + */ + public NumberEditor(JSpinner spinner) + { + super(spinner); + } + + /** + * Creates a new NumberEditor object. + * + * @param spinner DOCUMENT ME! + */ + public NumberEditor(JSpinner spinner, String decimalFormatPattern) + { + super(spinner); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public DecimalFormat getFormat() + { + return null; + } + + public SpinnerNumberModel getModel() + { + return (SpinnerNumberModel) getSpinner().getModel(); + } + } + + /** + * An editor class for a <code>JSpinner</code> that is used + * for displaying and editing dates (e.g. that uses + * <code>SpinnerDateModel</code> as model). + * + * The editor uses a {@link JTextField} with the value + * displayed by a {@link DateFormatter} instance. + */ + public static class DateEditor extends DefaultEditor + { + + /** The serialVersionUID. */ + private static final long serialVersionUID = -4279356973770397815L; + + /** The DateFormat instance used to format the date. */ + SimpleDateFormat dateFormat; + + /** + * Creates a new instance of DateEditor for the specified + * <code>JSpinner</code>. + * + * @param spinner the <code>JSpinner</code> for which to + * create a <code>DateEditor</code> instance + */ + public DateEditor(JSpinner spinner) + { + super(spinner); + init(new SimpleDateFormat()); + } + + /** + * Creates a new instance of DateEditor for the specified + * <code>JSpinner</code> using the specified date format + * pattern. + * + * @param spinner the <code>JSpinner</code> for which to + * create a <code>DateEditor</code> instance + * @param dateFormatPattern the date format to use + * + * @see SimpleDateFormat(String) + */ + public DateEditor(JSpinner spinner, String dateFormatPattern) + { + super(spinner); + init(new SimpleDateFormat(dateFormatPattern)); + } + + /** + * Initializes the JFormattedTextField for this editor. + * + * @param the date format to use in the formatted text field + */ + private void init(SimpleDateFormat format) + { + dateFormat = format; + getTextField().setFormatterFactory( + new JFormattedTextField.AbstractFormatterFactory() + { + public JFormattedTextField.AbstractFormatter + getFormatter(JFormattedTextField ftf) + { + return new DateFormatter(dateFormat); + } + }); + } + + /** + * Returns the <code>SimpleDateFormat</code> instance that is used to + * format the date value. + * + * @return the <code>SimpleDateFormat</code> instance that is used to + * format the date value + */ + public SimpleDateFormat getFormat() + { + return dateFormat; + } + + /** + * Returns the {@link SpinnerDateModel} that is edited by this editor. + * + * @return the <code>SpinnerDateModel</code> that is edited by this editor + */ + public SpinnerDateModel getModel() + { + return (SpinnerDateModel) getSpinner().getModel(); + } + } + + private static final long serialVersionUID = 3412663575706551720L; + + /** DOCUMENT ME! */ + private SpinnerModel model; + + /** DOCUMENT ME! */ + private JComponent editor; + + /** DOCUMENT ME! */ + private ChangeListener listener = new ChangeListener() + { + public void stateChanged(ChangeEvent evt) + { + fireStateChanged(); + } + }; + + /** + * Creates a JSpinner with <code>SpinnerNumberModel</code> + * + * @see javax.swing.SpinnerNumberModel + */ + public JSpinner() + { + this(new SpinnerNumberModel()); + } + + /** + * Creates a JSpinner with the specific model and sets the default editor + * + * @param model DOCUMENT ME! + */ + public JSpinner(SpinnerModel model) + { + this.model = model; + model.addChangeListener(listener); + setEditor(createEditor(model)); + updateUI(); + } + + /** + * If the editor is <code>JSpinner.DefaultEditor</code>, then forwards the + * call to it, otherwise do nothing. + * + * @throws ParseException DOCUMENT ME! + */ + public void commitEdit() throws ParseException + { + if (editor instanceof DefaultEditor) + ((DefaultEditor) editor).commitEdit(); + } + + /** + * Gets the current editor + * + * @return the current editor + * + * @see #setEditor + */ + public JComponent getEditor() + { + return editor; + } + + /** + * Changes the current editor to the new editor. This methods should remove + * the old listeners (if any) and adds the new listeners (if any). + * + * @param editor the new editor + * + * @throws IllegalArgumentException DOCUMENT ME! + * + * @see #getEditor + */ + public void setEditor(JComponent editor) + { + if (editor == null) + throw new IllegalArgumentException("editor may not be null"); + + if (this.editor instanceof DefaultEditor) + ((DefaultEditor) editor).dismiss(this); + else if (this.editor instanceof ChangeListener) + removeChangeListener((ChangeListener) this.editor); + + if (editor instanceof ChangeListener) + addChangeListener((ChangeListener) editor); + + this.editor = editor; + } + + /** + * Gets the underly model. + * + * @return the underly model + */ + public SpinnerModel getModel() + { + return model; + } + + /** + * Sets a new underlying model. + * + * @param newModel the new model to set + * + * @exception IllegalArgumentException if newModel is <code>null</code> + */ + public void setModel(SpinnerModel newModel) + { + if (newModel == null) + throw new IllegalArgumentException(); + + if (model == newModel) + return; + + SpinnerModel oldModel = model; + model = newModel; + firePropertyChange("model", oldModel, newModel); + + if (editor == null) + setEditor(createEditor(model)); + } + + /** + * Gets the next value without changing the current value. + * + * @return the next value + * + * @see javax.swing.SpinnerModel#getNextValue + */ + public Object getNextValue() + { + return model.getNextValue(); + } + + /** + * Gets the previous value without changing the current value. + * + * @return the previous value + * + * @see javax.swing.SpinnerModel#getPreviousValue + */ + public Object getPreviousValue() + { + return model.getPreviousValue(); + } + + /** + * Gets the <code>SpinnerUI</code> that handles this spinner + * + * @return the <code>SpinnerUI</code> + */ + public SpinnerUI getUI() + { + return (SpinnerUI) ui; + } + + /** + * Gets the current value of the spinner, according to the underly model, + * not the UI. + * + * @return the current value + * + * @see javax.swing.SpinnerModel#getValue + */ + public Object getValue() + { + return model.getValue(); + } + + /** + * DOCUMENT ME! + * + * @param value DOCUMENT ME! + */ + public void setValue(Object value) + { + model.setValue(value); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for this spinner. + * + * @return The UIClass identifier. "SpinnerUI" + */ + public String getUIClassID() + { + return "SpinnerUI"; + } + + /** + * This method resets the spinner's UI delegate to the default UI for the + * current look and feel. + */ + public void updateUI() + { + setUI((SpinnerUI) UIManager.getUI(this)); + } + + /** + * This method sets the spinner's UI delegate. + * + * @param ui The spinner's UI delegate. + */ + public void setUI(SpinnerUI ui) + { + super.setUI(ui); + } + + /** + * Adds a <code>ChangeListener</code> + * + * @param listener the listener to add + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * Remove a particular listener + * + * @param listener the listener to remove + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * Gets all the <code>ChangeListener</code>s + * + * @return all the <code>ChangeListener</code>s + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Fires a <code>ChangeEvent</code> to all the <code>ChangeListener</code>s + * added to this <code>JSpinner</code> + */ + protected void fireStateChanged() + { + ChangeEvent evt = new ChangeEvent(this); + ChangeListener[] listeners = getChangeListeners(); + + for (int i = 0; i < listeners.length; ++i) + listeners[i].stateChanged(evt); + } + + /** + * Creates an editor for this <code>JSpinner</code>. Really, it should be a + * <code>JSpinner.DefaultEditor</code>, but since that should be + * implemented by a JFormattedTextField, and one is not written, I am just + * using a dummy one backed by a JLabel. + * + * @param model DOCUMENT ME! + * + * @return the default editor + */ + protected JComponent createEditor(SpinnerModel model) + { + if (model instanceof SpinnerDateModel) + return new DateEditor(this); + else if (model instanceof SpinnerNumberModel) + return new NumberEditor(this); + else + return new DefaultEditor(this); + } +} diff --git a/libjava/classpath/javax/swing/JSplitPane.java b/libjava/classpath/javax/swing/JSplitPane.java new file mode 100644 index 00000000000..d7abce99a7c --- /dev/null +++ b/libjava/classpath/javax/swing/JSplitPane.java @@ -0,0 +1,815 @@ +/* JSplitPane.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Graphics; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; +import javax.swing.plaf.SplitPaneUI; + +/** + * This class implements JSplitPane. It is used to divide two components. By + * dragging the SplitPane's divider, the user can resize the two components. + * Note that the divider cannot resize a component to smaller than it's + * minimum size. + */ +public class JSplitPane extends JComponent implements Accessible +{ + /** + * DOCUMENT ME! + */ + protected class AccessibleJSplitPane extends JComponent.AccessibleJComponent + implements AccessibleValue + { + private static final long serialVersionUID = -1788116871416305366L; + + /** + * Creates a new AccessibleJSplitPane object. + * + * @param value0 DOCUMENT ME! + */ + protected AccessibleJSplitPane() + { + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param value0 DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + private static final long serialVersionUID = -5634142046175988380L; + + /** The constraints string used to add components to the bottom. */ + public static final String BOTTOM = "bottom"; + + /** The property fired when the continuousLayout property changes. */ + public static final String CONTINUOUS_LAYOUT_PROPERTY = "continuousLayout"; + + /** The property fired when the divider property changes. */ + public static final String DIVIDER = "divider"; + + /** The property fired when the divider location property changes. */ + public static final String DIVIDER_LOCATION_PROPERTY = "dividerLocation"; + + /** The property fired when the divider size property changes. */ + public static final String DIVIDER_SIZE_PROPERTY = "dividerSize"; + + /** + * The value of the orientation when the components are split horizontally. + */ + public static final int HORIZONTAL_SPLIT = 1; + + /** The property fired when the last divider location property changes. */ + public static final String LAST_DIVIDER_LOCATION_PROPERTY = "lastDividerLocation"; + + /** The constraints string used to add components to the left. */ + public static final String LEFT = "left"; + + /** The property fired when the one touch expandable property changes. */ + public static final String ONE_TOUCH_EXPANDABLE_PROPERTY = "oneTouchExpandable"; + + /** The property fired when the orientation property changes. */ + public static final String ORIENTATION_PROPERTY = "orientation"; + + /** The property fired when the resize weight property changes. */ + public static final String RESIZE_WEIGHT_PROPERTY = "resizeWeight"; + + /** The constraints string used to add components to the right. */ + public static final String RIGHT = "right"; + + /** The constraints string used to add components to the top. */ + public static final String TOP = "top"; + + /** The value of the orientation when the components are split vertically. */ + public static final int VERTICAL_SPLIT = 0; + + /** Whether the JSplitPane uses continuous layout. */ + protected boolean continuousLayout; + + /** Whether the JSplitPane uses one touch expandable buttons. */ + protected boolean oneTouchExpandable = false; + + // This is the master dividerSize variable and sets the BasicSplitPaneDivider one accordingly + + /** The size of the divider. */ + protected int dividerSize = 10; + + /** The last location of the divider given by the UI. */ + protected int lastDividerLocation; + + /** The orientation of the JSplitPane. */ + protected int orientation; + + /** The component on the top or left. */ + protected Component leftComponent; + + /** The component on the right or bottom. */ + protected Component rightComponent; + + /** Determines how extra space should be allocated. */ + private transient double resizeWeight; + + /** + * Creates a new JSplitPane object with the given orientation, layout mode, + * and left and right components. + * + * @param newOrientation The orientation to use. + * @param newContinuousLayout The layout mode to use. + * @param newLeftComponent The left component. + * @param newRightComponent The right component. + * + * @throws IllegalArgumentException DOCUMENT ME! + */ + public JSplitPane(int newOrientation, boolean newContinuousLayout, + Component newLeftComponent, Component newRightComponent) + { + if (newOrientation != HORIZONTAL_SPLIT && newOrientation != VERTICAL_SPLIT) + throw new IllegalArgumentException("orientation is invalid."); + orientation = newOrientation; + continuousLayout = newContinuousLayout; + setLeftComponent(newLeftComponent); + setRightComponent(newRightComponent); + + updateUI(); + } + + /** + * Creates a new JSplitPane object using nonContinuousLayout mode, the given + * orientation and left and right components. + * + * @param newOrientation The orientation to use. + * @param newLeftComponent The left component. + * @param newRightComponent The right component. + */ + public JSplitPane(int newOrientation, Component newLeftComponent, + Component newRightComponent) + { + this(newOrientation, false, newLeftComponent, newRightComponent); + } + + /** + * Creates a new JSplitPane object with the given layout mode and + * orientation. + * + * @param newOrientation The orientation to use. + * @param newContinuousLayout The layout mode to use. + */ + public JSplitPane(int newOrientation, boolean newContinuousLayout) + { + this(newOrientation, newContinuousLayout, null, null); + } + + /** + * Creates a new JSplitPane object using a nonContinuousLayout mode and the + * given orientation. + * + * @param newOrientation The orientation to use. + */ + public JSplitPane(int newOrientation) + { + this(newOrientation, false, null, null); + } + + /** + * Creates a new JSplitPane object using HORIZONTAL_SPLIT and a + * nonContinuousLayout mode. + */ + public JSplitPane() + { + this(HORIZONTAL_SPLIT, false, null, null); + } + + /** + * This method adds a component to the JSplitPane. The constraints object is + * a string that identifies where this component should go. If the + * constraints is not a known one, it will throw an + * IllegalArgumentException. The valid constraints are LEFT, TOP, RIGHT, + * BOTTOM and DIVIDER. + * + * @param comp The component to add. + * @param constraints The constraints string to use. + * @param index Where to place to component in the list of components. + * + * @throws IllegalArgumentException When the constraints is not a known identifier. + */ + protected void addImpl(Component comp, Object constraints, int index) + { + int left = 0; + int right = 1; + int div = 2; + int place; + if (constraints == null) + { + if (leftComponent == null) + constraints = LEFT; + else if (rightComponent == null) + constraints = RIGHT; + } + + if (constraints instanceof String) + { + String placement = (String) constraints; + + if (placement.equals(BOTTOM) || placement.equals(RIGHT)) + { + if (rightComponent != null) + remove(rightComponent); + rightComponent = comp; + } + else if (placement.equals(LEFT) || placement.equals(TOP)) + { + if (leftComponent != null) + remove(leftComponent); + leftComponent = comp; + } + else if (placement.equals(DIVIDER)) + constraints = null; + else + throw new IllegalArgumentException("Constraints is not a known identifier."); + + super.addImpl(comp, constraints, index); + } + invalidate(); + layout(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJSplitPane(); + + return accessibleContext; + } + + /** + * This method returns the bottom component. + * + * @return The bottom component. + */ + public Component getBottomComponent() + { + return rightComponent; + } + + /** + * This method returns the location of the divider. This method is passed to + * the UI. + * + * @return The location of the divider. + */ + public int getDividerLocation() + { + if (ui != null) + return ((SplitPaneUI) ui).getDividerLocation(this); + else + return -1; + } + + /** + * This method returns the size of the divider. + * + * @return The size of the divider. + */ + public int getDividerSize() + { + return dividerSize; + } + + /** + * This method returns the last divider location. + * + * @return The last divider location. + */ + public int getLastDividerLocation() + { + return lastDividerLocation; + } + + /** + * This method returns the left component. + * + * @return The left component. + */ + public Component getLeftComponent() + { + return leftComponent; + } + + /** + * This method returns the maximum divider location. This method is passed + * to the UI. + * + * @return DOCUMENT ME! + */ + public int getMaximumDividerLocation() + { + if (ui != null) + return ((SplitPaneUI) ui).getMaximumDividerLocation(this); + else + return -1; + } + + /** + * This method returns the minimum divider location. This method is passed + * to the UI. + * + * @return The minimum divider location. + */ + public int getMinimumDividerLocation() + { + if (ui != null) + return ((SplitPaneUI) ui).getMinimumDividerLocation(this); + else + return -1; + } + + /** + * This method returns the orientation that the JSplitPane is using. + * + * @return The current orientation. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method returns the current resize weight. + * + * @return The current resize weight. + */ + public double getResizeWeight() + { + return resizeWeight; + } + + /** + * This method returns the right component. + * + * @return The right component. + */ + public Component getRightComponent() + { + return rightComponent; + } + + /** + * This method returns the top component. + * + * @return The top component. + */ + public Component getTopComponent() + { + return leftComponent; + } + + /** + * This method returns the UI. + * + * @return The UI. + */ + public SplitPaneUI getUI() + { + return (SplitPaneUI) ui; + } + + /** + * This method returns true if the JSplitPane is using a continuousLayout. + * + * @return True if using a continuousLayout. + */ + public boolean isContinuousLayout() + { + return continuousLayout; + } + + /** + * This method returns true if the divider has one touch expandable buttons. + * + * @return True if one touch expandable is used. + */ + public boolean isOneTouchExpandable() + { + return oneTouchExpandable; + } + + /** + * This method returns true. + * + * @return true. + */ + public boolean isValidateRoot() + { + return true; + } + + /** + * This method overrides JComponent's paintChildren so the UI can be + * messaged when the children have finished painting. + * + * @param g The Graphics object to paint with. + */ + protected void paintChildren(Graphics g) + { + super.paintChildren(g); + if (ui != null) + ((SplitPaneUI) ui).finishedPaintingChildren(this, g); + } + + /** + * This method returns a String that describes this JSplitPane. The string + * is primarily used for debugging purposes. + * + * @return A String used for debugging purposes. + */ + protected String paramString() + { + return "JSplitPane"; + } + + /** + * This method removes the given component from the JSplitPane. + * + * @param component The Component to remove. + */ + public void remove(Component component) + { + if (component == leftComponent) + leftComponent = null; + else if (component == rightComponent) + rightComponent = null; + super.remove(component); + } + + /** + * This method removes the component at the given index. + * + * @param index The index of the component to remove. + */ + public void remove(int index) + { + Component component = getComponent(index); + if (component == leftComponent) + leftComponent = null; + else if (component == rightComponent) + rightComponent = null; + super.remove(index); + } + + /** + * This method removes all components from the JSplitPane. + */ + public void removeAll() + { + leftComponent = null; + rightComponent = null; + super.removeAll(); + } + + /** + * This method resets all children of the JSplitPane to their preferred + * sizes. + */ + public void resetToPreferredSizes() + { + if (ui != null) + ((SplitPaneUI) ui).resetToPreferredSizes(this); + } + + /** + * This method sets the bottom component. + * + * @param comp The Component to be placed at the bottom. + */ + public void setBottomComponent(Component comp) + { + if (comp != null) + add(comp, BOTTOM); + else + add(new JButton("right button"), BOTTOM); + } + + /** + * This method sets the layout mode for the JSplitPane. + * + * @param newContinuousLayout Whether the JSplitPane is in continuousLayout + * mode. + */ + public void setContinuousLayout(boolean newContinuousLayout) + { + if (newContinuousLayout != continuousLayout) + { + boolean oldValue = continuousLayout; + continuousLayout = newContinuousLayout; + firePropertyChange(CONTINUOUS_LAYOUT_PROPERTY, oldValue, + continuousLayout); + } + } + + /** + * This method sets the location of the divider. A value of 0 sets the + * divider to the farthest left. A value of 1 sets the divider to the + * farthest right. + * + * @param proportionalLocation A double that describes the location of the + * divider. + * + * @throws IllegalArgumentException DOCUMENT ME! + */ + public void setDividerLocation(double proportionalLocation) + { + if (proportionalLocation > 1 || proportionalLocation < 0) + throw new IllegalArgumentException("proportion has to be between 0 and 1."); + + int max = (orientation == HORIZONTAL_SPLIT) ? getWidth() : getHeight(); + setDividerLocation((int) (proportionalLocation * max)); + } + + /** + * This method sets the location of the divider. + * + * @param location The location of the divider. + */ + public void setDividerLocation(int location) + { + if (ui != null && location != getDividerLocation()) + { + int oldLocation = getDividerLocation(); + ((SplitPaneUI) ui).setDividerLocation(this, location); + firePropertyChange(DIVIDER_LOCATION_PROPERTY, oldLocation, location); + } + } + + /** + * This method sets the size of the divider. + * + * @param newSize The size of the divider. + */ + public void setDividerSize(int newSize) + { + if (newSize != dividerSize) + { + int oldSize = dividerSize; + dividerSize = newSize; + firePropertyChange(DIVIDER_SIZE_PROPERTY, oldSize, dividerSize); + } + } + + // This doesn't appear to do anything when set from user side. + // so it probably is only used from the UI side to change the + // lastDividerLocation var. + + /** + * This method sets the last location of the divider. + * + * @param newLastLocation The last location of the divider. + */ + public void setLastDividerLocation(int newLastLocation) + { + if (newLastLocation != lastDividerLocation) + { + int oldValue = lastDividerLocation; + lastDividerLocation = newLastLocation; + firePropertyChange(LAST_DIVIDER_LOCATION_PROPERTY, oldValue, + lastDividerLocation); + } + } + + /** + * This method sets the left component. + * + * @param comp The left component. + */ + public void setLeftComponent(Component comp) + { + if (comp != null) + add(comp, LEFT); + else + add(new JButton("left button"), LEFT); + } + + /** + * This method sets whether the divider has one touch expandable buttons. + * The one touch expandable buttons can expand the size of either component + * to the maximum allowed size. + * + * @param newValue Whether the divider will have one touch expandable + * buttons. + */ + public void setOneTouchExpandable(boolean newValue) + { + if (newValue != oneTouchExpandable) + { + boolean oldValue = oneTouchExpandable; + oneTouchExpandable = newValue; + firePropertyChange(ONE_TOUCH_EXPANDABLE_PROPERTY, oldValue, + oneTouchExpandable); + } + } + + /** + * This method sets the orientation of the JSplitPane. + * + * @param orientation The orientation of the JSplitPane. + * + * @throws IllegalArgumentException DOCUMENT ME! + */ + public void setOrientation(int orientation) + { + if (orientation != HORIZONTAL_SPLIT && orientation != VERTICAL_SPLIT) + throw new IllegalArgumentException("orientation must be one of VERTICAL_SPLIT, HORIZONTAL_SPLIT"); + if (orientation != this.orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange(ORIENTATION_PROPERTY, oldOrientation, + this.orientation); + } + } + + /** + * This method determines how extra space will be distributed among the left + * and right components. A value of 0 will allocate all extra space to the + * right component. A value of 1 indicates that all extra space will go to + * the left component. A value in between 1 and 0 will split the space + * accordingly. + * + * @param value The resize weight. + */ + public void setResizeWeight(double value) + { + resizeWeight = value; + } + + /** + * This method sets the right component. + * + * @param comp The right component. + */ + public void setRightComponent(Component comp) + { + if (comp != null) + add(comp, RIGHT); + else + add(new JButton("right button"), RIGHT); + } + + /** + * This method sets the top component. + * + * @param comp The top component. + */ + public void setTopComponent(Component comp) + { + if (comp != null) + add(comp, TOP); + else + add(new JButton("left button"), TOP); + } + + /** + * This method sets the UI used by the JSplitPane. + * + * @param ui The UI to use. + */ + public void setUI(SplitPaneUI ui) + { + super.setUI(ui); + } + + /** + * This method resets the UI to the one specified by the current Look and + * Feel. + */ + public void updateUI() + { + setUI((SplitPaneUI) UIManager.getUI(this)); + invalidate(); + repaint(); + } + + /** + * This method returns a string identifier to determine which UI class it + * needs. + * + * @return A string that identifies it's UI class. + */ + public String getUIClassID() + { + return "SplitPaneUI"; + } +} diff --git a/libjava/classpath/javax/swing/JTabbedPane.java b/libjava/classpath/javax/swing/JTabbedPane.java new file mode 100644 index 00000000000..828a69a24dc --- /dev/null +++ b/libjava/classpath/javax/swing/JTabbedPane.java @@ -0,0 +1,1478 @@ +/* JTabbedPane.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.io.Serializable; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.TabbedPaneUI; +import javax.swing.plaf.UIResource; + +/** + * This is a container for components. One component is displayed at a time. + * Users can switch between components by clicking on tabs. + * + * <p> + * Tabs can be oriented in several ways. They can be above, below, left and + * right of the component. Tabs can either wrap around (by creating multiple + * rows of tabs) or they can be scrolled (where only a subset of the tabs + * can be seen at once). More tabs can be added by calling the + * add/addTab/insertTab methods. + * </p> + */ +public class JTabbedPane extends JComponent implements Serializable, + Accessible, + SwingConstants +{ + /** + * DOCUMENT ME! + */ + protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent + implements AccessibleSelection, ChangeListener + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = 7610530885966830483L; + + /** + * Creates a new AccessibleJTabbedPane object. + */ + public AccessibleJTabbedPane() + { + super(); + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void stateChanged(ChangeEvent e) + { + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getAccessibleChildrenCount() + { + return 0; + } + + /** + * DOCUMENT ME! + * + * @param i DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Accessible getAccessibleChild(int i) + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleSelection getAccessibleSelection() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param p DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Accessible getAccessibleAt(Point p) + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getAccessibleSelectionCount() + { + return 0; + } + + /** + * DOCUMENT ME! + * + * @param i DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Accessible getAccessibleSelection(int i) + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param i DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isAccessibleChildSelected(int i) + { + return false; + } + + /** + * DOCUMENT ME! + * + * @param i DOCUMENT ME! + */ + public void addAccessibleSelection(int i) + { + } + + /** + * DOCUMENT ME! + * + * @param i DOCUMENT ME! + */ + public void removeAccessibleSelection(int i) + { + } + + /** + * DOCUMENT ME! + */ + public void clearAccessibleSelection() + { + } + + /** + * DOCUMENT ME! + */ + public void selectAllAccessibleSelection() + { + } + } + + /** + * A helper class that listens for changes to the model. + */ + protected class ModelListener implements ChangeListener, Serializable + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = 497359819958114132L; + + /** + * Creates a new ModelListener object. + */ + protected ModelListener() + { + } + + /** + * This method is called whenever the model is changed. + * + * @param e The ChangeEvent that is passed from the model. + */ + public void stateChanged(ChangeEvent e) + { + // Propagate to our listeners. + fireStateChanged(); + } + } + + /** + * A private class that holds all the information for each tab. + */ + private class Page + { + /** The tooltip string. */ + private String tip; + + /** The component associated with the tab. */ + private Component component; + + /** The active icon associated with the tab. */ + private transient Icon icon; + + /** The disabled icon associated with the tab. */ + private transient Icon disabledIcon; + + /** The tab's enabled status. */ + private transient boolean enabled = true; + + /** The string painted on the tab. */ + private transient String title; + + /** The background color of the tab. */ + private transient Color bg; + + /** The foreground color of the tab. */ + private transient Color fg; + + /** The mnemonic associated with the tab. */ + private transient int mnemonicKey; + + /** The index of the underlined character in the string. */ + private transient int underlinedChar = -1; + + /** + * Creates a new data storage for the tab. + * + * @param title The string displayed on the tab. + * @param icon The active icon displayed on the tab. + * @param component The component associated with the tab. + * @param tip The tooltip associated with the tab. + */ + protected Page(String title, Icon icon, Component component, String tip) + { + this.title = title; + this.icon = icon; + this.component = component; + this.tip = tip; + } + + /** + * This method returns the component associated with the tab. + * + * @return The component associated with the tab. + */ + public Component getComponent() + { + return component; + } + + /** + * This method sets the component associated with the tab. + * + * @param c The component associated with the tab. + */ + public void setComponent(Component c) + { + remove(component); + this.component = c; + add(c); + } + + /** + * This method returns the tooltip string. + * + * @return The tooltip string. + */ + public String getTip() + { + return tip; + } + + /** + * This method sets the tooltip string. + * + * @param tip The tooltip string. + */ + public void setTip(String tip) + { + this.tip = tip; + } + + /** + * This method returns the background color. + * + * @return The background color. + */ + public Color getBackground() + { + return bg; + } + + /** + * This method sets the background color. + * + * @param background The background color. + */ + public void setBackground(Color background) + { + bg = background; + } + + /** + * This method returns the foreground color. + * + * @return The foreground color. + */ + public Color getForeground() + { + return fg; + } + + /** + * This method sets the foreground color. + * + * @param foreground The foreground color. + */ + public void setForeground(Color foreground) + { + fg = foreground; + } + + /** + * This method returns the title associated with the tab. + * + * @return The title of the tab. + */ + public String getTitle() + { + return title; + } + + /** DOCUMENT ME! */ + private static final long serialVersionUID = 1614381073220130939L; + + /** + * This method sets the title of the tab. + * + * @param text The title of the tab. + */ + public void setTitle(String text) + { + title = text; + if (title != null && title.length() <= underlinedChar) + setDisplayedMnemonicIndex(title.length() - 1); + } + + /** + * This method returns the active icon. + * + * @return The active icon. + */ + public Icon getIcon() + { + return icon; + } + + /** + * This method sets the active icon. + * + * @param icon The active icon. + */ + public void setIcon(Icon icon) + { + this.icon = icon; + } + + /** + * This method returns the disabled icon. + * + * @return The disabled icon. + */ + public Icon getDisabledIcon() + { + if (disabledIcon == null && icon instanceof ImageIcon) + setDisabledIcon(icon); + return disabledIcon; + } + + /** + * This method sets the disabled icon. + * + * @param disabledIcon The disabled icon. + */ + public void setDisabledIcon(Icon disabledIcon) + { + this.disabledIcon = disabledIcon; + } + + /** + * This method returns whether the tab is enabled. + * + * @return Whether the tab is enabled. + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * This method sets whether the tab is enabled. + * + * @param enabled Whether this tab is enabled. + */ + public void setEnabled(boolean enabled) + { + this.enabled = enabled; + } + + /** + * This method returns the mnemonic. + * + * @return The mnemonic. + */ + public int getMnemonic() + { + return (int) mnemonicKey; + } + + /** + * This method sets the mnemonic. If the title is set, it will update the + * mnemonicIndex. + * + * @param key The mnemonic. + */ + public void setMnemonic(int key) + { + setMnemonic((char) key); + } + + /** + * This method sets the mnemonic. If the title is set, it will update the + * mnemonicIndex. + * + * @param aChar The mnemonic. + */ + public void setMnemonic(char aChar) + { + mnemonicKey = aChar; + if (title != null) + setDisplayedMnemonicIndex(title.indexOf(mnemonicKey)); + } + + /** + * This method returns the mnemonicIndex. + * + * @return The mnemonicIndex. + */ + public int getDisplayedMnemonicIndex() + { + return underlinedChar; + } + + /** + * This method sets the mnemonicIndex. + * + * @param index The mnemonicIndex. + * + * @throws IllegalArgumentException If index less than -1 || index greater + * or equal to title.length. + */ + public void setDisplayedMnemonicIndex(int index) + throws IllegalArgumentException + { + if (index < -1 || title != null && index >= title.length()) + throw new IllegalArgumentException(); + + if (title == null || mnemonicKey == 0 || (index > -1 && title.charAt(index) != mnemonicKey)) + index = -1; + + underlinedChar = index; + } + } + + private static final long serialVersionUID = 1614381073220130939L; + + /** The changeEvent used to fire changes to listeners. */ + protected ChangeEvent changeEvent; + + /** The listener that listens to the model. */ + protected ChangeListener changeListener; + + /** The model that describes this JTabbedPane. */ + protected SingleSelectionModel model; + + /** Indicates that the TabbedPane is in scrolling mode. */ + public static final int SCROLL_TAB_LAYOUT = 1; + + /** Indicates that the TabbedPane is in wrap mode. */ + public static final int WRAP_TAB_LAYOUT = 0; + + /** The current tabPlacement of the TabbedPane. */ + protected int tabPlacement = SwingConstants.TOP; + + /** The current tabLayoutPolicy of the TabbedPane. */ + private transient int layoutPolicy; + + /** The list of tabs associated with the TabbedPane. */ + transient Vector tabs = new Vector(); + + /** + * Creates a new JTabbedPane object with tabs on top and using wrap tab + * layout. + */ + public JTabbedPane() + { + this(SwingConstants.TOP, WRAP_TAB_LAYOUT); + } + + /** + * Creates a new JTabbedPane object using wrap tab layout and the given + * tabPlacement. + * + * @param tabPlacement Where the tabs will be placed. + */ + public JTabbedPane(int tabPlacement) + { + this(tabPlacement, WRAP_TAB_LAYOUT); + } + + /** + * Creates a new JTabbedPane object with the given tabPlacement and + * tabLayoutPolicy. + * + * @param tabPlacement Where the tabs will be placed. + * @param tabLayoutPolicy The way tabs will be placed. + * + * @throws IllegalArgumentException If tabLayoutPolicy or tabPlacement are + * not valid. + */ + public JTabbedPane(int tabPlacement, int tabLayoutPolicy) + { + if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT + && tabPlacement != LEFT) + throw new IllegalArgumentException("tabPlacement is not valid."); + if (tabLayoutPolicy != SCROLL_TAB_LAYOUT + && tabLayoutPolicy != WRAP_TAB_LAYOUT) + throw new IllegalArgumentException("tabLayoutPolicy is not valid."); + this.tabPlacement = tabPlacement; + layoutPolicy = tabLayoutPolicy; + + changeEvent = new ChangeEvent(this); + changeListener = createChangeListener(); + + model = new DefaultSingleSelectionModel(); + model.addChangeListener(changeListener); + + updateUI(); + } + + /** + * This method returns the UI used to display the JTabbedPane. + * + * @return The UI used to display the JTabbedPane. + */ + public TabbedPaneUI getUI() + { + return (TabbedPaneUI) ui; + } + + /** + * This method sets the UI used to display the JTabbedPane. + * + * @param ui The UI used to display the JTabbedPane. + */ + public void setUI(TabbedPaneUI ui) + { + super.setUI(ui); + } + + /** + * This method restores the UI to the defaults given by the UIManager. + */ + public void updateUI() + { + setUI((TabbedPaneUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns a string identifier that is used to determine which + * UI will be used with the JTabbedPane. + * + * @return A string identifier for the UI. + */ + public String getUIClassID() + { + return "TabbedPaneUI"; + } + + /** + * This method creates a ChangeListener that is used to listen to the model + * for events. + * + * @return A ChangeListener to listen to the model. + */ + protected ChangeListener createChangeListener() + { + return new ModelListener(); + } + + /** + * This method adds a ChangeListener to the JTabbedPane. + * + * @param l The ChangeListener to add. + */ + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + /** + * This method removes a ChangeListener to the JTabbedPane. + * + * @param l The ChangeListener to remove. + */ + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + /** + * This method fires a ChangeEvent to all the JTabbedPane's ChangeListeners. + */ + protected void fireStateChanged() + { + Object[] changeListeners = listenerList.getListenerList(); + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + for (int i = changeListeners.length - 2; i >= 0; i -= 2) + { + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + } + } + + /** + * This method returns all ChangeListeners registered with the JTabbedPane. + * + * @return The ChangeListeners registered with the JTabbedPane. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) super.getListeners(ChangeListener.class); + } + + /** + * This method returns the model used with the JTabbedPane. + * + * @return The JTabbedPane's model. + */ + public SingleSelectionModel getModel() + { + return model; + } + + /** + * This method changes the model property of the JTabbedPane. + * + * @param model The new model to use with the JTabbedPane. + */ + public void setModel(SingleSelectionModel model) + { + if (model != this.model) + { + SingleSelectionModel oldModel = this.model; + this.model.removeChangeListener(changeListener); + this.model = model; + this.model.addChangeListener(changeListener); + firePropertyChange("model", oldModel, this.model); + } + } + + /** + * This method returns the tabPlacement. + * + * @return The tabPlacement used with the JTabbedPane. + */ + public int getTabPlacement() + { + return tabPlacement; + } + + /** + * This method changes the tabPlacement property of the JTabbedPane. + * + * @param tabPlacement The tabPlacement to use. + * + * @throws IllegalArgumentException If tabPlacement is not one of TOP, + * BOTTOM, LEFT, or RIGHT. + */ + public void setTabPlacement(int tabPlacement) + { + if (tabPlacement != TOP && tabPlacement != BOTTOM && tabPlacement != RIGHT + && tabPlacement != LEFT) + throw new IllegalArgumentException("tabPlacement is not valid."); + if (tabPlacement != this.tabPlacement) + { + int oldPlacement = this.tabPlacement; + this.tabPlacement = tabPlacement; + firePropertyChange("tabPlacement", oldPlacement, this.tabPlacement); + } + } + + /** + * This method returns the tabLayoutPolicy. + * + * @return The tabLayoutPolicy. + */ + public int getTabLayoutPolicy() + { + return layoutPolicy; + } + + /** + * This method changes the tabLayoutPolicy property of the JTabbedPane. + * + * @param tabLayoutPolicy The tabLayoutPolicy to use. + * + * @throws IllegalArgumentException If tabLayoutPolicy is not one of + * SCROLL_TAB_LAYOUT or WRAP_TAB_LAYOUT. + */ + public void setTabLayoutPolicy(int tabLayoutPolicy) + { + if (tabLayoutPolicy != SCROLL_TAB_LAYOUT + && tabLayoutPolicy != WRAP_TAB_LAYOUT) + throw new IllegalArgumentException("tabLayoutPolicy is not valid."); + if (tabLayoutPolicy != layoutPolicy) + { + int oldPolicy = layoutPolicy; + layoutPolicy = tabLayoutPolicy; + firePropertyChange("tabLayoutPolicy", oldPolicy, layoutPolicy); + } + } + + /** + * This method returns the index of the tab that is currently selected. + * + * @return The index of the selected tab. + */ + public int getSelectedIndex() + { + return model.getSelectedIndex(); + } + + /** + * This method checks the index. + * + * @param index The index to check. + * @param start DOCUMENT ME! + * @param end DOCUMENT ME! + * + * @throws IndexOutOfBoundsException DOCUMENT ME! + */ + private void checkIndex(int index, int start, int end) + { + if (index < start || index >= end) + throw new IndexOutOfBoundsException("Index < " + start + " || Index >= " + + end); + } + + /** + * This method sets the selected index. This method will hide the old + * component and show the new component. + * + * @param index The index to set it at. + */ + public void setSelectedIndex(int index) + { + checkIndex(index, -1, tabs.size()); + if (index != getSelectedIndex()) + { + if (getSelectedIndex() != -1 && getSelectedComponent() != null) + getSelectedComponent().hide(); + if (index != -1 && getComponentAt(index) != null) + getComponentAt(index).show(); + model.setSelectedIndex(index); + } + } + + /** + * This method returns the component at the selected index. + * + * @return The component at the selected index. + */ + public Component getSelectedComponent() + { + return getComponentAt(getSelectedIndex()); + } + + /** + * This method sets the component at the selected index. + * + * @param c The component associated with the selected index. + */ + public void setSelectedComponent(Component c) + { + if (c.getParent() == this) + setSelectedIndex(indexOfComponent(c)); + else + setComponentAt(getSelectedIndex(), c); + } + + /** + * This method inserts tabs into JTabbedPane. This includes adding the + * component to the JTabbedPane and hiding it. + * + * @param title The title of the tab. + * @param icon The tab's icon. + * @param component The component associated with the tab. + * @param tip The tooltip for the tab. + * @param index The index to insert the tab at. + */ + public void insertTab(String title, Icon icon, Component component, + String tip, int index) + { + Page p = new Page(title, icon, component, tip); + tabs.insertElementAt(p, index); + + // Hide the component so we don't see it. Do it before we parent it + // so we don't trigger a repaint. + if (component != null) + { + component.hide(); + super.add(component); + } + + if (getSelectedIndex() == -1) + setSelectedIndex(0); + + layout(); + repaint(); + } + + /** + * This method adds a tab to the JTabbedPane. + * + * @param title The title of the tab. + * @param icon The icon for the tab. + * @param component The associated component. + * @param tip The associated tooltip. + */ + public void addTab(String title, Icon icon, Component component, String tip) + { + insertTab(title, icon, component, tip, tabs.size()); + } + + /** + * This method adds a tab to the JTabbedPane. + * + * @param title The title of the tab. + * @param icon The icon for the tab. + * @param component The associated component. + */ + public void addTab(String title, Icon icon, Component component) + { + insertTab(title, icon, component, null, tabs.size()); + } + + /** + * This method adds a tab to the JTabbedPane. + * + * @param title The title of the tab. + * @param component The associated component. + */ + public void addTab(String title, Component component) + { + insertTab(title, null, component, null, tabs.size()); + } + + /** + * This method adds a tab to the JTabbedPane. The title of the tab is the + * Component's name. If the Component is an instance of UIResource, it + * doesn't add the tab and instead add the component directly to the + * JTabbedPane. + * + * @param component The associated component. + * + * @return The Component that was added. + */ + public Component add(Component component) + { + if (component instanceof UIResource) + super.add(component); + else + insertTab(component.getName(), null, component, null, tabs.size()); + return component; + } + + /** + * This method adds a tab to the JTabbedPane. If the Component is an + * instance of UIResource, it doesn't add the tab and instead add the + * component directly to the JTabbedPane. + * + * @param title The title of the tab. + * @param component The associated component. + * + * @return The Component that was added. + */ + public Component add(String title, Component component) + { + if (component instanceof UIResource) + super.add(component); + else + insertTab(title, null, component, null, tabs.size()); + return component; + } + + /** + * This method adds a tab to the JTabbedPane. If the Component is an + * instance of UIResource, it doesn't add the tab and instead add the + * component directly to the JTabbedPane. + * + * @param component The associated component. + * @param index The index to insert the tab at. + * + * @return The Component that was added. + */ + public Component add(Component component, int index) + { + if (component instanceof UIResource) + super.add(component); + else + insertTab(component.getName(), null, component, null, index); + return component; + } + + /** + * This method adds a tab to the JTabbedPane. If the Component is an + * instance of UIResource, it doesn't add the tab and instead add the + * component directly to the JTabbedPane. If the constraints object is an + * icon, it will be used as the tab's icon. If the constraints object is a + * string, we will use it as the title. + * + * @param component The associated component. + * @param constraints The constraints object. + */ + public void add(Component component, Object constraints) + { + add(component, constraints, tabs.size()); + } + + /** + * This method adds a tab to the JTabbedPane. If the Component is an + * instance of UIResource, it doesn't add the tab and instead add the + * component directly to the JTabbedPane. If the constraints object is an + * icon, it will be used as the tab's icon. If the constraints object is a + * string, we will use it as the title. + * + * @param component The associated component. + * @param constraints The constraints object. + * @param index The index to insert the tab at. + */ + public void add(Component component, Object constraints, int index) + { + if (component instanceof UIResource) + super.add(component); + else + { + if (constraints instanceof String) + insertTab((String) constraints, null, component, null, index); + else + insertTab(component.getName(), + (constraints instanceof Icon) ? (Icon) constraints : null, + component, null, index); + } + } + + /** + * The tab and it's associated component are removed. After the component + * has been removed from the JTabbedPane, it's set visible to ensure that + * it can be seen. + * + * @param index The index of the tab to remove. + */ + public void removeTabAt(int index) + { + checkIndex(index, 0, tabs.size()); + Component c = getComponentAt(index); + super.remove(index); + c.show(); + tabs.remove(index); + } + + /** + * This method removes the component from the JTabbedPane. After the + * component has been removed from the JTabbedPane, it's set visible to + * ensure that it can be seen. + * + * @param component The Component to remove. + */ + public void remove(Component component) + { + // This simply removes the component. + int index = indexOfComponent(component); + super.remove(component); + component.show(); + setComponentAt(index, null); + } + + /** + * This method removes the tab and component from the JTabbedPane. It simply + * calls removeTabAt(int index). + * + * @param index The index of the tab to remove. + */ + public void remove(int index) + { + removeTabAt(index); + } + + /** + * This method removes all tabs and associated components from the + * JTabbedPane. + */ + public void removeAll() + { + for (int i = tabs.size() - 1; i >= 0; i--) + removeTabAt(i); + } + + /** + * This method returns how many tabs are in the JTabbedPane. + * + * @return The number of tabs in the JTabbedPane. + */ + public int getTabCount() + { + return tabs.size(); + } + + /** + * This method returns the number of runs used to paint the JTabbedPane. + * + * @return The number of runs. + */ + public int getTabRunCount() + { + return ((TabbedPaneUI) ui).getTabRunCount(this); + } + + /** + * This method returns the tab title given the index. + * + * @param index The index of the tab. + * + * @return The title for the tab. + */ + public String getTitleAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getTitle(); + } + + /** + * This method returns the active icon given the index. + * + * @param index The index of the tab. + * + * @return The active icon for the tab. + */ + public Icon getIconAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getIcon(); + } + + /** + * This method returns the disabled icon given the index. + * + * @param index The index of the tab. + * + * @return The disabled icon for the tab. + */ + public Icon getDisabledIconAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getDisabledIcon(); + } + + /** + * This method returns the tooltip string for the tab. + * + * @param index The index of the tab. + * + * @return The tooltip string for the tab. + */ + public String getToolTipTextAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getTip(); + } + + /** + * This method returns the foreground color for the tab. + * + * @param index The index of the tab. + * + * @return The foreground color for the tab. + */ + public Color getForegroundAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getForeground(); + } + + /** + * This method returns the background color for the tab. + * + * @param index The index of the tab. + * + * @return The background color for the tab. + */ + public Color getBackgroundAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getBackground(); + } + + /** + * This method returns the component associated with the tab. + * + * @param index The index of the tab. + * + * @return The component associated with the tab. + */ + public Component getComponentAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).getComponent(); + } + + /** + * This method returns whether this tab is enabled. Disabled tabs cannot be + * selected. + * + * @param index The index of the tab. + * + * @return Whether the tab is enabled. + */ + public boolean isEnabledAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((Page) tabs.elementAt(index)).isEnabled(); + } + + /** + * This method returns the mnemonic for the tab. + * + * @param tabIndex The index of the tab. + * + * @return The mnemonic for the tab. + */ + public int getMnemonicAt(int tabIndex) + { + checkIndex(tabIndex, 0, tabs.size()); + return ((Page) tabs.elementAt(tabIndex)).getMnemonic(); + } + + /** + * This method returns the mnemonic index for the tab. + * + * @param tabIndex The index of the tab. + * + * @return The mnemonic index for the tab. + */ + public int getDisplayedMnemonicIndexAt(int tabIndex) + { + checkIndex(tabIndex, 0, tabs.size()); + return ((Page) tabs.elementAt(tabIndex)).getDisplayedMnemonicIndex(); + } + + /** + * This method returns the bounds of the tab given the index. + * + * @param index The index of the tab. + * + * @return A rectangle describing the bounds of the tab. + */ + public Rectangle getBoundsAt(int index) + { + checkIndex(index, 0, tabs.size()); + return ((TabbedPaneUI) ui).getTabBounds(this, index); + } + + /** + * This method sets the title of the tab. + * + * @param index The index of the tab. + * @param title The new title. + */ + public void setTitleAt(int index, String title) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setTitle(title); + } + + /** + * This method sets the icon of the tab. + * + * @param index The index of the tab. + * @param icon The new icon. + */ + public void setIconAt(int index, Icon icon) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setIcon(icon); + } + + /** + * This method sets the disabled icon of the tab. + * + * @param index The index of the tab. + * @param disabledIcon The new disabled icon. + */ + public void setDisabledIconAt(int index, Icon disabledIcon) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setDisabledIcon(disabledIcon); + } + + /** + * This method sets the tooltip text of the tab. + * + * @param index The index of the tab. + * @param toolTipText The tooltip text. + */ + public void setToolTipTextAt(int index, String toolTipText) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setTip(toolTipText); + } + + /** + * This method sets the background color of the tab. + * + * @param index The index of the tab. + * @param background The background color of the tab. + */ + public void setBackgroundAt(int index, Color background) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setBackground(background); + } + + /** + * This method sets the foreground color of the tab. + * + * @param index The index of the tab. + * @param foreground The foreground color of the tab. + */ + public void setForegroundAt(int index, Color foreground) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setForeground(foreground); + } + + /** + * This method sets whether the tab is enabled. + * + * @param index The index of the tab. + * @param enabled Whether the tab is enabled. + */ + public void setEnabledAt(int index, boolean enabled) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setEnabled(enabled); + } + + /** + * This method sets the component associated with the tab. + * + * @param index The index of the tab. + * @param component The component associated with the tab. + */ + public void setComponentAt(int index, Component component) + { + checkIndex(index, 0, tabs.size()); + ((Page) tabs.elementAt(index)).setComponent(component); + } + + /** + * This method sets the displayed mnemonic index of the tab. + * + * @param tabIndex The index of the tab. + * @param mnemonicIndex The mnemonic index. + */ + public void setDisplayedMnemonicIndexAt(int tabIndex, int mnemonicIndex) + { + checkIndex(tabIndex, 0, tabs.size()); + ((Page) tabs.elementAt(tabIndex)).setDisplayedMnemonicIndex(mnemonicIndex); + } + + /** + * This method sets the mnemonic for the tab. + * + * @param tabIndex The index of the tab. + * @param mnemonic The mnemonic. + */ + public void setMnemonicAt(int tabIndex, int mnemonic) + { + checkIndex(tabIndex, 0, tabs.size()); + ((Page) tabs.elementAt(tabIndex)).setMnemonic(mnemonic); + } + + /** + * This method finds the index of a tab given the title. + * + * @param title The title that belongs to a tab. + * + * @return The index of the tab that has the title or -1 if not found. + */ + public int indexOfTab(String title) + { + int index = -1; + for (int i = 0; i < tabs.size(); i++) + { + if (((Page) tabs.elementAt(i)).getTitle().equals(title)) + { + index = i; + break; + } + } + return index; + } + + /** + * This method finds the index of a tab given the icon. + * + * @param icon The icon that belongs to a tab. + * + * @return The index of the tab that has the icon or -1 if not found. + */ + public int indexOfTab(Icon icon) + { + int index = -1; + for (int i = 0; i < tabs.size(); i++) + { + if (((Page) tabs.elementAt(i)).getIcon() == icon) + { + index = i; + break; + } + } + return index; + } + + /** + * This method finds the index of a tab given the component. + * + * @param component A component associated with a tab. + * + * @return The index of the tab that has this component or -1 if not found. + */ + public int indexOfComponent(Component component) + { + int index = -1; + for (int i = 0; i < tabs.size(); i++) + { + if (((Page) tabs.elementAt(i)).getComponent() == component) + { + index = i; + break; + } + } + return index; + } + + /** + * This method returns a tab index given an (x,y) location. The origin of + * the (x,y) pair will be the JTabbedPane's top left position. The tab + * returned will be the one that contains the point. This method is + * delegated to the UI. + * + * @param x The x coordinate of the point. + * @param y The y coordinate of the point. + * + * @return The index of the tab that contains the point. + */ + public int indexAtLocation(int x, int y) + { + return ((TabbedPaneUI) ui).tabForCoordinate(this, x, y); + } + + /** + * This method returns the tooltip text given a mouse event. + * + * @param event The mouse event. + * + * @return The tool tip text that is associated with this mouse event. + */ + public String getToolTipText(MouseEvent event) + { + int index = indexAtLocation(event.getX(), event.getY()); + return ((Page) tabs.elementAt(index)).getTip(); + } + + /** + * This method returns a string representation of this JTabbedPane. It is + * mainly used for debugging purposes. + * + * @return A string representation of this JTabbedPane. + */ + protected String paramString() + { + return "JTabbedPane"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJTabbedPane(); + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JTable.java b/libjava/classpath/javax/swing/JTable.java new file mode 100644 index 00000000000..505a4602d98 --- /dev/null +++ b/libjava/classpath/javax/swing/JTable.java @@ -0,0 +1,2170 @@ +/* JTable.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.Hashtable; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableColumnModelEvent; +import javax.swing.event.TableColumnModelListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.plaf.TableUI; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.DefaultTableColumnModel; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; +import javax.swing.table.TableModel; + +public class JTable extends JComponent + implements TableModelListener, Scrollable, TableColumnModelListener, + ListSelectionListener, CellEditorListener, Accessible +{ + + /** + * A cell renderer for boolean values. + */ + private class BooleanCellRenderer + extends DefaultTableCellRenderer + { + + /** + * The CheckBox that is used for rendering. + */ + private JCheckBox checkBox = new JCheckBox(); + + /** + * Returns the component that is used for rendering the value. + * + * @param table the JTable + * @param value the value of the object + * @param isSelected is the cell selected? + * @param hasFocus has the cell the focus? + * @param row the row to render + * @param column the cell to render + * + * @return this component (the default table cell renderer) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) + { + Boolean boolValue = (Boolean) value; + checkBox.setSelected(boolValue.booleanValue()); + return checkBox; + } + } + + /** + * A cell renderer for Date values. + */ + private class DateCellRenderer + extends DefaultTableCellRenderer + { + /** + * Returns the component that is used for rendering the value. + * + * @param table the JTable + * @param value the value of the object + * @param isSelected is the cell selected? + * @param hasFocus has the cell the focus? + * @param row the row to render + * @param column the cell to render + * + * @return this component (the default table cell renderer) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) + { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, + row, column); + if (value instanceof Date) + { + Date dateValue = (Date) value; + DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT); + setText(df.format(dateValue)); + } + return this; + } + } + + /** + * A cell renderer for Double values. + */ + private class DoubleCellRenderer + extends DefaultTableCellRenderer + { + /** + * Creates a new instance of NumberCellRenderer. + */ + public DoubleCellRenderer() + { + setHorizontalAlignment(JLabel.RIGHT); + } + + /** + * Returns the component that is used for rendering the value. + * + * @param table the JTable + * @param value the value of the object + * @param isSelected is the cell selected? + * @param hasFocus has the cell the focus? + * @param row the row to render + * @param column the cell to render + * + * @return this component (the default table cell renderer) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) + { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, + row, column); + if (value instanceof Double) + { + Double doubleValue = (Double) value; + NumberFormat nf = NumberFormat.getInstance(); + setText(nf.format(doubleValue.doubleValue())); + } + return this; + } + } + + /** + * A cell renderer for Float values. + */ + private class FloatCellRenderer + extends DefaultTableCellRenderer + { + /** + * Creates a new instance of NumberCellRenderer. + */ + public FloatCellRenderer() + { + setHorizontalAlignment(JLabel.RIGHT); + } + + /** + * Returns the component that is used for rendering the value. + * + * @param table the JTable + * @param value the value of the object + * @param isSelected is the cell selected? + * @param hasFocus has the cell the focus? + * @param row the row to render + * @param column the cell to render + * + * @return this component (the default table cell renderer) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) + { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, + row, column); + if (value instanceof Float) + { + Float floatValue = (Float) value; + NumberFormat nf = NumberFormat.getInstance(); + setText(nf.format(floatValue.floatValue())); + } + return this; + } + } + + /** + * A cell renderer for Number values. + */ + private class NumberCellRenderer + extends DefaultTableCellRenderer + { + /** + * Creates a new instance of NumberCellRenderer. + */ + public NumberCellRenderer() + { + setHorizontalAlignment(JLabel.RIGHT); + } + } + + /** + * A cell renderer for Icon values. + */ + private class IconCellRenderer + extends DefaultTableCellRenderer + { + /** + * Returns the component that is used for rendering the value. + * + * @param table the JTable + * @param value the value of the object + * @param isSelected is the cell selected? + * @param hasFocus has the cell the focus? + * @param row the row to render + * @param column the cell to render + * + * @return this component (the default table cell renderer) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, int row, + int column) + { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, + row, column); + if (value instanceof Icon) + { + Icon iconValue = (Icon) value; + setIcon(iconValue); + } + return this; + } + } + + private static final long serialVersionUID = 3876025080382781659L; + + + /** + * When resizing columns, do not automatically change any columns. In this + * case the table should be enclosed in a {@link JScrollPane} in order to + * accomodate cases in which the table size exceeds its visible area. + */ + public static final int AUTO_RESIZE_OFF = 0; + + /** + * When resizing column <code>i</code>, automatically change only the + * single column <code>i+1</code> to provide or absorb excess space + * requirements. + */ + public static final int AUTO_RESIZE_NEXT_COLUMN = 1; + + /** + * When resizing column <code>i</code> in a table of <code>n</code> + * columns, automatically change all columns in the range <code>[i+1, + * n)</code>, uniformly, to provide or absorb excess space requirements. + */ + public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2; + + /** + * When resizing column <code>i</code> in a table of <code>n</code> + * columns, automatically change all columns in the range <code>[0, + * n)</code> (with the exception of column i) uniformly, to provide or + * absorb excess space requirements. + */ + public static final int AUTO_RESIZE_ALL_COLUMNS = 4; + + /** + * When resizing column <code>i</code> in a table of <code>n</code> + * columns, automatically change column <code>n-1</code> (the last column + * in the table) to provide or absorb excess space requirements. + */ + public static final int AUTO_RESIZE_LAST_COLUMN = 3; + + + /** + * A table mapping {@link java.lang.Class} objects to + * {@link TableCellEditor} objects. This table is consulted by the + * FIXME + */ + protected Hashtable defaultEditorsByColumnClass; + + /** + * A table mapping {@link java.lang.Class} objects to + * {@link TableCellEditor} objects. This table is consulted by the + * FIXME + */ + protected Hashtable defaultRenderersByColumnClass; + + /** + * The column that is edited, -1 if the table is not edited currently. + */ + protected int editingColumn; + + /** + * The row that is edited, -1 if the table is not edited currently. + */ + protected int editingRow; + + /** + * The component that is used for editing. + * <code>null</code> if the table is not editing currently. + * + */ + protected transient Component editorComp; + + /** + * Whether or not the table should automatically compute a matching + * {@link TableColumnModel} and assign it to the {@link #columnModel} + * property when the {@link #dataModel} property is changed. + * + * @see #setModel(TableModel) + * @see #createColumnsFromModel() + * @see #setColumnModel(TableColumnModel) + * @see #setAutoCreateColumnsFromModel(boolean) + * @see #getAutoCreateColumnsFromModel() + */ + protected boolean autoCreateColumnsFromModel; + + /** + * A numeric code specifying the resizing behavior of the table. Must be + * one of {@link #AUTO_RESIZE_ALL_COLUMNS} (the default), {@link + * #AUTO_RESIZE_LAST_COLUMN}, {@link #AUTO_RESIZE_NEXT_COLUMN}, {@link + * #AUTO_RESIZE_SUBSEQUENT_COLUMNS}, or {@link #AUTO_RESIZE_OFF}. + * + * @see #doLayout() + * @see #setAutoResizeMode(int) + * @see #getAutoResizeMode() + */ + protected int autoResizeMode; + + /** + * The height in pixels of any row of the table. All rows in a table are + * of uniform height. This differs from column width, which varies on a + * per-column basis, and is stored in the individual columns of the + * {@link #columnModel}. + * + * @see #getRowHeight() + * @see #setRowHeight(int) + * @see TableColumn#getWidth() + * @see TableColumn#setWidth(int) + */ + protected int rowHeight; + + /** + * The height in pixels of the gap left between any two rows of the table. + * + * @see #setRowMargin(int) + * @see #getRowHeight() + * @see #getIntercellSpacing() + * @see #setIntercellSpacing(Dimension) + * @see TableColumnModel#getColumnMargin() + * @see TableColumnModel#setColumnMargin(int) + */ + protected int rowMargin; + + /** + * Whether or not the table should allow row selection. If the table + * allows both row <em>and</em> column selection, it is said to allow + * "cell selection". Previous versions of the JDK supported cell + * selection as an independent concept, but it is now represented solely + * in terms of simultaneous row and column selection. + * + * @see TableColumnModel#getColumnSelectionAllowed() + * @see #setRowSelectionAllowed(boolean) + * @see #getRowSelectionAllowed() + * @see #getCellSelectionEnabled() + * @see #setCellSelectionEnabled(boolean) + */ + protected boolean rowSelectionAllowed; + + /** + * @deprecated Use {@link #rowSelectionAllowed}, {@link + * #getColumnSelectionAllowed}, or the combined methods {@link + * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}. + */ + protected boolean cellSelectionEnabled; + + /** + * The model for data stored in the table. Confusingly, the published API + * requires that this field be called <code>dataModel</code>, despite its + * property name. The table listens to its model as a {@link + * TableModelListener}. + * + * @see #tableChanged(TableModelEvent) + * @see TableModel#addTableModelListener(TableModelListener) + */ + protected TableModel dataModel; + + /** + * <p>A model of various aspects of the columns of the table, <em>not + * including</em> the data stored in them. The {@link TableColumnModel} + * is principally concerned with holding a set of {@link TableColumn} + * objects, each of which describes the display parameters of a column + * and the numeric index of the column from the data model which the + * column is presenting.</p> + * + * <p>The TableColumnModel also contains a {@link ListSelectionModel} which + * indicates which columns are currently selected. This selection model + * works in combination with the {@link #selectionModel} of the table + * itself to specify a <em>table selection</em>: a combination of row and + * column selections.</p> + * + * <p>Most application programmers do not need to work with this property + * at all: setting {@link #autoCreateColumnsFromModel} will construct the + * columnModel automatically, and the table acts as a facade for most of + * the interesting properties of the columnModel anyways.</p> + * + * @see #setColumnModel(TableColumnModel) + * @see #getColumnModel() + */ + protected TableColumnModel columnModel; + + /** + * A model of the rows of this table which are currently selected. This + * model is used in combination with the column selection model held as a + * member of the {@link #columnModel} property, to represent the rows and + * columns (or both: cells) of the table which are currently selected. + * + * @see #rowSelectionAllowed + * @see #setSelectionModel(ListSelectionModel) + * @see #getSelectionModel() + * @see TableColumnModel#getSelectionModel() + * @see ListSelectionModel#addListSelectionListener(ListSelectionListener) + */ + protected ListSelectionModel selectionModel; + + /** + * The accessibleContext property. + */ + protected AccessibleContext accessibleContext; + + /** + * The current cell editor. + */ + protected TableCellEditor cellEditor; + + /** + * Whether or not drag-and-drop is enabled on this table. + * + * @see #setDragEnabled() + * @see #getDragEnabled() + */ + private boolean dragEnabled; + + /** + * The color to paint the grid lines of the table, when either {@link + * #showHorizontalLines} or {@link #showVerticalLines} is set. + * + * @see #setGridColor(Color) + * @see #getGridColor() + */ + protected Color gridColor; + + /** + * The size this table would prefer its viewport assume, if it is + * contained in a {@link JScrollPane}. + * + * @see #setPreferredScrollableViewportSize(Dimension) + * @see #getPreferredScrollableViewportSize() + */ + protected Dimension preferredViewportSize; + + /** + * The color to paint the background of selected cells. Fires a property + * change event with name {@link #SELECTION_BACKGROUND_CHANGED_PROPERTY} + * when its value changes. + * + * @see #setSelectionBackground(Color) + * @see #getSelectionBackground() + */ + protected Color selectionBackground; + + /** + * The name carried in property change events when the {@link + * #selectionBackground} property changes. + */ + private static final String SELECTION_BACKGROUND_CHANGED_PROPERTY = "selectionBackground"; + + /** + * The color to paint the foreground of selected cells. Fires a property + * change event with name {@link #SELECTION_FOREGROUND_CHANGED_PROPERTY} + * when its value changes. + * + * @see #setSelectionForeground(Color) + * @see #getSelectionForeground() + */ + protected Color selectionForeground; + + /** + * The name carried in property change events when the + * {@link #selectionForeground} property changes. + */ + private static final String SELECTION_FOREGROUND_CHANGED_PROPERTY = "selectionForeground"; + + /** + * The showHorizontalLines property. + */ + protected boolean showHorizontalLines; + + /** + * The showVerticalLines property. + */ + protected boolean showVerticalLines; + + /** + * The tableHeader property. + */ + protected JTableHeader tableHeader; + + + /** + * Creates a new <code>JTable</code> instance. + */ + public JTable () + { + this(null, null, null); + } + + /** + * Creates a new <code>JTable</code> instance. + * + * @param numRows an <code>int</code> value + * @param numColumns an <code>int</code> value + */ + public JTable (int numRows, int numColumns) + { + this(new DefaultTableModel(numRows, numColumns)); + } + + /** + * Creates a new <code>JTable</code> instance. + * + * @param data an <code>Object[][]</code> value + * @param columnNames an <code>Object[]</code> value + */ + public JTable(Object[][] data, Object[] columnNames) + { + this(new DefaultTableModel(data, columnNames)); + } + + /** + * Creates a new <code>JTable</code> instance. + * + * @param dm a <code>TableModel</code> value + */ + public JTable (TableModel dm) + { + this(dm, null, null); + } + + /** + * Creates a new <code>JTable</code> instance. + * + * @param dm a <code>TableModel</code> value + * @param cm a <code>TableColumnModel</code> value + */ + public JTable (TableModel dm, TableColumnModel cm) + { + this(dm, cm, null); + } + + /** + * Creates a new <code>JTable</code> instance. + * + * @param dm a <code>TableModel</code> value + * @param cm a <code>TableColumnModel</code> value + * @param sm a <code>ListSelectionModel</code> value + */ + public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm) + { + setModel(dm == null ? createDefaultDataModel() : dm); + setSelectionModel(sm == null ? createDefaultSelectionModel() : sm); + + this.columnModel = cm; + initializeLocalVars(); + updateUI(); + } + + protected void initializeLocalVars() + { + setTableHeader(createDefaultTableHeader()); + this.autoCreateColumnsFromModel = false; + if (columnModel == null) + { + this.autoCreateColumnsFromModel = true; + createColumnsFromModel(); + } + this.columnModel.addColumnModelListener(this); + + this.defaultRenderersByColumnClass = new Hashtable(); + createDefaultRenderers(); + + this.defaultEditorsByColumnClass = new Hashtable(); + createDefaultEditors(); + + this.autoResizeMode = AUTO_RESIZE_ALL_COLUMNS; + this.rowHeight = 16; + this.rowMargin = 1; + this.rowSelectionAllowed = true; + // this.accessibleContext = new AccessibleJTable(); + this.cellEditor = null; + // COMPAT: Both Sun and IBM have drag enabled + this.dragEnabled = true; + this.preferredViewportSize = new Dimension(450,400); + this.showHorizontalLines = true; + this.showVerticalLines = true; + this.editingColumn = -1; + this.editingRow = -1; + setIntercellSpacing(new Dimension(1,1)); + } + + /** + * Creates a new <code>JTable</code> instance. + * + * @param data a <code>Vector</code> value + * @param columnNames a <code>Vector</code> value + */ + public JTable(Vector data, Vector columnNames) + { + this(new DefaultTableModel(data, columnNames)); + } + + public void addColumn(TableColumn column) + { + if (column.getHeaderValue() == null) + { + String name = dataModel.getColumnName(column.getModelIndex()); + column.setHeaderValue(name); + } + + columnModel.addColumn(column); + } + + protected void createDefaultEditors() + { + //FIXME: Create the editor object. + } + + protected void createDefaultRenderers() + { + setDefaultRenderer(Boolean.class, new BooleanCellRenderer()); + setDefaultRenderer(Number.class, new NumberCellRenderer()); + setDefaultRenderer(Double.class, new DoubleCellRenderer()); + setDefaultRenderer(Double.class, new FloatCellRenderer()); + setDefaultRenderer(Date.class, new DateCellRenderer()); + setDefaultRenderer(Icon.class, new IconCellRenderer()); + } + + /** + * @deprecated 1.0.2, replaced by <code>new JScrollPane(JTable)</code> + */ + public static JScrollPane createScrollPaneForTable(JTable table) + { + return new JScrollPane(table); + } + + protected TableColumnModel createDefaultColumnModel() + { + return new DefaultTableColumnModel(); + } + + protected TableModel createDefaultDataModel() + { + return new DefaultTableModel(); + } + + protected ListSelectionModel createDefaultSelectionModel() + { + return new DefaultListSelectionModel(); + } + + protected JTableHeader createDefaultTableHeader() + { + return new JTableHeader(columnModel); + } + + private void createColumnsFromModel() + { + if (dataModel == null) + return; + + TableColumnModel cm = createDefaultColumnModel(); + + for (int i = 0; i < dataModel.getColumnCount(); ++i) + { + cm.addColumn(new TableColumn(i)); + } + this.setColumnModel(cm); + } + + // listener support + + public void columnAdded (TableColumnModelEvent event) + { + revalidate(); + repaint(); + } + + public void columnMarginChanged (ChangeEvent event) + { + revalidate(); + repaint(); + } + + public void columnMoved (TableColumnModelEvent event) + { + revalidate(); + repaint(); + } + + public void columnRemoved (TableColumnModelEvent event) + { + revalidate(); + repaint(); + } + + public void columnSelectionChanged (ListSelectionEvent event) + { + repaint(); + } + + public void editingCanceled (ChangeEvent event) + { + repaint(); + } + + public void editingStopped (ChangeEvent event) + { + repaint(); + } + + public void tableChanged (TableModelEvent event) + { + // update the column model from the table model if the structure has + // changed and the flag autoCreateColumnsFromModel is set + if ((event.getFirstRow() ==TableModelEvent.HEADER_ROW) + && autoCreateColumnsFromModel) + + createColumnsFromModel(); + + repaint(); + } + + public void valueChanged (ListSelectionEvent event) + { + repaint(); + } + + /** + * Returns index of the column that contains specified point + * or -1 if this table doesn't contain this point. + * + * @param point point to identify the column + * @return index of the column that contains specified point or + * -1 if this table doesn't contain this point. + */ + public int columnAtPoint(Point point) + { + int x0 = getLocation().x; + int ncols = getColumnCount(); + Dimension gap = getIntercellSpacing(); + TableColumnModel cols = getColumnModel(); + int x = point.x; + + for (int i = 0; i < ncols; ++i) + { + int width = cols.getColumn(i).getWidth() + (gap == null ? 0 : gap.width); + if (0 <= x && x < width) + return i; + x -= width; + } + + return -1; + } + + /** + * Returns index of the row that contains specified point or + * -1 if this table doesn't contain this point. + * + * @param point point to identify the row + * @return index of the row that contains specified point or + * -1 if this table doesn't contain this point. + */ + public int rowAtPoint(Point point) + { + int y0 = getLocation().y; + int nrows = getRowCount(); + Dimension gap = getIntercellSpacing(); + int height = getRowHeight() + (gap == null ? 0 : gap.height); + int y = point.y; + + for (int i = 0; i < nrows; ++i) + { + if (0 <= y && y < height) + return i; + y -= height; + } + + return -1; + } + + /** + * Calculate the visible rectangle for a particular row and column. The + * row and column are specified in visual terms; the column may not match + * the {@link #dataModel} column. + * + * @param row the visible row to get the cell rectangle of + * + * @param column the visible column to get the cell rectangle of, which may + * differ from the {@link #dataModel} column + * + * @param includeSpacing whether or not to include the cell margins in the + * resulting cell. If <code>false</code>, the result will only contain the + * inner area of the target cell, not including its margins. + * + * @return a rectangle enclosing the specified cell + */ + public Rectangle getCellRect(int row, + int column, + boolean includeSpacing) + { + int height = getHeight(); + int width = columnModel.getColumn(column).getWidth(); + int x_gap = columnModel.getColumnMargin(); + int y_gap = rowMargin; + + column = Math.max(0, Math.min(column, getColumnCount() - 1)); + row = Math.max(0, Math.min(row, getRowCount() - 1)); + + int x = 0; + int y = (height + y_gap) * row; + + for (int i = 0; i < column; ++i) + { + x += columnModel.getColumn(i).getWidth(); + x += x_gap; + } + + if (includeSpacing) + return new Rectangle(x, y, width, height); + else + return new Rectangle(x, y, width - x_gap, height - y_gap); + } + + public void clearSelection() + { + selectionModel.clearSelection(); + getColumnModel().getSelectionModel().clearSelection(); + } + + /** + * Get the value of the selectedRow property by delegation to + * the {@link ListSelectionModel#getMinSelectionIndex} method of the + * {@link #selectionModel} field. + * + * @return The current value of the selectedRow property + */ + public int getSelectedRow () + { + return selectionModel.getMinSelectionIndex(); + } + + /** + * Get the value of the {@link #selectionModel} property. + * + * @return The current value of the property + */ + public ListSelectionModel getSelectionModel() + { + //Neither Sun nor IBM returns null if rowSelection not allowed + return selectionModel; + } + + public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) + { + if (orientation == SwingConstants.VERTICAL) + return visibleRect.height * direction; + else + return visibleRect.width * direction; + } + + /** + * Get the value of the <code>scrollableTracksViewportHeight</code> property. + * + * @return The constant value <code>false</code> + */ + public boolean getScrollableTracksViewportHeight() + { + return false; + } + + /** + * Get the value of the <code>scrollableTracksViewportWidth</code> property. + * + * @return <code>true</code> unless the {@link #autoResizeMode} property is + * <code>AUTO_RESIZE_OFF</code> + */ + public boolean getScrollableTracksViewportWidth() + { + if (autoResizeMode == AUTO_RESIZE_OFF) + return false; + else + return true; + } + + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) + { + // FIXME: I don't exactly know what sun does here. in both cases they + // pick values which do *not* simply expose the next cell in a given + // scroll direction. + + if (orientation == SwingConstants.VERTICAL) + return rowHeight; + else + { + int sum = 0; + for (int i = 0; i < getColumnCount(); ++i) + sum += columnModel.getColumn(0).getWidth(); + return getColumnCount() == 0 ? 10 : sum / getColumnCount(); + } + } + + + public TableCellEditor getCellEditor(int row, int column) + { + TableCellEditor editor = columnModel.getColumn(column).getCellEditor(); + + if (editor == null) + editor = getDefaultEditor(dataModel.getColumnClass(column)); + + return editor; + } + + public TableCellEditor getDefaultEditor(Class columnClass) + { + if (defaultEditorsByColumnClass.containsKey(columnClass)) + return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass); + else + { + // FIXME: We have at least an editor for Object.class in our defaults. + TableCellEditor r = new DefaultCellEditor(new JTextField()); + defaultEditorsByColumnClass.put(columnClass, r); + return r; + } + } + + + + public TableCellRenderer getCellRenderer(int row, int column) + { + TableCellRenderer renderer = + columnModel.getColumn(column).getCellRenderer(); + + if (renderer == null) + renderer = getDefaultRenderer(dataModel.getColumnClass(column)); + + return renderer; + } + + public void setDefaultRenderer(Class columnClass, TableCellRenderer rend) + { + defaultRenderersByColumnClass.put(columnClass, rend); + } + + public TableCellRenderer getDefaultRenderer(Class columnClass) + { + if (defaultRenderersByColumnClass.containsKey(columnClass)) + return (TableCellRenderer) defaultRenderersByColumnClass.get(columnClass); + else + { + TableCellRenderer r = new DefaultTableCellRenderer(); + defaultRenderersByColumnClass.put(columnClass, r); + return r; + } + } + + public int convertColumnIndexToModel(int vc) + { + if (vc < 0) + return vc; + else + return columnModel.getColumn(vc).getModelIndex(); + } + + public int convertColumnIndexToView(int mc) + { + if (mc < 0) + return mc; + int ncols = getColumnCount(); + for (int vc = 0; vc < ncols; ++vc) + { + if (columnModel.getColumn(vc).getModelIndex() == mc) + return vc; + } + return -1; + } + + public Component prepareRenderer(TableCellRenderer renderer, + int row, + int column) + { + boolean rsa = getRowSelectionAllowed(); + boolean csa = getColumnSelectionAllowed(); + boolean rs = rsa ? getSelectionModel().isSelectedIndex(row) : false; + boolean cs = csa ? columnModel.getSelectionModel().isSelectedIndex(column) : false; + boolean isSelected = ((rsa && csa && rs && cs) + || (rsa && !csa && rs) + || (!rsa && csa && cs)); + + return renderer.getTableCellRendererComponent(this, + dataModel.getValueAt(row, + convertColumnIndexToModel(column)), + isSelected, + false, // hasFocus + row, column); + } + + + /** + * Get the value of the {@link #autoCreateColumnsFromModel} property. + * + * @return The current value of the property + */ + public boolean getAutoCreateColumnsFromModel() + { + return autoCreateColumnsFromModel; + } + + /** + * Get the value of the {@link #autoResizeMode} property. + * + * @return The current value of the property + */ + public int getAutoResizeMode() + { + return autoResizeMode; + } + + /** + * Get the value of the {@link #rowHeight} property. + * + * @return The current value of the property + */ + public int getRowHeight() + { + return rowHeight; + } + + /** + * Get the value of the {@link #rowMargin} property. + * + * @return The current value of the property + */ + public int getRowMargin() + { + return rowMargin; + } + + /** + * Get the value of the {@link #rowSelectionAllowed} property. + * + * @return The current value of the property + */ + public boolean getRowSelectionAllowed() + { + return rowSelectionAllowed; + } + + /** + * Get the value of the {@link #cellSelectionEnabled} property. + * + * @return The current value of the property + */ + public boolean getCellSelectionEnabled() + { + return getColumnSelectionAllowed() && getRowSelectionAllowed(); + } + + /** + * Get the value of the {@link #dataModel} property. + * + * @return The current value of the property + */ + public TableModel getModel() + { + return dataModel; + } + + /** + * Get the value of the <code>columnCount</code> property by + * delegation to the @{link #columnModel} field. + * + * @return The current value of the columnCount property + */ + public int getColumnCount() + { + return columnModel.getColumnCount(); + } + + /** + * Get the value of the <code>rowCount</code> property by + * delegation to the @{link #dataModel} field. + * + * @return The current value of the rowCount property + */ + public int getRowCount() + { + return dataModel.getRowCount(); + } + + /** + * Get the value of the {@link #columnModel} property. + * + * @return The current value of the property + */ + public TableColumnModel getColumnModel() + { + return columnModel; + } + + /** + * Get the value of the <code>selectedColumn</code> property by + * delegation to the @{link #columnModel} field. + * + * @return The current value of the selectedColumn property + */ + public int getSelectedColumn() + { + return columnModel.getSelectionModel().getMinSelectionIndex(); + } + + private static int countSelections(ListSelectionModel lsm) + { + int lo = lsm.getMinSelectionIndex(); + int hi = lsm.getMaxSelectionIndex(); + int sum = 0; + if (lo != -1 && hi != -1) + { + switch (lsm.getSelectionMode()) + { + case ListSelectionModel.SINGLE_SELECTION: + sum = 1; + break; + + case ListSelectionModel.SINGLE_INTERVAL_SELECTION: + sum = hi - lo + 1; + break; + + case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: + for (int i = lo; i <= hi; ++i) + if (lsm.isSelectedIndex(i)) + ++sum; + break; + } + } + return sum; + } + + private static int[] getSelections(ListSelectionModel lsm) + { + int sz = countSelections(lsm); + int [] ret = new int[sz]; + + int lo = lsm.getMinSelectionIndex(); + int hi = lsm.getMaxSelectionIndex(); + int j = 0; + java.util.ArrayList ls = new java.util.ArrayList(); + if (lo != -1 && hi != -1) + { + switch (lsm.getSelectionMode()) + { + case ListSelectionModel.SINGLE_SELECTION: + ret[0] = lo; + break; + + case ListSelectionModel.SINGLE_INTERVAL_SELECTION: + for (int i = lo; i <= hi; ++i) + ret[j++] = i; + break; + + case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: + for (int i = lo; i <= hi; ++i) + if (lsm.isSelectedIndex(i)) + ret[j++] = i; + break; + } + } + return ret; + } + + /** + * Get the value of the <code>selectedColumnCount</code> property by + * delegation to the @{link #columnModel} field. + * + * @return The current value of the selectedColumnCount property + */ + public int getSelectedColumnCount() + { + return countSelections(columnModel.getSelectionModel()); + } + + /** + * Get the value of the <code>selectedColumns</code> property by + * delegation to the @{link #columnModel} field. + * + * @return The current value of the selectedColumns property + */ + public int[] getSelectedColumns() + { + return getSelections(columnModel.getSelectionModel()); + } + + /** + * Get the value of the <code>columnSelectionAllowed</code> property. + * + * @return The current value of the columnSelectionAllowed property + */ + public boolean getColumnSelectionAllowed() + { + return getColumnModel().getColumnSelectionAllowed(); + } + + /** + * Get the value of the <code>selectedRowCount</code> property by + * delegation to the @{link #selectionModel} field. + * + * @return The current value of the selectedRowCount property + */ + public int getSelectedRowCount() + { + return countSelections(selectionModel); + } + + /** + * Get the value of the <code>selectedRows</code> property by + * delegation to the @{link #selectionModel} field. + * + * @return The current value of the selectedRows property + */ + public int[] getSelectedRows() + { + return getSelections(selectionModel); + } + + /** + * Get the value of the {@link #accessibleContext} property. + * + * @return The current value of the property + */ + public AccessibleContext getAccessibleContext() + { + return accessibleContext; + } + + /** + * Get the value of the {@link #cellEditor} property. + * + * @return The current value of the property + */ + public TableCellEditor getCellEditor() + { + return cellEditor; + } + + /** + * Get the value of the {@link #dragEnabled} property. + * + * @return The current value of the property + */ + public boolean getDragEnabled() + { + return dragEnabled; + } + + /** + * Get the value of the {@link #gridColor} property. + * + * @return The current value of the property + */ + public Color getGridColor() + { + return gridColor; + } + + /** + * Get the value of the <code>intercellSpacing</code> property. + * + * @return The current value of the property + */ + public Dimension getIntercellSpacing() + { + return new Dimension(columnModel.getColumnMargin(), rowMargin); + } + + /** + * Get the value of the {@link #preferredViewportSize} property. + * + * @return The current value of the property + */ + public Dimension getPreferredScrollableViewportSize() + { + return preferredViewportSize; + } + + /** + * Get the value of the {@link #selectionBackground} property. + * + * @return The current value of the property + */ + public Color getSelectionBackground() + { + return selectionBackground; + } + + /** + * Get the value of the {@link #selectionForeground} property. + * + * @return The current value of the property + */ + public Color getSelectionForeground() + { + return selectionForeground; + } + + /** + * Get the value of the {@link #showHorizontalLines} property. + * + * @return The current value of the property + */ + public boolean getShowHorizontalLines() + { + return showHorizontalLines; + } + + /** + * Get the value of the {@link #showVerticalLines} property. + * + * @return The current value of the property + */ + public boolean getShowVerticalLines() + { + return showVerticalLines; + } + + /** + * Get the value of the {@link #tableHeader} property. + * + * @return The current value of the property + */ + public JTableHeader getTableHeader() + { + return tableHeader; + } + + /** + * Removes specified column from displayable columns of this table. + * + * @param column column to removed + */ + public void removeColumn(TableColumn column) + { + columnModel.removeColumn(column); + } + + /** + * Moves column at the specified index to new given location. + * + * @param column index of the column to move + * @param targetColumn index specifying new location of the column + */ + public void moveColumn(int column,int targetColumn) + { + columnModel.moveColumn(column, targetColumn); + } + + /** + * Set the value of the {@link #autoCreateColumnsFromModel} flag. If the + * flag changes from <code>false</code> to <code>true</code>, the + * {@link #createDefaultColumnsFromModel()} method is called. + * + * @param autoCreate the new value of the flag. + */ + public void setAutoCreateColumnsFromModel(boolean autoCreate) + { + if (autoCreateColumnsFromModel != autoCreate) + { + autoCreateColumnsFromModel = autoCreate; + if (autoCreate) + createDefaultColumnsFromModel(); + } + } + + /** + * Set the value of the {@link #autoResizeMode} property. + * + * @param a The new value of the autoResizeMode property + */ + public void setAutoResizeMode(int a) + { + autoResizeMode = a; + revalidate(); + repaint(); + } + + /** + * Set the value of the {@link #rowHeight} property. + * + * @param r The new value of the rowHeight property + */ + public void setRowHeight(int r) + { + if (rowHeight < 1) + throw new IllegalArgumentException(); + + rowHeight = r; + revalidate(); + repaint(); + } + + /** + * Set the value of the {@link #rowMargin} property. + * + * @param r The new value of the rowMargin property + */ + public void setRowMargin(int r) + { + rowMargin = r; + revalidate(); + repaint(); + } + + /** + * Set the value of the {@link #rowSelectionAllowed} property. + * + * @param r The new value of the rowSelectionAllowed property + */ + public void setRowSelectionAllowed(boolean r) + { + rowSelectionAllowed = r; + repaint(); + } + + /** + * Set the value of the {@link #cellSelectionEnabled} property. + * + * @param c The new value of the cellSelectionEnabled property + */ + public void setCellSelectionEnabled(boolean c) + { + setColumnSelectionAllowed(c); + setRowSelectionAllowed(c); + // for backward-compatibility sake: + cellSelectionEnabled = true; + } + + /** + * <p>Set the value of the {@link #dataModel} property.</p> + * + * <p>Unregister <code>this</code> as a {@link TableModelListener} from + * previous {@link #dataModel} and register it with new parameter + * <code>m</code>.</p> + * + * @param m The new value of the model property + */ + public void setModel(TableModel m) + { + // Throw exception is m is null. + if (m == null) + throw new IllegalArgumentException(); + + // Don't do anything if setting the current model again. + if (dataModel == m) + return; + + // Remove table as TableModelListener from old model. + if (dataModel != null) + dataModel.removeTableModelListener(this); + + if (m != null) + { + // Set property. + dataModel = m; + + // Add table as TableModelListener to new model. + dataModel.addTableModelListener(this); + + // Automatically create columns. + if (autoCreateColumnsFromModel) + createColumnsFromModel(); + } + + // Repaint table. + revalidate(); + repaint(); + } + + /** + * <p>Set the value of the {@link #columnModel} property.</p> + * + * <p>Unregister <code>this</code> as a {@link TableColumnModelListener} + * from previous {@link #columnModel} and register it with new parameter + * <code>c</code>.</p> + * + * @param c The new value of the columnModel property + */ + public void setColumnModel(TableColumnModel c) + { + if (c == null) + throw new IllegalArgumentException(); + TableColumnModel tmp = columnModel; + if (tmp != null) + tmp.removeColumnModelListener(this); + if (c != null) + c.addColumnModelListener(this); + columnModel = c; + if (dataModel != null && columnModel != null) + { + int ncols = getColumnCount(); + for (int i = 0; i < ncols; ++i) + columnModel.getColumn(i).setHeaderValue(dataModel.getColumnName(i)); + } + + // according to Sun's spec we also have to set the tableHeader's + // column model here + if (tableHeader != null) + tableHeader.setColumnModel(c); + + revalidate(); + repaint(); + } + + /** + * Set the value of the <code>columnSelectionAllowed</code> property. + * + * @param c The new value of the property + */ + public void setColumnSelectionAllowed(boolean c) + { + getColumnModel().setColumnSelectionAllowed(c); + repaint(); + } + + /** + * <p>Set the value of the {@link #selectionModel} property.</p> + * + * <p>Unregister <code>this</code> as a {@link ListSelectionListener} + * from previous {@link #selectionModel} and register it with new + * parameter <code>s</code>.</p> + * + * @param s The new value of the selectionModel property + */ + public void setSelectionModel(ListSelectionModel s) + { + if (s == null) + throw new IllegalArgumentException(); + ListSelectionModel tmp = selectionModel; + if (tmp != null) + tmp.removeListSelectionListener(this); + if (s != null) + s.addListSelectionListener(this); + selectionModel = s; + } + + /** + * Set the value of the <code>selectionMode</code> property by + * delegation to the {@link #selectionModel} field. The same selection + * mode is set for row and column selection models. + * + * @param s The new value of the property + */ + public void setSelectionMode(int s) + { + selectionModel.setSelectionMode(s); + columnModel.getSelectionModel().setSelectionMode(s); + + repaint(); + } + + /** + * <p>Set the value of the {@link #cellEditor} property.</p> + * + * <p>Unregister <code>this</code> as a {@link CellEditorListener} from + * previous {@link #cellEditor} and register it with new parameter + * <code>c</code>.</p> + * + * @param c The new value of the cellEditor property + */ + public void setCellEditor(TableCellEditor c) + { + TableCellEditor tmp = cellEditor; + if (tmp != null) + tmp.removeCellEditorListener(this); + if (c != null) + c.addCellEditorListener(this); + cellEditor = c; + } + + /** + * Set the value of the {@link #dragEnabled} property. + * + * @param d The new value of the dragEnabled property + */ + public void setDragEnabled(boolean d) + { + dragEnabled = d; + } + + /** + * Set the value of the {@link #gridColor} property. + * + * @param g The new value of the gridColor property + */ + public void setGridColor(Color g) + { + gridColor = g; + repaint(); + } + + /** + * Set the value of the <code>intercellSpacing</code> property. + * + * @param i The new value of the intercellSpacing property + */ + public void setIntercellSpacing(Dimension i) + { + rowMargin = i.height; + columnModel.setColumnMargin(i.width); + repaint(); + } + + /** + * Set the value of the {@link #preferredViewportSize} property. + * + * @param p The new value of the preferredViewportSize property + */ + public void setPreferredScrollableViewportSize(Dimension p) + { + preferredViewportSize = p; + revalidate(); + repaint(); + } + + /** + * <p>Set the value of the {@link #selectionBackground} property.</p> + * + * <p>Fire a PropertyChangeEvent with name {@link + * #SELECTION_BACKGROUND_CHANGED_PROPERTY} to registered listeners, if + * selectionBackground changed.</p> + * + * @param s The new value of the selectionBackground property + */ + public void setSelectionBackground(Color s) + { + Color tmp = selectionBackground; + selectionBackground = s; + if (((tmp == null && s != null) + || (s == null && tmp != null) + || (tmp != null && s != null && !tmp.equals(s)))) + firePropertyChange(SELECTION_BACKGROUND_CHANGED_PROPERTY, tmp, s); + repaint(); + } + + /** + * <p>Set the value of the {@link #selectionForeground} property.</p> + * + * <p>Fire a PropertyChangeEvent with name {@link + * #SELECTION_FOREGROUND_CHANGED_PROPERTY} to registered listeners, if + * selectionForeground changed.</p> + * + * @param s The new value of the selectionForeground property + */ + public void setSelectionForeground(Color s) + { + Color tmp = selectionForeground; + selectionForeground = s; + if (((tmp == null && s != null) + || (s == null && tmp != null) + || (tmp != null && s != null && !tmp.equals(s)))) + firePropertyChange(SELECTION_FOREGROUND_CHANGED_PROPERTY, tmp, s); + repaint(); + } + + /** + * Set the value of the <code>showGrid</code> property. + * + * @param s The new value of the showGrid property + */ + public void setShowGrid(boolean s) + { + setShowVerticalLines(s); + setShowHorizontalLines(s); + } + + /** + * Set the value of the {@link #showHorizontalLines} property. + * + * @param s The new value of the showHorizontalLines property + */ + public void setShowHorizontalLines(boolean s) + { + showHorizontalLines = s; + repaint(); + } + + /** + * Set the value of the {@link #showVerticalLines} property. + * + * @param s The new value of the showVerticalLines property + */ + public void setShowVerticalLines(boolean s) + { + showVerticalLines = s; + repaint(); + } + + /** + * Set the value of the {@link #tableHeader} property. + * + * @param t The new value of the tableHeader property + */ + public void setTableHeader(JTableHeader t) + { + if (tableHeader != null) + tableHeader.setTable(null); + tableHeader = t; + if (tableHeader != null) + tableHeader.setTable(this); + revalidate(); + repaint(); + } + + protected void configureEnclosingScrollPane() + { + JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this); + if (jsp != null && tableHeader != null) + { + jsp.setColumnHeaderView(tableHeader); + } + } + + protected void unconfigureEnclosingScrollPane() + { + JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this); + if (jsp != null) + { + jsp.setColumnHeaderView(null); + } + } + + + public void addNotify() + { + super.addNotify(); + configureEnclosingScrollPane(); + } + + public void removeNotify() + { + super.addNotify(); + unconfigureEnclosingScrollPane(); + } + + + /** + * This distributes the superfluous width in a table evenly on its columns. + * + * The implementation used here is different to that one described in + * the JavaDocs. It is much simpler, and seems to work very well. + * + * TODO: correctly implement the algorithm described in the JavaDoc + */ + private void distributeSpill(TableColumn[] cols, int spill) + { + int average = spill / cols.length; + for (int i = 0; i < cols.length; i++) + { + cols[i].setWidth(cols[i].getWidth() + average); + } + } + + public void doLayout() + { + TableColumn resizingColumn = null; + + int ncols = getColumnCount(); + if (ncols < 1) + return; + + int[] pref = new int[ncols]; + int prefSum = 0; + int rCol = -1; + + if (tableHeader != null) + resizingColumn = tableHeader.getResizingColumn(); + + for (int i = 0; i < ncols; ++i) + { + TableColumn col = columnModel.getColumn(i); + int p = col.getWidth(); + pref[i] = p; + prefSum += p; + if (resizingColumn == col) + rCol = i; + } + + int spill = getWidth() - prefSum; + + if (resizingColumn != null) + { + TableColumn col; + TableColumn [] cols; + + switch (getAutoResizeMode()) + { + case AUTO_RESIZE_LAST_COLUMN: + col = columnModel.getColumn(ncols-1); + col.setWidth(col.getPreferredWidth() + spill); + break; + + case AUTO_RESIZE_NEXT_COLUMN: + col = columnModel.getColumn(ncols-1); + col.setWidth(col.getPreferredWidth() + spill); + break; + + case AUTO_RESIZE_ALL_COLUMNS: + cols = new TableColumn[ncols]; + for (int i = 0; i < ncols; ++i) + cols[i] = columnModel.getColumn(i); + distributeSpill(cols, spill); + break; + + case AUTO_RESIZE_SUBSEQUENT_COLUMNS: + cols = new TableColumn[ncols]; + for (int i = rCol; i < ncols; ++i) + cols[i] = columnModel.getColumn(i); + distributeSpill(cols, spill); + break; + + case AUTO_RESIZE_OFF: + default: + } + } + else + { + TableColumn [] cols = new TableColumn[ncols]; + for (int i = 0; i < ncols; ++i) + cols[i] = columnModel.getColumn(i); + distributeSpill(cols, spill); + } + } + + /** + * @deprecated Replaced by <code>doLayout()</code> + */ + public void sizeColumnsToFit(boolean lastColumnOnly) + { + doLayout(); + } + + /** + * Obsolete since JDK 1.4. Please use <code>doLayout()</code>. + */ + public void sizeColumnsToFit(int resizingColumn) + { + doLayout(); + } + + public String getUIClassID() + { + return "TableUI"; + } + + /** + * This method returns the table's UI delegate. + * + * @return The table's UI delegate. + */ + public TableUI getUI() + { + return (TableUI) ui; + } + + /** + * This method sets the table's UI delegate. + * + * @param ui The table's UI delegate. + */ + public void setUI(TableUI ui) + { + super.setUI(ui); + } + + public void updateUI() + { + setUI((TableUI) UIManager.getUI(this)); + revalidate(); + repaint(); + } + + public Class getColumnClass(int column) + { + return dataModel.getColumnClass(column); + } + + public String getColumnName(int column) + { + int modelColumn = columnModel.getColumn(column).getModelIndex(); + return dataModel.getColumnName(modelColumn); + } + + public int getEditingColumn() + { + return editingColumn; + } + + public void setEditingColumn(int column) + { + editingColumn = column; + } + + public int getEditingRow() + { + return editingRow; + } + + public void setEditingRow(int column) + { + editingRow = column; + } + + public Component getEditorComponent() + { + return editorComp; + } + + public boolean isEditing() + { + return editorComp != null; + } + + public void setDefaultEditor(Class columnClass, TableCellEditor editor) + { + if (editor != null) + defaultEditorsByColumnClass.put(columnClass, editor); + else + defaultEditorsByColumnClass.remove(columnClass); + } + + public void addColumnSelectionInterval(int index0, int index1) + { + if ((index0 < 0 || index0 > (getColumnCount()-1) + || index1 < 0 || index1 > (getColumnCount()-1))) + throw new IllegalArgumentException("Column index out of range."); + + getColumnModel().getSelectionModel().addSelectionInterval(index0, index1); + } + + public void addRowSelectionInterval(int index0, int index1) + { + if ((index0 < 0 || index0 > (getRowCount()-1) + || index1 < 0 || index1 > (getRowCount()-1))) + throw new IllegalArgumentException("Row index out of range."); + + getSelectionModel().addSelectionInterval(index0, index1); + } + + public void setColumnSelectionInterval(int index0, int index1) + { + if ((index0 < 0 || index0 > (getColumnCount()-1) + || index1 < 0 || index1 > (getColumnCount()-1))) + throw new IllegalArgumentException("Column index out of range."); + + getColumnModel().getSelectionModel().setSelectionInterval(index0, index1); + } + + public void setRowSelectionInterval(int index0, int index1) + { + if ((index0 < 0 || index0 > (getRowCount()-1) + || index1 < 0 || index1 > (getRowCount()-1))) + throw new IllegalArgumentException("Row index out of range."); + + getSelectionModel().setSelectionInterval(index0, index1); + } + + public void removeColumnSelectionInterval(int index0, int index1) + { + if ((index0 < 0 || index0 > (getColumnCount()-1) + || index1 < 0 || index1 > (getColumnCount()-1))) + throw new IllegalArgumentException("Column index out of range."); + + getColumnModel().getSelectionModel().removeSelectionInterval(index0, index1); + } + + public void removeRowSelectionInterval(int index0, int index1) + { + if ((index0 < 0 || index0 > (getRowCount()-1) + || index1 < 0 || index1 > (getRowCount()-1))) + throw new IllegalArgumentException("Row index out of range."); + + getSelectionModel().removeSelectionInterval(index0, index1); + } + + public boolean isColumnSelected(int column) + { + return getColumnModel().getSelectionModel().isSelectedIndex(column); + } + + public boolean isRowSelected(int row) + { + return getSelectionModel().isSelectedIndex(row); + } + + public boolean isCellSelected(int row, int column) + { + return isRowSelected(row) && isColumnSelected(column); + } + + public void selectAll() + { + setColumnSelectionInterval(0, getColumnCount() - 1); + setRowSelectionInterval(0, getRowCount() - 1); + } + + public Object getValueAt(int row, int column) + { + return dataModel.getValueAt(row, convertColumnIndexToModel(column)); + } + + public void setValueAt(Object value, int row, int column) + { + dataModel.setValueAt(value, row, convertColumnIndexToModel(column)); + } + + public TableColumn getColumn(Object identifier) + { + return columnModel.getColumn(columnModel.getColumnIndex(identifier)); + } + + /** + * Returns <code>true</code> if the specified cell is editable, and + * <code>false</code> otherwise. + * + * @param row the row index. + * @param column the column index. + * + * @return A boolean. + */ + public boolean isCellEditable(int row, int column) + { + return dataModel.isCellEditable(row, convertColumnIndexToModel(column)); + } + + /** + * Clears any existing columns from the <code>JTable</code>'s + * {@link TableColumnModel} and creates new columns to match the values in + * the data ({@link TableModel}) used by the table. + * + * @see #setAutoCreateColumnsFromModel(boolean) + */ + public void createDefaultColumnsFromModel() + { + // remove existing columns + int columnIndex = columnModel.getColumnCount() - 1; + while (columnIndex >= 0) + { + columnModel.removeColumn(columnModel.getColumn(columnIndex)); + columnIndex--; + } + + // add new columns to match the TableModel + int columnCount = dataModel.getColumnCount(); + for (int c = 0; c < columnCount; c++) + { + TableColumn column = new TableColumn(c); + column.setIdentifier(dataModel.getColumnName(c)); + columnModel.addColumn(column); + } + } + + public void changeSelection (int rowIndex, int columnIndex, boolean toggle, boolean extend) + { + if (toggle && extend) + { + // Leave the selection state as is, but move the anchor + // index to the specified location + selectionModel.setAnchorSelectionIndex(rowIndex); + getColumnModel().getSelectionModel().setAnchorSelectionIndex(columnIndex); + } + else if (toggle) + { + // Toggle the state of the specified cell + if (isCellSelected(rowIndex,columnIndex)) + { + selectionModel.removeSelectionInterval(rowIndex,rowIndex); + getColumnModel().getSelectionModel().removeSelectionInterval(columnIndex,columnIndex); + } + else + { + selectionModel.addSelectionInterval(rowIndex,rowIndex); + getColumnModel().getSelectionModel().addSelectionInterval(columnIndex,columnIndex); + } + } + else if (extend) + { + // Extend the previous selection from the anchor to the + // specified cell, clearing all other selections + selectionModel.setLeadSelectionIndex(rowIndex); + getColumnModel().getSelectionModel().setLeadSelectionIndex(columnIndex); + } + else + { + // Clear the previous selection and ensure the new cell + // is selected + selectionModel.clearSelection(); + selectionModel.setSelectionInterval(rowIndex,rowIndex); + getColumnModel().getSelectionModel().clearSelection(); + getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex); + + + } + } +} diff --git a/libjava/classpath/javax/swing/JTextArea.java b/libjava/classpath/javax/swing/JTextArea.java new file mode 100644 index 00000000000..fb35eb3d14c --- /dev/null +++ b/libjava/classpath/javax/swing/JTextArea.java @@ -0,0 +1,550 @@ +/* JTextArea.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Rectangle; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.Element; +import javax.swing.text.JTextComponent; +import javax.swing.text.PlainDocument; +import javax.swing.text.View; + +/** + * The <code>JTextArea</code> component provides a multi-line area for displaying + * and editing plain text. The component is designed to act as a lightweight + * replacement for the heavyweight <code>java.awt.TextArea</code> component, + * which provides similar functionality using native widgets. + * <p> + * + * This component has additional functionality to the AWT class. It follows + * the same design pattern as seen in other text components, such as + * <code>JTextField</code>, <code>JTextPane</code> and <code>JEditorPane</code>, + * and embodied in <code>JTextComponent</code>. These classes separate the text + * (the model) from its appearance within the onscreen component (the view). The + * text is held within a <code>javax.swing.text.Document</code> object, which can + * also maintain relevant style information where necessary. As a result, it is the + * document that should be monitored for textual changes, via + * <code>DocumentEvent</code>s delivered to registered + * <code>DocumentListener</code>s, rather than this component. + * <p> + * + * Unlike <code>java.awt.TextArea</code>, <code>JTextArea</code> does not + * handle scrolling. Instead, this functionality is delegated to a + * <code>JScrollPane</code>, which can contain the text area and handle + * scrolling when required. Likewise, the word wrapping functionality + * of the AWT component is converted to a property of this component + * and the <code>rows</code> and <code>columns</code> properties + * are used in calculating the preferred size of the scroll pane's + * view port. + * + * @author Michael Koch (konqueror@gmx.de) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see java.awt.TextArea + * @see javax.swing.JTextComponent + * @see javax.swing.JTextField + * @see javax.swing.JTextPane + * @see javax.swing.JEditorPane + * @see javax.swing.text.Document + * @see javax.swing.text.DocumentEvent + * @see javax.swing.text.DocumentListener + */ + +public class JTextArea extends JTextComponent +{ + /** + * Compatible with Sun's JDK + */ + private static final long serialVersionUID = -6141680179310439825L; + + /** + * The number of rows used by the component. + */ + private int rows; + + /** + * The number of columns used by the component. + */ + private int columns; + + /** + * Whether line wrapping is enabled or not. + */ + private boolean lineWrap; + + /** + * The number of characters equal to a tab within the text. + */ + private int tabSize = 8; + + private boolean wrapStyleWord; + + /** + * Creates a new <code>JTextArea</code> object. + */ + public JTextArea() + { + this(null, null, 0, 0); + } + + /** + * Creates a new <code>JTextArea</code> object. + * + * @param text the initial text + */ + public JTextArea(String text) + { + this(null, text, 0, 0); + } + + /** + * Creates a new <code>JTextArea</code> object. + * + * @param rows the number of rows + * @param columns the number of cols + * + * @exception IllegalArgumentException if rows or columns are negative + */ + public JTextArea(int rows, int columns) + { + this(null, null, rows, columns); + } + + /** + * Creates a new <code>JTextArea</code> object. + * + * @param text the initial text + * @param rows the number of rows + * @param columns the number of cols + * + * @exception IllegalArgumentException if rows or columns are negative + */ + public JTextArea(String text, int rows, int columns) + { + this(null, text, rows, columns); + } + + /** + * Creates a new <code>JTextArea</code> object. + * + * @param the document model to use + */ + public JTextArea(Document doc) + { + this(doc, null, 0, 0); + } + + /** + * Creates a new <code>JTextArea</code> object. + * + * @param the document model to use + * @param text the initial text + * @param rows the number of rows + * @param columns the number of cols + * + * @exception IllegalArgumentException if rows or columns are negative + */ + public JTextArea(Document doc, String text, int rows, int columns) + { + setDocument(doc == null ? createDefaultModel() : doc); + setText(text); + setRows(rows); + setColumns(columns); + } + + /** + * Appends the supplied text to the current contents + * of the document model. + * + * @param toAppend the text to append + */ + public void append(String toAppend) + { + try + { + getDocument().insertString(getText().length(), toAppend, null); + } + catch (BadLocationException exception) + { + /* This shouldn't happen in theory -- but, if it does... */ + throw new RuntimeException("Unexpected exception occurred.", exception); + } + } + + /** + * Creates the default document model. + * + * @return a new default model + */ + protected Document createDefaultModel() + { + return new PlainDocument(); + } + + /** + * Returns true if the width of this component should be forced + * to match the width of a surrounding view port. When line wrapping + * is turned on, this method returns true. + * + * @return true if lines are wrapped. + */ + public boolean getScrollableTracksViewportWidth() + { + return lineWrap ? true : super.getScrollableTracksViewportWidth(); + } + + /** + * Returns the increment that is needed to expose exactly one new line + * of text. This is implemented here to return the values of + * {@link #getRowHeight} and {@link getColumnWidth}, depending on + * the value of the argument <code>direction</code>. + * + * @param visibleRect the view area that is visible in the viewport + * @param orientation either {@link SwingConstants.VERTICAL} or + * {@link SwingConstants.HORIZONTAL} + * @param direction less than zero for up/left scrolling, greater + * than zero for down/right scrolling + * + * @return the increment that is needed to expose exactly one new row + * or column of text + * + * @throws IllegalArgumentException if <code>orientation</code> is invalid + */ + public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, + int direction) + { + if (orientation == SwingConstants.VERTICAL) + return getRowHeight(); + else if (orientation == SwingConstants.HORIZONTAL) + return getColumnWidth(); + else + throw new IllegalArgumentException("orientation must be either " + + "javax.swing.SwingConstants.VERTICAL " + + "or " + + "javax.swing.SwingConstants.HORIZONTAL" + ); + } + + /** + * Returns the preferred size of that text component in the case + * it is embedded within a JScrollPane. This uses the column and + * row settings if they are explicitly set, or fall back to + * the superclass's behaviour. + * + * @return the preferred size of that text component in the case + * it is embedded within a JScrollPane + */ + public Dimension getPreferredScrollableViewportSize() + { + if ((rows > 0) && (columns > 0)) + return new Dimension(columns * getColumnWidth(), rows * getRowHeight()); + else + return super.getPreferredScrollableViewportSize(); + } + + /** + * Returns the UI class ID string. + * + * @return the string "TextAreaUI" + */ + public String getUIClassID() + { + return "TextAreaUI"; + } + + /** + * Returns the current number of columns. + * + * @return number of columns + */ + public int getColumns() + { + return columns; + } + + /** + * Sets the number of rows. + * + * @param columns number of columns + * + * @exception IllegalArgumentException if columns is negative + */ + public void setColumns(int columns) + { + if (columns < 0) + throw new IllegalArgumentException(); + + this.columns = columns; + } + + /** + * Returns the current number of rows. + * + * @return number of rows + */ + public int getRows() + { + return rows; + } + + /** + * Sets the number of rows. + * + * @param columns number of columns + * + * @exception IllegalArgumentException if rows is negative + */ + public void setRows(int rows) + { + if (rows < 0) + throw new IllegalArgumentException(); + + this.rows = rows; + } + + /** + * Checks whether line wrapping is enabled. + * + * @return <code>true</code> if line wrapping is enabled, + * <code>false</code> otherwise + */ + public boolean getLineWrap() + { + return lineWrap; + } + + /** + * Enables/disables line wrapping. + * + * @param wrapping <code>true</code> to enable line wrapping, + * <code>false</code> otherwise + */ + public void setLineWrap(boolean flag) + { + if (lineWrap == flag) + return; + + boolean oldValue = lineWrap; + lineWrap = flag; + firePropertyChange("lineWrap", oldValue, lineWrap); + } + + /** + * Checks whether word style wrapping is enabled. + * + * @return <code>true</code> if word style wrapping is enabled, + * <code>false</code> otherwise + */ + public boolean getWrapStyleWord() + { + return wrapStyleWord; + } + + /** + * Enables/Disables word style wrapping. + * + * @param flag <code>true</code> to enable word style wrapping, + * <code>false</code> otherwise + */ + public void setWrapStyleWord(boolean flag) + { + if (wrapStyleWord == flag) + return; + + boolean oldValue = wrapStyleWord; + wrapStyleWord = flag; + firePropertyChange("wrapStyleWord", oldValue, wrapStyleWord); + } + + /** + * Returns the number of characters used for a tab. + * This defaults to 8. + * + * @return the current number of spaces used for a tab. + */ + public int getTabSize() + { + return tabSize; + } + + /** + * Sets the number of characters used for a tab to the + * supplied value. If a change to the tab size property + * occurs (i.e. newSize != tabSize), a property change event + * is fired. + * + * @param newSize The new number of characters to use for a tab. + */ + public void setTabSize(int newSize) + { + if (tabSize == newSize) + return; + + int oldValue = tabSize; + tabSize = newSize; + firePropertyChange("tabSize", oldValue, tabSize); + } + + protected int getColumnWidth() + { + FontMetrics metrics = getToolkit().getFontMetrics(getFont()); + return metrics.charWidth('m'); + } + + public int getLineCount() + { + return getDocument().getDefaultRootElement().getElementCount(); + } + + public int getLineStartOffset(int line) + throws BadLocationException + { + int lineCount = getLineCount(); + + if (line < 0 || line > lineCount) + throw new BadLocationException("Non-existing line number", line); + + Element lineElem = getDocument().getDefaultRootElement().getElement(line); + return lineElem.getStartOffset(); + } + + public int getLineEndOffset(int line) + throws BadLocationException + { + int lineCount = getLineCount(); + + if (line < 0 || line > lineCount) + throw new BadLocationException("Non-existing line number", line); + + Element lineElem = getDocument().getDefaultRootElement().getElement(line); + return lineElem.getEndOffset(); + } + + public int getLineOfOffset(int offset) + throws BadLocationException + { + Document doc = getDocument(); + + if (offset < doc.getStartPosition().getOffset() + || offset >= doc.getEndPosition().getOffset()) + throw new BadLocationException("offset outside of document", offset); + + return doc.getDefaultRootElement().getElementIndex(offset); + } + + protected int getRowHeight() + { + FontMetrics metrics = getToolkit().getFontMetrics(getFont()); + return metrics.getHeight(); + } + + /** + * Inserts the supplied text at the specified position. Nothing + * happens in the case that the model or the supplied string is null + * or of zero length. + * + * @param string The string of text to insert. + * @param position The position at which to insert the supplied text. + * @throws IllegalArgumentException if the position is < 0 or greater + * than the length of the current text. + */ + public void insert(String string, int position) + { + // Retrieve the document model. + Document doc = getDocument(); + + // Check the model and string for validity. + if (doc == null + || string == null + || string.length() == 0) + return; + + // Insert the text into the model. + try + { + doc.insertString(position, string, null); + } + catch (BadLocationException e) + { + throw new IllegalArgumentException("The supplied position, " + + position + ", was invalid."); + } + } + + public void replaceRange(String text, int start, int end) + { + Document doc = getDocument(); + + if (start > end + || start < doc.getStartPosition().getOffset() + || end >= doc.getEndPosition().getOffset()) + throw new IllegalArgumentException(); + + try + { + doc.remove(start, end - start); + doc.insertString(start, text, null); + } + catch (BadLocationException e) + { + // This cannot happen as we check offset above. + } + } + + /** + * Returns the preferred size for the JTextArea. This is the maximum of + * the size that is needed to display the content and the requested size + * as per {@link #getColumns} and {@link #getRows}. + * + * @return the preferred size of the JTextArea + */ + public Dimension getPreferredSize() + { + int reqWidth = getColumns() * getColumnWidth(); + int reqHeight = getRows() * getRowHeight(); + View view = getUI().getRootView(this); + int neededWidth = (int) view.getPreferredSpan(View.HORIZONTAL); + int neededHeight = (int) view.getPreferredSpan(View.VERTICAL); + return new Dimension(Math.max(reqWidth, neededWidth), + Math.max(reqHeight, neededHeight)); + } +} diff --git a/libjava/classpath/javax/swing/JTextField.java b/libjava/classpath/javax/swing/JTextField.java new file mode 100644 index 00000000000..7d8407fa019 --- /dev/null +++ b/libjava/classpath/javax/swing/JTextField.java @@ -0,0 +1,441 @@ +/* JTextField.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.accessibility.AccessibleStateSet; +import javax.swing.text.AttributeSet; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import javax.swing.text.PlainDocument; +import javax.swing.text.TextAction; + +public class JTextField extends JTextComponent + implements SwingConstants +{ + /** + * AccessibleJTextField + */ + protected class AccessibleJTextField extends AccessibleJTextComponent + { + private static final long serialVersionUID = 8255147276740453036L; + + /** + * Constructor AccessibleJTextField + */ + protected AccessibleJTextField() + { + } + + /** + * getAccessibleStateSet + * @return AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + } + + private static final long serialVersionUID = 353853209832607592L; + + private static final Action[] actions; + + /** + * Name of the action that gets sent when the content of the text field + * gets accepted. + */ + public static final String notifyAction = "notify-field-accept"; + + static + { + actions = new Action[1]; + actions[0] = new TextAction(notifyAction) + { + public void actionPerformed(ActionEvent event) + { + JTextField textField = (JTextField) event.getSource(); + textField.fireActionPerformed(); + } + }; + } + + private int columns; + private int align; + private int scrollOffset; + + /** @since 1.3 */ + private Action action; + + /** @since 1.3 */ + private String actionCommand; + + private PropertyChangeListener actionPropertyChangeListener; + + /** + * Creates a new instance of <code>JTextField</code>. + */ + public JTextField() + { + this(null, null, 0); + } + + /** + * Creates a new instance of <code>JTextField</code>. + * + * @param text the initial text + */ + public JTextField(String text) + { + this(null, text, 0); + } + + /** + * Creates a new instance of <code>JTextField</code>. + * + * @param columns the number of columns + * + * @exception IllegalArgumentException if columns %lt; 0 + */ + public JTextField(int columns) + { + this(null, null, columns); + } + + /** + * Creates a new instance of <code>JTextField</code>. + * + * @param text the initial text + * @param columns the number of columns + * + * @exception IllegalArgumentException if columns %lt; 0 + */ + public JTextField(String text, int columns) + { + this(null, text, columns); + } + + /** + * Creates a new instance of <code>JTextField</code>. + * + * @param doc the document to use + * @param text the initial text + * @param columns the number of columns + * + * @exception IllegalArgumentException if columns %lt; 0 + */ + public JTextField(Document doc, String text, int columns) + { + if (columns < 0) + throw new IllegalArgumentException(); + + this.columns = columns; + + setDocument(doc == null ? createDefaultModel() : doc); + + if (text != null) + setText(text); + + // default value for alignment + align = LEADING; + } + + /** + * Creates the default model for this text field. + * This implementation returns an instance of <code>PlainDocument</code>. + * + * @return a new instance of the default model + */ + protected Document createDefaultModel() + { + // subclassed to swallow newlines + return new PlainDocument() { + public void insertString(int offset, String str, AttributeSet a) + throws BadLocationException + { + if (str.indexOf('\n') == -1) + super.insertString(offset, str, a); + } + }; + } + + /** + * Returns the class ID for the UI. + * + * @return "TextFieldUI"; + */ + public String getUIClassID() + { + return "TextFieldUI"; + } + + /** + * Adds a new listener object to this text field. + * + * @param listener the listener to add + */ + public void addActionListener(ActionListener listener) + { + listenerList.add(ActionListener.class, listener); + } + + /** + * Removes a listener object from this text field. + * + * @param listener the listener to remove + */ + public void removeActionListener(ActionListener listener) + { + listenerList.remove(ActionListener.class, listener); + } + + /** + * Returns all registered <code>ActionListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public ActionListener[] getActionListeners() + { + return (ActionListener[]) getListeners(ActionListener.class); + } + + /** + * Sends an action event to all registered + * <code>ActionListener</code> objects. + */ + protected void fireActionPerformed() + { + ActionEvent event = new ActionEvent(this, 0, notifyAction); + ActionListener[] listeners = getActionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].actionPerformed(event); + } + + /** + * Returns the number of columns of this text field. + * + * @return the number of columns + */ + public int getColumns() + { + return columns; + } + + public void setColumns(int columns) + { + if (columns < 0) + throw new IllegalArgumentException(); + + this.columns = columns; + invalidate(); + repaint(); + } + + public int getHorizontalAlignment() + { + return align; + } + + public void setHorizontalAlignment(int newAlign) + { + if (align == newAlign) + return; + + int oldAlign = align; + align = newAlign; + firePropertyChange("horizontalAlignment", oldAlign, newAlign); + invalidate(); + repaint(); + } + + public void setFont(Font newFont) + { + super.setFont(newFont); + revalidate(); + } + + public Dimension getPreferredSize() + { + Dimension size = super.getPreferredSize(); + + if (columns != 0) + size.width = columns * getColumnWidth(); + + return size; + } + + /** + * Returns the scroll offset in pixels. + * + * @return the scroll offset + */ + public int getScrollOffset() + { + return scrollOffset; + } + + /** + * Sets the scroll offset in pixels. + * + * @param offset the scroll offset + */ + public void setScrollOffset(int offset) + { + scrollOffset = offset; + } + + public Action[] getActions() + { + return TextAction.augmentList(super.getActions(), actions); + } + + public void postActionEvent() + { + String command = actionCommand != null ? actionCommand : getText(); + ActionEvent event = new ActionEvent(this, 0, command); + ActionListener[] listeners = getActionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].actionPerformed(event); + } + + /** + * @since 1.3 + */ + public Action getAction() + { + return action; + } + + /** + * @since 1.3 + */ + public void setAction(Action newAction) + { + if (action == newAction) + return; + + if (action != null) + { + removeActionListener(action); + action.removePropertyChangeListener(actionPropertyChangeListener); + actionPropertyChangeListener = null; + } + + Action oldAction = action; + action = newAction; + + if (action != null) + { + addActionListener(action); + actionPropertyChangeListener = + createActionPropertyChangeListener(action); + action.addPropertyChangeListener(actionPropertyChangeListener); + } + + firePropertyChange("horizontalAlignment", oldAction, newAction); + } + + /** + * @since 1.3 + */ + public void setActionCommand(String command) + { + actionCommand = command; + } + + /** + * @since 1.3 + */ + protected PropertyChangeListener createActionPropertyChangeListener(Action action) + { + return new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent event) + { + // Update properties "action" and "horizontalAlignment". + String name = event.getPropertyName(); + + if (name.equals("enabled")) + { + boolean enabled = ((Boolean) event.getNewValue()).booleanValue(); + JTextField.this.setEnabled(enabled); + } + else if (name.equals(Action.SHORT_DESCRIPTION)) + { + JTextField.this.setToolTipText((String) event.getNewValue()); + } + } + }; + } + + /** + * @since 1.3 + */ + protected void configurePropertiesFromAction(Action action) + { + if (action != null) + { + setEnabled(action.isEnabled()); + setToolTipText((String) action.getValue(Action.SHORT_DESCRIPTION)); + } + else + { + setEnabled(true); + setToolTipText(null); + } + } + + protected int getColumnWidth() + { + FontMetrics metrics = getToolkit().getFontMetrics(getFont()); + return metrics.charWidth('m'); + } +} diff --git a/libjava/classpath/javax/swing/JTextPane.java b/libjava/classpath/javax/swing/JTextPane.java new file mode 100644 index 00000000000..532181258c8 --- /dev/null +++ b/libjava/classpath/javax/swing/JTextPane.java @@ -0,0 +1,270 @@ +/* JTextPane.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.io.IOException; +import java.io.ObjectOutputStream; + +import javax.swing.text.AttributeSet; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.Style; +import javax.swing.text.StyledDocument; +import javax.swing.text.StyledEditorKit; + +/** + * JTextPane + * @author Andrew Selkirk + * @version 1.0 + */ +public class JTextPane extends JEditorPane { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * uiClassID + */ + private static final String uiClassID = "TextPaneUI"; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor JTextPane + */ + public JTextPane() { + // TODO + } // JTextPane() + + /** + * Constructor JTextPane + * @param document TODO + */ + public JTextPane(StyledDocument document) { + // TODO + } // JTextPane() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getUIClassID + * @returns String + */ + public String getUIClassID() { + return uiClassID; + } // getUIClassID() + + /** + * setDocument + * @param document TODO + */ + public void setDocument(Document document) { + super.setDocument(document); // TODO + } // setDocument() + + /** + * getStyledDocument + * @returns StyledDocument + */ + public StyledDocument getStyledDocument() { + return null; // TODO + } // getStyledDocument() + + /** + * setStyledDocument + * @param document TODO + */ + public void setStyledDocument(StyledDocument document) { + // TODO + } // setStyledDocument() + + /** + * replaceSelection + * @param content TODO + */ + public void replaceSelection(String content) { + super.replaceSelection(content); // TODO + } // replaceSelection() + + /** + * insertComponent + * @param component TODO + */ + public void insertComponent(Component component) { + // TODO + } // insertComponent() + + /** + * insertIcon + * @param icon TODO + */ + public void insertIcon(Icon icon) { + // TODO + } // insertIcon() + + /** + * addStyle + * @param nm TODO + * @param parent TODO + * @returns Style + */ + public Style addStyle(String nm, Style parent) { + return null; // TODO + } // addStyle() + + /** + * removeStyle + * @param nm TODO + */ + public void removeStyle(String nm) { + // TODO + } // removeStyle() + + /** + * getStyle + * @param nm TODO + * @returns Style + */ + public Style getStyle(String nm) { + return null; // TODO + } // getStyle() + + /** + * getLogicalStyle + * @returns Style + */ + public Style getLogicalStyle() { + return null; // TODO + } // getLogicalStyle() + + /** + * setLogicalStyle + * @param style TODO + */ + public void setLogicalStyle(Style style) { + // TODO + } // setLogicalStyle() + + /** + * getCharacterAttributes + * @returns AttributeSet + */ + public AttributeSet getCharacterAttributes() { + return null; // TODO + } // getCharacterAttributes() + + /** + * setCharacterAttributes + * @param attribute TODO + * @param replace TODO + */ + public void setCharacterAttributes(AttributeSet attribute, + boolean replace) { + // TODO + } // setCharacterAttributes() + + /** + * getParagraphAttributes + * @returns AttributeSet + */ + public AttributeSet getParagraphAttributes() { + return null; // TODO + } // getParagraphAttributes() + + /** + * setParagraphAttributes + * @param attribute TODO + * @param replace TODO + */ + public void setParagraphAttributes(AttributeSet attribute, + boolean replace) { + // TODO + } // setParagraphAttributes() + + /** + * getInputAttributes + * @returns MutableAttributeSet + */ + public MutableAttributeSet getInputAttributes() { + return null; // TODO + } // getInputAttributes() + + /** + * getStyledEditorKit + * @returns StyledEditorKit + */ + protected final StyledEditorKit getStyledEditorKit() { + return null; // TODO + } // getStyledEditorKit() + + /** + * createDefaultEditorKit + * @returns EditorKit + */ + protected EditorKit createDefaultEditorKit() { + return super.createDefaultEditorKit(); // TODO + } // createDefaultEditorKit() + + /** + * setEditorKit + * @param editor TODO + */ + public final void setEditorKit(EditorKit editor) { + super.setEditorKit(editor); // TODO + } // setEditorKit() + + /** + * paramString + * @returns String + */ + protected String paramString() { + return super.paramString(); // TODO + } // paramString() + + +} // JTextPane diff --git a/libjava/classpath/javax/swing/JToggleButton.java b/libjava/classpath/javax/swing/JToggleButton.java new file mode 100644 index 00000000000..0e1b9e60111 --- /dev/null +++ b/libjava/classpath/javax/swing/JToggleButton.java @@ -0,0 +1,323 @@ +/* JToggleButton.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.event.ActionEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleState; +import javax.swing.plaf.ButtonUI; + +/** + * The <code>JToggleButton</code> component provides a stateful button, + * which can be either selected or unselected. This provides the basis + * for the implementations of radio buttons (<code>JRadioButton</code>) + * and check boxes (<code>JCheckBox</code>). + * + * @author Michael Koch (konqueror@gmx.de) + * @author Graydon Hoare (graydon@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see JRadioButton + * @see JCheckBox + * @since 1.2 + */ +public class JToggleButton extends AbstractButton implements Accessible +{ + /** + * This class provides accessibility support for the toggle button. + */ + protected class AccessibleJToggleButton + extends AccessibleAbstractButton + implements ItemListener + { + private static final long serialVersionUID = -8652952712161229225L; + + /** + * Constructor for the accessible toggle button. + */ + public AccessibleJToggleButton() + { + super(); + /* Register the accessible toggle button as a listener for item events */ + addItemListener(this); + } + + /** + * Returns the accessible role for the toggle button. + * + * @return An instance of <code>AccessibleRole</code>, describing + * the role of the toggle button. + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.TOGGLE_BUTTON; + } + + /** + * Monitors the toggle button for state changes and fires accessible + * property change events when they occur. + * + * @param event the event that occurred. + */ + public void itemStateChanged(ItemEvent event) + { + /* Fire a state property change event as the button's state has changed */ + if (event.getStateChange() == ItemEvent.SELECTED) + { + /* State has changed from unselected (null) to selected */ + firePropertyChange(ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.SELECTED); + } + else + { + /* State has changed from selected to unselected (null) */ + firePropertyChange(ACCESSIBLE_STATE_PROPERTY, AccessibleState.ENABLED, null); + } + } + + } + + /** + * The model handles the storage and maintenance of the state of + * the toggle button. This follows the same paradigm (the MVC + * or Model-View-Controller design pattern) employed by + * other Swing components, where the data associated with a component + * is stored separately from the display aspects. + */ + public static class ToggleButtonModel extends DefaultButtonModel + { + /** + * Compatible with Sun's JDK. + */ + private static final long serialVersionUID = -1589950750899943974L; + + /** + * Sets the pressed state of the button. The selected state + * of the button also changes follwing the button being pressed. + * + * @param b true if the button is pressed down. + */ + public void setPressed(boolean p) + { + // cannot change PRESSED state unless button is enabled + if (! isEnabled()) + return; + + // if this call does not represent a CHANGE in state, then return + if ((p && isPressed()) || (!p && !isPressed())) + return; + + // make the change + if (p) + stateMask = stateMask | PRESSED; + else + stateMask = stateMask & (~PRESSED); + + // notify interested ChangeListeners + fireStateChanged(); + + // setPressed(false) == mouse release on us, + // if we were armed, we flip the selected state. + if (!p && isArmed()) + { + fireActionPerformed(new ActionEvent(this, + ActionEvent.ACTION_PERFORMED, + actionCommand)); + setSelected(! isSelected()); + } + } + } + + /** + * Compatible with Sun's JDK. + */ + private static final long serialVersionUID = -3128248873429850443L; + + /** + * Constructs an unselected toggle button with no text or icon. + */ + public JToggleButton() + { + this(null, null, false); + } + + /** + * Constructs a toggle button using the labelling, state + * and icon specified by the supplied action. + * + * @param a the action to use to define the properties of the button. + */ + public JToggleButton(Action a) + { + this(); + setAction(a); + } + + /** + * Constructs an unselected toggle button with the supplied icon + * and no text. + * + * @param icon the icon to use. + */ + public JToggleButton(Icon icon) + { + this(null, icon, false); + } + + /** + * Constructs a toggle button with the supplied icon and state. + * + * @param icon the icon to use. + * @param selected if true, the toggle button is initially in the + * selected state. Otherwise, the button is unselected. + */ + public JToggleButton(Icon icon, boolean selected) + { + this(null, icon, selected); + } + + /** + * Constructs an unselected toggle button using the supplied text + * and no icon. + * + * @param text the text to use. + */ + public JToggleButton(String text) + { + this(text, null, false); + } + + /** + * Constructs a toggle button with the supplied text and state. + * + * @param text the text to use. + * @param selected if true, the toggle button is initially in the + * selected state. Otherwise, the button is unselected. + */ + public JToggleButton(String text, boolean selected) + { + this(text, null, selected); + } + + /** + * Constructs an unselected toggle button with the supplied text + * and icon. + * + * @param text the text to use. + * @param icon the icon to use. + */ + public JToggleButton(String text, Icon icon) + { + this(text, icon, false); + } + + /** + * Constructs a toggle button with the supplied text, icon and state. + * + * @param text the text to use. + * @param icon the icon to use. + * @param selected if true, the toggle button is initially in the + * selected state. Otherwise, the button is unselected. + */ + public JToggleButton (String text, Icon icon, boolean selected) + { + super(); + init(text, icon); + + setModel(new ToggleButtonModel()); + model.setSelected(selected); + } + + /** + * Gets the AccessibleContext associated with this <code>JToggleButton</code>. + * The context is created, if necessary. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + /* Create the context if this is the first request */ + if (accessibleContext == null) + { + /* Create the context */ + accessibleContext = new AccessibleJToggleButton(); + } + return accessibleContext; + } + + /** + * Returns a string that specifies the name of the Look and Feel + * class that renders this component. + * + * @return The Look and Feel UI class in <code>String</code> form. + */ + public String getUIClassID() + { + return "ToggleButtonUI"; + } + + /** + * Returns a textual representation of this component for debugging. + * Users should not depend on anything as regards the content or formatting + * of this string, except for the fact that the returned string may never be + * null (only empty). + * + * @return the component in <code>String</code> form for debugging. + */ + protected String paramString() + { + return super.paramString(); + } + + /** + * This method resets the toggle button's UI delegate to the default UI for + * the current look and feel. + */ + public void updateUI() + { + setUI((ButtonUI)UIManager.getUI(this)); + } + +} + + + diff --git a/libjava/classpath/javax/swing/JToolBar.java b/libjava/classpath/javax/swing/JToolBar.java new file mode 100644 index 00000000000..649919e0618 --- /dev/null +++ b/libjava/classpath/javax/swing/JToolBar.java @@ -0,0 +1,779 @@ +/* JToolBar.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.beans.PropertyChangeListener; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.swing.JButton; +import javax.swing.plaf.ToolBarUI; + +/** + * JToolBar is a component that provides a toolbar to Swing programs. Users + * can add buttons (or actions that will be represented by JButtons) as well + * as other components to the JToolBar. JToolBars can be dragged in and out + * of their parent components. If the JToolBar is dragged out of the parent, + * then it will be displayed in its own RootPaneContainer. For dragging to + * work properly, JToolBars need to be placed in a Container that has a + * BorderLayout. That parent Container cannot have components in the NORTH, + * EAST, SOUTH, or WEST components (that is not the JToolBar). + */ +public class JToolBar extends JComponent implements SwingConstants, Accessible +{ + /** + * AccessibleJToolBar + */ + protected class AccessibleJToolBar extends AccessibleJComponent + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = -5516888265903814215L; + + /** + * Constructor AccessibleJToolBar + */ + protected AccessibleJToolBar() + { + } + + /** + * getAccessibleStateSet + * + * @return AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; // TODO + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.TOOL_BAR; + } + } + + /** + * This is the private JToolBar layout manager. + */ + private class DefaultToolBarLayout implements LayoutManager + { + /** + * This method is called when a new component is added to the container. + * + * @param name The name of the component added. + * @param comp The component that was added. + */ + public void addLayoutComponent(String name, Component comp) + { + // Do nothing. + } + + /** + * This method is called to lay out the given container to position and + * size the child components. + * + * @param c The container to lay out. + * + * @throws Error DOCUMENT ME! + */ + public void layoutContainer(Container c) + { + if (! (c instanceof JToolBar)) + throw new Error("DefaultToolBarLayout can only be used on JToolBars."); + Insets insets = getInsets(); + Insets margin = getMargin(); + int middle; + if (margin != null) + { + insets.left += margin.left; + insets.top += margin.top; + insets.bottom += margin.bottom; + insets.right += margin.right; + } + Component[] components = c.getComponents(); + Dimension tdims = c.getSize(); + int start = 0; + Dimension pref; + + if (getOrientation() == SwingUtilities.HORIZONTAL) + { + start += insets.left; + for (int i = 0; i < components.length; i++) + { + if (components[i] != null && components[i].isVisible()) + { + pref = components[i].getPreferredSize(); + if (pref != null) + { + middle = (tdims.height - pref.height) / 2; + components[i].setBounds(start, middle, pref.width, + pref.height); + start += pref.width; + } + } + } + } + else + { + start += insets.top; + for (int i = 0; i < components.length; i++) + { + if (components[i] != null && components[i].isVisible()) + { + pref = components[i].getPreferredSize(); + if (pref != null) + { + middle = (tdims.width - pref.width) / 2; + components[i].setBounds(middle, start, pref.width, + pref.height); + start += pref.height; + } + } + } + } + } + + /** + * This method returns the minimum size of the given container given the + * child components. + * + * @param parent The container to measure. + * + * @return The minimum size of the given container. + */ + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + /** + * This method returns the preferred size of the given container given the + * child components. + * + * @param parent The container to measure. + * + * @return The preferred size of the given container. + */ + public Dimension preferredLayoutSize(Container parent) + { + int orientation = getOrientation(); + Component[] components = getComponents(); + + int limit = 0; + int total = 0; + Dimension dims; + + int w = 0; + int h = 0; + + if (orientation == SwingConstants.HORIZONTAL) + { + for (int i = 0; i < components.length; i++) + { + dims = components[i].getPreferredSize(); + if (dims != null) + { + if (dims.height > limit) + limit = dims.height; + total += dims.width; + } + } + w = total; + h = limit; + } + else + { + for (int i = 0; i < components.length; i++) + { + dims = components[i].getPreferredSize(); + if (dims != null) + { + if (dims.width > limit) + limit = dims.width; + total += dims.height; + } + } + w = limit; + h = total; + } + + Insets insets = getInsets(); + w += insets.left + insets.right; + h += insets.top + insets.bottom; + + Insets margin = getMargin(); + if (margin != null) + { + w += margin.left + margin.right; + h += margin.top + margin.bottom; + } + + return new Dimension(w, h); + } + + /** + * This method is called when the given component is removed from the + * container. + * + * @param comp The component removed. + */ + public void removeLayoutComponent(Component comp) + { + // Do nothing. + } + } + + /** + * This is an extension of JSeparator used in toolbars. Unlike JSeparator, + * nothing is painted for this Separator, it is only blank space that + * separates components. + */ + public static class Separator extends JSeparator + { + /** DOCUMENT ME! */ + private static final long serialVersionUID = -1656745644823105219L; + + /** + * Creates a new Separator object. + */ + public Separator() + { + super(); + } // Separator() + + /** + * Creates a new Separator object with the given size. + * + * @param size The size of the separator. + */ + public Separator(Dimension size) + { + setPreferredSize(size); + } // Separator() + + /** + * This method returns the String ID of the UI class of Separator. + * + * @return The UI class' String ID. + */ + public String getUIClassID() + { + return "ToolBarSeparatorUI"; + } // getUIClassID() + + /** + * This method returns the preferred size of the Separator. + * + * @return The preferred size of the Separator. + */ + public Dimension getPreferredSize() + { + return super.getPreferredSize(); + } // getPreferredSize() + + /** + * This method returns the maximum size of the Separator. + * + * @return The maximum size of the Separator. + */ + public Dimension getMaximumSize() + { + return super.getPreferredSize(); + } // getMaximumSize() + + /** + * This method returns the minimum size of the Separator. + * + * @return The minimum size of the Separator. + */ + public Dimension getMinimumSize() + { + return super.getPreferredSize(); + } // getMinimumSize() + + /** + * This method returns the size of the Separator. + * + * @return The size of the Separator. + */ + public Dimension getSeparatorSize() + { + return super.getPreferredSize(); + } // getSeparatorSize() + + /** + * This method sets the size of the Separator. + * + * @param size The new size of the Separator. + */ + public void setSeparatorSize(Dimension size) + { + setPreferredSize(size); + } // setSeparatorSize() + } // Separator + + /** DOCUMENT ME! */ + private static final long serialVersionUID = -1269915519555129643L; + + /** Whether the JToolBar paints its border. */ + private transient boolean paintBorder = true; + + /** The extra insets around the JToolBar. */ + private transient Insets margin; + + /** Whether the JToolBar can float (and be dragged around). */ + private transient boolean floatable = true; + + /** Whether the buttons will have rollover borders. */ + private transient boolean rollover; + + /** The orientation of the JToolBar. */ + private int orientation = HORIZONTAL; + + /** + * This method creates a new JToolBar object with horizontal orientation + * and no name. + */ + public JToolBar() + { + this(null, HORIZONTAL); + } // JToolBar() + + /** + * This method creates a new JToolBar with the given orientation and no + * name. + * + * @param orientation JToolBar orientation (HORIZONTAL or VERTICAL) + */ + public JToolBar(int orientation) + { + this(null, orientation); + } // JToolBar() + + /** + * This method creates a new JToolBar object with the given name and + * horizontal orientation. + * + * @param name Name assigned to undocked tool bar. + */ + public JToolBar(String name) + { + this(name, HORIZONTAL); + } // JToolBar() + + /** + * This method creates a new JToolBar object with the given name and + * orientation. + * + * @param name Name assigned to undocked tool bar. + * @param orientation JToolBar orientation (HORIZONTAL or VERTICAL) + */ + public JToolBar(String name, int orientation) + { + setName(name); + setOrientation(orientation); + setLayout(new DefaultToolBarLayout()); + revalidate(); + updateUI(); + } // JToolBar() + + /** + * This method adds a new JButton that performs the given Action to the + * JToolBar. + * + * @param action The Action to add to the JToolBar. + * + * @return The JButton that wraps the Action. + */ + public JButton add(Action action) + { + JButton b = createActionComponent(action); + add(b); + return b; + } // add() + + /** + * This method paints the border if the borderPainted property is true. + * + * @param graphics The graphics object to paint with. + */ + protected void paintBorder(Graphics graphics) + { + if (paintBorder && isFloatable()) + super.paintBorder(graphics); + } // paintBorder() + + /** + * This method returns the UI class used to paint this JToolBar. + * + * @return The UI class for this JToolBar. + */ + public ToolBarUI getUI() + { + return (ToolBarUI) ui; + } // getUI() + + /** + * This method sets the UI used with the JToolBar. + * + * @param ui The UI used with the JToolBar. + */ + public void setUI(ToolBarUI ui) + { + super.setUI(ui); + } // setUI() + + /** + * This method resets the UI used to the Look and Feel defaults. + */ + public void updateUI() + { + setUI((ToolBarUI) UIManager.getUI(this)); + revalidate(); + repaint(); + } // updateUI() + + /** + * This method returns the String identifier for the UI class to the used + * with the JToolBar. + * + * @return The String identifier for the UI class. + */ + public String getUIClassID() + { + return "ToolBarUI"; + } // getUIClassID() + + /** + * This method sets the rollover property for the JToolBar. In rollover + * mode, JButtons inside the JToolBar will only display their borders when + * the mouse is moving over them. + * + * @param b The new rollover property. + */ + public void setRollover(boolean b) + { + if (b != rollover) + { + rollover = b; + firePropertyChange("rollover", ! rollover, rollover); + revalidate(); + repaint(); + } + } + + /** + * This method returns the rollover property. + * + * @return The rollover property. + */ + public boolean isRollover() + { + return rollover; + } + + /** + * This method returns the index of the given component. + * + * @param component The component to find. + * + * @return The index of the given component. + */ + public int getComponentIndex(Component component) + { + Component[] components = getComponents(); + if (components == null) + return -1; + + for (int i = 0; i < components.length; i++) + if (components[i] == component) + return i; + + return -1; + } // getComponentIndex() + + /** + * This method returns the component at the given index. + * + * @param index The index of the component. + * + * @return The component at the given index. + */ + public Component getComponentAtIndex(int index) + { + return getComponent(index); + } // getComponentAtIndex() + + /** + * This method returns the margin property. + * + * @return The margin property. + */ + public Insets getMargin() + { + return margin; + } // getMargin() + + /** + * This method sets the margin property. The margin property determines the + * extra space between the children components of the JToolBar and the + * border. + * + * @param margin The margin property. + */ + public void setMargin(Insets margin) + { + if ((this.margin != null && margin == null) + || (this.margin == null && margin != null) + || (margin != null && this.margin != null + && (margin.left != this.margin.left + || margin.right != this.margin.right || margin.top != this.margin.top + || margin.bottom != this.margin.bottom))) + { + Insets oldMargin = this.margin; + this.margin = margin; + firePropertyChange("margin", oldMargin, this.margin); + revalidate(); + repaint(); + } + } // setMargin() + + /** + * This method returns the borderPainted property. + * + * @return The borderPainted property. + */ + public boolean isBorderPainted() + { + return paintBorder; + } // isBorderPainted() + + /** + * This method sets the borderPainted property. If set to false, the border + * will not be painted. + * + * @param painted Whether the border will be painted. + */ + public void setBorderPainted(boolean painted) + { + if (painted != paintBorder) + { + paintBorder = painted; + firePropertyChange("borderPainted", ! paintBorder, + paintBorder); + repaint(); + } + } // setBorderPainted() + + /** + * This method returns the floatable property. + * + * @return The floatable property. + */ + public boolean isFloatable() + { + return floatable; + } // isFloatable() + + /** + * This method sets the floatable property. If set to false, the JToolBar + * cannot be dragged. + * + * @param floatable Whether the JToolBar can be dragged. + */ + public void setFloatable(boolean floatable) + { + if (floatable != this.floatable) + { + this.floatable = floatable; + firePropertyChange("floatable", ! floatable, floatable); + } + } // setFloatable() + + /** + * This method returns the orientation of the JToolBar. + * + * @return The orientation of the JToolBar. + */ + public int getOrientation() + { + return orientation; + } // getOrientation() + + /** + * This method sets the layout manager to be used with the JToolBar. + * + * @param mgr The Layout Manager used with the JToolBar. + */ + public void setLayout(LayoutManager mgr) + { + super.setLayout(mgr); + revalidate(); + repaint(); + } // setLayout() + + /** + * This method sets the orientation property for JToolBar. + * + * @param orientation The new orientation for JToolBar. + * + * @throws IllegalArgumentException If the orientation is not HORIZONTAL or + * VERTICAL. + */ + public void setOrientation(int orientation) + { + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); + if (orientation != this.orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange("orientation", oldOrientation, this.orientation); + revalidate(); + repaint(); + } + } // setOrientation() + + /** + * This method adds a Separator of default size to the JToolBar. + */ + public void addSeparator() + { + add(new Separator()); + } // addSeparator() + + /** + * This method adds a Separator with the given size to the JToolBar. + * + * @param size The size of the Separator. + */ + public void addSeparator(Dimension size) + { + add(new Separator(size)); + } // addSeparator() + + /** + * This method is used to create JButtons which can be added to the JToolBar + * for the given action. + * + * @param action The action to create a JButton for. + * + * @return The JButton created from the action. + */ + protected JButton createActionComponent(Action action) + { + return new JButton(action); + } // createActionComponent() + + /** + * This method creates a pre-configured PropertyChangeListener which updates + * the control as changes are made to the Action. However, this is no + * longer the recommended way of adding Actions to Containers. As such, + * this method returns null. + * + * @param button The JButton to configure a PropertyChangeListener for. + * + * @return null. + */ + protected PropertyChangeListener createActionChangeListener(JButton button) + { + // XXX: As specified, this returns null. But seems kind of strange, usually deprecated methods don't just return null, verify! + return null; + } // createActionChangeListener() + + /** + * This method overrides Container's addImpl method. If a JButton is added, + * it is disabled. + * + * @param component The Component to add. + * @param constraints The Constraints placed on the component. + * @param index The index to place the Component at. + */ + protected void addImpl(Component component, Object constraints, int index) + { + // XXX: Sun says disable button but test cases show otherwise. + super.addImpl(component, constraints, index); + + // if we added a Swing Button then adjust this a little + if (component instanceof AbstractButton) + { + AbstractButton b = (AbstractButton) component; + b.setRolloverEnabled(rollover); + b.updateUI(); + } + + } // addImpl() + + /** + * This method returns a String description of the JToolBar. + * + * @return A String description of the JToolBar. + */ + protected String paramString() + { + return "JToolBar"; + } // paramString() + + /** + * getAccessibleContext + * + * @return AccessibleContext + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJToolBar(); + + return accessibleContext; + } +} diff --git a/libjava/classpath/javax/swing/JToolTip.java b/libjava/classpath/javax/swing/JToolTip.java new file mode 100644 index 00000000000..8d774782780 --- /dev/null +++ b/libjava/classpath/javax/swing/JToolTip.java @@ -0,0 +1,197 @@ +/* JToolTip.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.AWTEvent; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.plaf.ToolTipUI; + +/** + * This class is used to display ToolTips. ToolTips are small floating windows + * that display text when the mouse comes to rest over a Component. ToolTips + * are set for JComponents using JComponent.setToolTipText(String). + */ +public class JToolTip extends JComponent implements Accessible +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = -1138929898906751643L; + + /** + * DOCUMENT ME! + */ + protected class AccessibleJToolTip extends AccessibleJComponent + { + private static final long serialVersionUID = -6222548177795408476L; + + /** + * Creates a new AccessibleJToolTip object. + */ + protected AccessibleJToolTip() + { + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getAccessibleDescription() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + } + + /** The text to display in the JToolTip. */ + String text; + + /** The JComponent this JToolTip is used for. */ + JComponent component; + + /** + * Creates a new JToolTip object. + */ + public JToolTip() + { + disableEvents(AWTEvent.MOUSE_EVENT_MASK); + updateUI(); + } + + /** + * This method returns the text this JToolTip displays. + * + * @return The text that this JToolTip displays. + */ + public String getTipText() + { + return text; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * This method returns the JComponent this JToolTip displays for. + * + * @return The JComponent this JToolTip displays for. + */ + public JComponent getComponent() + { + return component; + } + + /** + * This method returns the UI responsible for displaying this JToolTip. + * + * @return The UI responsible for displaying this JToolTip. + */ + public ToolTipUI getUI() + { + return (ToolTipUI) ui; + } + + /** + * This method returns the String identifier for the UI class. + * + * @return The String identifier for the UI class. + */ + public String getUIClassID() + { + return "ToolTipUI"; + } + + /** + * This method returns a debugging String describing the JToolTip. + * + * @return A debugging String describing the JToolTip. + */ + protected String paramString() + { + return "JToolTip"; + } + + /** + * This method sets the JComponent that the JToolTip displays for. + * + * @param c The JComponent that the JToolTip displays for. + */ + public void setComponent(JComponent c) + { + component = c; + } + + /** + * This method sets the text that the JToolTip displays. + * + * @param tipText The text that the JToolTip displays. + */ + public void setTipText(String tipText) + { + text = tipText; + } + + /** + * This method resets the UI used to the Look and Feel default. + */ + public void updateUI() + { + setUI((ToolTipUI) UIManager.getUI(this)); + revalidate(); + repaint(); + } +} diff --git a/libjava/classpath/javax/swing/JTree.java b/libjava/classpath/javax/swing/JTree.java new file mode 100644 index 00000000000..bccd983b756 --- /dev/null +++ b/libjava/classpath/javax/swing/JTree.java @@ -0,0 +1,1829 @@ +/* JTree.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Vector; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.event.TreeWillExpandListener; +import javax.swing.plaf.TreeUI; +import javax.swing.text.Position; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.DefaultTreeSelectionModel; +import javax.swing.tree.ExpandVetoException; +import javax.swing.tree.TreeCellEditor; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; + +public class JTree + extends JComponent + implements Scrollable, Accessible +{ + /** + * Listens to the model of the JTree and updates the property + * <code>expandedState</code> if nodes are removed or changed. + */ + protected class TreeModelHandler + implements + TreeModelListener + { + + /** + * Creates a new instance of TreeModelHandler. + */ + protected TreeModelHandler() + { + } + + /** + * Notifies when a node has changed in some ways. This does not include + * that a node has changed its location or changed it's children. It + * only means that some attributes of the node have changed that might + * affect its presentation. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeNodesChanged(TreeModelEvent ev) + { + // nothing to do here + } + + /** + * Notifies when a node is inserted into the tree. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeNodesInserted(TreeModelEvent ev) + { + // nothing to do here + } + + /** + * Notifies when a node is removed from the tree. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeNodesRemoved(TreeModelEvent ev) + { + // TODO: The API docs suggest that this method should do something + // but I cannot really see what has to be done here ... + } + + /** + * Notifies when the structure of the tree is changed. + * + * This method is called after the actual change occured. + * + * @param ev the TreeModelEvent describing the change + */ + public void treeStructureChanged(TreeModelEvent ev) + { + // set state of new path + TreePath path = ev.getTreePath(); + setExpandedState(path, isExpanded(path)); + } + } // TreeModelHandler + + /** + * This redirects TreeSelectionEvents and rewrites the source of it to be + * this JTree. This is typically done when the tree model generates an + * event, but the JTree object associated with that model should be listed + * as the actual source of the event. + */ + protected class TreeSelectionRedirector + implements + TreeSelectionListener, + Serializable + { + /** The serial version UID. */ + private static final long serialVersionUID = -3505069663646241664L; + + /** + * Creates a new instance of TreeSelectionRedirector + */ + protected TreeSelectionRedirector() + { + } + + /** + * Notifies when the tree selection changes. + * + * @param ev the TreeSelectionEvent that describes the change + */ + public void valueChanged(TreeSelectionEvent ev) + { + TreeSelectionEvent rewritten = (TreeSelectionEvent) ev + .cloneWithSource(JTree.this); + fireValueChanged(rewritten); + JTree.this.repaint(); + } + } // TreeSelectionRedirector + + /** + * A TreeModel that does not allow anything to be selected. + */ + protected static class EmptySelectionModel + extends + DefaultTreeSelectionModel + { + /** The serial version UID. */ + private static final long serialVersionUID = -5815023306225701477L; + + /** + * The shared instance of this model. + */ + protected static final EmptySelectionModel sharedInstance = new EmptySelectionModel(); + + /** + * Creates a new instance of EmptySelectionModel. + */ + protected EmptySelectionModel() + { + } + + /** + * Returns the shared instance of EmptySelectionModel. + * + * @return the shared instance of EmptySelectionModel + */ + public static EmptySelectionModel sharedInstance() + { + return sharedInstance; + } + + /** + * This catches attempts to set a selection and sets nothing instead. + * + * @param paths not used here + */ + public void setSelectionPaths(TreePath[] paths) + { + // we don't allow selections in this class + } + + /** + * This catches attempts to add something to the selection. + * + * @param paths not used here + */ + public void addSelectionPaths(TreePath[] paths) + { + // we don't allow selections in this class + } + + /** + * This catches attempts to remove something from the selection. + * + * @param paths not used here + */ + public void removeSelectionPaths(TreePath[] paths) + { + // we don't allow selections in this class + } + }// EmptySelectionModel + + private static final long serialVersionUID = 7559816092864483649L; + public static final String CELL_EDITOR_PROPERTY = "cellEditor"; + public static final String CELL_RENDERER_PROPERTY = "cellRenderer"; + public static final String EDITABLE_PROPERTY = "editable"; + public static final String INVOKES_STOP_CELL_EDITING_PROPERTY = "invokesStopCellEditing"; + public static final String LARGE_MODEL_PROPERTY = "largeModel"; + public static final String ROOT_VISIBLE_PROPERTY = "rootVisible"; + public static final String ROW_HEIGHT_PROPERTY = "rowHeight"; + public static final String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand"; + public static final String SELECTION_MODEL_PROPERTY = "selectionModel"; + public static final String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles"; + public static final String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount"; + public static final String TREE_MODEL_PROPERTY = "model"; + public static final String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount"; + + /** @since 1.3 */ + public static final String ANCHOR_SELECTION_PATH_PROPERTY = "anchorSelectionPath"; + + /** @since 1.3 */ + public static final String LEAD_SELECTION_PATH_PROPERTY = "leadSelectionPath"; + + /** @since 1.3 */ + public static final String EXPANDS_SELECTED_PATHS_PROPERTY = "expandsSelectedPaths"; + private static final Object EXPANDED = new Object(); + private static final Object COLLAPSED = new Object(); + private boolean dragEnabled; + private boolean expandsSelectedPaths; + private TreePath anchorSelectionPath; + private TreePath leadSelectionPath; + + /* + * This contains the state of all nodes in the tree. Al/ entries map the + * TreePath of a note to to its state. Valid states are EXPANDED and + * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED. + */ + private Hashtable nodeStates = new Hashtable(); + protected transient TreeCellEditor cellEditor; + protected transient TreeCellRenderer cellRenderer; + protected boolean editable; + protected boolean invokesStopCellEditing; + protected boolean largeModel; + protected boolean rootVisible; + protected int rowHeight; + protected boolean scrollsOnExpand; + protected transient TreeSelectionModel selectionModel; + protected boolean showsRootHandles; + protected int toggleClickCount; + protected transient TreeModel treeModel; + protected int visibleRowCount; + + /** + * Handles TreeModelEvents to update the expandedState. + */ + protected transient TreeModelListener treeModelListener; + + /** + * Redirects TreeSelectionEvents so that the source is this JTree. + */ + protected TreeSelectionRedirector selectionRedirector = + new TreeSelectionRedirector(); + + /** + * Creates a new <code>JTree</code> object. + */ + public JTree() + { + this(createTreeModel(null)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param value the initial nodes in the tree + */ + public JTree(Hashtable value) + { + this(createTreeModel(value)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param value the initial nodes in the tree + */ + public JTree(Object[] value) + { + this(createTreeModel(value)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param model the model to use + */ + public JTree(TreeModel model) + { + setModel(model); + setSelectionModel(EmptySelectionModel.sharedInstance()); + selectionModel.addTreeSelectionListener(selectionRedirector); + setCellRenderer(new DefaultTreeCellRenderer()); + updateUI(); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param root the root node + */ + public JTree(TreeNode root) + { + this(root, false); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param root the root node + * @param asksAllowChildren if false, all nodes without children are leaf + * nodes. If true, only nodes that do not allow children are leaf + * nodes. + */ + public JTree(TreeNode root, boolean asksAllowChildren) + { + this(new DefaultTreeModel(root, asksAllowChildren)); + } + + /** + * Creates a new <code>JTree</code> object. + * + * @param value the initial nodes in the tree + */ + public JTree(Vector value) + { + this(createTreeModel(value)); + } + + public static class DynamicUtilTreeNode + extends + DefaultMutableTreeNode + { + protected Object childValue; + protected boolean loadedChildren; + + /** + * Currently not set or used by this class. It might be set and used in + * later versions of this class. + */ + protected boolean hasChildren; + + public DynamicUtilTreeNode(Object value, Object children) + { + super(value); + childValue = children; + loadedChildren = false; + } + + public int getChildCount() + { + loadChildren(); + return super.getChildCount(); + } + + protected void loadChildren() + { + if (!loadedChildren) + { + createChildren(this, childValue); + loadedChildren = true; + } + } + + public Enumeration children() + { + loadChildren(); + return super.children(); + } + + /** + * Returns the child node at position <code>pos</code>. Subclassed + * here to load the children if necessary. + * + * @param pos the position of the child node to fetch + * + * @return the childnode at the specified position + */ + public TreeNode getChildAt(int pos) + { + loadChildren(); + return super.getChildAt(pos); + } + + public boolean isLeaf() + { + return (childValue == null || !(childValue instanceof Hashtable + || childValue instanceof Vector || childValue.getClass() + .isArray())); + } + + public static void createChildren(DefaultMutableTreeNode parent, + Object children) + { + if (children instanceof Hashtable) + { + Hashtable tab = (Hashtable) children; + Enumeration e = tab.keys(); + while (e.hasMoreElements()) + { + Object key = e.nextElement(); + Object val = tab.get(key); + parent.add(new DynamicUtilTreeNode(key, val)); + } + } else if (children instanceof Vector) + { + Iterator i = ((Vector) children).iterator(); + while (i.hasNext()) + { + Object n = i.next(); + parent.add(new DynamicUtilTreeNode(n, n)); + } + } else if (children != null && children.getClass().isArray()) + { + Object[] arr = (Object[]) children; + for (int i = 0; i < arr.length; ++i) + parent.add(new DynamicUtilTreeNode(arr[i], arr[i])); + } + } + } + + public int getRowForPath(TreePath path) + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getRowForPath(this, path); + + return -1; + } + + public TreePath getPathForRow(int row) + { + TreeUI ui = getUI(); + return ui != null ? ui.getPathForRow(this, row) : null; + } + + protected TreePath[] getPathBetweenRows(int index0, int index1) + { + TreeUI ui = getUI(); + + if (ui == null) + return null; + + int minIndex = Math.min(index0, index1); + int maxIndex = Math.max(index0, index1); + TreePath[] paths = new TreePath[maxIndex - minIndex + 1]; + + for (int i = minIndex; i <= maxIndex; ++i) + paths[i - minIndex] = ui.getPathForRow(this, i); + + return paths; + } + + /** + * Creates a new <code>TreeModel</code> object. + * + * @param value the values stored in the model + */ + protected static TreeModel createTreeModel(Object value) + { + return new DefaultTreeModel(new DynamicUtilTreeNode(value, value)); + } + + /** + * Return the UI associated with this <code>JTree</code> object. + * + * @return the associated <code>TreeUI</code> object + */ + public TreeUI getUI() + { + return (TreeUI) ui; + } + + /** + * Sets the UI associated with this <code>JTree</code> object. + * + * @param ui the <code>TreeUI</code> to associate + */ + public void setUI(TreeUI ui) + { + super.setUI(ui); + } + + /** + * This method resets the UI used to the Look and Feel defaults.. + */ + public void updateUI() + { + setUI((TreeUI) UIManager.getUI(this)); + revalidate(); + repaint(); + } + + /** + * This method returns the String ID of the UI class of Separator. + * + * @return The UI class' String ID. + */ + public String getUIClassID() + { + return "TreeUI"; + } + + /** + * Gets the AccessibleContext associated with this + * <code>JToggleButton</code>. + * + * @return the associated context + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * Returns the preferred viewport size.. + * + * @return the preferred size + */ + public Dimension getPreferredScrollableViewportSize() + { + return null; + } + + public int getScrollableUnitIncrement(Rectangle visibleRect, + int orientation, int direction) + { + return 1; + } + + public int getScrollableBlockIncrement(Rectangle visibleRect, + int orientation, int direction) + { + return 1; + } + + public boolean getScrollableTracksViewportWidth() + { + return false; + } + + public boolean getScrollableTracksViewportHeight() + { + return false; + } + + /** + * Adds a <code>TreeExpansionListener</code> object to the tree. + * + * @param listener the listener to add + */ + public void addTreeExpansionListener(TreeExpansionListener listener) + { + listenerList.add(TreeExpansionListener.class, listener); + } + + /** + * Removes a <code>TreeExpansionListener</code> object from the tree. + * + * @param listener the listener to remove + */ + public void removeTreeExpansionListener(TreeExpansionListener listener) + { + listenerList.remove(TreeExpansionListener.class, listener); + } + + /** + * Returns all added <code>TreeExpansionListener</code> objects. + * + * @return an array of listeners + */ + public TreeExpansionListener[] getTreeExpansionListeners() + { + return (TreeExpansionListener[]) getListeners(TreeExpansionListener.class); + } + + /** + * Notifies all listeners that the tree was collapsed. + * + * @param path the path to the node that was collapsed + */ + public void fireTreeCollapsed(TreePath path) + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeExpansionListener[] listeners = getTreeExpansionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeCollapsed(event); + } + + /** + * Notifies all listeners that the tree was expanded. + * + * @param path the path to the node that was expanded + */ + public void fireTreeExpanded(TreePath path) + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeExpansionListener[] listeners = getTreeExpansionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeExpanded(event); + } + + /** + * Adds a <code>TreeSelctionListener</code> object to the tree. + * + * @param listener the listener to add + */ + public void addTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.add(TreeSelectionListener.class, listener); + } + + /** + * Removes a <code>TreeSelectionListener</code> object from the tree. + * + * @param listener the listener to remove + */ + public void removeTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.remove(TreeSelectionListener.class, listener); + } + + /** + * Returns all added <code>TreeSelectionListener</code> objects. + * + * @return an array of listeners + */ + public TreeSelectionListener[] getTreeSelectionListeners() + { + return (TreeSelectionListener[]) + getListeners(TreeSelectionListener.class); + } + + /** + * Notifies all listeners when the selection of the tree changed. + * + * @param event the event to send + */ + protected void fireValueChanged(TreeSelectionEvent event) + { + TreeSelectionListener[] listeners = getTreeSelectionListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].valueChanged(event); + } + + /** + * Adds a <code>TreeWillExpandListener</code> object to the tree. + * + * @param listener the listener to add + */ + public void addTreeWillExpandListener(TreeWillExpandListener listener) + { + listenerList.add(TreeWillExpandListener.class, listener); + } + + /** + * Removes a <code>TreeWillExpandListener</code> object from the tree. + * + * @param listener the listener to remove + */ + public void removeTreeWillExpandListener(TreeWillExpandListener listener) + { + listenerList.remove(TreeWillExpandListener.class, listener); + } + + /** + * Returns all added <code>TreeWillExpandListener</code> objects. + * + * @return an array of listeners + */ + public TreeWillExpandListener[] getTreeWillExpandListeners() + { + return (TreeWillExpandListener[]) + getListeners(TreeWillExpandListener.class); + } + + /** + * Notifies all listeners that the tree will collapse. + * + * @param path the path to the node that will collapse + */ + public void fireTreeWillCollapse(TreePath path) throws ExpandVetoException + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeWillExpandListener[] listeners = getTreeWillExpandListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeWillCollapse(event); + } + + /** + * Notifies all listeners that the tree will expand. + * + * @param path the path to the node that will expand + */ + public void fireTreeWillExpand(TreePath path) throws ExpandVetoException + { + TreeExpansionEvent event = new TreeExpansionEvent(this, path); + TreeWillExpandListener[] listeners = getTreeWillExpandListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].treeWillExpand(event); + } + + /** + * Returns the model of this <code>JTree</code> object. + * + * @return the associated <code>TreeModel</code> + */ + public TreeModel getModel() + { + return treeModel; + } + + /** + * Sets the model to use in <code>JTree</code>. + * + * @param model the <code>TreeModel</code> to use + */ + public void setModel(TreeModel model) + { + if (treeModel == model) + return; + + TreeModel oldValue = treeModel; + treeModel = model; + + firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model); + + // add treeModelListener to the new model + if (treeModelListener == null) + treeModelListener = createTreeModelListener(); + model.addTreeModelListener(treeModelListener); + } + + /** + * Checks if this <code>JTree</code> object is editable. + * + * @return <code>true</code> if this tree object is editable, + * <code>false</code> otherwise + */ + public boolean isEditable() + { + return editable; + } + + /** + * Sets the <code>editable</code> property. + * + * @param flag <code>true</code> to make this tree object editable, + * <code>false</code> otherwise + */ + public void setEditable(boolean flag) + { + if (editable == flag) + return; + + boolean oldValue = editable; + editable = flag; + firePropertyChange(EDITABLE_PROPERTY, oldValue, editable); + } + + /** + * Checks if the root element is visible. + * + * @return <code>true</code> if the root element is visible, + * <code>false</code> otherwise + */ + public boolean isRootVisible() + { + return rootVisible; + } + + public void setRootVisible(boolean flag) + { + if (rootVisible == flag) + return; + + boolean oldValue = rootVisible; + rootVisible = flag; + firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag); + } + + public boolean getShowsRootHandles() + { + return showsRootHandles; + } + + public void setShowsRootHandles(boolean flag) + { + if (showsRootHandles == flag) + return; + + boolean oldValue = showsRootHandles; + showsRootHandles = flag; + firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue, flag); + } + + public TreeCellEditor getCellEditor() + { + + return cellEditor; + } + + public void setCellEditor(TreeCellEditor editor) + { + if (cellEditor == editor) + return; + + TreeCellEditor oldValue = cellEditor; + cellEditor = editor; + firePropertyChange(CELL_EDITOR_PROPERTY, oldValue, editor); + } + + public TreeCellRenderer getCellRenderer() + { + return cellRenderer; + } + + public void setCellRenderer(TreeCellRenderer newRenderer) + { + if (cellRenderer == newRenderer) + return; + + TreeCellRenderer oldValue = cellRenderer; + cellRenderer = newRenderer; + firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, newRenderer); + } + + public TreeSelectionModel getSelectionModel() + { + return selectionModel; + } + + public void setSelectionModel(TreeSelectionModel model) + { + if (selectionModel == model) + return; + + if (selectionModel != null) + selectionModel.removeTreeSelectionListener(selectionRedirector); + + TreeSelectionModel oldValue = selectionModel; + selectionModel = model; + + if (selectionModel != null) + selectionModel.addTreeSelectionListener(selectionRedirector); + + firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model); + revalidate(); + repaint(); + } + + public int getVisibleRowCount() + { + return visibleRowCount; + } + + public void setVisibleRowCount(int rows) + { + if (visibleRowCount == rows) + return; + + int oldValue = visibleRowCount; + visibleRowCount = rows; + firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldValue, rows); + } + + public boolean isLargeModel() + { + return largeModel; + } + + public void setLargeModel(boolean large) + { + if (largeModel == large) + return; + + boolean oldValue = largeModel; + largeModel = large; + firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, large); + } + + public int getRowHeight() + { + + return rowHeight; + } + + public void setRowHeight(int height) + { + if (rowHeight == height) + return; + + int oldValue = rowHeight; + rowHeight = height; + firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, height); + } + + public boolean isFixedRowHeight() + { + return rowHeight > 0; + } + + public boolean getInvokesStopCellEditing() + { + return invokesStopCellEditing; + } + + public void setInvokesStopCellEditing(boolean invoke) + { + if (invokesStopCellEditing == invoke) + return; + + boolean oldValue = invokesStopCellEditing; + invokesStopCellEditing = invoke; + firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY, + oldValue, invoke); + } + + /** + * @since 1.3 + */ + public int getToggleClickCount() + { + return toggleClickCount; + } + + /** + * @since 1.3 + */ + public void setToggleClickCount(int count) + { + if (toggleClickCount == count) + return; + + int oldValue = toggleClickCount; + toggleClickCount = count; + firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldValue, count); + } + + public void scrollPathToVisible(TreePath path) + { + if (path == null) + return; + + Rectangle rect = getPathBounds(path); + + if (rect == null) + return; + + scrollRectToVisible(rect); + } + + public void scrollRowToVisible(int row) + { + scrollPathToVisible(getPathForRow(row)); + } + + public boolean getScrollsOnExpand() + { + return scrollsOnExpand; + } + + public void setScrollsOnExpand(boolean scroll) + { + if (scrollsOnExpand == scroll) + return; + + boolean oldValue = scrollsOnExpand; + scrollsOnExpand = scroll; + firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue, scroll); + } + + public void setSelectionPath(TreePath path) + { + selectionModel.setSelectionPath(path); + } + + public void setSelectionPaths(TreePath[] paths) + { + selectionModel.setSelectionPaths(paths); + } + + public void setSelectionRow(int row) + { + TreePath path = getPathForRow(row); + + if (path != null) + selectionModel.setSelectionPath(path); + } + + public void setSelectionRows(int[] rows) + { + // Make sure we have an UI so getPathForRow() does not return null. + if (rows == null || getUI() == null) + return; + + TreePath[] paths = new TreePath[rows.length]; + + for (int i = rows.length - 1; i >= 0; --i) + paths[i] = getPathForRow(rows[i]); + + setSelectionPaths(paths); + } + + public void setSelectionInterval(int index0, int index1) + { + TreePath[] paths = getPathBetweenRows(index0, index1); + + if (paths != null) + setSelectionPaths(paths); + } + + public void addSelectionPath(TreePath path) + { + selectionModel.addSelectionPath(path); + } + + public void addSelectionPaths(TreePath[] paths) + { + selectionModel.addSelectionPaths(paths); + } + + public void addSelectionRow(int row) + { + TreePath path = getPathForRow(row); + + if (path != null) + selectionModel.addSelectionPath(path); + } + + public void addSelectionRows(int[] rows) + { + // Make sure we have an UI so getPathForRow() does not return null. + if (rows == null || getUI() == null) + return; + + TreePath[] paths = new TreePath[rows.length]; + + for (int i = rows.length - 1; i >= 0; --i) + paths[i] = getPathForRow(rows[i]); + + addSelectionPaths(paths); + } + + public void addSelectionInterval(int index0, int index1) + { + TreePath[] paths = getPathBetweenRows(index0, index1); + + if (paths != null) + addSelectionPaths(paths); + } + + public void removeSelectionPath(TreePath path) + { + selectionModel.removeSelectionPath(path); + } + + public void removeSelectionPaths(TreePath[] paths) + { + selectionModel.removeSelectionPaths(paths); + } + + public void removeSelectionRow(int row) + { + TreePath path = getPathForRow(row); + + if (path != null) + selectionModel.removeSelectionPath(path); + } + + public void removeSelectionRows(int[] rows) + { + if (rows == null || getUI() == null) + return; + + TreePath[] paths = new TreePath[rows.length]; + + for (int i = rows.length - 1; i >= 0; --i) + paths[i] = getPathForRow(rows[i]); + + removeSelectionPaths(paths); + } + + public void removeSelectionInterval(int index0, int index1) + { + TreePath[] paths = getPathBetweenRows(index0, index1); + + if (paths != null) + removeSelectionPaths(paths); + } + + public void clearSelection() + { + selectionModel.clearSelection(); + setLeadSelectionPath(null); + } + + public TreePath getLeadSelectionPath() + { + return leadSelectionPath; + } + + /** + * @since 1.3 + */ + public void setLeadSelectionPath(TreePath path) + { + if (leadSelectionPath == path) + return; + + TreePath oldValue = leadSelectionPath; + leadSelectionPath = path; + firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path); + } + + /** + * @since 1.3 + */ + public TreePath getAnchorSelectionPath() + { + return anchorSelectionPath; + } + + /** + * @since 1.3 + */ + public void setAnchorSelectionPath(TreePath path) + { + if (anchorSelectionPath == path) + return; + + TreePath oldValue = anchorSelectionPath; + anchorSelectionPath = path; + firePropertyChange(ANCHOR_SELECTION_PATH_PROPERTY, oldValue, path); + } + + public int getLeadSelectionRow() + { + return selectionModel.getLeadSelectionRow(); + } + + public int getMaxSelectionRow() + { + return selectionModel.getMaxSelectionRow(); + } + + public int getMinSelectionRow() + { + return selectionModel.getMinSelectionRow(); + } + + public int getSelectionCount() + { + return selectionModel.getSelectionCount(); + } + + public TreePath getSelectionPath() + { + return selectionModel.getSelectionPath(); + } + + public TreePath[] getSelectionPaths() + { + return selectionModel.getSelectionPaths(); + } + + public int[] getSelectionRows() + { + return selectionModel.getSelectionRows(); + } + + public boolean isPathSelected(TreePath path) + { + return selectionModel.isPathSelected(path); + } + + public boolean isRowSelected(int row) + { + return selectionModel.isPathSelected(getPathForRow(row)); + } + + public boolean isSelectionEmpty() + { + return selectionModel.isSelectionEmpty(); + } + + /** + * Return the value of the <code>dragEnabled</code> property. + * + * @return the value + * + * @since 1.4 + */ + public boolean getDragEnabled() + { + return dragEnabled; + } + + /** + * Set the <code>dragEnabled</code> property. + * + * @param enabled new value + * + * @since 1.4 + */ + public void setDragEnabled(boolean enabled) + { + + dragEnabled = enabled; + } + + public int getRowCount() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getRowCount(this); + + return 0; + } + + public void collapsePath(TreePath path) + { + setExpandedState(path, false); + } + + public void collapseRow(int row) + { + if (row < 0 || row >= getRowCount()) + return; + + TreePath path = getPathForRow(row); + + if (path != null) + collapsePath(path); + } + + public void expandPath(TreePath path) + { + // Don't expand if last path component is a leaf node. + if ((path == null) || (treeModel.isLeaf(path.getLastPathComponent()))) + return; + + setExpandedState(path, true); + } + + public void expandRow(int row) + { + if (row < 0 || row >= getRowCount()) + return; + + TreePath path = getPathForRow(row); + + if (path != null) + expandPath(path); + } + + public boolean isCollapsed(TreePath path) + { + return !isExpanded(path); + } + + public boolean isCollapsed(int row) + { + if (row < 0 || row >= getRowCount()) + return false; + + TreePath path = getPathForRow(row); + + if (path != null) + return isCollapsed(path); + + return false; + } + + public boolean isExpanded(TreePath path) + { + if (path == null) + return false; + + Object state = nodeStates.get(path); + + if ((state == null) || (state != EXPANDED)) + return false; + + TreePath parent = path.getParentPath(); + + if (parent != null) + return isExpanded(parent); + + return true; + } + + public boolean isExpanded(int row) + { + if (row < 0 || row >= getRowCount()) + return false; + + TreePath path = getPathForRow(row); + + if (path != null) + return isExpanded(path); + + return false; + } + + /** + * @since 1.3 + */ + public boolean getExpandsSelectedPaths() + { + return expandsSelectedPaths; + } + + /** + * @since 1.3 + */ + public void setExpandsSelectedPaths(boolean flag) + { + if (expandsSelectedPaths == flag) + return; + + boolean oldValue = expandsSelectedPaths; + expandsSelectedPaths = flag; + firePropertyChange(EXPANDS_SELECTED_PATHS_PROPERTY, oldValue, flag); + } + + public Rectangle getPathBounds(TreePath path) + { + TreeUI ui = getUI(); + + if (ui == null) + return null; + + return ui.getPathBounds(this, path); + } + + public Rectangle getRowBounds(int row) + { + TreePath path = getPathForRow(row); + + if (path != null) + return getPathBounds(path); + + return null; + } + + public boolean isEditing() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.isEditing(this); + + return false; + } + + public boolean stopEditing() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.stopEditing(this); + + return false; + } + + public void cancelEditing() + { + TreeUI ui = getUI(); + + if (ui != null) + ui.cancelEditing(this); + } + + public void startEditingAtPath(TreePath path) + { + TreeUI ui = getUI(); + + if (ui != null) + ui.startEditingAtPath(this, path); + } + + public TreePath getEditingPath() + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getEditingPath(this); + + return null; + } + + public TreePath getPathForLocation(int x, int y) + { + TreePath path = getClosestPathForLocation(x, y); + + if (path != null) + { + Rectangle rect = getPathBounds(path); + + if ((rect != null) && rect.contains(x, y)) + return path; + } + + return null; + } + + public int getRowForLocation(int x, int y) + { + TreePath path = getPathForLocation(x, y); + + if (path != null) + return getRowForPath(path); + + return -1; + } + + public TreePath getClosestPathForLocation(int x, int y) + { + TreeUI ui = getUI(); + + if (ui != null) + return ui.getClosestPathForLocation(this, x, y); + + return null; + } + + public int getClosestRowForLocation(int x, int y) + { + TreePath path = getClosestPathForLocation(x, y); + + if (path != null) + return getRowForPath(path); + + return -1; + } + + public Object getLastSelectedPathComponent() + { + TreePath path = getSelectionPath(); + + if (path != null) + return path.getLastPathComponent(); + + return null; + } + + private void checkExpandParents(TreePath path) throws ExpandVetoException + { + + TreePath parent = path.getParentPath(); + + if (parent != null) + checkExpandParents(parent); + + fireTreeWillExpand(path); + } + + private void doExpandParents(TreePath path, boolean state) + { + TreePath parent = path.getParentPath(); + + if (isExpanded(parent)) + { + nodeStates.put(path, state ? EXPANDED : COLLAPSED); + return; + } + + if (parent != null) + doExpandParents(parent, false); + + nodeStates.put(path, state ? EXPANDED : COLLAPSED); + } + + protected void setExpandedState(TreePath path, boolean state) + { + if (path == null) + return; + + TreePath parent = path.getParentPath(); + + try + { + if (parent != null) + checkExpandParents(parent); + } + catch (ExpandVetoException e) + { + // Expansion vetoed. + return; + } + + doExpandParents(path, state); + } + + protected void clearToggledPaths() + { + nodeStates.clear(); + } + + protected Enumeration getDescendantToggledPaths(TreePath parent) + { + if (parent == null) + return null; + + Enumeration nodes = nodeStates.keys(); + Vector result = new Vector(); + + while (nodes.hasMoreElements()) + { + TreePath path = (TreePath) nodes.nextElement(); + + if (path.isDescendant(parent)) + result.addElement(path); + } + + return result.elements(); + } + + public boolean hasBeenExpanded(TreePath path) + { + if (path == null) + return false; + + return nodeStates.get(path) != null; + } + + public boolean isVisible(TreePath path) + { + if (path == null) + return false; + + TreePath parent = path.getParentPath(); + + if (parent == null) + return true; // Is root node. + + return isExpanded(parent); + } + + public void makeVisible(TreePath path) + { + if (path == null) + return; + + expandPath(path.getParentPath()); + } + + public boolean isPathEditable(TreePath path) + { + return isEditable(); + } + + /** + * Creates and returns an instance of {@link TreeModelHandler}. + * + * @returns an instance of {@link TreeModelHandler} + */ + protected TreeModelListener createTreeModelListener() + { + return new TreeModelHandler(); + } + + /** + * Returns a sample TreeModel that can be used in a JTree. This can be used + * in Bean- or GUI-Builders to show something interesting. + * + * @return a sample TreeModel that can be used in a JTree + */ + protected static TreeModel getDefaultTreeModel() + { + DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root node"); + DefaultMutableTreeNode child1 = new DefaultMutableTreeNode( + "Child node 1"); + DefaultMutableTreeNode child11 = new DefaultMutableTreeNode( + "Child node 1.1"); + DefaultMutableTreeNode child12 = new DefaultMutableTreeNode( + "Child node 1.2"); + DefaultMutableTreeNode child13 = new DefaultMutableTreeNode( + "Child node 1.3"); + DefaultMutableTreeNode child2 = new DefaultMutableTreeNode( + "Child node 2"); + DefaultMutableTreeNode child21 = new DefaultMutableTreeNode( + "Child node 2.1"); + DefaultMutableTreeNode child22 = new DefaultMutableTreeNode( + "Child node 2.2"); + DefaultMutableTreeNode child23 = new DefaultMutableTreeNode( + "Child node 2.3"); + DefaultMutableTreeNode child24 = new DefaultMutableTreeNode( + "Child node 2.4"); + + DefaultMutableTreeNode child3 = new DefaultMutableTreeNode( + "Child node 3"); + root.add(child1); + root.add(child2); + root.add(child3); + child1.add(child11); + child1.add(child12); + child1.add(child13); + child2.add(child21); + child2.add(child22); + child2.add(child23); + child2.add(child24); + return new DefaultTreeModel(root); + } + + /** + * Converts the specified value to a String. This is used by the renderers + * of this JTree and its nodes. + * + * This implementation simply returns <code>value.toString()</code> and + * ignores all other parameters. Subclass this method to control the + * conversion. + * + * @param value the value that is converted to a String + * @param selected indicates if that value is selected or not + * @param expanded indicates if that value is expanded or not + * @param leaf indicates if that value is a leaf node or not + * @param row the row of the node + * @param hasFocus indicates if that node has focus or not + */ + public String convertValueToText(Object value, boolean selected, + boolean expanded, boolean leaf, int row, boolean hasFocus) + { + return value.toString(); + } + + /** + * A String representation of this JTree. This is intended to be used for + * debugging. The returned string may be empty but may not be + * <code>null</code>. + * + * @return a String representation of this JTree + */ + public String paramString() + { + // TODO: this is completely legal, but it would possibly be nice + // to return some more content, like the tree structure, some properties + // etc ... + return ""; + } + + /** + * Returns all TreePath objects which are a descendants of the given path + * and are exapanded at the moment of the execution of this method. If the + * state of any node is beeing toggled while this method is executing this + * change may be left unaccounted. + * + * @param path The parent of this request + * @return An Enumeration containing TreePath objects + */ + public Enumeration getExpandedDescendants(TreePath path) + { + Enumeration paths = nodeStates.keys(); + Vector relevantPaths = new Vector(); + while (paths.hasMoreElements()) + { + TreePath nextPath = (TreePath) paths.nextElement(); + if (nodeStates.get(nextPath) == EXPANDED + && path.isDescendant(nextPath)) + { + relevantPaths.add(nextPath); + } + } + return relevantPaths.elements(); + } + + /** + * Returns the next table element (beginning from the row + * <code>startingRow</code> that starts with <code>prefix</code>. + * Searching is done in the direction specified by <code>bias</code>. + * + * @param prefix the prefix to search for in the cell values + * @param startingRow the index of the row where to start searching from + * @param bias the search direction, either {@link Position.Bias.Forward} or + * {@link Position.Bias.Backward} + * + * @return the path to the found element or -1 if no such element has been + * found + * + * @throws IllegalArgumentException if prefix is <code>null</code> or + * startingRow is not valid + * + * @since 1.4 + */ + public TreePath getNextMatch(String prefix, int startingRow, + Position.Bias bias) + { + if (prefix == null) + throw new IllegalArgumentException( + "The argument 'prefix' must not be" + " null."); + if (startingRow < 0) + throw new IllegalArgumentException( + "The argument 'startingRow' must not" + + " be less than zero."); + + int size = getRowCount(); + if (startingRow > size) + throw new IllegalArgumentException( + "The argument 'startingRow' must not" + + " be greater than the number of" + + " elements in the TreeModel."); + + TreePath foundPath = null; + if (bias == Position.Bias.Forward) + { + for (int i = startingRow; i < size; i++) + { + TreePath path = getPathForRow(i); + Object o = path.getLastPathComponent(); + // FIXME: in the following call to convertValueToText the + // last argument (hasFocus) should be done right. + String item = convertValueToText(o, isRowSelected(i), + isExpanded(i), treeModel.isLeaf(o), i, false); + if (item.startsWith(prefix)) + { + foundPath = path; + break; + } + } + } else + { + for (int i = startingRow; i >= 0; i--) + { + TreePath path = getPathForRow(i); + Object o = path.getLastPathComponent(); + // FIXME: in the following call to convertValueToText the + // last argument (hasFocus) should be done right. + String item = convertValueToText(o, isRowSelected(i), + isExpanded(i), treeModel.isLeaf(o), i, false); + if (item.startsWith(prefix)) + { + foundPath = path; + break; + } + } + } + return foundPath; + } + + /** + * Removes any paths in the current set of selected paths that are + * descendants of <code>path</code>. If <code>includePath</code> is set + * to <code>true</code> and <code>path</code> itself is selected, then + * it will be removed too. + * + * @param path the path from which selected descendants are to be removed + * @param includePath if <code>true</code> then <code>path</code> itself + * will also be remove if it's selected + * + * @return <code>true</code> if something has been removed, + * <code>false</code> otherwise + * + * @since 1.3 + */ + protected boolean removeDescendantSelectedPaths(TreePath path, + boolean includeSelected) + { + boolean removedSomething = false; + TreePath[] selected = getSelectionPaths(); + for (int index = 0; index < selected.length; index++) + { + if ((selected[index] == path && includeSelected) + || (selected[index].isDescendant(path))) + { + removeSelectionPath(selected[index]); + removedSomething = true; + } + } + return removedSomething; + } +} diff --git a/libjava/classpath/javax/swing/JViewport.java b/libjava/classpath/javax/swing/JViewport.java new file mode 100644 index 00000000000..397cb31acdf --- /dev/null +++ b/libjava/classpath/javax/swing/JViewport.java @@ -0,0 +1,490 @@ +/* JViewport.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.io.Serializable; + +import javax.swing.border.Border; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ViewportUI; + +/** + * + * <pre> + * _ + * +-------------------------------+ ...........Y1 \ + * | view | . \ + * | (this component's child) | . > VY + * | | . / = Y2-Y1 + * | +------------------------------+ ....Y2_/ + * | | viewport | | . + * | | (this component) | | . + * | | | | . + * | | | | . + * | | | | . + * | | | | . + * | +------------------------------+ ....Y3 + * | | . + * | . | . . + * | . | . . + * +---------.---------------------+ ...........Y4 + * . . . . + * . . . . + * . . . . + * X1.......X2.....................X3.......X4 + * \____ ___/ + * \/ + * VX = X2-X1 + *</pre> + * + * <p>A viewport is, like all swing components, located at some position in + * the swing component tree; that location is exactly the same as any other + * components: the viewport's "bounds".</p> + * + * <p>But in terms of drawing its child, the viewport thinks of itself as + * covering a particular position <em>of the view's coordinate space</em>. + * For example, the {@link javax.JViewPort.getViewPosition} method returns + * the position <code>(VX,VY)</code> shown above, which is an position in + * "view space", even though this is <em>implemented</em> by positioning + * the underlying child at position <code>(-VX,-VY)</code></p> + * + */ +public class JViewport extends JComponent +{ + + /** + * A {@link java.awt.event.ComponentListener} that listens for + * changes of the view's size. This class forbids changes of the view + * component's size that would exceed the viewport's size. + */ + protected class ViewListener + extends ComponentAdapter + implements Serializable + { + private static final long serialVersionUID = -2812489404285958070L; + + /** + * Creates a new instance of ViewListener. + */ + protected ViewListener() + { + } + + /** + * Receives notification when a component (in this case: the view + * component) changes it's size. + * + * @param ev the ComponentEvent describing the change + */ + public void componentResized(ComponentEvent ev) + { + // According to some tests that I did with Sun's implementation + // this class is supposed to make sure that the view component + // is not resized to a larger size than the viewport. + // This is not documented anywhere. What I did is: I subclassed JViewport + // and ViewListener and 'disabled' the componentResized method by + // overriding it and not calling super.componentResized(). + // When this method is disabled I can set the size on the view component + // normally, when it is enabled, it gets immediatly resized back, + // after a resize attempt that would exceed the Viewport's size. + Component comp = ev.getComponent(); + Dimension newSize = comp.getSize(); + Dimension viewportSize = getSize(); + boolean revert = false; + if (newSize.width > viewportSize.width) + { + newSize.width = viewportSize.width; + revert = true; + } + if (newSize.height > viewportSize.height) + { + newSize.height = viewportSize.height; + revert = true; + } + if (revert == true) + comp.setSize(newSize); + } + } + + private static final long serialVersionUID = -6925142919680527970L; + + public static final int SIMPLE_SCROLL_MODE = 0; + public static final int BLIT_SCROLL_MODE = 1; + public static final int BACKINGSTORE_SCROLL_MODE = 2; + + ChangeEvent changeEvent = new ChangeEvent(this); + + int scrollMode; + + protected boolean scrollUnderway; + protected boolean isViewSizeSet; + + /** + * The width and height of the Viewport's area in terms of view + * coordinates. Typically this will be the same as the width and height + * of the viewport's bounds, unless the viewport transforms units of + * width and height, which it may do, for example if it magnifies or + * rotates its view. + * + * @see #toViewCoordinates + */ + Dimension extentSize; + + /** + * The width and height of the view in its own coordinate space. + */ + + Dimension viewSize; + + Point lastPaintPosition; + + /** + * The ViewListener instance. + */ + ViewListener viewListener; + + public JViewport() + { + setOpaque(true); + setScrollMode(BLIT_SCROLL_MODE); + setLayout(createLayoutManager()); + updateUI(); + } + + public Dimension getExtentSize() + { + if (extentSize == null) + return toViewCoordinates(getSize()); + else + return extentSize; + } + + public Dimension toViewCoordinates(Dimension size) + { + return size; + } + + public Point toViewCoordinates(Point p) + { + Point pos = getViewPosition(); + return new Point(p.x + pos.x, + p.y + pos.y); + } + + public void setExtentSize(Dimension newSize) + { + extentSize = newSize; + fireStateChanged(); + } + + /** + * Returns the viewSize when set, or the preferred size of the set + * Component view. If no viewSize and no Component view is set an + * empty Dimension is returned. + */ + public Dimension getViewSize() + { + if (isViewSizeSet) + return viewSize; + else + { + Component view = getView(); + if (view != null) + return view.getPreferredSize(); + else + return new Dimension(); + } + } + + + public void setViewSize(Dimension newSize) + { + viewSize = newSize; + Component view = getView(); + if (view != null) + view.setSize(viewSize); + isViewSizeSet = true; + fireStateChanged(); + } + + /** + * Get the viewport's position in view space. Despite confusing name, + * this really does return the viewport's (0,0) position in view space, + * not the view's position. + */ + + public Point getViewPosition() + { + Component view = getView(); + if (view == null) + return new Point(0,0); + else + { + Point p = view.getLocation(); + p.x = -p.x; + p.y = -p.y; + return p; + } + } + + public void setViewPosition(Point p) + { + Component view = getView(); + if (view != null) + { + Point q = new Point(-p.x, -p.y); + view.setLocation(q); + fireStateChanged(); + } + } + + public Rectangle getViewRect() + { + return new Rectangle(getViewPosition(), + getExtentSize()); + } + + /** + * @deprecated 1.4 + */ + public boolean isBackingStoreEnabled() + { + return scrollMode == BACKINGSTORE_SCROLL_MODE; + } + + /** + * @deprecated 1.4 + */ + public void setBackingStoreEnabled(boolean b) + { + if (b && scrollMode != BACKINGSTORE_SCROLL_MODE) + { + scrollMode = BACKINGSTORE_SCROLL_MODE; + fireStateChanged(); + } + } + + public void setScrollMode(int mode) + { + scrollMode = mode; + fireStateChanged(); + } + + public int getScrollMode() + { + return scrollMode; + } + + public Component getView() + { + if (getComponentCount() == 0) + return null; + + return getComponents()[0]; + } + + public void setView(Component v) + { + while (getComponentCount() > 0) + { + if (viewListener != null) + getView().removeComponentListener(viewListener); + remove(0); + } + + if (v != null) + { + if (viewListener == null) + viewListener = createViewListener(); + v.addComponentListener(viewListener); + add(v); + fireStateChanged(); + } + } + + public void revalidate() + { + fireStateChanged(); + super.revalidate(); + } + + public void reshape(int x, int y, int w, int h) + { + boolean changed = + (x != getX()) + || (y != getY()) + || (w != getWidth()) + || (h != getHeight()); + super.reshape(x, y, w, h); + if (changed) + fireStateChanged(); + } + + protected void addImpl(Component comp, Object constraints, int index) + { + if (getComponentCount() > 0) + remove(getComponents()[0]); + + super.addImpl(comp, constraints, index); + } + + public final Insets getInsets() + { + return new Insets(0,0,0,0); + } + + public final Insets getInsets(Insets insets) + { + if (insets == null) + return getInsets(); + insets.top = 0; + insets.bottom = 0; + insets.left = 0; + insets.right = 0; + return insets; + } + + public boolean isOptimizedDrawingEnabled() + { + return false; + } + + public void paint(Graphics g) + { + paintComponent(g); + } + + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) getListeners(ChangeListener.class); + } + + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + for (int i = 0; i < listeners.length; ++i) + listeners[i].stateChanged(changeEvent); + } + + /** + * This method returns the String ID of the UI class of Separator. + * + * @return The UI class' String ID. + */ + public String getUIClassID() + { + return "ViewportUI"; + } + + /** + * This method resets the UI used to the Look and Feel defaults.. + */ + public void updateUI() + { + setUI((ViewportUI) UIManager.getUI(this)); + } + + /** + * This method returns the viewport's UI delegate. + * + * @return The viewport's UI delegate. + */ + public ViewportUI getUI() + { + return (ViewportUI) ui; + } + + /** + * This method sets the viewport's UI delegate. + * + * @param ui The viewport's UI delegate. + */ + public void setUI(ViewportUI ui) + { + super.setUI(ui); + } + + public final void setBorder(Border border) + { + if (border != null) + throw new IllegalArgumentException(); + } + + /** + * Creates a {@link ViewListener} that is supposed to listen for + * size changes on the view component. + * + * @return a ViewListener instance + */ + protected ViewListener createViewListener() + { + return new ViewListener(); + } + + /** + * Creates the LayoutManager that is used for this viewport. Override + * this method if you want to use a custom LayoutManager. + * + * @return a LayoutManager to use for this viewport + */ + protected LayoutManager createLayoutManager() + { + return new ViewportLayout(); + } +} diff --git a/libjava/classpath/javax/swing/JWindow.java b/libjava/classpath/javax/swing/JWindow.java new file mode 100644 index 00000000000..449900370c6 --- /dev/null +++ b/libjava/classpath/javax/swing/JWindow.java @@ -0,0 +1,245 @@ +/* JWindow.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.LayoutManager; +import java.awt.Window; +import java.awt.event.KeyEvent; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; + +/** + * Unlike JComponent derivatives, JWindow inherits from + * java.awt.Window. But also lets a look-and-feel component to its work. + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class JWindow extends Window implements Accessible, RootPaneContainer +{ + private static final long serialVersionUID = 5420698392125238833L; + + protected JRootPane rootPane; + + /** + * @specnote rootPaneCheckingEnabled is false to comply with J2SE 5.0 + */ + protected boolean rootPaneCheckingEnabled = false; + + protected AccessibleContext accessibleContext; + + /** + * Tells us if we're in the initialization stage. + * If so, adds go to top-level Container, otherwise they go + * to the content pane for this container. + */ + private boolean initStageDone = false; + + public JWindow() + { + super(SwingUtilities.getOwnerFrame()); + windowInit(); + } + + public JWindow(GraphicsConfiguration gc) + { + super(SwingUtilities.getOwnerFrame(), gc); + windowInit(); + } + + public JWindow(Frame owner) + { + super(owner); + windowInit(); + } + + public JWindow(Window owner) + { + super(owner); + windowInit(); + } + + public JWindow(Window owner, GraphicsConfiguration gc) + { + super(owner, gc); + windowInit(); + } + + protected void windowInit() + { + super.setLayout(new BorderLayout(1, 1)); + getRootPane(); // will do set/create + // Now we're done init stage, adds and layouts go to content pane. + initStageDone = true; + } + + public Dimension getPreferredSize() + { + return super.getPreferredSize(); + } + + public void setLayout(LayoutManager manager) + { + // Check if we're in initialization stage. If so, call super.setLayout + // otherwise, valid calls go to the content pane. + if (initStageDone) + { + if (isRootPaneCheckingEnabled()) + throw new Error("Cannot set layout. Use getContentPane().setLayout()" + + " instead."); + getContentPane().setLayout(manager); + } + else + super.setLayout(manager); + } + + public void setLayeredPane(JLayeredPane layeredPane) + { + getRootPane().setLayeredPane(layeredPane); + } + + public JLayeredPane getLayeredPane() + { + return getRootPane().getLayeredPane(); + } + + public JRootPane getRootPane() + { + if (rootPane == null) + setRootPane(createRootPane()); + return rootPane; + } + + protected void setRootPane(JRootPane root) + { + if (rootPane != null) + remove(rootPane); + + rootPane = root; + add(rootPane, BorderLayout.CENTER); + } + + protected JRootPane createRootPane() + { + return new JRootPane(); + } + + public Container getContentPane() + { + return getRootPane().getContentPane(); + } + + public void setContentPane(Container contentPane) + { + getRootPane().setContentPane(contentPane); + } + + public Component getGlassPane() + { + return getRootPane().getGlassPane(); + } + + public void setGlassPane(Component glassPane) + { + getRootPane().setGlassPane(glassPane); + } + + + protected void addImpl(Component comp, Object constraints, int index) + { + // If we're adding in the initialization stage use super.add. + // otherwise pass the add onto the content pane. + if (!initStageDone) + super.addImpl(comp, constraints, index); + else + { + if (isRootPaneCheckingEnabled()) + throw new Error("Do not use add() on JWindow directly. Use " + + "getContentPane().add() instead"); + getContentPane().add(comp, constraints, index); + } + } + + public void remove(Component comp) + { + // If we're removing the root pane, use super.remove. Otherwise + // pass it on to the content pane instead. + if (comp == rootPane) + super.remove(rootPane); + else + getContentPane().remove(comp); + } + + protected boolean isRootPaneCheckingEnabled() + { + return rootPaneCheckingEnabled; + } + + protected void setRootPaneCheckingEnabled(boolean enabled) + { + rootPaneCheckingEnabled = enabled; + } + + public void update(Graphics g) + { + paint(g); + } + + protected void processKeyEvent(KeyEvent e) + { + super.processKeyEvent(e); + } + + public AccessibleContext getAccessibleContext() + { + return null; + } + + protected String paramString() + { + return "JWindow"; + } +} diff --git a/libjava/classpath/javax/swing/KeyStroke.java b/libjava/classpath/javax/swing/KeyStroke.java new file mode 100644 index 00000000000..12a280c217a --- /dev/null +++ b/libjava/classpath/javax/swing/KeyStroke.java @@ -0,0 +1,122 @@ +/* KeyStroke.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.AWTKeyStroke; +import java.awt.event.KeyEvent; +import java.io.Serializable; + +public class KeyStroke + extends AWTKeyStroke + implements Serializable +{ + private static final long serialVersionUID = -9060180771037902530L; + + // Called by java.awt.AWTKeyStroke.registerSubclass via reflection. + private KeyStroke() + { + } + + private KeyStroke(char keyChar, int keyCode, int modifiers, + boolean onKeyRelease) + { + super(keyChar, keyCode, modifiers, onKeyRelease); + } + + static + { + AWTKeyStroke.registerSubclass(KeyStroke.class); + } + + public static KeyStroke getKeyStroke(char keyChar) + { + return (KeyStroke) getAWTKeyStroke(keyChar); + } + + /** + * @deprecated Use {@link #getKeyStroke(char)} + * + * This method, unlike all the other factory methods on this object, + * returns a non-cached, non-shared object. New code should not use it. + */ + public static KeyStroke getKeyStroke(char keyChar, boolean onKeyRelease) + { + return new KeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, onKeyRelease); + } + + public static KeyStroke getKeyStroke(Character keyChar, int modifiers) + { + return (KeyStroke) getAWTKeyStroke(keyChar, modifiers); + } + + public static KeyStroke getKeyStroke(int keyCode, int modifiers, + boolean onKeyRelease) + { + return (KeyStroke) getAWTKeyStroke(keyCode, modifiers, onKeyRelease); + } + + public static KeyStroke getKeyStroke(int keyCode, int modifiers) + { + return (KeyStroke) getAWTKeyStroke(keyCode, modifiers); + } + + /** + * Returns the KeyStroke according to <code>getAWTKeyStroke()</code>. + * But it returns null instead of throwing + * <code>IllegalArugmentException</code> when + * the keystoke sequence cannot be parsed from the given string. + */ + public static KeyStroke getKeyStroke(String str) + { + try + { + return (KeyStroke) getAWTKeyStroke(str); + } + catch (IllegalArgumentException iae) + { + return null; + } + } + + public static KeyStroke getKeyStrokeForEvent(KeyEvent event) + { + return (KeyStroke) getAWTKeyStrokeForEvent(event); + } + +} diff --git a/libjava/classpath/javax/swing/LayoutFocusTraversalPolicy.java b/libjava/classpath/javax/swing/LayoutFocusTraversalPolicy.java new file mode 100644 index 00000000000..2d135157d85 --- /dev/null +++ b/libjava/classpath/javax/swing/LayoutFocusTraversalPolicy.java @@ -0,0 +1,89 @@ +/* LayoutFocusTraversalPolicy.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.io.Serializable; +import java.util.Comparator; + +/** + * @author Graydon Hoare + * @author Michael Koch + * + * @since 1.4 + */ +public class LayoutFocusTraversalPolicy + extends SortingFocusTraversalPolicy + implements Serializable +{ + private static class LayoutComparator + implements Comparator + { + public LayoutComparator() + { + // Do nothing here. + } + + public int compare(Object o1, Object o2) + { + Component comp1 = (Component) o1; + Component comp2 = (Component) o2; + + int x1 = comp1.getX(); + int y1 = comp1.getY(); + int x2 = comp2.getX(); + int y2 = comp2.getY(); + + if (x1 == x2 && y1 == y2) + return 0; + + if ((y1 < y2) || ((y1 == y2) && (x1 < x2))) + return -1; + + return 1; + } + } + + private static final long serialVersionUID = 4312146927238881442L; + + public LayoutFocusTraversalPolicy() + { + super(new LayoutComparator()); + } +} diff --git a/libjava/classpath/javax/swing/ListCellRenderer.java b/libjava/classpath/javax/swing/ListCellRenderer.java new file mode 100644 index 00000000000..6ce115ea70c --- /dev/null +++ b/libjava/classpath/javax/swing/ListCellRenderer.java @@ -0,0 +1,52 @@ +/* ListCellRenderer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; + +/** + * Renders the cells of a {@link JList}. + */ +public interface ListCellRenderer +{ + Component getListCellRendererComponent(JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus); +} diff --git a/libjava/classpath/javax/swing/ListModel.java b/libjava/classpath/javax/swing/ListModel.java new file mode 100644 index 00000000000..736627e85a7 --- /dev/null +++ b/libjava/classpath/javax/swing/ListModel.java @@ -0,0 +1,80 @@ +/* ListModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import javax.swing.event.ListDataListener; + +/** + * The data model that is typically used in {@link JList}. + * + * @author Graydon Hoare (graydon@redhat.com) + */ +public interface ListModel +{ + /** + * Return the number of data elements in the list. + * + * @return The number of data elements in the list + */ + int getSize(); + + /** + * Retrieves a data element at a specified index. + * + * @param index The index of the element to retrieve + * + * @return The data element at the specified index + */ + Object getElementAt(int index); + + /** + * Add a listener object to this model. The listener will be called + * any time the set of elements in the model is changed. + * + * @param l The listener to add + */ + void addListDataListener(ListDataListener l); + + /** + * Add a listener object to this model. The listener will no longer be + * called when the set of elements in the model is changed. + * + * @param l The listener to remove + */ + void removeListDataListener(ListDataListener l); +} diff --git a/libjava/classpath/javax/swing/ListSelectionModel.java b/libjava/classpath/javax/swing/ListSelectionModel.java new file mode 100644 index 00000000000..f4680d737fb --- /dev/null +++ b/libjava/classpath/javax/swing/ListSelectionModel.java @@ -0,0 +1,86 @@ +/* ListSelectionModel.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import javax.swing.event.ListSelectionListener; + +/** + * The model that is used in {@link JList} to define the selected/not-selected + * cells of that list. + */ +public interface ListSelectionModel +{ + int SINGLE_SELECTION = 0; + int SINGLE_INTERVAL_SELECTION = 1; + int MULTIPLE_INTERVAL_SELECTION = 2; + + void setSelectionMode(int a); + int getSelectionMode(); + + void clearSelection(); + + int getMinSelectionIndex(); + int getMaxSelectionIndex(); + + boolean isSelectedIndex(int a); + + boolean isSelectionEmpty(); + void setSelectionInterval(int index0, int index1); + void addSelectionInterval(int index0, + int index1); + void removeSelectionInterval(int index0, + int index1); + void insertIndexInterval(int index, + int length, + boolean before); + void removeIndexInterval(int index0, + int index1); + + int getAnchorSelectionIndex(); + void setAnchorSelectionIndex(int index); + int getLeadSelectionIndex(); + void setLeadSelectionIndex(int index); + + void setValueIsAdjusting(boolean valueIsAdjusting); + boolean getValueIsAdjusting(); + + void addListSelectionListener(ListSelectionListener listener); + void removeListSelectionListener(ListSelectionListener listener); + +} diff --git a/libjava/classpath/javax/swing/LookAndFeel.java b/libjava/classpath/javax/swing/LookAndFeel.java new file mode 100644 index 00000000000..8858742711d --- /dev/null +++ b/libjava/classpath/javax/swing/LookAndFeel.java @@ -0,0 +1,236 @@ +/* LookAndFeel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Toolkit; + +import javax.swing.text.JTextComponent; + +public abstract class LookAndFeel +{ + /** + * This method is called once by UIManager.setLookAndFeel to create + * the look and feel specific defaults table. + * + * @return the UI defaults + */ + public UIDefaults getDefaults() + { + return null; + } + + /** + * Returns a description of the look and feel. + * + * @return A description of the look and feel. + */ + public abstract String getDescription(); + + public static Object getDesktopPropertyValue(String systemPropertyName, + Object fallbackValue) + { + Object value = Toolkit.getDefaultToolkit().getDesktopProperty(systemPropertyName); + return value != null ? value : fallbackValue; + } + + /** + * Returns an identifier for the look and feel. + * + * @return An identifier for the look and feel. + */ + public abstract String getID(); + + /** + * Returns the name for the look and feel. + * + * @return The name for the look and feel. + */ + public abstract String getName(); + + /** + * Returns true when the Look and Feel supports window decorations, + * false others. This method returns always false and needs to be overwritten + * when the derived Look and Feel supports this. + * + * @return false + * + * @since 1.4 + */ + public boolean getSupportsWindowDecorations() + { + return false; + } + + /** + * UIManager.setLookAndFeel calls this method before the first call + * (and typically the only call) to getDefaults(). + */ + public void initialize() + { + } + + /** + * Convenience method for installing a component's default Border object + * on the specified component if either the border is currently null + * or already an instance of UIResource. + */ + public static void installBorder(JComponent c, String defaultBorderName) + { + } + + /** + * Convenience method for initializing a component's foreground and + * background color properties with values from the current defaults table. + */ + public static void installColors(JComponent c, String defaultBgName, String defaultFgName) + { + } + + /** + * Convenience method for initializing a components foreground background + * and font properties with values from the current defaults table. + */ + public static void installColorsAndFont(JComponent component, + String defaultBgName, + String defaultFgName, + String defaultFontName) + { + } + + /** + * Returns <code>true</code> if the look and feel is the "native" look and + * feel for the current platform, and <code>false</code> otherwise. + * + * @return A flag indicating whether or not this is the native look and feel + * for the current platform. + */ + public abstract boolean isNativeLookAndFeel(); + + /** + * Returns <code>true</code> if the look and feel is supported on the + * current operating system, and <code>false</code> otherwise. This + * mechanism is provided so that it is possible to prevent a look and feel + * from being used on some operating systems (usually for legal, not + * technical, reasons). + * + * @return A flag indicating whether or not the look and feel is supported + * on the current platform. + */ + public abstract boolean isSupportedLookAndFeel(); + + /** + * Loads the bindings in keys into retMap. + */ + public static void loadKeyBindings(InputMap retMap, Object[] keys) + { + } + + /** + * Creates a ComponentInputMap from keys. + */ + public static ComponentInputMap makeComponentInputMap(JComponent c, + Object[] keys) + { + return null; + } + + /** + * Utility method that creates a UIDefaults.LazyValue that creates an + * ImageIcon UIResource for the specified gifFile filename. + */ + public static Object makeIcon(Class baseClass, String gifFile) + { + return null; + } + + /** + * Creates a InputMap from keys. + */ + public static InputMap makeInputMap(Object[] keys) + { + return null; + } + + /** + * Convenience method for building lists of KeyBindings. + */ + public static JTextComponent.KeyBinding[] makeKeyBindings(Object[] keyBindingList) + { + return null; + } + + /** + * Invoked when the user attempts an invalid operation. The default implement + * just beeps. Subclasses that wish to change this need to override this + * method. + * + * @param component the component the error occured in + */ + public void provideErrorFeedback(Component component) + { + Toolkit.getDefaultToolkit().beep(); + } + + /** + * Returns a string that displays and identifies this object's properties. + * + * @return the string "LookAndFeel" + */ + public String toString() + { + return "LookAndFeel"; + } + + /** + * UIManager.setLookAndFeel calls this method just before we're replaced by + * a new default look and feel. + */ + public void uninitialize() + { + } + + /** + * Convenience method for un-installing a component's default border on the + * specified component if the border is currently an instance of UIResource. + */ + public static void uninstallBorder(JComponent c) + { + } +} diff --git a/libjava/classpath/javax/swing/MenuElement.java b/libjava/classpath/javax/swing/MenuElement.java new file mode 100644 index 00000000000..46eb8c2a5fe --- /dev/null +++ b/libjava/classpath/javax/swing/MenuElement.java @@ -0,0 +1,93 @@ +/* MenuElement.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +/** + * Defines the methods that any menu element in a {@link JMenu} must + * implement. + * + * @author Andrew Selkirk + */ +public interface MenuElement { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * processMouseEvent + * @param event TODO + * @param path TODO + * @param manager TODO + */ + void processMouseEvent(MouseEvent event, + MenuElement[] path, MenuSelectionManager manager); + + /** + * processKeyEvent + * @param event TODO + * @param path TODO + * @param manager TODO + */ + void processKeyEvent(KeyEvent event, + MenuElement[] path, MenuSelectionManager manager); + + /** + * menuSelectionChanged + * @param included TODO + */ + void menuSelectionChanged(boolean included); + + /** + * getSubElements + * @returns MenuElement[] + */ + MenuElement[] getSubElements(); + + /** + * getComponent + * @returns Component + */ + Component getComponent(); + + +} // MenuElement diff --git a/libjava/classpath/javax/swing/MenuSelectionManager.java b/libjava/classpath/javax/swing/MenuSelectionManager.java new file mode 100644 index 00000000000..acaee974e3a --- /dev/null +++ b/libjava/classpath/javax/swing/MenuSelectionManager.java @@ -0,0 +1,387 @@ +/* MenuSelectionManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Vector; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +/** + * This class manages current menu selectection. It provides + * methods to clear and set current selected menu path. + * It also fires StateChange event to its registered + * listeners whenever selected path of the current menu hierarchy + * changes. + * + */ +public class MenuSelectionManager +{ + /** ChangeEvent fired when selected path changes*/ + protected ChangeEvent changeEvent = new ChangeEvent(this); + + /** List of listeners for this MenuSelectionManager */ + protected EventListenerList listenerList = new EventListenerList(); + + /** Default manager for the current menu hierarchy*/ + private static final MenuSelectionManager manager = new MenuSelectionManager(); + + /** Path to the currently selected menu */ + private Vector selectedPath = new Vector(); + + /** + * Fires StateChange event to registered listeners + */ + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners[i].stateChanged(changeEvent); + } + + /** + * Adds ChangeListener to this MenuSelectionManager + * + * @param listener ChangeListener to add + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * Removes ChangeListener from the list of registered listeners + * for this MenuSelectionManager. + * + * @param listener ChangeListner to remove + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * Returns list of registered listeners with MenuSelectionManager + * + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Unselects all the menu elements on the selection path + */ + public void clearSelectedPath() + { + // Send events from the bottom most item in the menu - hierarchy to the + // top most + for (int i = selectedPath.size() - 1; i >= 0; i--) + ((MenuElement) selectedPath.get(i)).menuSelectionChanged(false); + + // clear selected path + selectedPath.clear(); + + // notify all listeners that the selected path was changed + fireStateChanged(); + } + + /** + * This method returns menu element on the selected path that contains + * given source point. If no menu element on the selected path contains this + * point, then null is returned. + * + * @param source Component relative to which sourcePoint is given + * @param sourcePoint point for which we want to find menu element that contains it + * + * @return Returns menu element that contains given source point and belongs + * to the currently selected path. Null is return if no such menu element found. + */ + public Component componentForPoint(Component source, Point sourcePoint) + { + // Convert sourcePoint to screen coordinates. + Point sourcePointOnScreen = sourcePoint; + SwingUtilities.convertPointToScreen(sourcePointOnScreen, source); + + Point compPointOnScreen; + Component resultComp = null; + + // For each menu element on the selected path, express its location + // in terms of screen coordinates and check if there is any + // menu element on the selected path that contains given source point. + for (int i = 0; i < selectedPath.size(); i++) + { + Component comp = ((Component) selectedPath.get(i)); + Dimension size = comp.getSize(); + + // convert location of this menu item to screen coordinates + compPointOnScreen = comp.getLocationOnScreen(); + + if (compPointOnScreen.x <= sourcePointOnScreen.x + && sourcePointOnScreen.x < compPointOnScreen.x + size.width + && compPointOnScreen.y <= sourcePointOnScreen.y + && sourcePointOnScreen.y < compPointOnScreen.y + size.height) + { + Point p = sourcePointOnScreen; + SwingUtilities.convertPointFromScreen(p, comp); + resultComp = SwingUtilities.getDeepestComponentAt(comp, p.x, p.y); + break; + } + } + return resultComp; + } + + /** + * Returns shared instance of MenuSelection Manager + * + * @return default Manager + */ + public static MenuSelectionManager defaultManager() + { + return manager; + } + + /** + * Returns path representing current menu selection + * + * @return Current selection path + */ + public MenuElement[] getSelectedPath() + { + MenuElement[] path = new MenuElement[selectedPath.size()]; + + for (int i = 0; i < path.length; i++) + path[i] = (MenuElement) selectedPath.get(i); + + return path; + } + + /** + * Returns true if specified component is part of current menu + * heirarchy and false otherwise + * + * @param c Component for which to check + * @return True if specified component is part of current menu + */ + public boolean isComponentPartOfCurrentMenu(Component c) + { + MenuElement[] subElements; + for (int i = 0; i < selectedPath.size(); i++) + { + subElements = ((MenuElement) selectedPath.get(i)).getSubElements(); + for (int j = 0; j < subElements.length; j++) + { + if ((subElements[j].getComponent()).equals(c)) + return true; + } + } + + return false; + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void processKeyEvent(KeyEvent e) + { + throw new UnsupportedOperationException("not implemented"); + } + + /** + * Forwards given mouse event to all of the source subcomponents. + * + * @param event Mouse event + */ + public void processMouseEvent(MouseEvent event) + { + Component source = ((Component) event.getSource()); + + // In the case of drag event, event.getSource() returns component + // where drag event originated. However menu element processing this + // event should be the one over which mouse is currently located, + // which is not necessary the source of the drag event. + Component mouseOverMenuComp; + + // find over which menu element the mouse is currently located + if (event.getID() == MouseEvent.MOUSE_DRAGGED + || event.getID() == MouseEvent.MOUSE_RELEASED) + mouseOverMenuComp = componentForPoint(source, event.getPoint()); + else + mouseOverMenuComp = source; + + // Process this event only if mouse is located over some menu element + if (mouseOverMenuComp != null && (mouseOverMenuComp instanceof MenuElement)) + { + MenuElement[] path = getPath(mouseOverMenuComp); + ((MenuElement) mouseOverMenuComp).processMouseEvent(event, path, + manager); + + // FIXME: Java specification says that mouse events should be + // forwarded to subcomponents. The code below does it, but + // menu's work fine without it. This code is commented for now. + + /* + MenuElement[] subComponents = ((MenuElement) mouseOverMenuComp) + .getSubElements(); + + for (int i = 0; i < subComponents.length; i++) + { + subComponents[i].processMouseEvent(event, path, manager); + } + */ + } + else + { + if (event.getID() == MouseEvent.MOUSE_RELEASED) + clearSelectedPath(); + } + } + + /** + * Sets menu selection to the specified path + * + * @param path new selection path + */ + public void setSelectedPath(MenuElement[] path) + { + if (path == null) + { + clearSelectedPath(); + return; + } + + int i; + int minSize = path.length; // size of the smaller path. + + if (path.length > selectedPath.size()) + { + minSize = selectedPath.size(); + + // if new selected path contains more elements then current + // selection then first add all elements at + // the indexes > selectedPath.size + for (i = selectedPath.size(); i < path.length; i++) + { + selectedPath.add(path[i]); + path[i].menuSelectionChanged(true); + } + } + + else if (path.length < selectedPath.size()) + { + // if new selected path contains less elements then current + // selection then first remove all elements from the selection + // at the indexes > path.length + for (i = selectedPath.size() - 1; i >= path.length; i--) + { + ((MenuElement) selectedPath.get(i)).menuSelectionChanged(false); + selectedPath.remove(i); + } + + minSize = path.length; + } + + // Now compare elements in new and current selection path at the + // same location and adjust selection until + // same menu elements will be encountered at the + // same index in both current and new selection path. + MenuElement oldSelectedItem; + + for (i = minSize - 1; i >= 0; i--) + { + oldSelectedItem = (MenuElement) selectedPath.get(i); + + if (path[i].equals(oldSelectedItem)) + break; + + oldSelectedItem.menuSelectionChanged(false); + path[i].menuSelectionChanged(true); + selectedPath.setElementAt(path[i], i); + } + + fireStateChanged(); + } + + /** + * Returns path to the specified component + * + * @param c component for which to find path for + * + * @return path to the specified component + */ + private MenuElement[] getPath(Component c) + { + // FIXME: There is the same method in BasicMenuItemUI. However I + // cannot use it here instead of this method, since I cannot assume that + // all the menu elements on the selected path are JMenuItem or JMenu. + // For now I've just duplicated it here. Please + // fix me or delete me if another better approach will be found, and + // this method will not be necessary. + ArrayList path = new ArrayList(); + + // if given component is JMenu, we also need to include + // it's popup menu in the path + if (c instanceof JMenu) + path.add(((JMenu) c).getPopupMenu()); + while (c instanceof MenuElement) + { + path.add(0, (MenuElement) c); + + if (c instanceof JPopupMenu) + c = ((JPopupMenu) c).getInvoker(); + else + c = c.getParent(); + } + + MenuElement[] pathArray = new MenuElement[path.size()]; + path.toArray(pathArray); + return pathArray; + } +} diff --git a/libjava/classpath/javax/swing/MutableComboBoxModel.java b/libjava/classpath/javax/swing/MutableComboBoxModel.java new file mode 100644 index 00000000000..ee79dac03a5 --- /dev/null +++ b/libjava/classpath/javax/swing/MutableComboBoxModel.java @@ -0,0 +1,82 @@ +/* MutableComboBoxModel.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +/** + * A data model used in {@link JComboBox}es that keeps track of the + * components data and provides methods to insert and remove elements from + * it. The classes implementing this interface should + * fire appropriate events indicating the undergoing change in the data model. + * + * @author Andrew Selkirk + * @author Olga Rodimina + */ +public interface MutableComboBoxModel extends ComboBoxModel +{ + /** + * This method adds given object to its data model. + * + * @param object element to add to the data model. + */ + void addElement(Object object); + + /** + * This method removes elements located at the given index in the data + * model. + * + * @param index index specifying location of the element to remove. + */ + void removeElementAt(int index); + + /** + * This method inserts givent element to the data model, at the specified + * index. + * + * @param object element to insert + * @param index index specifying the position in the data model where the + * given element should be inserted. + */ + void insertElementAt(Object object, int index); + + /** + * This method removes given element from the data model + * + * @param element to remove. + */ + void removeElement(Object object); +} // MutableComboBoxModel diff --git a/libjava/classpath/javax/swing/OverlayLayout.java b/libjava/classpath/javax/swing/OverlayLayout.java new file mode 100644 index 00000000000..e8aef98a521 --- /dev/null +++ b/libjava/classpath/javax/swing/OverlayLayout.java @@ -0,0 +1,191 @@ +/* OverlayLayout.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.LayoutManager2; +import java.io.Serializable; + +/** + * OverlayLayout + * @author Andrew Selkirk + * @version 1.0 + */ +public class OverlayLayout + implements LayoutManager2, Serializable +{ + private static final long serialVersionUID = 18082829169631543L; + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * target + */ + private Container target; + + /** + * xChildren + */ + private SizeRequirements[] xChildren; + + /** + * yChildren + */ + private SizeRequirements[] yChildren; + + /** + * xTotal + */ + private SizeRequirements xTotal; + + /** + * yTotal + */ + private SizeRequirements yTotal; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor OverlayLayout + * @param target TODO + */ + public OverlayLayout(Container target) { + // TODO + } // OverlayLayout() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * invalidateLayout + * @param target TODO + */ + public void invalidateLayout(Container target) { + // TODO + } // invalidateLayout() + + /** + * addLayoutComponent + * @param string TODO + * @param component TODO + */ + public void addLayoutComponent(String string, Component component) { + // TODO + } // addLayoutComponent() + + /** + * addLayoutComponent + * @param component TODO + * @param constraints TODO + */ + public void addLayoutComponent(Component component, Object constraints) { + // TODO + } // addLayoutComponent() + + /** + * removeLayoutComponent + * @param component TODO + */ + public void removeLayoutComponent(Component component) { + // TODO + } // removeLayoutComponent() + + /** + * preferredLayoutSize + * @param target TODO + * @returns Dimension + */ + public Dimension preferredLayoutSize(Container target) { + return null; // TODO + } // preferredLayoutSize() + + /** + * minimumLayoutSize + * @param target TODO + * @returns Dimension + */ + public Dimension minimumLayoutSize(Container target) { + return null; // TODO + } // minimumLayoutSize() + + /** + * maximumLayoutSize + * @param target TODO + * @returns Dimension + */ + public Dimension maximumLayoutSize(Container target) { + return null; // TODO + } // maximumLayoutSize() + + /** + * getLayoutAlignmentX + * @param target TODO + * @returns float + */ + public float getLayoutAlignmentX(Container target) { + return (float) 0.0; // TODO + } // getLayoutAlignmentX() + + /** + * getLayoutAlignmentY + * @param target TODO + * @returns float + */ + public float getLayoutAlignmentY(Container target) { + return (float) 0.0; // TODO + } // getLayoutAlignmentY() + + /** + * layoutContainer + * @param target TODO + */ + public void layoutContainer(Container target) { + // TODO + } // layoutContainer() + + +} // OverlayLayout diff --git a/libjava/classpath/javax/swing/Popup.java b/libjava/classpath/javax/swing/Popup.java new file mode 100644 index 00000000000..69e1f516802 --- /dev/null +++ b/libjava/classpath/javax/swing/Popup.java @@ -0,0 +1,189 @@ +/* Popup.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; + + +/** + * Manages a popup window that displays a Component on top of + * everything else. + * + * <p>To obtain an instance of <code>Popup</code>, use the + * {@link javax.swing.PopupFactory}. + * + * @since 1.4 + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class Popup +{ + /** + * Constructs a new <code>Popup</code> given its owner, + * contents and the screen position where the popup + * will appear. + * + * @param owner the Component to which <code>x</code> and + * <code>y</code> are relative, or <code>null</code> for + * placing the popup relative to the origin of the screen. + * + * @param contents the contents that will be displayed inside + * the <code>Popup</code>. + * + * @param x the horizontal position where the Popup will appear. + * + * @param y the vertical position where the Popup will appear. + * + * @throws IllegalArgumentException if <code>contents</code> + * is <code>null</code>. + */ + protected Popup(Component owner, Component contents, + int x, int y) + { + if (contents == null) + throw new IllegalArgumentException(); + + // The real stuff happens in the implementation of subclasses, + // for instance JWindowPopup. + } + + + /** + * Constructs a new <code>Popup</code>. + */ + protected Popup() + { + } + + + /** + * Displays the <code>Popup</code> on the screen. Nothing happens + * if it is currently shown. + */ + public void show() + { + // Implemented by subclasses, for instance JWindowPopup. + } + + + /** + * Removes the <code>Popup</code> from the screen. Nothing happens + * if it is currently hidden. + */ + public void hide() + { + // Implemented by subclasses, for instance JWindowPopup. + } + + + /** + * A <code>Popup</code> that uses a <code>JWindow</code> for + * displaying its contents. + * + * @see PopupFactory#getPopup + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + static class JWindowPopup + extends Popup + { + /** + * The <code>JWindow</code> used for displaying the contents + * of the popup. + */ + JWindow window; + + + /** + * Constructs a new <code>JWindowPopup</code> given its owner, + * contents and the screen position where the popup + * will appear. + * + * @param owner the Component to which <code>x</code> and + * <code>y</code> are relative, or <code>null</code> for + * placing the popup relative to the origin of the screen. + * + * @param contents the contents that will be displayed inside + * the <code>Popup</code>. + * + * @param x the horizontal position where the Popup will appear. + * + * @param y the vertical position where the Popup will appear. + * + * @throws IllegalArgumentException if <code>contents</code> + * is <code>null</code>. + */ + public JWindowPopup(Component owner, Component contents, + int x, int y) + { + /* Checks whether contents is null. */ + super(owner, contents, x, y); + + window = new JWindow(); + window.getRootPane().add(contents); + window.setLocation(x, y); + window.pack(); + } + + + /** + * Displays the popup's <code>JWindow</code> on the screen. + * Nothing happens if it is already visible. + */ + public void show() + { + window.show(); + } + + + /** + * Removes the popup's <code>JWindow</code> from the + * screen. Nothing happens if it is currently not visible. + */ + public void hide() + { + /* Calling dispose() instead of hide() will conserve native + * system resources, for example memory in an X11 server. + * They will automatically be re-allocated by a call to + * show(). + */ + window.dispose(); + } + } +} diff --git a/libjava/classpath/javax/swing/PopupFactory.java b/libjava/classpath/javax/swing/PopupFactory.java new file mode 100644 index 00000000000..29cf86d5530 --- /dev/null +++ b/libjava/classpath/javax/swing/PopupFactory.java @@ -0,0 +1,139 @@ +/* PopupFactory.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; + + +/** + * A factory for <code>Popup</code> objects. These are used to + * managed little windows that float over everything else, + * typically containing a popup menu. + * + * @since 1.4 + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class PopupFactory +{ + /** + * The shared factory object. + * + * @see #getSharedFactory + * @see #setSharedFactory + */ + private static PopupFactory sharedFactory; + + + /** + * Constructs a new <code>PopupFactory</code>. Usually, a single + * <code>PopupFactory</code> is shared among multiple consumers + * of <code>Popup</code>. Use {@link #getSharedInstance} to retrieve + * the current factory. + */ + public PopupFactory() + { + } + + + /** + * Sets the shared factory. + * + * @param factory the PopupFactory that future invocations of + * {@link #getSharedInstance} will return. + * + * @throws IllegalArgumentException if <code>factory</code> + * is <code>null</code>. + */ + public static void setSharedInstance(PopupFactory factory) + { + if (factory == null) + throw new IllegalArgumentException(); + + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + sharedFactory = factory; + } + + + /** + * Retrieves the shared factory, creating a new factory if + * necessary. + * + * @return a <code>PopupFactory</code> that can be used + * to create <code>Popup</code> objects. + */ + public static PopupFactory getSharedInstance() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (sharedFactory == null) + sharedFactory = new PopupFactory(); + + return sharedFactory; + } + + + /** + * Creates a new <code>Popup</code> given its owner, + * contents and the screen position where the popup + * will appear. + * + * @param owner the Component to which <code>x</code> and + * <code>y</code> are relative, or <code>null</code> for + * placing the popup relative to the origin of the screen. + * + * @param contents the contents that will be displayed inside + * the <code>Popup</code>. + * + * @param x the horizontal position where the Popup will appear. + * + * @param y the vertical position where the Popup will appear. + * + * @throws IllegalArgumentException if <code>contents</code> + * is <code>null</code>. + */ + public Popup getPopup(Component owner, Component contents, + int x, int y) + { + return new Popup.JWindowPopup(owner, contents, x, y); + } +} diff --git a/libjava/classpath/javax/swing/ProgressMonitor.java b/libjava/classpath/javax/swing/ProgressMonitor.java new file mode 100644 index 00000000000..844258f1b90 --- /dev/null +++ b/libjava/classpath/javax/swing/ProgressMonitor.java @@ -0,0 +1,228 @@ +/* ProgressMonitor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; + +/** + * ProgressMonitor + * @author Andrew Selkirk + * @version 1.0 + */ +public class ProgressMonitor { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * parentComponent + */ + private Component component; + + /** + * note + */ + private String note; + + /** + * message + */ + private Object message; + + /** + * millisToDecideToPopup + */ + private int millisToDecideToPopup; + + /** + * millisToPopup + */ + private int millisToPopup; + + /** + * min + */ + private int minimum; + + /** + * max + */ + private int maximum; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor ProgressMonitor + * @param component TODO + * @param message TODO + * @param note TODO + * @param minimum TODO + * @param maximum TODO + */ + public ProgressMonitor(Component component, Object message, + String note, int minimum, int maximum) { + + // Set Data + this.component = component; + this.message = message; + this.note = note; + this.minimum = minimum; + this.maximum = maximum; + + // TODO + } // ProgressMonitor() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * close + */ + public void close() { + // TODO + } // close() + + /** + * setProgress + * @param progress TODO + */ + public void setProgress(int progress) { + // TODO + } // setProgress() + + /** + * getMinimum + * @returns int + */ + public int getMinimum() { + return minimum; // TODO + } // getMinimum() + + /** + * setMinimum + * @param minimum TODO + */ + public void setMinimum(int minimum) { + this.minimum = minimum; + // TODO + } // setMinimum() + + /** + * getMaximum + * @returns int + */ + public int getMaximum() { + return maximum; // TODO + } // getMaximum() + + /** + * setMaximum + * @param maximum TODO + */ + public void setMaximum(int maximum) { + this.maximum = maximum; + // TODO + } // setMaximum() + + /** + * isCanceled + * @returns boolean + */ + public boolean isCanceled() { + return false; // TODO + } // isCanceled() + + /** + * getMillisToDecideToPopup + * @returns int + */ + public int getMillisToDecideToPopup() { + return millisToDecideToPopup; // TODO + } // getMillisToDecideToPopup() + + /** + * setMillisToDecideToPopup + * @param time TODO + */ + public void setMillisToDecideToPopup(int time) { + millisToDecideToPopup = time; + // TODO + } // setMillisToDecideToPopup() + + /** + * getMillisToPopup + * @returns int + */ + public int getMillisToPopup() { + return millisToPopup; // TODO + } // getMillisToPopup() + + /** + * setMillisToPopup + * @param time TODO + */ + public void setMillisToPopup(int time) { + millisToPopup = time; + // TODO + } // setMillisToPopup() + + /** + * getNote + * @returns String + */ + public String getNote() { + return note; // TODO + } // getNote() + + /** + * setNote + * @param note TODO + */ + public void setNote(String note) { + this.note = note; + // TODO + } // setNote() + + +} // ProgressMonitor diff --git a/libjava/classpath/javax/swing/ProgressMonitorInputStream.java b/libjava/classpath/javax/swing/ProgressMonitorInputStream.java new file mode 100644 index 00000000000..2022a1c24a3 --- /dev/null +++ b/libjava/classpath/javax/swing/ProgressMonitorInputStream.java @@ -0,0 +1,160 @@ +/* ProgressMonitorInputStream.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * ProgressMonitorInputStream + * @author Andrew Selkirk + * @version 1.0 + */ +public class ProgressMonitorInputStream extends FilterInputStream { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * monitor + */ + private ProgressMonitor monitor; + + /** + * nread + */ + private int nread; + + /** + * size + */ + private int size; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor ProgressMonitorInputStream + * @param component TODO + * @param message TODO + * @param stream TODO + */ + public ProgressMonitorInputStream(Component component, Object message, + InputStream stream) { + super(stream); + // TODO + } // ProgressMonitorInputStream() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * reset + * @exception IOException TODO + */ + public synchronized void reset() throws IOException { + // TODO + } // reset() + + /** + * read + * @exception IOException TODO + * @returns int + */ + public int read() throws IOException { + return 0; // TODO + } // read() + + /** + * read + * @param data TODO + * @exception IOException TODO + * @returns int + */ + public int read(byte[] data) throws IOException { + return 0; // TODO + } // read() + + /** + * read + * @param data TODO + * @param offset TODO + * @param length TODO + * @exception IOException TODO + * @returns int + */ + public int read(byte[] data, int offset, int length) throws IOException { + return 0; // TODO + } // read() + + /** + * skip + * @param length TODO + * @exception IOException TODO + * @returns long + */ + public long skip(long length) throws IOException { + return 0; // TODO + } // skip() + + /** + * close + * @exception IOException TODO + */ + public void close() throws IOException { + // TODO + } // close() + + /** + * getProgressMonitor + * @returns ProgressMonitor + */ + public ProgressMonitor getProgressMonitor() { + return null; // TODO + } // getProgressMonitor() + + +} // ProgressMonitorInputStream diff --git a/libjava/classpath/javax/swing/Renderer.java b/libjava/classpath/javax/swing/Renderer.java new file mode 100644 index 00000000000..c803e38fcc0 --- /dev/null +++ b/libjava/classpath/javax/swing/Renderer.java @@ -0,0 +1,72 @@ +/* Renderer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; + +/** + * This interface is not used and exists only for compatibility. + * It probably has been replaced by {@link ListCellRenderer}, {@link + * javax.swing.table.TableCellRenderer} and {@link + * javax.swing.tree.TreeCellRenderer}. + * + * @specnote This interface is not used and exists only for compatibility. + * + * @author Andrew Selkirk + */ +public interface Renderer { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * setValue + * @param value TODO + * @param selected TODO + */ + void setValue(Object value, boolean selected); + + /** + * getComponent + * @returns Component + */ + Component getComponent(); + + +} // Renderer diff --git a/libjava/classpath/javax/swing/RepaintManager.java b/libjava/classpath/javax/swing/RepaintManager.java new file mode 100644 index 00000000000..8c4c323c90a --- /dev/null +++ b/libjava/classpath/javax/swing/RepaintManager.java @@ -0,0 +1,568 @@ +/* RepaintManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Rectangle; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +/** + * <p>The repaint manager holds a set of dirty regions, invalid components, + * and a double buffer surface. The dirty regions and invalid components + * are used to coalesce multiple revalidate() and repaint() calls in the + * component tree into larger groups to be refreshed "all at once"; the + * double buffer surface is used by root components to paint + * themselves.</p> + * + * <p>In general, painting is very confusing in swing. see <a + * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this + * document</a> for more details.</p> + * + * @author Graydon Hoare (graydon@redhat.com) + */ +public class RepaintManager +{ + + /** + * <p>A helper class which is placed into the system event queue at + * various times in order to facilitate repainting and layout. There is + * typically only one of these objects active at any time. When the + * {@link RepaintManager} is told to queue a repaint, it checks to see if + * a {@link RepaintWorker} is "live" in the system event queue, and if + * not it inserts one using {@link SwingUtilities.invokeLater}.</p> + * + * <p>When the {@link RepaintWorker} comes to the head of the system + * event queue, its {@link RepaintWorker#run} method is executed by the + * swing paint thread, which revalidates all invalid components and + * repaints any damage in the swing scene.</p> + */ + + protected class RepaintWorker + implements Runnable + { + boolean live; + public RepaintWorker() + { + live = false; + } + public synchronized void setLive(boolean b) + { + live = b; + } + public synchronized boolean isLive() + { + return live; + } + public void run() + { + RepaintManager rm = RepaintManager.globalManager; + setLive(false); + rm.validateInvalidComponents(); + rm.paintDirtyRegions(); + } + } + + + /** + * A table storing the dirty regions of components. The keys of this + * table are components, the values are rectangles. Each component maps + * to exactly one rectangle. When more regions are marked as dirty on a + * component, they are union'ed with the existing rectangle. + * + * @see #addDirtyRegion + * @see #getDirtyRegion + * @see #isCompletelyDirty + * @see #markCompletelyClean + * @see #markCompletelyDirty + */ + Hashtable dirtyComponents; + + /** + * A single, shared instance of the helper class. Any methods which mark + * components as invalid or dirty eventually activate this instance. It + * is added to the event queue if it is not already active, otherwise + * reused. + * + * @see #addDirtyRegion + * @see #addInvalidComponent + */ + RepaintWorker repaintWorker; + + /** + * The set of components which need revalidation, in the "layout" sense. + * There is no additional information about "what kind of layout" they + * need (as there is with dirty regions), so it is just a vector rather + * than a table. + * + * @see #addInvalidComponent + * @see #removeInvalidComponent + * @see #validateInvalidComponents + */ + Vector invalidComponents; + + /** + * Whether or not double buffering is enabled on this repaint + * manager. This is merely a hint to clients; the RepaintManager will + * always return an offscreen buffer when one is requested. + * + * @see #getDoubleBufferingEnabled + * @see #setDoubleBufferingEnabled + */ + boolean doubleBufferingEnabled; + + /** + * The current offscreen buffer. This is reused for all requests for + * offscreen drawing buffers. It grows as necessary, up to {@link + * #doubleBufferMaximumSize}, but there is only one shared instance. + * + * @see #getOffscreenBuffer + * @see #doubleBufferMaximumSize + */ + Image doubleBuffer; + + /** + * The maximum width and height to allocate as a double buffer. Requests + * beyond this size are ignored. + * + * @see #paintDirtyRegions + * @see #getDoubleBufferMaximumSize + * @see #setDoubleBufferMaximumSize + */ + Dimension doubleBufferMaximumSize; + + + /** + * The global, shared RepaintManager instance. This is reused for all + * components in all windows. This is package-private to avoid an accessor + * method. + * + * @see #currentManager + * @see #setCurrentManager + */ + static RepaintManager globalManager; + + /** + * Create a new RepaintManager object. + */ + public RepaintManager() + { + dirtyComponents = new Hashtable(); + invalidComponents = new Vector(); + repaintWorker = new RepaintWorker(); + doubleBufferMaximumSize = new Dimension(2000,2000); + doubleBufferingEnabled = true; + } + + /** + * Get the value of the shared {@link #globalManager} instance, possibly + * returning a special manager associated with the specified + * component. The default implementaiton ignores the component parameter. + * + * @param component A component to look up the manager of + * + * @return The current repaint manager + * + * @see #setCurrentManager + */ + public static RepaintManager currentManager(Component component) + { + if (globalManager == null) + globalManager = new RepaintManager(); + return globalManager; + } + + /** + * Get the value of the shared {@link #globalManager} instance, possibly + * returning a special manager associated with the specified + * component. The default implementaiton ignores the component parameter. + * + * @param component A component to look up the manager of + * + * @return The current repaint manager + * + * @see #setCurrentManager + */ + public static RepaintManager currentManager(JComponent component) + { + return currentManager((Component)component); + } + + /** + * Set the value of the shared {@link #globalManager} instance. + * + * @param manager The new value of the shared instance + * + * @see #currentManager + */ + public static void setCurrentManager(RepaintManager manager) + { + globalManager = manager; + } + + /** + * Add a component to the {@link #invalidComponents} vector. If the + * {@link #repaintWorker} class is not active, insert it in the system + * event queue. + * + * @param component The component to add + * + * @see #removeInvalidComponent + */ + public synchronized void addInvalidComponent(JComponent component) + { + Component ancestor = component.getParent(); + + while (ancestor != null + && (! (ancestor instanceof JComponent) + || ! ((JComponent) ancestor).isValidateRoot() )) + ancestor = ancestor.getParent(); + + if (ancestor != null + && ancestor instanceof JComponent + && ((JComponent) ancestor).isValidateRoot()) + component = (JComponent) ancestor; + + if (invalidComponents.contains(component)) + return; + + invalidComponents.add(component); + + if (! repaintWorker.isLive()) + { + repaintWorker.setLive(true); + SwingUtilities.invokeLater(repaintWorker); + } + } + + /** + * Remove a component from the {@link #invalidComponents} vector. + * + * @param component The component to remove + * + * @see #addInvalidComponent + */ + public synchronized void removeInvalidComponent(JComponent component) + { + invalidComponents.removeElement(component); + } + + /** + * Add a region to the set of dirty regions for a specified component. + * This involves union'ing the new region with any existing dirty region + * associated with the component. If the {@link #repaintWorker} class + * is not active, insert it in the system event queue. + * + * @param component The component to add a dirty region for + * @param x The left x coordinate of the new dirty region + * @param y The top y coordinate of the new dirty region + * @param w The width of the new dirty region + * @param h The height of the new dirty region + * + * @see #addDirtyRegion + * @see #getDirtyRegion + * @see #isCompletelyDirty + * @see #markCompletelyClean + * @see #markCompletelyDirty + */ + public synchronized void addDirtyRegion(JComponent component, int x, int y, + int w, int h) + { + if (w == 0 || h == 0) + return; + + Rectangle r = new Rectangle(x, y, w, h); + if (dirtyComponents.containsKey(component)) + r = r.union((Rectangle)dirtyComponents.get(component)); + dirtyComponents.put(component, r); + if (! repaintWorker.isLive()) + { + repaintWorker.setLive(true); + SwingUtilities.invokeLater(repaintWorker); + } + } + + /** + * Get the dirty region associated with a component, or <code>null</code> + * if the component has no dirty region. + * + * @param component The component to get the dirty region of + * + * @return The dirty region of the component + * + * @see #dirtyComponents + * @see #addDirtyRegion + * @see #isCompletelyDirty + * @see #markCompletelyClean + * @see #markCompletelyDirty + */ + public Rectangle getDirtyRegion(JComponent component) + { + return (Rectangle) dirtyComponents.get(component); + } + + /** + * Mark a component as dirty over its entire bounds. + * + * @param component The component to mark as dirty + * + * @see #dirtyComponents + * @see #addDirtyRegion + * @see #getDirtyRegion + * @see #isCompletelyDirty + * @see #markCompletelyClean + */ + public void markCompletelyDirty(JComponent component) + { + Rectangle r = component.getBounds(); + addDirtyRegion(component, r.x, r.y, r.width, r.height); + } + + /** + * Remove all dirty regions for a specified component + * + * @param component The component to mark as clean + * + * @see #dirtyComponents + * @see #addDirtyRegion + * @see #getDirtyRegion + * @see #isCompletelyDirty + * @see #markCompletelyDirty + */ + public void markCompletelyClean(JComponent component) + { + dirtyComponents.remove(component); + } + + /** + * Return <code>true</code> if the specified component is completely + * contained within its dirty region, otherwise <code>false</code> + * + * @param component The component to check for complete dirtyness + * + * @return Whether the component is completely dirty + * + * @see #dirtyComponents + * @see #addDirtyRegion + * @see #getDirtyRegion + * @see #isCompletelyDirty + * @see #markCompletelyClean + */ + public boolean isCompletelyDirty(JComponent component) + { + Rectangle dirty = (Rectangle) dirtyComponents.get(component); + if (dirty == null) + return false; + Rectangle r = component.getBounds(); + if (r == null) + return true; + return dirty.contains(r); + } + + /** + * Validate all components which have been marked invalid in the {@link + * #invalidComponents} vector. + */ + public void validateInvalidComponents() + { + for (Enumeration e = invalidComponents.elements(); e.hasMoreElements(); ) + { + JComponent comp = (JComponent) e.nextElement(); + if (! (comp.isVisible() && comp.isShowing())) + continue; + comp.validate(); + } + invalidComponents.clear(); + } + + /** + * Repaint all regions of all components which have been marked dirty in + * the {@link #dirtyComponents} table. + */ + public void paintDirtyRegions() + { + // step 1: pull out roots and calculate spanning damage + + HashMap roots = new HashMap(); + for (Enumeration e = dirtyComponents.keys(); e.hasMoreElements(); ) + { + JComponent comp = (JComponent) e.nextElement(); + if (! (comp.isVisible() && comp.isShowing())) + continue; + Rectangle damaged = getDirtyRegion(comp); + if (damaged.width == 0 || damaged.height == 0) + continue; + JRootPane root = comp.getRootPane(); + // If the component has no root, no repainting will occur. + if (root == null) + continue; + Rectangle rootDamage = SwingUtilities.convertRectangle(comp, damaged, root); + if (! roots.containsKey(root)) + { + roots.put(root, rootDamage); + } + else + { + roots.put(root, ((Rectangle)roots.get(root)).union(rootDamage)); + } + } + dirtyComponents.clear(); + + // step 2: paint those roots + Iterator i = roots.entrySet().iterator(); + while(i.hasNext()) + { + Map.Entry ent = (Map.Entry) i.next(); + JRootPane root = (JRootPane) ent.getKey(); + Rectangle rect = (Rectangle) ent.getValue(); + root.paintImmediately(rect); + } + } + + /** + * Get an offscreen buffer for painting a component's image. This image + * may be smaller than the proposed dimensions, depending on the value of + * the {@link #doubleBufferMaximumSize} property. + * + * @param component The component to return an offscreen buffer for + * @param proposedWidth The proposed width of the offscreen buffer + * @param proposedHeight The proposed height of the offscreen buffer + * + * @return A shared offscreen buffer for painting + * + * @see #doubleBuffer + */ + public Image getOffscreenBuffer(Component component, int proposedWidth, + int proposedHeight) + { + if (doubleBuffer == null + || (((doubleBuffer.getWidth(null) < proposedWidth) + || (doubleBuffer.getHeight(null) < proposedHeight)) + && (proposedWidth < doubleBufferMaximumSize.width) + && (proposedHeight < doubleBufferMaximumSize.height))) + { + doubleBuffer = component.createImage(proposedWidth, proposedHeight); + } + return doubleBuffer; + } + + /** + * Creates and returns a volatile offscreen buffer for the specified + * component that can be used as a double buffer. The returned image + * is a {@link VolatileImage}. Its size will be <code>(proposedWidth, + * proposedHeight)</code> except when the maximum double buffer size + * has been set in this RepaintManager. + * + * @param comp the Component for which to create a volatile buffer + * @param proposedWidth the proposed width of the buffer + * @param proposedHeight the proposed height of the buffer + * + * @since 1.4 + * + * @see {@link VolatileImage} + */ + public Image getVolatileOffscreenBuffer(Component comp, int proposedWidth, + int proposedHeight) + { + int maxWidth = doubleBufferMaximumSize.width; + int maxHeight = doubleBufferMaximumSize.height; + return comp.createVolatileImage(Math.min(maxWidth, proposedWidth), + Math.min(maxHeight, proposedHeight)); + } + + + /** + * Get the value of the {@link #doubleBufferMaximumSize} property. + * + * @return The current value of the property + * + * @see #setDoubleBufferMaximumSize + */ + public Dimension getDoubleBufferMaximumSize() + { + return doubleBufferMaximumSize; + } + + /** + * Set the value of the {@link #doubleBufferMaximumSize} property. + * + * @param size The new value of the property + * + * @see #getDoubleBufferMaximumSize + */ + public void setDoubleBufferMaximumSize(Dimension size) + { + doubleBufferMaximumSize = size; + } + + /** + * Set the value of the {@link #doubleBufferingEnabled} property. + * + * @param buffer The new value of the property + * + * @see #getDoubleBufferingEnabled + */ + public void setDoubleBufferingEnabled(boolean buffer) + { + doubleBufferingEnabled = buffer; + } + + /** + * Get the value of the {@link #doubleBufferingEnabled} property. + * + * @return The current value of the property + * + * @see #setDoubleBufferingEnabled + */ + public boolean isDoubleBufferingEnabled() + { + return doubleBufferingEnabled; + } + + public String toString() + { + return "RepaintManager"; + } +} diff --git a/libjava/classpath/javax/swing/RootPaneContainer.java b/libjava/classpath/javax/swing/RootPaneContainer.java new file mode 100644 index 00000000000..b121f958a92 --- /dev/null +++ b/libjava/classpath/javax/swing/RootPaneContainer.java @@ -0,0 +1,100 @@ +/* RootPaneContainer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; + +/** + * Components that contain a single {@link JRootPane} as only child + * implement this interface, typically this is implemented by the + * Swing top-level containers. + * + * @author Andrew Selkirk + */ +public interface RootPaneContainer { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getRootPane + * @returns JRootPane + */ + JRootPane getRootPane(); + + /** + * setContentPane + * @param contentPane TODO + */ + void setContentPane(Container contentPane); + + /** + * getContentPane + * @returns Container + */ + Container getContentPane(); + + /** + * setLayeredPane + * @param layeredPane TODO + */ + void setLayeredPane(JLayeredPane layeredPane); + + /** + * getLayeredPane + * @returns JLayeredPane + */ + JLayeredPane getLayeredPane(); + + /** + * setGlassPane + * @param glassPane TODO + */ + void setGlassPane(Component glassPane); + + /** + * getGlassPane + * @returns Component + */ + Component getGlassPane(); + + +} // RootPaneContainer diff --git a/libjava/classpath/javax/swing/ScrollPaneConstants.java b/libjava/classpath/javax/swing/ScrollPaneConstants.java new file mode 100644 index 00000000000..b5860609f06 --- /dev/null +++ b/libjava/classpath/javax/swing/ScrollPaneConstants.java @@ -0,0 +1,152 @@ +/* ScrollPaneConstants.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +/** + * Defines some constants that are used in {@link JScrollPane} and related + * components. + * + * @author Andrew Selkirk + */ +public interface ScrollPaneConstants +{ + /** + * VIEWPORT + */ + String VIEWPORT = "VIEWPORT"; + + /** + * VERTICAL_SCROLLBAR + */ + String VERTICAL_SCROLLBAR = "VERTICAL_SCROLLBAR"; + + /** + * HORIZONTAL_SCROLLBAR + */ + String HORIZONTAL_SCROLLBAR = "HORIZONTAL_SCROLLBAR"; + + /** + * ROW_HEADER + */ + String ROW_HEADER = "ROW_HEADER"; + + /** + * COLUMN_HEADER + */ + String COLUMN_HEADER = "COLUMN_HEADER"; + + /** + * LOWER_LEFT_CORNER + */ + String LOWER_LEFT_CORNER = "LOWER_LEFT_CORNER"; + + /** + * LOWER_RIGHT_CORNER + */ + String LOWER_RIGHT_CORNER = "LOWER_RIGHT_CORNER"; + + /** + * UPPER_LEFT_CORNER + */ + String UPPER_LEFT_CORNER = "UPPER_LEFT_CORNER"; + + /** + * UPPER_RIGHT_CORNER + */ + String UPPER_RIGHT_CORNER = "UPPER_RIGHT_CORNER"; + + /** + * LOWER_LEADING_CORNER + */ + String LOWER_LEADING_CORNER = "LOWER_LEADING_CORNER"; + + /** + * LOWER_TRAILING_CORNER + */ + String LOWER_TRAILING_CORNER = "LOWER_TRAILING_CORNER"; + + /** + * UPPER_LEADING_CORNER + */ + String UPPER_LEADING_CORNER = "UPPER_LEADING_CORNER"; + + /** + * UPPER_TRAILING_CORNER + */ + String UPPER_TRAILING_CORNER = "UPPER_TRAILING_CORNER"; + + /** + * VERTICAL_SCROLLBAR_POLICY + */ + String VERTICAL_SCROLLBAR_POLICY = "VERTICAL_SCROLLBAR_POLICY"; + + /** + * HORIZONTAL_SCROLLBAR_POLICY + */ + String HORIZONTAL_SCROLLBAR_POLICY = "HORIZONTAL_SCROLLBAR_POLICY"; + + /** + * VERTICAL_SCROLLBAR_AS_NEEDED + */ + int VERTICAL_SCROLLBAR_AS_NEEDED = 20; + + /** + * VERTICAL_SCROLLBAR_NEVER + */ + int VERTICAL_SCROLLBAR_NEVER = 21; + + /** + * VERTICAL_SCROLLBAR_ALWAYS + */ + int VERTICAL_SCROLLBAR_ALWAYS = 22; + + /** + * HORIZONTAL_SCROLLBAR_AS_NEEDED + */ + int HORIZONTAL_SCROLLBAR_AS_NEEDED = 30; + + /** + * HORIZONTAL_SCROLLBAR_NEVER + */ + int HORIZONTAL_SCROLLBAR_NEVER = 31; + + /** + * HORIZONTAL_SCROLLBAR_ALWAYS + */ + int HORIZONTAL_SCROLLBAR_ALWAYS = 32; +} diff --git a/libjava/classpath/javax/swing/ScrollPaneLayout.java b/libjava/classpath/javax/swing/ScrollPaneLayout.java new file mode 100644 index 00000000000..75a6f9aa208 --- /dev/null +++ b/libjava/classpath/javax/swing/ScrollPaneLayout.java @@ -0,0 +1,484 @@ +/* ScrollPaneLayout.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.border.Border; + +/** + * ScrollPaneLayout + * @author Andrew Selkirk + * @version 1.0 + */ +public class ScrollPaneLayout + implements LayoutManager, ScrollPaneConstants, Serializable +{ + private static final long serialVersionUID = -4480022884523193743L; + + public static class UIResource extends ScrollPaneLayout + implements javax.swing.plaf.UIResource { + public UIResource() { + } + } + + protected JViewport viewport; + protected JScrollBar vsb; + protected JScrollBar hsb; + protected JViewport rowHead; + protected JViewport colHead; + protected Component lowerLeft; + protected Component lowerRight; + protected Component upperLeft; + protected Component upperRight; + protected int vsbPolicy; + protected int hsbPolicy; + + public ScrollPaneLayout() { + + } + + public void syncWithScrollPane(JScrollPane scrollPane) { + viewport = scrollPane.getViewport(); + rowHead = scrollPane.getRowHeader(); + colHead = scrollPane.getColumnHeader(); + vsb = scrollPane.getVerticalScrollBar(); + hsb = scrollPane.getHorizontalScrollBar(); + vsbPolicy = scrollPane.getVerticalScrollBarPolicy(); + hsbPolicy = scrollPane.getHorizontalScrollBarPolicy(); + lowerLeft = scrollPane.getCorner(LOWER_LEFT_CORNER); + lowerRight = scrollPane.getCorner(LOWER_RIGHT_CORNER); + upperLeft = scrollPane.getCorner(UPPER_LEFT_CORNER); + upperRight = scrollPane.getCorner(UPPER_RIGHT_CORNER); + } + + protected Component addSingletonComponent(Component oldComponent, + Component newComponent) { + return null; + } + + public void addLayoutComponent(String key, Component component) + { + if (key == VIEWPORT) + viewport = (JViewport) component; + else if (key == VERTICAL_SCROLLBAR) + vsb = (JScrollBar) component; + else if (key == HORIZONTAL_SCROLLBAR) + hsb = (JScrollBar) component; + else if (key == ROW_HEADER) + rowHead = (JViewport) component; + else if (key == COLUMN_HEADER) + colHead = (JViewport) component; + else if (key == LOWER_RIGHT_CORNER) + lowerRight = component; + else if (key == UPPER_RIGHT_CORNER) + upperRight = component; + else if (key == LOWER_LEFT_CORNER) + lowerLeft = component; + else if (key == UPPER_LEFT_CORNER) + upperLeft = component; + } + + public void removeLayoutComponent(Component component) { + if (component == viewport) + viewport = null; + else if (component == vsb) + vsb = null; + else if (component == hsb) + hsb = null; + else if (component == rowHead) + rowHead = null; + else if (component == colHead) + colHead = null; + else if (component == lowerRight) + lowerRight = null; + else if (component == upperRight) + upperRight = null; + else if (component == lowerLeft) + lowerLeft = null; + else if (component == upperLeft) + upperLeft = null; + } + + public int getVerticalScrollBarPolicy() + { + return vsbPolicy; + } + + public void setVerticalScrollBarPolicy(int policy) + { + vsbPolicy = policy; + } + + public int getHorizontalScrollBarPolicy() + { + return hsbPolicy; + } + + public void setHorizontalScrollBarPolicy(int policy) + { + hsbPolicy = policy; + } + + public JViewport getViewport() + { + return viewport; + } + + public JScrollBar getHorizontalScrollBar() + { + return hsb; + } + + public JScrollBar getVerticalScrollBar() + { + return vsb; + } + + public JViewport getRowHeader() + { + return rowHead; + } + + public JViewport getColumnHeader() + { + return colHead; + } + + public Component getCorner(String key) + { + if (key == LOWER_RIGHT_CORNER) + return lowerRight; + else if (key == UPPER_RIGHT_CORNER) + return upperRight; + else if (key == LOWER_LEFT_CORNER) + return lowerLeft; + else if (key == UPPER_LEFT_CORNER) + return upperLeft; + return null; + } + + private static void maybeSetPreferredSize(JComponent src, Dimension dim) + { + Dimension tmp = null; + if (src != null) + tmp = src.getPreferredSize(); + if (tmp != null) + dim.setSize(tmp); + } + + private static void maybeSetMinimumSize(JComponent src, Dimension dim) + { + Dimension tmp = null; + if (src != null) + tmp = src.getMinimumSize(); + if (tmp != null) + dim.setSize(tmp); + } + + public Dimension preferredLayoutSize(Container parent) + { + if (parent != null && parent instanceof JScrollPane) + { + JScrollPane sc = (JScrollPane) parent; + synchronized (sc.getTreeLock ()) + { + Dimension insetsSize = new Dimension(0,0); + Dimension viewportSize = new Dimension(0,0); + Dimension viewportInsetsSize = new Dimension(0,0); + Dimension columnHeaderSize = new Dimension(0,0); + Dimension rowHeaderSize = new Dimension(0,0); + Dimension verticalScrollBarSize = new Dimension(0,0); + Dimension horizontalScrollBarSize = new Dimension(0,0); + + Insets insets = sc.getInsets(); + Border viewportBorder = sc.getViewportBorder(); + Insets viewportInsets = null; + + if (viewportBorder != null) + { + viewportInsets = viewportBorder.getBorderInsets(parent); + if (viewportInsets != null) + viewportInsetsSize.setSize(viewportInsets.left + viewportInsets.right, + viewportInsets.top + viewportInsets.bottom); + } + + if (insets != null) + insetsSize.setSize(insets.left + insets.right, + insets.top + insets.bottom); + + if (viewport != null) + { + Component view = null; + Scrollable scr = null; + Dimension pref = null; + + view = viewport.getView(); + if (view != null && view instanceof Scrollable) + scr = (Scrollable) view; + if (scr != null) + pref = scr.getPreferredScrollableViewportSize(); + if (pref == null) + pref = viewport.getPreferredSize(); + if (pref != null) + viewportSize.setSize(pref); + } + + maybeSetPreferredSize(colHead, columnHeaderSize); + maybeSetPreferredSize(rowHead, rowHeaderSize); + maybeSetPreferredSize(vsb, verticalScrollBarSize); + maybeSetPreferredSize(hsb, horizontalScrollBarSize); + + return new Dimension(insetsSize.width + + viewportSize.width + + viewportInsetsSize.width + + rowHeaderSize.width + + verticalScrollBarSize.width, + insetsSize.height + + viewportSize.height + + viewportInsetsSize.height + + columnHeaderSize.height + + horizontalScrollBarSize.height); + } + } + else + { + return new Dimension(0,0); + } + } + + public Dimension minimumLayoutSize(Container parent) + { + if (parent instanceof JScrollPane) + { + JScrollPane sc = (JScrollPane) parent; + synchronized (sc.getTreeLock ()) + { + Dimension insetsSize = new Dimension(0,0); + Dimension viewportSize = new Dimension(0,0); + Dimension viewportInsetsSize = new Dimension(0,0); + Dimension columnHeaderSize = new Dimension(0,0); + Dimension rowHeaderSize = new Dimension(0,0); + Dimension verticalScrollBarSize = new Dimension(0,0); + Dimension horizontalScrollBarSize = new Dimension(0,0); + + Insets insets = sc.getInsets(); + Border viewportBorder = sc.getViewportBorder(); + Insets viewportInsets = null; + + if (viewportBorder != null) + { + viewportInsets = viewportBorder.getBorderInsets(parent); + if (viewportInsets != null) + viewportInsetsSize.setSize(viewportInsets.left + viewportInsets.right, + viewportInsets.top + viewportInsets.bottom); + } + + if (insets != null) + insetsSize.setSize(insets.left + insets.right, + insets.top + insets.bottom); + + maybeSetMinimumSize(colHead, columnHeaderSize); + maybeSetMinimumSize(rowHead, rowHeaderSize); + + if (vsbPolicy != VERTICAL_SCROLLBAR_NEVER) + maybeSetMinimumSize(vsb, verticalScrollBarSize); + + if (hsbPolicy != HORIZONTAL_SCROLLBAR_NEVER) + maybeSetMinimumSize(hsb, horizontalScrollBarSize); + + return new Dimension(insetsSize.width + + viewportSize.width + + viewportInsetsSize.width + + rowHeaderSize.width + + verticalScrollBarSize.width, + insetsSize.height + + viewportSize.height + + viewportInsetsSize.height + + columnHeaderSize.height + + horizontalScrollBarSize.height); + } + } + else + { + return new Dimension(0,0); + } + } + + /** + * + * +----+--------------------+----+ y1 + * | c1 | column header | c2 | + * +----+--------------------+----+ y2 + * | r | | v | + * | o | | | + * | w | | s | + * | | | r | + * | h | | o | + * | e | viewport | l | + * | a | | l | + * | d | | b | + * | e | | a | + * | r | | r | + * +----+--------------------+----+ y3 + * | c3 | h scrollbar | c4 | + * +----+--------------------+----+ y4 + * x1 x2 x3 x4 + * + */ + public void layoutContainer(Container parent) + { + if (parent instanceof JScrollPane) + { + JScrollPane sc = (JScrollPane) parent; + synchronized (sc.getTreeLock ()) + { + JViewport viewport = sc.getViewport(); + Dimension viewSize = viewport.getViewSize(); + Point viewPos = viewport.getViewPosition(); + + int x1 = 0, x2 = 0, x3 = 0, x4 = 0; + int y1 = 0, y2 = 0, y3 = 0, y4 = 0; + + Rectangle scrollPaneBounds = SwingUtilities.calculateInnerArea(sc, null); + + x1 = scrollPaneBounds.x; + y1 = scrollPaneBounds.y; + x4 = scrollPaneBounds.x + scrollPaneBounds.width; + y4 = scrollPaneBounds.y + scrollPaneBounds.height; + + if (colHead != null) + y2 = y1 + colHead.getPreferredSize().height; + else + y2 = y1; + + if (rowHead != null) + x2 = x1 + rowHead.getPreferredSize().width; + else + x2 = x1; + + int vsbPolicy = sc.getVerticalScrollBarPolicy(); + int hsbPolicy = sc.getHorizontalScrollBarPolicy(); + + x3 = x4 - vsb.getPreferredSize().width; + y3 = y4 - hsb.getPreferredSize().height; + + boolean showVsb = + (vsb != null) + && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) + || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED + && viewSize.height > (y3 - y2))); + + boolean showHsb = + (hsb != null) + && ((hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) + || (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED + && viewSize.width > (x3 - x2))); + + if (!showVsb) + x3 = x4; + + if (!showHsb) + y3 = y4; + + // now set the layout + + if (viewport != null) + viewport.setBounds(new Rectangle(x2, y2, x3-x2, y3-y2)); + + if (colHead != null) + colHead.setBounds(new Rectangle(x2, y1, x3-x2, y2-y1)); + + if (rowHead != null) + rowHead.setBounds(new Rectangle(x1, y2, x2-x1, y3-y2)); + + if (showVsb) + { + vsb.setVisible(true); + vsb.setBounds(new Rectangle(x3, y2, x4-x3, y3-y2)); + } + else if (vsb != null) + vsb.setVisible(false); + + if (showHsb) + { + hsb.setVisible(true); + hsb.setBounds(new Rectangle(x2, y3, x3-x2, y4-y3)); + } + else if (hsb != null) + hsb.setVisible(false); + + if (upperLeft != null) + upperLeft.setBounds(new Rectangle(x1, y1, x2-x1, y2-y1)); + + if (upperRight != null) + upperRight.setBounds(new Rectangle(x3, y1, x4-x3, y2-y1)); + + if (lowerLeft != null) + lowerLeft.setBounds(new Rectangle(x1, y3, x2-x1, y4-y3)); + + if (lowerRight != null) + lowerRight.setBounds(new Rectangle(x3, y3, x4-x3, y4-y3)); + + } + } + } + + /** + * Returns the bounds of the border around a ScrollPane's viewport. + * + * @param scrollPane the ScrollPane for which's viewport the border + * is requested + * + * @deprecated As of Swing 1.1 replaced by + * {@link javax.swing.JScrollPane#getViewportBorderBounds}. + */ + public Rectangle getViewportBorderBounds(JScrollPane scrollPane) { + return null; + } + + +} diff --git a/libjava/classpath/javax/swing/Scrollable.java b/libjava/classpath/javax/swing/Scrollable.java new file mode 100644 index 00000000000..19732192330 --- /dev/null +++ b/libjava/classpath/javax/swing/Scrollable.java @@ -0,0 +1,56 @@ +/* Scrollable.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Dimension; +import java.awt.Rectangle; + +/** + * Defines the method that a component should implement to behave nicely + * in {@link JScrollPane}s. Note that this is not required for a component + * to be used in a <code>JScrollPane</code>, but can highly improve the + * user experience when scrolling the component. + */ +public interface Scrollable +{ + Dimension getPreferredScrollableViewportSize(); + int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction); + int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction); + boolean getScrollableTracksViewportWidth(); + boolean getScrollableTracksViewportHeight(); +} diff --git a/libjava/classpath/javax/swing/SingleSelectionModel.java b/libjava/classpath/javax/swing/SingleSelectionModel.java new file mode 100644 index 00000000000..b5380c857a3 --- /dev/null +++ b/libjava/classpath/javax/swing/SingleSelectionModel.java @@ -0,0 +1,91 @@ +/* SingleSelectionModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import javax.swing.event.ChangeListener; + +/** + * A data model that is used in components that support at most one + * selected element, like {@link JTabbedPane}, {@link JMenu} and + * {@link JPopupMenu}. + * + * @author Andrew Selkirk + */ +public interface SingleSelectionModel { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getSelectedIndex + * @returns int + */ + int getSelectedIndex(); + + /** + * setSelectedIndex + * @param index TODO + */ + void setSelectedIndex(int index); + + /** + * clearSelection + */ + void clearSelection(); + + /** + * isSelected + * @returns boolean + */ + boolean isSelected(); + + /** + * addChangeListener + * @param listener TODO + */ + void addChangeListener(ChangeListener listener); + + /** + * removeChangeListener + * @param listener TODO + */ + void removeChangeListener(ChangeListener listener); + + +} // SingleSelectionModel diff --git a/libjava/classpath/javax/swing/SizeRequirements.java b/libjava/classpath/javax/swing/SizeRequirements.java new file mode 100644 index 00000000000..430aeed5151 --- /dev/null +++ b/libjava/classpath/javax/swing/SizeRequirements.java @@ -0,0 +1,329 @@ +/* SizeRequirements.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.Serializable; + +/** + * This class calculates information about the size and position requirements + * of components. + * + * Two types of layout are supported: + * <ul> + * <li>Tiled: the components are placed at position top-left or bottom-right + * position within their allocated space</li> + * <li>Aligned: the components are placed aligned in their allocated space + * according to their alignment value</li> + * </ul> + * + * @author Andrew Selkirk + * @author Roman Kennke (roman@kennke.org) + */ +public class SizeRequirements implements Serializable +{ + /** + * The serialVersionUID. + */ + private static final long serialVersionUID = 9217749429906736553L; + + /** + * The minimum reasonable width or height of a component. + */ + public int minimum; + + /** + * The preferred width or height of a component. + */ + public int preferred; + + /** + * The maximum reasonable width or height of a component. + */ + public int maximum; + + /** + * The horizontal or vertical alignment of a component. + */ + public float alignment; + + /** + * Creates a SizeRequirements object with minimum, preferred and + * maximum size set to zero, and an alignment value of 0.5. + */ + public SizeRequirements() + { + this (0, 0, 0, 0.5F); + } + + /** + * Creates a SizeRequirements object with the specified minimum, + * preferred, maximum and alignment values. + * + * @param min the minimum reasonable size of the component + * @param pref the preferred size of the component + * @param max the maximum size of the component + * @param align the alignment of the component + */ + public SizeRequirements(int min, int pref, int max, float align) + { + minimum = min; + preferred = pref; + maximum = max; + alignment = align; + } + + /** + * Returns a String representation of this SizeRequirements object, + * containing information about the minimum, preferred, maximum and + * alignment value. + * + * @return a String representation of this SizeRequirements object + */ + public String toString() + { + return null; // TODO + } + + /** + * Calculates how much space is nessecary to place a set of components + * end-to-end. The size requirements of the components is specified + * in <code>children</code>. + * + * @param children the SizeRequirements of each of the components + * + * @return the SizeRequirements that describe how much space is needed + * to place the components end-to-end + */ + public static SizeRequirements + getTiledSizeRequirements(SizeRequirements[] children) + { + SizeRequirements result = new SizeRequirements(); + for (int i = 0; i < children.length; i++) + { + result.minimum += children[i].minimum; + result.preferred += children[i].preferred; + result.maximum += children[i].maximum; + } + return result; + } + + /** + * Calculates how much space is nessecary to place a set of components + * aligned according to their alignment value. + * The size requirements of the components is specified in + * <code>children</code>. + * + * @param children the SizeRequirements of each of the components + * + * @return the SizeRequirements that describe how much space is needed + * to place the components aligned + */ + public static SizeRequirements + getAlignedSizeRequirements(SizeRequirements[] children) + { + return null; // TODO + } + + /** + * Calculate the offsets and spans of the components, when they should + * be placed end-to-end. + * + * You must specify the amount of allocated space in + * <code>allocated</code>, the total size requirements of the set of + * components in <code>total</code> (this can be calculated using + * {@link #getTiledSizeRequirements} and the size requirements of the + * components in <code>children</code>. + * + * The calculated offset and span values for each component are then + * stored in the arrays <code>offsets</code> and <code>spans</code>. + * + * The components are placed in the forward direction, beginning with + * an offset of 0. + * + * @param allocated the amount of allocated space + * @param total the total size requirements of the components + * @param children the size requirement of each component + * @param offsets will hold the offset values for each component + * @param spans will hold the span values for each component + */ + public static void calculateTiledPositions(int allocated, + SizeRequirements total, + SizeRequirements[] children, + int[] offsets, int[] spans) + { + calculateTiledPositions(allocated, total, children, offsets, spans, true); + } + + /** + * Calculate the offsets and spans of the components, when they should + * be placed end-to-end. + * + * You must specify the amount of allocated space in + * <code>allocated</code>, the total size requirements of the set of + * components in <code>total</code> (this can be calculated using + * {@link #getTiledSizeRequirements} and the size requirements of the + * components in <code>children</code>. + * + * The calculated offset and span values for each component are then + * stored in the arrays <code>offsets</code> and <code>spans</code>. + * + * Depending on the value of <code>forward</code> the components are + * placed in the forward direction (left-right or top-bottom), where + * the offsets begin with 0, or in the reverse direction + * (right-left or bottom-top). + * + * @param allocated the amount of allocated space + * @param total the total size requirements of the components + * @param children the size requirement of each component + * @param offsets will hold the offset values for each component + * @param spans will hold the span values for each component + * @param forward whether the components should be placed in the forward + * direction (left-right or top-bottom) or reverse direction + * (right-left or bottom-top) + */ + public static void calculateTiledPositions(int allocated, + SizeRequirements total, + SizeRequirements[] children, + int[] offsets, int[] spans, + boolean forward) + { + if (forward) + { + int offset = 0; + for (int i = 0; i < children.length; i++) + { + offsets[i] = offset; + spans[i] = children[i].preferred; + offset += children[i].preferred; + } + } + else + { + int offset = allocated; + for (int i = 0; i < children.length; i++) + { + offset -= children[i].preferred; + offsets[i] = offset; + spans[i] = children[i].preferred; + } + } + } + + /** + * Calculate the offsets and spans of the components, when they should + * be placed end-to-end. + * + * You must specify the amount of allocated space in + * <code>allocated</code>, the total size requirements of the set of + * components in <code>total</code> (this can be calculated using + * {@link #getTiledSizeRequirements} and the size requirements of the + * components in <code>children</code>. + * + * The calculated offset and span values for each component are then + * stored in the arrays <code>offsets</code> and <code>spans</code>. + * + * The components are tiled in the forward direction, beginning with + * an offset of 0. + * + * @param allocated the amount of allocated space + * @param total the total size requirements of the components + * @param children the size requirement of each component + * @param offsets will hold the offset values for each component + * @param spans will hold the span values for each component + */ + public static void calculateAlignedPositions(int allocated, + SizeRequirements total, + SizeRequirements[] children, + int[] offsets, int[] spans) + { + calculateTiledPositions(allocated, total, children, offsets, spans, true); + } + + /** + * Calculate the offsets and spans of the components, when they should + * be placed end-to-end. + * + * You must specify the amount of allocated space in + * <code>allocated</code>, the total size requirements of the set of + * components in <code>total</code> (this can be calculated using + * {@link #getTiledSizeRequirements} and the size requirements of the + * components in <code>children</code>. + * + * The calculated offset and span values for each component are then + * stored in the arrays <code>offsets</code> and <code>spans</code>. + * + * Depending on the value of <code>forward</code> the components are + * placed in the forward direction (left-right or top-bottom), where + * the offsets begin with 0, or in the reverse direction + * (right-left or bottom-top). + * + * @param allocated the amount of allocated space + * @param total the total size requirements of the components + * @param children the size requirement of each component + * @param offsets will hold the offset values for each component + * @param spans will hold the span values for each component + * @param forward whether the components should be placed in the forward + * direction (left-right or top-bottom) or reverse direction + * (right-left or bottom-top) + */ + public static void calculateAlignedPositions(int allocated, + SizeRequirements total, + SizeRequirements[] children, + int[] offset, int[] spans, + boolean forward) + { + // TODO + } + + /** + * Returns an array of new preferred sizes for the children based on + * <code>delta</code>. <code>delta</code> specifies a change in the + * allocated space. The sizes of the children will be shortened or + * lengthened to accomodate the new allocation. + * + * @param delta the change of the size of the total allocation for + * the components + * @param children the size requirements of each component + * + * @return the new preferred sizes for each component + */ + public static int[] adjustSizes(int delta, SizeRequirements[] children) + { + return null; // TODO + } +} diff --git a/libjava/classpath/javax/swing/SizeSequence.java b/libjava/classpath/javax/swing/SizeSequence.java new file mode 100644 index 00000000000..cf6e5f042a1 --- /dev/null +++ b/libjava/classpath/javax/swing/SizeSequence.java @@ -0,0 +1,249 @@ +/* SizeSequence.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +/** + * SizeSequence + * @author Andrew Selkirk + * @version 1.0 + */ +public class SizeSequence { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * sizes + */ + private int[] sizes = new int[0]; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor SizeSequence + */ + public SizeSequence() { + sizes = new int[0]; + } // SizeSequence() + + /** + * Constructor SizeSequence + * @param numEntries TODO + */ + public SizeSequence(int numEntries) { + this(numEntries, 0); + } // SizeSequence() + + /** + * Constructor SizeSequence + * @param numEntries TODO + * @param value TODO + */ + public SizeSequence(int numEntries, int value) { + insertEntries(0, numEntries, value); + } // SizeSequence() + + /** + * Constructor SizeSequence + * @param sizes TODO + */ + public SizeSequence(int[] sizes) { + setSizes(sizes); + } // SizeSequence() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * setSize + * @param index TODO + * @param size TODO + */ + public void setSize(int index, int size) { + sizes[index] = size; + } // setSize() + + /** + * getIndex + * @param position TODO + * @returns int + */ + public int getIndex(int position) { + return 0; // TODO + } // getIndex() + + /** + * getSize + * @param index TODO + * @returns int + */ + public int getSize(int index) { + return sizes[index]; + } // getSize() + + /** + * setSizes + * @param sizes TODO + */ + public void setSizes(int[] sizes) { + + // Variables + int index; + + // Initialize Sizes + this.sizes = new int[sizes.length]; + for (index = 0; index < sizes.length; index++) { + this.sizes[index] = sizes[index]; + } // for + + } // setSizes() + + /** + * getSizes + * @returns int[] + */ + public int[] getSizes() { + + // Variables + int[] array; + int index; + + // Create New Array + array = new int[sizes.length]; + for (index = 0; index < sizes.length; index++) { + array[index] = sizes[index]; + } // for + + // Return Newly created array + return array; + + } // getSizes() + + /** + * getPosition + * @param index TODO + * @returns int + */ + public int getPosition(int index) { + + // Variables + int position; + int loop; + + // Process Sizes + position = 0; + for (loop = 0; loop < index; loop++) { + position += sizes[loop]; + } // for + + // Return Position + return position; + + } // getPosition() + + /** + * insertEntries + * @param start TODO + * @param length TODO + * @param value TODO + */ + public void insertEntries(int start, int length, int value) { + + // Variables + int[] array; + int index; + int arrayIndex; + int loop; + + // Create New Array + array = new int[sizes.length + length]; + arrayIndex = 0; + for (index = 0; index < sizes.length; index++) { + if (index == start) { + for (loop = 0; loop < length; loop++) { + array[arrayIndex] = value; + arrayIndex++; + } // for + } else { + array[arrayIndex] = sizes[index]; + arrayIndex++; + } // if + } // for + + } // insertEntries() + + /** + * removeEntries + * @param start TODO + * @param length TODO + */ + public void removeEntries(int start, int length) { + + // Variables + int[] array; + int index; + int arrayIndex; + + // Sanity Check + if ((start + length) > sizes.length) { + throw new IllegalArgumentException("Specified start/length that " + + "is greater than available sizes"); + } // if + + // Create New Array + array = new int[sizes.length - length]; + arrayIndex = 0; + for (index = 0; index < sizes.length; index++) { + if (index == start) { + index += length - 1; + } else { + array[arrayIndex] = sizes[index]; + arrayIndex++; + } // if + } // for + + } // removeEntries() + + +} // SizeSequence diff --git a/libjava/classpath/javax/swing/SortingFocusTraversalPolicy.java b/libjava/classpath/javax/swing/SortingFocusTraversalPolicy.java new file mode 100644 index 00000000000..48f864b5bd9 --- /dev/null +++ b/libjava/classpath/javax/swing/SortingFocusTraversalPolicy.java @@ -0,0 +1,333 @@ +/* SortingFocusTraversalPolicy.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.util.Comparator; +import java.util.Iterator; +import java.util.TreeSet; + +/** + * @author Graydon Hoare + * @author Michael Koch + * + * @since 1.4 + */ +public class SortingFocusTraversalPolicy + extends InternalFrameFocusTraversalPolicy +{ + /** + * The comparator used to sort elements in the focus traversal cycle + * managed by this class. + */ + Comparator comparator; + + /** + * <p>Whether or not to perform an "implicit DownCycle" when selecting + * successor components within a focus cycle.</p> + * + * <p>When this is true, requesting the "next" component following a + * component which is a focus cycle root (and, necessarily, a container) + * will enter the focus cycle root of that container, and return its + * default focus.</p> + * + * <p>When this property is false, requesting the "next" component will + * simply advance within the containing focus cycle, subject to the + * {@link #comparator} order and the {@link #accept} judgment.</p> + * + * @see #getNextFocusableComponent + */ + boolean implicitDownCycleTraversal = true; + + /** + * Creates a new <code>SortingFocusTraversalPolicy</code> with no + * comparator set. + */ + protected SortingFocusTraversalPolicy() + { + // Do nothing here. + } + + /** + * Creates a new <code>SortingFocusTraversalPolicy</code> with the given + * comparator set. + * + * @param the comparator to set + */ + public SortingFocusTraversalPolicy(Comparator comparator) + { + this.comparator = comparator; + } + + /** + * Decide whether a component is an acceptable focus owner. + * + * @param comp The component which is a candidate for focus ownership. + * + * @return true if the component is focusable, displayable, visible, and + * enabled; otherwise false + */ + protected boolean accept(Component comp) + { + return (comp.isVisible() + && comp.isDisplayable() + && comp.isEnabled() + && comp.isFocusable()); + } + + /** + * Get the current value of the {@link #comparator} property. + * + * @return the current value of the property + * + * @see #setComparator + */ + protected Comparator getComparator() + { + return comparator; + } + + /** + * Set the current value of the {@link #comparator} property. + * + * @param comparator the new value of the property + * + * @see #getComparator + */ + protected void setComparator(Comparator comparator) + { + this.comparator = comparator; + } + + private TreeSet getSortedCycle(Container root, TreeSet set) + { + if (set == null) + set = (getComparator() == null + ? new TreeSet() + : new TreeSet(getComparator())); + + if (root != null) + { + Component[] comps = root.getComponents(); + for (int i = 0; i < comps.length; ++i) + { + Component c = comps[i]; + if (accept(c)) + set.add(c); + if (c instanceof Container) + getSortedCycle((Container) c, set); + } + } + return set; + } + + /** + * Return the component which follows the specified component in this + * focus cycle, relative to the order imposed by {@link + * #comparator}. Candidate components are only considered if they are + * accepted by the {@link #accept} method. + * + * If {@link #getImplicitDownCycleTraversal} is <code>true</code> and the + * <code>comp</code> is a focus cycle root, an "implicit DownCycle" + * occurs and the method returns the + * <code>getDefaultComponent(comp)</code>. + * + * @param root the focus cycle root to search for a successor within + * @param comp the component to search for the successor of + * + * @return the component following the specified component under + * the specified root, or null if no such component is found + * + * @throws IllegalArgumentException if either argument is null, or + * if the root is not a focus cycle root of the component + */ + public Component getComponentAfter(Container root, + Component comp) + { + if (comp == null || root == null || !comp.isFocusCycleRoot(root)) + throw new IllegalArgumentException(); + + if (getImplicitDownCycleTraversal() + && comp instanceof Container + && ((Container)comp).isFocusCycleRoot()) + { + return getDefaultComponent((Container) comp); + } + + TreeSet set = getSortedCycle(root, null); + Iterator i = set.iterator(); + while (i.hasNext()) + { + Component c = (Component) i.next(); + if (c != null && c.equals(comp)) + { + if (i.hasNext()) + return (Component) i.next(); + break; + } + } + return null; + } + + + /** + * Return the component which precedes the specified component in this + * focus cycle, relative to the order imposed by {@link + * #comparator}. Candidate components are only considered if they are + * accepted by the {@link #accept} method. + * + * @param root the focus cycle root to search for a predecessor within + * @param comp the component to search for the predecessor of + * + * @return the component preceding the specified component under the + * specified root, or null if no such component is found + * + * @throws IllegalArgumentException if either argument is null, or + * if the root is not a focus cycle root of the component + */ + public Component getComponentBefore(Container root, + Component comp) + { + if (comp == null || root == null || !comp.isFocusCycleRoot(root)) + throw new IllegalArgumentException(); + TreeSet set = getSortedCycle(root, null); + Iterator i = set.iterator(); + Component prev = null; + while (i.hasNext()) + { + Component c = (Component) i.next(); + if (c != null && c.equals(comp)) + break; + prev = c; + } + return prev; + } + + /** + * Return the default component of <code>root</code>, which is by default + * the same as the first component, returned by {@link + * #getFirstComponent}. + * + * @param root the focus cycle root to return the default component of + * + * @return the default focus component for <code>root</code> + * + * @throws IllegalArgumentException if root is null + */ + public Component getDefaultComponent(Container root) + { + return getFirstComponent(root); + } + + /** + * Return the first focusable component of the focus cycle root + * <code>comp</code> under the ordering imposed by the {@link + * #comparator} property. Candidate components are only considered if + * they are accepted by the {@link #accept} method. + * + * @param root the focus cycle root to search for the first component of + * + * @return the first component under <code>root</code>, or null if + * no components are found. + * + * @throws IllegalArgumentException if root is null + */ + public Component getFirstComponent(Container root) + { + if (root == null) + throw new IllegalArgumentException(); + TreeSet set = getSortedCycle(root, null); + Iterator i = set.iterator(); + if (i.hasNext()) + return (Component) i.next(); + return null; + } + + /** + * Return the last focusable component of the focus cycle root + * <code>comp</code> under the ordering imposed by the {@link + * #comparator} property. Candidate components are only considered if + * they are accepted by the {@link #accept} method. + * + * @param root the focus cycle root to search for the last component of + * + * @return the last component under <code>root</code>, or null if + * no components are found. + * + * @throws IllegalArgumentException if root is null + */ + public Component getLastComponent(Container root) + { + if (root == null) + throw new IllegalArgumentException(); + TreeSet set = getSortedCycle(root, null); + Iterator i = set.iterator(); + Component last = null; + while (i.hasNext()) + last = (Component) i.next(); + return last; + } + + /** + * Return the current value of the {@link implicitDownCycleTraversal} + * property. + * + * @return the current value of the property + * + * @see setImplicitDownCycleTraversal + */ + public boolean getImplicitDownCycleTraversal() + { + return implicitDownCycleTraversal; + } + + /** + * Set the current value of the {@link implicitDownCycleTraversal} + * property. + * + * @param down the new value of the property + * + * @see getImplicitDownCycleTraversal + */ + public void setImplicitDownCycleTraversal(boolean down) + { + implicitDownCycleTraversal = down; + } +} diff --git a/libjava/classpath/javax/swing/SpinnerDateModel.java b/libjava/classpath/javax/swing/SpinnerDateModel.java new file mode 100644 index 00000000000..c0de7d55c8e --- /dev/null +++ b/libjava/classpath/javax/swing/SpinnerDateModel.java @@ -0,0 +1,237 @@ +/* SpinnerDateModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.io.Serializable; +import java.util.Calendar; +import java.util.Date; + +/** + * SpinnerDateModel + * + * Implements a SpinnerModel for dates, rotating a calendar field such as + * month, year, day, week, hour, minute. + * + * @author Sven de Marothy + * @version 0.1 (first implementation) + */ +public class SpinnerDateModel extends AbstractSpinnerModel + implements Serializable +{ + private Calendar date; + private Comparable start; + private Comparable end; + private int calendarField; + + /** + * For compatability with Sun's JDK + * FIXME: Which fields should be serialized? + */ + private static final long serialVersionUID = -4802518107105940612L; + + /** + * Constructs a SpinnerDateModel using the current date, + * no start or end limit, and Calendar.DAY_OF_MONTH as the calendar field. + */ + public SpinnerDateModel() + { + this(new Date(), null, null, Calendar.DAY_OF_MONTH); + } + + /** + * Constructs a SpinnerDateModel which spins a given calendar field, + * using a given date and start and end date limits. + * @param value - the initial Date value + * @param start - start limit, as a Date object, or <code>null</code> + * for no lower limit. + * @param end - end limit, or <code>null</code> for no upper limit. + * @param calendarField - the <code>Calendar</code> field to spin, + * (Calendar.ZONE_OFFSET and Calendar.DST_OFFSET are invalid) + */ + public SpinnerDateModel(Date value, Comparable start, Comparable end, + int calendarField) + { + date = Calendar.getInstance(); + date.setTime(value); + this.start = start; + this.end = end; + setCalendarField(calendarField); + } + + /** + * Returns the value of the Calendar field to spin. + */ + public int getCalendarField() + { + return calendarField; + } + + /** + * Returns the current date in the sequence. + * @return a <code>Date</code> object. + */ + public Date getDate() + { + return date.getTime(); + } + + /** + * Returns the starting limit of the SpinnerModel. + * @return a Date object, or <code>null</code> if there is no limit. + */ + public Comparable getStart() + { + return start; + } + + /** + * Returns the end limit of the SpinnerModel. + * @return a Date object, or <code>null</code> if there is no limit. + */ + public Comparable getEnd() + { + return end; + } + + /** + * Returns the current date in the sequence, + * this method returns the same as <code>getDate()</code>. + * @return a <code>Date</code> object. + */ + public Object getValue() + { + return date.getTime(); + } + + /** + * Returns the next date in the sequence, or <code>null</code> if the + * next date is equal to or past the end limit. + * @return a Date object, or <code>null</code>. + */ + public Object getNextValue() + { + Calendar nextCal = Calendar.getInstance(); + nextCal.setTime(date.getTime()); + nextCal.roll(calendarField, true); + Date nextDate = nextCal.getTime(); + if (end != null) + if (end.compareTo(nextDate) < 0) + return null; + return nextDate; + } + + /** + * Returns the previous date in the sequence, or <code>null</code> if the + * next date is equal to or past the end limit. + * @return a Date object, or <code>null</code>. + */ + public Object getPreviousValue() + { + Calendar prevCal = Calendar.getInstance(); + prevCal.setTime(date.getTime()); + prevCal.roll(calendarField, false); + Date prevDate = prevCal.getTime(); + if (end != null) + if (end.compareTo(prevDate) > 0) + return null; + return prevDate; + } + + /** + * Sets the date field to change. It must be a valid Calendar field, + * excluding Calendar.ZONE_OFFSET and Calendar.DST_OFFSET. + * @param calendarField - the calendar field to set. + */ + public void setCalendarField(int calendarField) + { + if (calendarField < 0 || calendarField >= Calendar.FIELD_COUNT + || calendarField == Calendar.ZONE_OFFSET + || calendarField == Calendar.DST_OFFSET) + throw new IllegalArgumentException("Illegal calendarField"); + + if (this.calendarField != calendarField) + { + this.calendarField = calendarField; + fireStateChanged(); + } + } + + /** + * Sets the starting date limit for the sequence. + * + * @param start - a Date object of the limit date, + * or <code>null</code> for no limit. + */ + public void setStart(Comparable start) + { + if (this.start != start) + { + this.start = start; + fireStateChanged(); + } + } + + /** + * Sets the end date limit for the sequence. + * + * @param end - a Date object of the limit date, + * or <code>null</code> for no limit. + */ + public void setEnd(Comparable end) + { + if (this.end != end) + { + this.end = end; + fireStateChanged(); + } + } + + /** + * Sets the current date in the sequence. + * + * @param value - a Date object. + */ + public void setValue(Object value) + { + if (! (value instanceof Date) || value == null) + throw new IllegalArgumentException("Value not a date."); + date.setTime((Date) value); + fireStateChanged(); + } +} diff --git a/libjava/classpath/javax/swing/SpinnerListModel.java b/libjava/classpath/javax/swing/SpinnerListModel.java new file mode 100644 index 00000000000..a0dc4d14462 --- /dev/null +++ b/libjava/classpath/javax/swing/SpinnerListModel.java @@ -0,0 +1,296 @@ +/* SpinnerListModel.java -- A spinner model backed by a list or an array. + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * An implementation of <code>SpinnerModel</code> which uses the values + * contained within a list or an array. The backing list or array is + * only stored as a reference within the class. As a result, changes + * made elsewhere to the members of the list or array are reflected by + * this model. + * <p> + * + * The model itself inherits a list of <code>ChangeListener</code>s from + * <code>AbstractSpinnerModel</code>. As this code is unaware of changes + * made to the backing list or array, it is the responsibility of the + * application using the model to invoke <code>fireStateChanged()</code>, + * in order to notify any <code>ChangeListener</code>s, when the list or array + * changes. The model handles notification when the reference itself + * is changed via <code>setList()</code> or when the current value is + * set directly using <code>setValue()</code>. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see SpinnerModel + * @see AbstractSpinnerModel + * @see JSpinner + * @since 1.4 + */ + +public class SpinnerListModel + extends AbstractSpinnerModel + implements Serializable +{ + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 3358804052191994516L; + + /** + * The backing list for this model. + */ + private List list; + + /** + * The current index in the list. + */ + private transient int index; + + /** + * Constructs a default <code>SpinnerListModel</code>. This + * is a model backed by a list containing only the single + * <code>String</code> element, "empty". + */ + public SpinnerListModel() + { + List defaultList; + + /* Create an empty list */ + defaultList = new ArrayList(); + /* Add the string "empty" */ + defaultList.add("empty"); + /* Set the list */ + setList(defaultList); + } + + /** + * Constructs a <code>SpinnerListModel</code> using the supplied list. + * The model maintains a reference to this list, and returns + * consecutive elements in response to calls to <code>getNextValue()</code>. + * The initial value is that at position 0, so an initial call + * to <code>getValue()</code> returns the same as <code>list.get(0)</code>. + * + * @param list The list to use for this model. + * @throws IllegalArgumentException if the list is null or contains no + * elements. + * @see SpinnerListModel#getNextValue() + * @see SpinnerListModel#getValue() + */ + public SpinnerListModel(List list) + { + /* Retain a reference to the valid list */ + setList(list); + } + + /** + * Constructs a <code>SpinnerListModel</code> using the supplied array. + * The model stores a reference to the wrapper list returned by + * <code>Arrays.asList()</code>. The wrapper list reflects modifications + * in the underlying array, so these changes will also be reflected + * by the model. The model produces consecutive elements from the array + * in response to calls to <code>getNextValue()</code>. The initial + * value returned by <code>getValue()</code> is the same as + * <code>array[0]</code>. + * + * @param array The array to use for this model. + * @throws IllegalArgumentException if the array is null or contains + * no elements. + * @see Arrays#asList(Object[]) + * @see SpinnerListModel#getNextValue() + * @see SpinnerListModel#getValue() + */ + public SpinnerListModel(Object[] array) + { + /* Check for a null or zero-sized array */ + if (array == null || array.length == 0) + { + throw new IllegalArgumentException("The supplied array was invalid."); + } + /* + Retain a reference to a wrapper around the valid array + The array, in list form, will be tested again here, but we can't really + avoid this -- a null value to Arrays.asList will throw a NullPointerException + */ + setList(Arrays.asList(array)); + } + + /** + * Returns the backing list for this model. + * + * @return The backing list. + */ + public List getList() + { + return list; + } + + /** + * Returns the next value from the list, which is the same as the element + * stored at the current index + 1. Null is returned if there are no more + * values to be returned (the end of the list has been reached). An + * ambiguity can occur here, as null may also be returned as a valid list + * element. This operation does not change the current value. + * + * @return The next value from the list or null. + */ + public Object getNextValue() + { + /* Check for a next value */ + if (index < (list.size() - 1)) + { + /* Return the element at the next index */ + return list.get(index + 1); + } + else + { + /* Return null as this is the end of the list */ + return null; + } + } + + /** + * Returns the previous value from the list, which is the same as the element + * stored at the current index - 1. Null is returned if there are no more + * values to be returned (the start of the list has been reached). An + * ambiguity can occur here, as null may also be returned as a valid list + * element. This operation does not change the current value. + * + * @return The previous value from the list or null. + */ + public Object getPreviousValue() + { + /* Check for a previous value. */ + if (index > 0) + { + /* Return the element at the previous position */ + return list.get(index - 1); + } + else + { + /* Return null as this is the start of the list */ + return null; + } + } + + /** + * Returns the current value of the model. Initially, this will + * be the element at position 0. On later invocations, this will + * be the last element returned by <code>getNextValue()</code> + * or <code>getPreviousValue()</code>. + * + * @return The current value. + * @see SpinnerListModel#getPreviousValue() + * @see SpinnerListModel#getNextValue() + */ + public Object getValue() + { + return list.get(index); + } + + /** + * Changes the backing list for this model. The model only stores + * a reference to the list, so any changes made to the list elsewhere + * will be reflected in the values returned by the model. A + * <code>ChangeEvent</code> is fired if the list being used actually + * changes (i.e. the new list is not referentially equal (!=) to the + * old one). + * + * @param list The new list to use. + * @throws IllegalArgumentException if the list is null or contains + * no elements. + * @see ChangeEvent + */ + public void setList(List list) + { + /* Check for null or zero size list */ + if (list == null || list.size() == 0) + { + throw new IllegalArgumentException("The supplied list was invalid."); + } + /* Check for a change of referenced list */ + if (this.list != list) + { + /* Store the new list */ + this.list = list; + /* Notify listeners of a change */ + fireStateChanged(); + } + /* We reset the other values in either case */ + /* Set the index to 0 */ + index = 0; + } + + /** + * Sets the current value of the model to be the one supplied. + * The value must exist within the backing list in order for + * the change to take place. Otherwise, an exception is thrown. + * The value used is the first occurrence of the value within + * the backing list. Listeners are notified of this change. + * Following the change, <code>getNextValue()</code> and + * <code>getPreviousValue()</code> return the objects following + * and prior to the supplied value, respectively. + * + * @param value The requested new value of the list. + * @throws IllegalArgumentException if the supplied value does + * not exist in the backing list. + * @see SpinnerListModel#getPreviousValue() + * @see SpinnerListModel#getNextValue() + */ + public void setValue(Object value) + { + int valueIndex; + + /* Search for the value in the list */ + valueIndex = list.indexOf(value); + /* Check for the value being found */ + if (valueIndex == -1) + { + throw new IllegalArgumentException("The supplied value does not " + + "exist in this list"); + } + /* Make the indices match */ + index = valueIndex; + /* Notify the listeners */ + fireStateChanged(); + } + +} diff --git a/libjava/classpath/javax/swing/SpinnerModel.java b/libjava/classpath/javax/swing/SpinnerModel.java new file mode 100644 index 00000000000..4ad962bbf79 --- /dev/null +++ b/libjava/classpath/javax/swing/SpinnerModel.java @@ -0,0 +1,111 @@ +/* SpinnerModel.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import javax.swing.event.ChangeListener; + +/** + * The data model that is used in {@link JSpinner}s. + * + * @since 1.4 + */ +public interface SpinnerModel +{ + /** + * Sets the current value of the model to that specified. + * Implementations can choose to refuse to accept the value + * and throw an exception instead. For example, a date model + * may throw invalid dates, or a list model may throw out + * values which don't exist in the underlying list. Models + * may also throw out unusual values, such as null. The decision + * is left to the discretion of the implementator. If the + * operation succeeds, the implementation should also notify + * any registered <code>ChangeListener</code>s. + * + * @param value The new value of the model. + * @throws IllegalArgumentException if the model does not accept + * the given value. + */ + void setValue(Object value); + + /** + * Returns the current value of the model. + * + * @return The current value. + */ + Object getValue(); + + /** + * Returns the next value from the model. If the model is bounded, + * this method may return null when the upper bound is met. + * The current value is not changed. + * + * @return The next value, or null if there are no more values + * to retrieve. + */ + Object getNextValue(); + + /** + * Returns the previous value from the model. If the model is + * bounded, this method may return null when the lower bound is + * met. The current value is not changed. + * + * @return The previous value, or null if there are no more + * values to retrieve. + */ + Object getPreviousValue(); + + /** + * Adds a <code>ChangeListener</code> to the list of registered + * listeners. Each listener is notified when the current value + * is changed. + * + * @param listener The new listener to register. + */ + void addChangeListener(ChangeListener listener); + + /** + * Removes a given <code>ChangeListener</code> from the list + * of registered listeners. + * + * @param listener The listener to remove. + */ + void removeChangeListener(ChangeListener listener); + +} diff --git a/libjava/classpath/javax/swing/SpinnerNumberModel.java b/libjava/classpath/javax/swing/SpinnerNumberModel.java new file mode 100644 index 00000000000..2274c9ec038 --- /dev/null +++ b/libjava/classpath/javax/swing/SpinnerNumberModel.java @@ -0,0 +1,298 @@ +/* SpinnerNumberModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.io.Serializable; + +/** + * SpinnerNumberModel + * + * @author Ka-Hing Cheung + * @version 1.0 + */ +public class SpinnerNumberModel extends AbstractSpinnerModel + implements Serializable +{ + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 7279176385485777821L; + + /** DOCUMENT ME! */ + private Number value; + + /** DOCUMENT ME! */ + private Comparable minimum; + + /** DOCUMENT ME! */ + private Comparable maximum; + + /** DOCUMENT ME! */ + private Number stepSize; + + /** + * Creates a <code>SpinnerNumberModel</code> with initial value 0, step 1, + * and no maximum nor minimum. + */ + public SpinnerNumberModel() + { + this(new Integer(0), null, null, new Integer(1)); + } + + /** + * Creates a <code>SpinnerNumberModel</code> with double precision + * + * @param value the initial value + * @param minimum the minimum value + * @param maximum the maximum value + * @param stepSize the step size + * @throws IllegalArgumentException if minimum <= value <= maximum does not + * hold + */ + public SpinnerNumberModel(double value, double minimum, double maximum, + double stepSize) + { + this(new Double(value), new Double(minimum), new Double(maximum), + new Double(stepSize)); + } + + /** + * Creates a <code>SpinnerNumberModel</code> with integer precision + * + * @param value the initial value + * @param minimum the minimum value + * @param maximum the maximum value + * @param stepSize the step size + * @throws IllegalArgumentException if minimum <= value <= maximum does not + * hold + */ + public SpinnerNumberModel(int value, int minimum, int maximum, int stepSize) + { + this(new Integer(value), new Integer(minimum), new Integer(maximum), + new Integer(stepSize)); + } + + /** + * Creates a <code>SpinnerNumberModel</code> with <code>Number</code>s and + * <code>Comparable</code>s. + * + * @param value the initial value + * @param minimum the minimum value, if null there's no minimum + * @param maximum the maximum value, if null there's no maximum + * @param stepSize the step size + * + * @throws IllegalArgumentException if minimum <= value <= maximum + * does not hold + */ + public SpinnerNumberModel(Number value, Comparable minimum, + Comparable maximum, Number stepSize) + { + if (stepSize == null) + throw new IllegalArgumentException("stepSize may not be null"); + if (value == null) + throw new IllegalArgumentException("value may not be null"); + if (minimum != null) + { + if (minimum.compareTo(value) > 0) + throw new IllegalArgumentException("minimum is not <= value"); + } + else + minimum = new Comparable() + { + public int compareTo(Object obj) + { + return -1; + } + }; + + + if (maximum != null) + { + if (maximum.compareTo(value) < 0) + throw new IllegalArgumentException("maximum is not >= value"); + } + else + maximum = new Comparable() + { + public int compareTo(Object obj) + { + return 1; + } + }; + + + this.value = value; + this.stepSize = stepSize; + this.minimum = minimum; + this.maximum = maximum; + } + + /** + * Sets the new value and fire a change event + * + * @param value the new value + * + * @throws IllegalArgumentException if minimum <= value <= maximum + * does not hold + */ + public void setValue(Object value) + { + if (! (value instanceof Number)) + throw new IllegalArgumentException("value must be a Number"); + + this.value = (Number) value; + fireStateChanged(); + } + + /** + * Gets the current value + * + * @return the current value + */ + public Object getValue() + { + return value; + } + + /** + * Gets the next value without changing the current value, or null if the + * current value is maximum. + * + * @return the next value + */ + public Object getNextValue() + { + Number num; + + if (value instanceof Double) + num = new Double(value.doubleValue() + stepSize.doubleValue()); + else if (value instanceof Float) + num = new Double(value.floatValue() + stepSize.floatValue()); + else if (value instanceof Long) + num = new Long(value.longValue() + stepSize.longValue()); + else if (value instanceof Integer) + num = new Integer(value.intValue() + stepSize.intValue()); + else if (value instanceof Short) + num = new Short((short) (value.shortValue() + stepSize.shortValue())); + else + num = new Byte((byte) (value.byteValue() + stepSize.byteValue())); + + return maximum.compareTo(num) >= 0 ? num : null; + } + + /** + * Gets the previous value without changing the current value, or null if + * the current value is minimum. + * + * @return the previous value + */ + public Object getPreviousValue() + { + Number num; + + if (value instanceof Double) + num = new Double(value.doubleValue() - stepSize.doubleValue()); + else if (value instanceof Float) + num = new Double(value.floatValue() - stepSize.floatValue()); + else if (value instanceof Long) + num = new Long(value.longValue() - stepSize.longValue()); + else if (value instanceof Integer) + num = new Integer(value.intValue() - stepSize.intValue()); + else if (value instanceof Short) + num = new Short((short) (value.shortValue() - stepSize.shortValue())); + else + num = new Byte((byte) (value.byteValue() - stepSize.byteValue())); + + return minimum.compareTo(num) <= 0 ? num : null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getNumber() + { + return value; + } + + public Comparable getMinimum() + { + return minimum; + } + + public void setMinimum(Comparable newMinimum) + { + if (minimum != newMinimum) + { + minimum = newMinimum; + fireStateChanged(); + } + } + + public Comparable getMaximum() + { + return maximum; + } + + public void setMaximum(Comparable newMaximum) + { + if (maximum != newMaximum) + { + maximum = newMaximum; + fireStateChanged(); + } + } + + public Number getStepSize() + { + return stepSize; + } + + public void setStepSize(Number newStepSize) + { + if (newStepSize == null) + throw new IllegalArgumentException(); + + if (stepSize != newStepSize) + { + stepSize = newStepSize; + fireStateChanged(); + } + } +} diff --git a/libjava/classpath/javax/swing/Spring.java b/libjava/classpath/javax/swing/Spring.java new file mode 100644 index 00000000000..4255e86f8e6 --- /dev/null +++ b/libjava/classpath/javax/swing/Spring.java @@ -0,0 +1,580 @@ +/* Spring.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +/** + * Calculates the space between component edges, that are layed out by + * {@link SpringLayout}. + * <p> + * A Spring defines a minimum, preferred and maximum distance for each edge + * (north, east, south, west) of a component. + * </p> + * However, springs are not static, their actual values are computed at + * runtime. That means, if a Spring C is defined as the sum of Spring A and + * Spring B, then the values (min, pref and max) are not calculated at + * creation of Spring C, but instead always when {@link #getValue} is + * called. So, when Spring A or Spring B changes, this is reflected in + * Spring C. + * + * @author Roman Kennke (roman@ontographics.com) + */ +public abstract class Spring +{ + + /** Indicates a not-set value. **/ + public static final int UNSET = -2147483648; + + /** + * Creates a new Spring object. This constructor is used by the static + * methods which create Springs. + */ + protected Spring() + { + } + + /** + * Creates a Spring which min, pref and max values are all the same. + * These kind of Springs are 'struts'. + * + * @param val the constant for min, pref and max values. + * @return a Spring object with constant values for min, pref and max. + */ + public static Spring constant(int val) + { + return new SimpleSpring(val, val, val); + } + + /** Creates a Spring which min, pref and max values are constants. + * @param min the constant for the minimum value. + * @param pref the constant for the preferred value. + * @param max the constant for the maximum value. + * @return a Spring object with constant values for min, pref and max. + */ + public static Spring constant(int min, int pref, int max) + { + return new SimpleSpring(min, pref, max); + } + + /** + * Returns the maximum value of the Spring. + * + * @return the maximum value. + */ + public abstract int getMaximumValue(); + + /** + * Returns the minimum value of this Spring. + * + * @return the minimum value. + */ + public abstract int getMinimumValue(); + + /** + * Return the preferred value of this Spring. + * + * @return the preferred value. + */ + public abstract int getPreferredValue(); + + /** + * Return the actual value of this Spring. + * + * @return the actual value of this Spring. + */ + public abstract int getValue(); + + /** + * Creates and returns a Spring, which always has the maximum values + * min = max(min_s1, min_s2), pref = max(pref_s1, pref_s2), max = + * max(max_s1, max_s2). + * + * @param s1 the first summand of the max Spring. + * @param s2 the second summand of the max Spring. + * @return a Spring which is max(s1, s2). + */ + public static Spring max(Spring s1, Spring s2) + { + return new MaxSpring(s1, s2); + } + + /** + * Creates and returns a Spring, which is always the negation of s. + * min = -min_s, pref = -pref_s, max = -max_pref. + * + * @param s the Spring to be negated. + * @return the negative of <code>s</code>. + */ + public static Spring minus(Spring s) + { + return new MinusSpring(s); + } + + /** + * Sets the actual value. If <code>value</code> is out of the (min, max) + * bounds, then the value is adjusted, so that is inside these bounds. + * + * @param value the value to be set. + */ + public abstract void setValue(int value); + + /** + * Creates and returns a Spring, which is always the sum of s1 and s2. + * min_sum = min_s1 + min_s2, pref_sum = pref_s1 + pref_s2, max_sum = + * max_s1 + max_s2. + * + * @param s1 the 1st summand of the sum Spring. + * @param s2 the 2nd summand of the sum Spring. + * @return a sum which is <code>s1 + s2</code>. + */ + public static Spring sum(Spring s1, Spring s2) + { + return new AddSpring(s1, s2); + } + + /** + * A simple Spring, that holds constant values for min, pref and max. + * + * @author Roman Kennke (roman@ontographics.com) + */ + private static final class SimpleSpring extends Spring + { + + /** The constant value for min. */ + private final int min; + + /** The constant value for pref. */ + private final int pref; + + /** The constant value for max. */ + private final int max; + + /** The actual value of the spring. */ + private int value; + + /** + * Creates a new SimpleSpring object. + * + * @param min the constant minimum value. + * @param pref the constant preferred value. + * @param max the constant maximum value. + */ + public SimpleSpring(int newMin, int newPref, int newMax) + { + min = newMin; + pref = newPref; + max = newMax; + value = Spring.UNSET; + } + + /** + * Returns the maximum value of this Spring. + * + * @return the maximum value. + */ + public int getMaximumValue() + { + return max; + } + + /** + * Returns the minimum value of this Spring. + * + * @return the minimum value. + */ + public int getMinimumValue() + { + return min; + } + + /** + * Returns the preferred value of this Spring. + * + * @return the preferred value. + */ + public int getPreferredValue() + { + return pref; + } + + /** + * Return the actual current value of this Spring. + * + * @return the current value. + */ + public int getValue() + { + + if (value == Spring.UNSET) + { + value = pref; + } + + return value; + } + + /** + * Sets the current value. + * + * @param val the value to be set. + */ + public void setValue(int val) + { + + if (val > max) + { + value = max; + } + else if (val < min) + { + value = min; + } + else + { + value = val; + } + } + + } + + + /** + * A Spring, that is the sum of two other Springs. + * + * @author Roman Kennke (roman@ontographics.com) + */ + private static final class AddSpring extends Spring + { + + /** The springs, that are the 'operands' of this Spring. */ + private final Spring s1; + private final Spring s2; + + /** The current value for this Spring. */ + private int value; + + /** + * Creates a new AddSpring object. + * + * @param s1 the first operand. + * @param s2 the second operand. + */ + protected AddSpring(Spring s1, Spring s2) + { + super(); + this.s1 = s1; + this.s2 = s2; + value = Spring.UNSET; + } + + /** + * Returns the maximum value of this Spring. + * + * @return the maximum value. + */ + public int getMaximumValue() + { + int max1 = s1.getMaximumValue(); + int max2 = s2.getMaximumValue(); + return max1 + max2; + } + + /** + * Return the minimum value of this Spring. + * + * @return the minimum value. + */ + public int getMinimumValue() + { + int min1 = s1.getMinimumValue(); + int min2 = s2.getMinimumValue(); + return min1 + min2; + } + + /** + * Returns the preferred value of this Spring. + * + * @return the preferred value. + */ + public int getPreferredValue() + { + int pref1 = s1.getPreferredValue(); + int pref2 = s2.getPreferredValue(); + return pref1 + pref2; + } + + /** + * Returns the actual current value of this Spring. + * + * @return the current value of this Spring. + */ + public int getValue() + { + if (value == Spring.UNSET) + { + int val1 = s1.getValue(); + int val2 = s2.getValue(); + value = val1 + val2; + } + return value; + } + + /** + * Sets the current value. + * + * @param val the value to be set. + */ + public void setValue(int val) + { + + if (val > getMaximumValue()) + { + value = getMaximumValue(); + } + else if (val < getMinimumValue()) + { + value = getMinimumValue(); + } + else + { + value = val; + } + + } + + } + + + /** + * A Spring that is calculated as the negation of another Spring. + * + * @author Roman Kennke (roman@ontographics.com) + */ + private static final class MinusSpring extends Spring + { + + /** The Spring from which to calculate the negation. */ + private final Spring s; + + /** The current value of this Spring. */ + private int value; + + /** + * Creates a new MinusSpring object. + * @param s the Spring from which to calculate the negation. + */ + protected MinusSpring(Spring s) + { + super(); + this.s = s; + value = Spring.UNSET; + } + + /** Returns the maximum value of this Spring. + * + * @return the maximum value. + */ + public int getMaximumValue() + { + return -s.getMinimumValue(); + } + + /** + * Returns the minimum value of this Spring. + * + * @return the minimum value. + */ + public int getMinimumValue() + { + return -s.getMaximumValue(); + } + + /** + * Returns the preferred value of this Spring. + * + * @return the preferred value. + */ + public int getPreferredValue() + { + return -s.getPreferredValue(); + } + + /** + * Returns the current value of this Spring. + * + * @return the current value. + */ + public int getValue() + { + if (value == Spring.UNSET) + { + value = -s.getValue(); + } + return value; + } + + /** + * Sets the current value. + * + * @param val the value to be set. + */ + public void setValue(int val) + { + + if (val > getMaximumValue()) + { + value = getMaximumValue(); + } + else if (val < getMinimumValue()) + { + value = getMinimumValue(); + } + else + { + value = val; + } + + } + + } + + + /** + * A Spring, that is calculated as the maximum of two Springs. + * + * @author Roman Kennke (roman@ontographics.com) + */ + private static final class MaxSpring extends Spring + { + + /** The two other Springs from which to calculate the maximum. */ + private final Spring s1; + private final Spring s2; + + /** The current value of this Spring. */ + private int value; + + /** + * Creates a new MaxSpring object. + * + * @param s1 the 1st operand. + * @param s2 the 2nd operand. + */ + protected MaxSpring(Spring s1, Spring s2) + { + super(); + this.s1 = s1; + this.s2 = s2; + value = Spring.UNSET; + } + + + /** + * Returns the maximum value of this Spring. + * + * @return the maximum value. + */ + public int getMaximumValue() + { + int max1 = s1.getMaximumValue(); + int max2 = s2.getMaximumValue(); + return Math.max(max1, max2); + } + + /** + * Returns the minimum value of this Spring. + * + * @return the minimum value. + */ + public int getMinimumValue() + { + int min1 = s1.getMinimumValue(); + int min2 = s2.getMinimumValue(); + return Math.max(min1, min2); + } + + /** + * Returns the preferred value of this Spring. + * + * @return the preferred value. + */ + public int getPreferredValue() + { + int pref1 = s1.getPreferredValue(); + int pref2 = s2.getPreferredValue(); + return Math.max(pref1, pref2); + } + + /** + * Returns the actual value of this Spring. + * + * @return the current value. + */ + public int getValue() + { + if (value == Spring.UNSET) + { + int val1 = s1.getValue(); + int val2 = s2.getValue(); + value = Math.max(val1, val2); + } + return value; + } + + /** + * Sets the current value. + * + * @param val the value to be set. + */ + public void setValue(int val) + { + + if (val > getMaximumValue()) + { + value = getMaximumValue(); + } + else if (val < getMinimumValue()) + { + value = getMinimumValue(); + } + else + { + value = val; + } + } + } +} diff --git a/libjava/classpath/javax/swing/SpringLayout.java b/libjava/classpath/javax/swing/SpringLayout.java new file mode 100644 index 00000000000..b45edba5357 --- /dev/null +++ b/libjava/classpath/javax/swing/SpringLayout.java @@ -0,0 +1,657 @@ +/* SpringLayout.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.LayoutManager2; +import java.util.HashMap; +import java.util.Map; + +/** + * A very flexible layout manager. Components are laid out by defining the + * relationships between them. The relationships are expressed as + * {@link Spring}s. You can attach a Spring for each edge of a component and + * link it to an edge of a different component. For example, you can say, + * the northern edge of component A should be attached to the southern edge + * of component B, and the space between them should be something between + * x and y pixels, and preferably z pixels. + * <p>While quite simple, this layout manager can be used to emulate most other + * layout managers, and can also be used to solve some layout problems, which + * would be hard to solve with other layout managers.</p> + * + * @author Roman Kennke (roman@ontographics.com) + */ +public class SpringLayout implements LayoutManager2 +{ + + /** The right edge of a component. */ + public static final String EAST = "East"; + + /** The top edge of a component. */ + public static final String NORTH = "North"; + + /** The bottom edge of a component. */ + public static final String SOUTH = "South"; + + /** The left edge of a component. */ + public static final String WEST = "West"; + + /** maps components to their constraints. */ + private Map constraintsMap; + + /** + * The constraints that define the relationships between components. + * Each Constraints object can hold 4 Springs: one for each edge of the + * component. Additionally it can hold Springs for the components width + * and the components height. Since the height and width constraints are + * dependend on the other constraints, a component can be over-constraint. + * In this case (like when all of NORTH, SOUTH and HEIGHT are constraint), + * the values are adjusted, so that the mathematics still hold true. + * + * @author Roman Kennke (roman@ontographics.com) + */ + public static class Constraints + { + + // The constraints for each edge, and width and height. + /** The Spring for the left edge. */ + private Spring x; + + /** The Spring for the upper edge. */ + private Spring y; + + /** The Spring for the height. */ + private Spring height; + + /** The Spring for the width. */ + private Spring width; + + /** The Spring for the right edge. */ + private Spring east; + + /** The Spring for the bottom edge. */ + private Spring south; + + /** + * Creates a new Constraints object. + * There is no constraint set. + */ + public Constraints() + { + x = y = height = width = east = south = null; + } + + /** + * Creates a new Constraints object. + * + * @param x the constraint for the left edge of the component. + * @param y the constraint for the upper edge of the component. + */ + public Constraints(Spring x, Spring y) + { + this.x = x; + this.y = y; + width = height = east = south = null; + } + + /** + * Creates a new Constraints object. + * + * @param x the constraint for the left edge of the component. + * @param y the constraint for the upper edge of the component. + * @param width the constraint for the width of the component. + * @param height the constraint for the height of the component. + */ + public Constraints(Spring x, Spring y, Spring width, Spring height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + east = south = null; + } + + /** + * Returns the constraint for the edge with the <code>edgeName</code>. + * This is expected to be one of + * {@link #EAST}, {@link #WEST}, {@link NORTH} or {@link SOUTH}. + * + * @param edgeName the name of the edge. + * @return the constraint for the specified edge. + */ + public Spring getConstraint(String edgeName) + { + Spring retVal = null; + if (edgeName.equals(SpringLayout.NORTH)) + retVal = y; + else if (edgeName.equals(SpringLayout.WEST)) + retVal = x; + else if (edgeName.equals(SpringLayout.SOUTH)) + { + retVal = south; + if ((retVal == null) && (y != null) && (height != null)) + retVal = Spring.sum(y, height); + } + else if (edgeName.equals(SpringLayout.EAST)) + { + retVal = east; + if ((retVal == null) && (x != null) && (width != null)) + retVal = Spring.sum(x, width); + } + + return retVal; + } + + /** + * Returns the constraint for the height of the component. + * + * @return the height constraint. + */ + public Spring getHeight() + { + Spring retVal = height; + if ((retVal == null) && (y != null) && (south != null)) + { + retVal = Spring.sum(south, Spring.minus(y)); + } + return retVal; + } + + /** + * Returns the constraint for the width of the component. + * + * @return the width constraint. + */ + public Spring getWidth() + { + Spring retVal = width; + if ((retVal == null) && (x != null) && (east != null)) + { + retVal = Spring.sum(east, Spring.minus(x)); + } + return retVal; + } + + /** + * Returns the constraint for the left edge of the component. + * + * @return the left-edge constraint (== WEST). + */ + public Spring getX() + { + Spring retVal = x; + if ((retVal == null) && (width != null) && (east != null)) + { + retVal = Spring.sum(east, Spring.minus(width)); + } + return retVal; + } + + /** + * Returns the constraint for the upper edge of the component. + * + * @return the upper-edge constraint (== NORTH). + */ + public Spring getY() + { + Spring retVal = y; + if ((retVal == null) && (height != null) && (south != null)) + { + retVal = Spring.sum(south, Spring.minus(height)); + } + return retVal; + } + + /** + * Sets a constraint for the specified edge. If this leads to an + * over-constrained situation, the constraints get adjusted, so that + * the mathematics still hold true. + * + * @param edgeName the name of the edge, one of {@link #EAST}, + * {@link #WEST}, {@link NORTH} or {@link SOUTH}. + * @param s the constraint to be set. + */ + public void setConstraint(String edgeName, Spring s) + { + + if (edgeName.equals(SpringLayout.WEST)) + { + x = s; + if ((width != null) && (east != null)) + width = Spring.sum(east, Spring.minus(x)); + } + else if (edgeName.equals(SpringLayout.NORTH)) + { + y = s; + if ((height != null) && (south != null)) + height = Spring.sum(south, Spring.minus(y)); + } + else if (edgeName.equals(SpringLayout.EAST)) + { + east = s; + if ((x != null) && (width != null)) + x = Spring.sum(east, Spring.minus(width)); + } + else if (edgeName.equals(SpringLayout.SOUTH)) + { + south = s; + if ((height != null) && (y != null)) + y = Spring.sum(south, Spring.minus(height)); + } + + } + + /** + * Sets the height-constraint. + * + * @param s the constraint to be set. + */ + public void setHeight(Spring s) + { + height = s; + if ((south != null) && (y != null)) + south = Spring.sum(y, height); + + } + + /** + * Sets the width-constraint. + * + * @param s the constraint to be set. + */ + public void setWidth(Spring s) + { + width = s; + if ((east != null) && (x != null)) + east = Spring.sum(x, width); + + } + + /** + * Sets the WEST-constraint. + * + * @param s the constraint to be set. + */ + public void setX(Spring s) + { + x = s; + if ((width != null) && (east != null)) + width = Spring.sum(east, Spring.minus(x)); + + } + + /** + * Sets the NORTH-constraint. + * + * @param s the constraint to be set. + */ + public void setY(Spring s) + { + y = s; + if ((height != null) && (south != null)) + height = Spring.sum(south, Spring.minus(y)); + + } + } + + /** + * Creates a new SpringLayout. + */ + public SpringLayout() + { + + constraintsMap = new HashMap(); + } + + /** + * Adds a layout component and a constraint object to this layout. + * This method is usually only called by a {@java.awt.Container}s add + * Method. + * + * @param component the component to be added. + * @param constraint the constraint to be set. + */ + public void addLayoutComponent(Component component, Object constraint) + { + constraintsMap.put(component, constraint); + } + + + /** + * Adds a layout component and a constraint object to this layout. + * This method is usually only called by a {@java.awt.Container}s add + * Method. This method does nothing, since SpringLayout does not manage + * String-indexed components. + * + * @param component the component to be added. + * @param constraint the constraint to be set. + */ + public void addLayoutComponent(String name, Component c) + { + // do nothing here. + } + + /** + * Returns the constraint of the edge named by <code>edgeName</code>. + * + * @param c the component from which to get the constraint. + * @param edgeName the name of the edge, one of {@link #EAST}, + * {@link #WEST}, {@link NORTH} or {@link SOUTH}. + * @return the constraint of the edge <code>edgeName</code> of the + * component c. + */ + public Spring getConstraint(String edgeName, Component c) + { + Constraints constraints = getConstraints(c); + return constraints.getConstraint(edgeName); + } + + /** + * Returns the {@link Constraints} object associated with the specified + * component. + * + * @param c the component for which to determine the constraint. + * @return the {@link Constraints} object associated with the specified + * component. + */ + public SpringLayout.Constraints getConstraints(Component c) + { + Constraints constraints = (Constraints) constraintsMap.get(c); + if (constraints == null) + { + Container parent = c.getParent(); + constraints = new Constraints(); + if (parent != null) + { + constraints.setX + (Spring.constant(parent.getInsets().left)); + constraints.setY + (Spring.constant(parent.getInsets().top)); + } + else + { + constraints.setX + (Spring.constant(0)); + constraints.setY + (Spring.constant(0)); + + } + constraints.setWidth + (Spring.constant(c.getMinimumSize().width, + c.getPreferredSize().width, + c.getMaximumSize().width)); + constraints.setHeight + (Spring.constant(c.getMinimumSize().height, + c.getPreferredSize().height, + c.getMaximumSize().height)); + + constraintsMap.put(c, constraints); + + } + + return constraints; + } + + /** + * Returns the X alignment of the Container <code>p</code>. + * + * @param p the {@link java.awt.Container} for which to determine the X + * alignment. + * @return always 0.0 + */ + public float getLayoutAlignmentX(Container p) + { + return 0.0F; + } + + /** + * Returns the Y alignment of the Container <code>p</code>. + * + * @param p the {@link java.awt.Container} for which to determine the Y + * alignment. + * @return always 0.0 + */ + public float getLayoutAlignmentY(Container p) + { + return 0.0F; + } + + /** + * Recalculate a possibly cached layout. + */ + public void invalidateLayout(Container p) + { + // nothing to do here yet + } + + /** + * Lays out the container <code>p</code>. + * + * @param p the container to be laid out. + */ + public void layoutContainer(Container p) + { + + addLayoutComponent(p, new Constraints(Spring.constant(0), + Spring.constant(0))); + + int offsetX = p.getInsets().left; + int offsetY = p.getInsets().right; + + Component[] components = p.getComponents(); + for (int index = 0; index < components.length; index++) + { + Component c = components[index]; + Constraints constraints = getConstraints(c); + int x = constraints.getX().getValue(); + int y = constraints.getY().getValue(); + int width = constraints.getWidth().getValue(); + int height = constraints.getHeight().getValue(); + + c.setLocation(x + offsetX, y + offsetY); + c.setSize(width, height); + } + + } + + /** + * Calculates the maximum size of the layed out container. This + * respects the maximum sizes of all contained components. + * + * @param p the container to be laid out. + * @return the maximum size of the container. + */ + public Dimension maximumLayoutSize(Container p) + { + int maxX = 0; + int maxY = 0; + + int offsetX = p.getInsets().left; + int offsetY = p.getInsets().right; + + Component[] components = p.getComponents(); + for (int index = 0; index < components.length; index++) + { + Component c = components[index]; + Constraints constraints = getConstraints(c); + int x = constraints.getX().getMaximumValue(); + int y = constraints.getY().getMaximumValue(); + int width = constraints.getWidth().getMaximumValue(); + int height = constraints.getHeight().getMaximumValue(); + + int rightEdge = offsetX + x + width; + if (rightEdge > maxX) + maxX = rightEdge; + int bottomEdge = offsetY + y + height; + if (bottomEdge > maxY) + maxY = bottomEdge; + } + + return new Dimension(maxX, maxY); + } + + + /** + * Calculates the minimum size of the layed out container. This + * respects the minimum sizes of all contained components. + * + * @param p the container to be laid out. + * @return the minimum size of the container. + */ + public Dimension minimumLayoutSize(Container p) + { + int maxX = 0; + int maxY = 0; + + int offsetX = p.getInsets().left; + int offsetY = p.getInsets().right; + + Component[] components = p.getComponents(); + for (int index = 0; index < components.length; index++) + { + Component c = components[index]; + Constraints constraints = getConstraints(c); + int x = constraints.getX().getMinimumValue(); + int y = constraints.getY().getMinimumValue(); + int width = constraints.getWidth().getMinimumValue(); + int height = constraints.getHeight().getMinimumValue(); + + int rightEdge = offsetX + x + width; + if (rightEdge > maxX) + maxX = rightEdge; + int bottomEdge = offsetY + y + height; + if (bottomEdge > maxY) + maxY = bottomEdge; + } + + return new Dimension(maxX, maxY); + } + + /** + * Calculates the preferred size of the layed out container. This + * respects the preferred sizes of all contained components. + * + * @param p the container to be laid out. + * @return the preferred size of the container. + */ + public Dimension preferredLayoutSize(Container p) + { + int maxX = 0; + int maxY = 0; + + int offsetX = p.getInsets().left; + int offsetY = p.getInsets().right; + + Component[] components = p.getComponents(); + for (int index = 0; index < components.length; index++) + { + Component c = components[index]; + Constraints constraints = getConstraints(c); + int x = constraints.getX().getPreferredValue(); + int y = constraints.getY().getPreferredValue(); + int width = constraints.getWidth().getPreferredValue(); + int height = constraints.getHeight().getPreferredValue(); + + int rightEdge = offsetX + x + width; + if (rightEdge > maxX) + maxX = rightEdge; + int bottomEdge = offsetY + y + height; + if (bottomEdge > maxY) + maxY = bottomEdge; + } + + return new Dimension(maxX, maxY); + } + + /** + * Attaches the edge <code>e1</code> of component <code>c1</code> to + * the edge <code>e2</code> of component <code>c2</code> width the + * fixed strut <code>pad</code>. + * + * @param e1 the edge of component 1. + * @param c1 the component 1. + * @param pad the space between the components in pixels. + * @param e2 the edge of component 2. + * @param c2 the component 2. + */ + public void putConstraint(String e1, Component c1, int pad, String e2, + Component c2) + { + Constraints constraints1 = getConstraints(c1); + Constraints constraints2 = getConstraints(c2); + + Spring strut = Spring.constant(pad); + Spring otherEdge = constraints2.getConstraint(e2); + constraints1.setConstraint(e1, Spring.sum(strut, otherEdge)); + + } + + /** + * Attaches the edge <code>e1</code> of component <code>c1</code> to + * the edge <code>e2</code> of component <code>c2</code> width the + * {@link Spring} <code>s</code>. + * + * @param e1 the edge of component 1. + * @param c1 the component 1. + * @param s the space between the components as a {@link Spring} object. + * @param e2 the edge of component 2. + * @param c2 the component 2. + */ + public void putConstraint(String e1, Component c1, Spring s, String e2, + Component c2) + { + Constraints constraints1 = getConstraints(c1); + Constraints constraints2 = getConstraints(c2); + + Spring otherEdge = constraints2.getConstraint(e2); + constraints1.setConstraint(e1, Spring.sum(s, otherEdge)); + + } + + /** + * Removes a layout component. + * @param c the layout component to remove. + */ + public void removeLayoutComponent(Component c) + { + // do nothing here + } +} diff --git a/libjava/classpath/javax/swing/SwingConstants.java b/libjava/classpath/javax/swing/SwingConstants.java new file mode 100644 index 00000000000..bed8a467b15 --- /dev/null +++ b/libjava/classpath/javax/swing/SwingConstants.java @@ -0,0 +1,77 @@ +/* SwingConstants.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +/** + * Defines constant values that are used throughout the Swing packages. + */ +public interface SwingConstants +{ + int CENTER = 0; + int TOP = 1; + int LEFT = 2; + int BOTTOM = 3; + int RIGHT = 4; + + int NORTH = 1; + int NORTH_EAST = 2; + int EAST = 3; + int SOUTH_EAST = 4; + int SOUTH = 5; + int SOUTH_WEST = 6; + int WEST = 7; + int NORTH_WEST = 8; + + int HORIZONTAL = 0; + int VERTICAL = 1; + + int LEADING = 10; + int TRAILING = 11; + + /** + * @since 1.4 + */ + int NEXT = 12; + + /** + * @since 1.4 + */ + int PREVIOUS = 13; +} + diff --git a/libjava/classpath/javax/swing/SwingUtilities.java b/libjava/classpath/javax/swing/SwingUtilities.java new file mode 100644 index 00000000000..69b634579e5 --- /dev/null +++ b/libjava/classpath/javax/swing/SwingUtilities.java @@ -0,0 +1,1395 @@ +/* SwingUtilities.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.applet.Applet; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleStateSet; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.InputMapUIResource; + +/** + * This class contains a number of static utility functions which are + * useful when drawing swing components, dispatching events, or calculating + * regions which need painting. + * + * @author Graydon Hoare (graydon@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class SwingUtilities + implements SwingConstants +{ + /** + * This frame should be used as parent for JWindow or JDialog + * that doesn't an owner + */ + private static OwnerFrame ownerFrame; + + private SwingUtilities() + { + // Do nothing. + } + + /** + * Calculates the portion of the base rectangle which is inside the + * insets. + * + * @param base The rectangle to apply the insets to + * @param insets The insets to apply to the base rectangle + * @param ret A rectangle to use for storing the return value, or + * <code>null</code> + * + * @return The calculated area inside the base rectangle and its insets, + * either stored in ret or a new Rectangle if ret is <code>null</code> + * + * @see #calculateInnerArea + */ + public static Rectangle calculateInsetArea(Rectangle base, Insets insets, + Rectangle ret) + { + if (ret == null) + ret = new Rectangle(); + ret.setBounds(base.x + insets.left, base.y + insets.top, + base.width - (insets.left + insets.right), + base.height - (insets.top + insets.bottom)); + return ret; + } + + /** + * Calculates the portion of the component's bounds which is inside the + * component's border insets. This area is usually the area a component + * should confine its painting to. The coordinates are returned in terms + * of the <em>component's</em> coordinate system, where (0,0) is the + * upper left corner of the component's bounds. + * + * @param c The component to measure the bounds of + * @param r A Rectangle to store the return value in, or + * <code>null</code> + * + * @return The calculated area inside the component and its border + * insets + * + * @see #calculateInsetArea + */ + public static Rectangle calculateInnerArea(JComponent c, Rectangle r) + { + Rectangle b = getLocalBounds(c); + return calculateInsetArea(b, c.getInsets(), r); + } + + /** + * Returns the focus owner or <code>null</code> if <code>comp</code> is not + * the focus owner or a parent of it. + * + * @param comp the focus owner or a parent of it + * + * @return the focus owner, or <code>null</code> + * + * @deprecated 1.4 Replaced by + * <code>KeyboardFocusManager.getFocusOwner()</code>. + */ + public static Component findFocusOwner(Component comp) + { + // Get real focus owner. + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getFocusOwner(); + + // Check if comp is the focus owner or a parent of it. + Component tmp = focusOwner; + + while (tmp != null) + { + if (tmp == comp) + return focusOwner; + + tmp = tmp.getParent(); + } + + return null; + } + + /** + * Returns the <code>Accessible</code> child of the specified component + * which appears at the supplied <code>Point</code>. If there is no + * child located at that particular pair of co-ordinates, null is returned + * instead. + * + * @param c the component whose children may be found at the specified + * point. + * @param p the point at which to look for the existence of children + * of the specified component. + * @return the <code>Accessible</code> child at the point, <code>p</code>, + * or null if there is no child at this point. + * @see javax.accessibility.AccessibleComponent#getAccessibleAt + */ + public static Accessible getAccessibleAt(Component c, Point p) + { + return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p); + } + + /** + * <p> + * Returns the <code>Accessible</code> child of the specified component + * that has the supplied index within the parent component. The indexing + * of the children is zero-based, making the first child have an index of + * 0. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose child should be returned. + * @param i the index of the child within the parent component. + * @return the <code>Accessible</code> child at index <code>i</code> + * in the component, <code>c</code>. + * @see javax.accessibility.AccessibleContext#getAccessibleChild + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChild + */ + public static Accessible getAccessibleChild(Component c, int i) + { + return c.getAccessibleContext().getAccessibleChild(i); + } + + /** + * <p> + * Returns the number of <code>Accessible</code> children within + * the supplied component. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose children should be counted. + * @return the number of children belonging to the component, + * <code>c</code>. + * @see javax.accessibility.AccessibleContext#getAccessibleChildrenCount + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleChildrenCount + */ + public static int getAccessibleChildrenCount(Component c) + { + return c.getAccessibleContext().getAccessibleChildrenCount(); + } + + /** + * <p> + * Returns the zero-based index of the specified component + * within its parent. If the component doesn't have a parent, + * -1 is returned. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose parental index should be found. + * @return the index of the component within its parent, or -1 + * if the component doesn't have a parent. + * @see javax.accessibility.AccessibleContext#getAccessibleIndexInParent + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleIndexInParent + */ + public static int getAccessibleIndexInParent(Component c) + { + return c.getAccessibleContext().getAccessibleIndexInParent(); + } + + /** + * <p> + * Returns a set of <code>AccessibleState</code>s, which represent + * the state of the supplied component. + * </p> + * <p> + * Caution is advised when using this method, as its operation relies + * on the behaviour of varying implementations of an abstract method. + * For greater surety, direct use of the AWT component implementation + * of this method is advised. + * </p> + * + * @param c the component whose accessible state should be retrieved. + * @return a set of <code>AccessibleState</code> objects, which represent + * the state of the supplied component. + * @see javax.accessibility.AccessibleContext#getAccessibleStateSet + * @see java.awt.Component.AccessibleAWTComponent#getAccessibleStateSet + */ + public static AccessibleStateSet getAccessibleStateSet(Component c) + { + return c.getAccessibleContext().getAccessibleStateSet(); + } + + /** + * Calculates the bounds of a component in the component's own coordinate + * space. The result has the same height and width as the component's + * bounds, but its location is set to (0,0). + * + * @param aComponent The component to measure + * + * @return The component's bounds in its local coordinate space + */ + public static Rectangle getLocalBounds(Component aComponent) + { + Rectangle bounds = aComponent.getBounds(); + return new Rectangle(0, 0, bounds.width, bounds.height); + } + + /** + * If <code>comp</code> is a RootPaneContainer, return its JRootPane. + * Otherwise call <code>getAncestorOfClass(JRootPane.class, a)</code>. + * + * @param comp The component to get the JRootPane of + * + * @return a suitable JRootPane for <code>comp</code>, or <code>null</code> + * + * @see javax.swing.RootPaneContainer#getRootPane + * @see #getAncestorOfClass + */ + public static JRootPane getRootPane(Component comp) + { + if (comp instanceof RootPaneContainer) + return ((RootPaneContainer)comp).getRootPane(); + else + return (JRootPane) getAncestorOfClass(JRootPane.class, comp); + } + + /** + * Returns the least ancestor of <code>comp</code> which has the + * specified name. + * + * @param name The name to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of <code>comp</code> with the given + * name, or <code>null</code> if no such ancestor exists + * + * @see java.awt.Component#getName + * @see #getAncestorOfClass + */ + public static Container getAncestorNamed(String name, Component comp) + { + while (comp != null && (comp.getName() != name)) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Returns the least ancestor of <code>comp</code> which is an instance + * of the specified class. + * + * @param c The class to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of <code>comp</code> which is an instance + * of the given class, or <code>null</code> if no such ancestor exists + * + * @see #getAncestorOfClass + * @see #windowForComponent + */ + public static Container getAncestorOfClass(Class c, Component comp) + { + while (comp != null && (! c.isInstance(comp))) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Returns the first ancestor of <code>comp</code> that is a {@link Window} + * or <code>null</code> if <code>comp</code> is not contained in a + * {@link Window}. + * + * This is equivalent to calling + * <code>getAncestorOfClass(Window, comp)</code> or + * <code>windowForComponent(comp)</code>. + * + * @param comp the component for which we are searching the ancestor Window + * + * @return the first ancestor Window of <code>comp</code> or + * <code>null</code> if <code>comp</code> is not contained in a Window + */ + public static Window getWindowAncestor(Component comp) + { + return (Window) getAncestorOfClass(Window.class, comp); + } + + /** + * Equivalent to calling <code>getAncestorOfClass(Window, comp)</code>. + * + * @param comp The component to search for an ancestor window + * + * @return An ancestral window, or <code>null</code> if none exists + */ + public static Window windowForComponent(Component comp) + { + return (Window) getAncestorOfClass(Window.class, comp); + } + + /** + * Returns the "root" of the component tree containint <code>comp</code> + * The root is defined as either the <em>least</em> ancestor of + * <code>comp</code> which is a {@link Window}, or the <em>greatest</em> + * ancestor of <code>comp</code> which is a {@link Applet} if no {@link + * Window} ancestors are found. + * + * @param comp The component to search for a root + * + * @return The root of the component's tree, or <code>null</code> + */ + public static Component getRoot(Component comp) + { + Applet app = null; + Window win = null; + + while (comp != null) + { + if (win == null && comp instanceof Window) + win = (Window) comp; + else if (comp instanceof Applet) + app = (Applet) comp; + comp = comp.getParent(); + } + + if (win != null) + return win; + else + return app; + } + + /** + * Return true if a descends from b, in other words if b is an + * ancestor of a. + * + * @param a The child to search the ancestry of + * @param b The potential ancestor to search for + * + * @return true if a is a descendent of b, false otherwise + */ + public static boolean isDescendingFrom(Component a, Component b) + { + while (true) + { + if (a == null || b == null) + return false; + if (a == b) + return true; + a = a.getParent(); + } + } + + /** + * Returns the deepest descendent of parent which is both visible and + * contains the point <code>(x,y)</code>. Returns parent when either + * parent is not a container, or has no children which contain + * <code>(x,y)</code>. Returns <code>null</code> when either + * <code>(x,y)</code> is outside the bounds of parent, or parent is + * <code>null</code>. + * + * @param parent The component to search the descendents of + * @param x Horizontal coordinate to search for + * @param y Vertical coordinate to search for + * + * @return A component containing <code>(x,y)</code>, or + * <code>null</code> + * + * @see java.awt.Container#findComponentAt + */ + public static Component getDeepestComponentAt(Component parent, int x, int y) + { + if (parent == null || (! parent.contains(x, y))) + return null; + + if (! (parent instanceof Container)) + return parent; + + Container c = (Container) parent; + return c.findComponentAt(x, y); + } + + /** + * Converts a point from a component's local coordinate space to "screen" + * coordinates (such as the coordinate space mouse events are delivered + * in). This operation is equivalent to translating the point by the + * location of the component (which is the origin of its coordinate + * space). + * + * @param p The point to convert + * @param c The component which the point is expressed in terms of + * + * @see convertPointFromScreen + */ + public static void convertPointToScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(c0.x, c0.y); + } + + /** + * Converts a point from "screen" coordinates (such as the coordinate + * space mouse events are delivered in) to a component's local coordinate + * space. This operation is equivalent to translating the point by the + * negation of the component's location (which is the origin of its + * coordinate space). + * + * @param p The point to convert + * @param c The component which the point should be expressed in terms of + */ + public static void convertPointFromScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(-c0.x, -c0.y); + } + + /** + * Converts a point <code>(x,y)</code> from the coordinate space of one + * component to another. This is equivalent to converting the point from + * <code>source</code> space to screen space, then back from screen space + * to <code>destination</code> space. If exactly one of the two + * Components is <code>null</code>, it is taken to refer to the root + * ancestor of the other component. If both are <code>null</code>, no + * transformation is done. + * + * @param source The component which the point is expressed in terms of + * @param x Horizontal coordinate of point to transform + * @param y Vertical coordinate of point to transform + * @param destination The component which the return value will be + * expressed in terms of + * + * @return The point <code>(x,y)</code> converted from the coordinate space of the + * source component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertRectangle + * @see #getRoot + */ + public static Point convertPoint(Component source, int x, int y, + Component destination) + { + Point pt = new Point(x, y); + + if (source == null && destination == null) + return pt; + + if (source == null) + source = getRoot(destination); + + if (destination == null) + destination = getRoot(source); + + if (source.isShowing() && destination.isShowing()) + { + convertPointToScreen(pt, source); + convertPointFromScreen(pt, destination); + } + + return pt; + } + + public static Point convertPoint(Component source, Point aPoint, Component destination) + { + return convertPoint(source, aPoint.x, aPoint.y, destination); + } + + /** + * Converts a rectangle from the coordinate space of one component to + * another. This is equivalent to converting the rectangle from + * <code>source</code> space to screen space, then back from screen space + * to <code>destination</code> space. If exactly one of the two + * Components is <code>null</code>, it is taken to refer to the root + * ancestor of the other component. If both are <code>null</code>, no + * transformation is done. + * + * @param source The component which the rectangle is expressed in terms of + * @param rect The rectangle to convert + * @param destination The component which the return value will be + * expressed in terms of + * + * @return A new rectangle, equal in size to the input rectangle, but + * with its position converted from the coordinate space of the source + * component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertPoint + * @see #getRoot + */ + public static Rectangle convertRectangle(Component source, + Rectangle rect, + Component destination) + { + Point pt = convertPoint(source, rect.x, rect.y, destination); + return new Rectangle(pt.x, pt.y, rect.width, rect.height); + } + + /** + * Convert a mouse event which refrers to one component to another. This + * includes changing the mouse event's coordinate space, as well as the + * source property of the event. If <code>source</code> is + * <code>null</code>, it is taken to refer to <code>destination</code>'s + * root component. If <code>destination</code> is <code>null</code>, the + * new event will remain expressed in <code>source</code>'s coordinate + * system. + * + * @param source The component the mouse event currently refers to + * @param sourceEvent The mouse event to convert + * @param destination The component the new mouse event should refer to + * + * @return A new mouse event expressed in terms of the destination + * component's coordinate space, and with the destination component as + * its source + * + * @see #convertPoint + */ + public static MouseEvent convertMouseEvent(Component source, + MouseEvent sourceEvent, + Component destination) + { + Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(), + destination); + + return new MouseEvent(destination, sourceEvent.getID(), + sourceEvent.getWhen(), sourceEvent.getModifiersEx(), + newpt.x, newpt.y, sourceEvent.getClickCount(), + sourceEvent.isPopupTrigger(), sourceEvent.getButton()); + } + + /** + * Recursively walk the component tree under <code>comp</code> calling + * <code>updateUI</code> on each {@link JComponent} found. This causes + * the entire tree to re-initialize its UI delegates. + * + * @param comp The component to walk the children of, calling <code>updateUI</code> + */ + public static void updateComponentTreeUI(Component comp) + { + if (comp == null) + return; + + if (comp instanceof Container) + { + Component[] children = ((Container)comp).getComponents(); + for (int i = 0; i < children.length; ++i) + updateComponentTreeUI(children[i]); + } + + if (comp instanceof JComponent) + ((JComponent)comp).updateUI(); + } + + + /** + * <p>Layout a "compound label" consisting of a text string and an icon + * which is to be placed near the rendered text. Once the text and icon + * are laid out, the text rectangle and icon rectangle parameters are + * altered to store the calculated positions.</p> + * + * <p>The size of the text is calculated from the provided font metrics + * object. This object should be the metrics of the font you intend to + * paint the label with.</p> + * + * <p>The position values control where the text is placed relative to + * the icon. The horizontal position value should be one of the constants + * <code>LEADING</code>, <code>TRAILING</code>, <code>LEFT</code>, + * <code>RIGHT</code> or <code>CENTER</code>. The vertical position value + * should be one fo the constants <code>TOP</code>, <code>BOTTOM</code> + * or <code>CENTER</code>.</p> + * + * <p>The text-icon gap value controls the number of pixels between the + * icon and the text.</p> + * + * <p>The alignment values control where the text and icon are placed, as + * a combined unit, within the view rectangle. The horizontal alignment + * value should be one of the constants <code>LEADING</code>, + * <code>TRAILING</code>, <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. The vertical alignment valus should be one of the + * constants <code>TOP</code>, <code>BOTTOM</code> or + * <code>CENTER</code>.</p> + * + * <p>If the <code>LEADING</code> or <code>TRAILING</code> constants are + * given for horizontal alignment or horizontal text position, they are + * interpreted relative to the provided component's orientation property, + * a constant in the {@link java.awt.ComponentOrientation} class. For + * example, if the component's orientation is <code>LEFT_TO_RIGHT</code>, + * then the <code>LEADING</code> value is a synonym for <code>LEFT</code> + * and the <code>TRAILING</code> value is a synonym for + * <code>RIGHT</code></p> + * + * <p>If the text and icon are equal to or larger than the view + * rectangle, the horizontal and vertical alignment values have no + * affect.</p> + * + * @param c A component used for its orientation value + * @param fm The font metrics used to measure the text + * @param text The text to place in the compound label + * @param icon The icon to place next to the text + * @param verticalAlignment The vertical alignment of the label relative + * to its component + * @param horizontalAlignment The horizontal alignment of the label + * relative to its component + * @param verticalTextPosition The vertical position of the label's text + * relative to its icon + * @param horizontalTextPosition The horizontal position of the label's + * text relative to its icon + * @param viewR The view rectangle, specifying the area which layout is + * constrained to + * @param iconR A rectangle which is modified to hold the laid-out + * position of the icon + * @param textR A rectangle which is modified to hold the laid-out + * position of the text + * @param textIconGap The distance between text and icon + * + * @return The string of characters, possibly truncated with an elipsis, + * which is laid out in this label + */ + + public static String layoutCompoundLabel(JComponent c, + FontMetrics fm, + String text, + Icon icon, + int verticalAlignment, + int horizontalAlignment, + int verticalTextPosition, + int horizontalTextPosition, + Rectangle viewR, + Rectangle iconR, + Rectangle textR, + int textIconGap) + { + + // Fix up the orientation-based horizontal positions. + + if (horizontalTextPosition == LEADING) + { + if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) + horizontalTextPosition = RIGHT; + else + horizontalTextPosition = LEFT; + } + else if (horizontalTextPosition == TRAILING) + { + if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) + horizontalTextPosition = LEFT; + else + horizontalTextPosition = RIGHT; + } + + // Fix up the orientation-based alignments. + + if (horizontalAlignment == LEADING) + { + if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) + horizontalAlignment = RIGHT; + else + horizontalAlignment = LEFT; + } + else if (horizontalAlignment == TRAILING) + { + if (c.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT) + horizontalAlignment = LEFT; + else + horizontalAlignment = RIGHT; + } + + return layoutCompoundLabel(fm, text, icon, + verticalAlignment, + horizontalAlignment, + verticalTextPosition, + horizontalTextPosition, + viewR, iconR, textR, textIconGap); + } + + /** + * <p>Layout a "compound label" consisting of a text string and an icon + * which is to be placed near the rendered text. Once the text and icon + * are laid out, the text rectangle and icon rectangle parameters are + * altered to store the calculated positions.</p> + * + * <p>The size of the text is calculated from the provided font metrics + * object. This object should be the metrics of the font you intend to + * paint the label with.</p> + * + * <p>The position values control where the text is placed relative to + * the icon. The horizontal position value should be one of the constants + * <code>LEFT</code>, <code>RIGHT</code> or <code>CENTER</code>. The + * vertical position value should be one fo the constants + * <code>TOP</code>, <code>BOTTOM</code> or <code>CENTER</code>.</p> + * + * <p>The text-icon gap value controls the number of pixels between the + * icon and the text.</p> + * + * <p>The alignment values control where the text and icon are placed, as + * a combined unit, within the view rectangle. The horizontal alignment + * value should be one of the constants <code>LEFT</code>, <code>RIGHT</code> or + * <code>CENTER</code>. The vertical alignment valus should be one of the + * constants <code>TOP</code>, <code>BOTTOM</code> or + * <code>CENTER</code>.</p> + * + * <p>If the text and icon are equal to or larger than the view + * rectangle, the horizontal and vertical alignment values have no + * affect.</p> + * + * <p>Note that this method does <em>not</em> know how to deal with + * horizontal alignments or positions given as <code>LEADING</code> or + * <code>TRAILING</code> values. Use the other overloaded variant of this + * method if you wish to use such values. + * + * @param fm The font metrics used to measure the text + * @param text The text to place in the compound label + * @param icon The icon to place next to the text + * @param verticalAlignment The vertical alignment of the label relative + * to its component + * @param horizontalAlignment The horizontal alignment of the label + * relative to its component + * @param verticalTextPosition The vertical position of the label's text + * relative to its icon + * @param horizontalTextPosition The horizontal position of the label's + * text relative to its icon + * @param viewR The view rectangle, specifying the area which layout is + * constrained to + * @param iconR A rectangle which is modified to hold the laid-out + * position of the icon + * @param textR A rectangle which is modified to hold the laid-out + * position of the text + * @param textIconGap The distance between text and icon + * + * @return The string of characters, possibly truncated with an elipsis, + * which is laid out in this label + */ + + public static String layoutCompoundLabel(FontMetrics fm, + String text, + Icon icon, + int verticalAlignment, + int horizontalAlignment, + int verticalTextPosition, + int horizontalTextPosition, + Rectangle viewR, + Rectangle iconR, + Rectangle textR, + int textIconGap) + { + + // Work out basic height and width. + + if (icon == null) + { + textIconGap = 0; + iconR.width = 0; + iconR.height = 0; + } + else + { + iconR.width = icon.getIconWidth(); + iconR.height = icon.getIconHeight(); + } + if (text == null) + { + textIconGap = 0; + textR.width = 0; + textR.height = 0; + } + else + { + int fromIndex = 0; + textR.width = fm.stringWidth(text); + textR.height = fm.getHeight(); + while (text.indexOf('\n', fromIndex) != -1) + { + textR.height += fm.getHeight(); + fromIndex = text.indexOf('\n', fromIndex) + 1; + } + } + + // Work out the position of text and icon, assuming the top-left coord + // starts at (0,0). We will fix that up momentarily, after these + // "position" decisions are made and we look at alignment. + + switch (horizontalTextPosition) + { + case LEFT: + textR.x = 0; + iconR.x = textR.width + textIconGap; + break; + case RIGHT: + iconR.x = 0; + textR.x = iconR.width + textIconGap; + break; + case CENTER: + int centerLine = Math.max(textR.width, iconR.width) / 2; + textR.x = centerLine - textR.width/2; + iconR.x = centerLine - iconR.width/2; + break; + } + + switch (verticalTextPosition) + { + case TOP: + textR.y = 0; + iconR.y = (horizontalTextPosition == CENTER + ? textR.height + textIconGap : 0); + break; + case BOTTOM: + iconR.y = 0; + textR.y = (horizontalTextPosition == CENTER + ? iconR.height + textIconGap + : iconR.height - textR.height); + break; + case CENTER: + int centerLine = Math.max(textR.height, iconR.height) / 2; + textR.y = centerLine - textR.height/2; + iconR.y = centerLine - iconR.height/2; + break; + } + // The two rectangles are laid out correctly now, but only assuming + // that their upper left corner is at (0,0). If we have any alignment other + // than TOP and LEFT, we need to adjust them. + + Rectangle u = textR.union(iconR); + int horizontalAdjustment = viewR.x; + int verticalAdjustment = viewR.y; + switch (verticalAlignment) + { + case TOP: + break; + case BOTTOM: + verticalAdjustment += (viewR.height - u.height); + break; + case CENTER: + verticalAdjustment += ((viewR.height/2) - (u.height/2)); + break; + } + switch (horizontalAlignment) + { + case LEFT: + break; + case RIGHT: + horizontalAdjustment += (viewR.width - u.width); + break; + case CENTER: + horizontalAdjustment += ((viewR.width/2) - (u.width/2)); + break; + } + + iconR.x += horizontalAdjustment; + iconR.y += verticalAdjustment; + + textR.x += horizontalAdjustment; + textR.y += verticalAdjustment; + + return text; + } + + /** + * Calls {@link java.awt.EventQueue.invokeLater} with the + * specified {@link Runnable}. + */ + public static void invokeLater(Runnable doRun) + { + java.awt.EventQueue.invokeLater(doRun); + } + + /** + * Calls {@link java.awt.EventQueue.invokeAndWait} with the + * specified {@link Runnable}. + */ + public static void invokeAndWait(Runnable doRun) + throws InterruptedException, + InvocationTargetException + { + java.awt.EventQueue.invokeAndWait(doRun); + } + + /** + * Calls {@link java.awt.EventQueue.isEventDispatchThread}. + */ + public static boolean isEventDispatchThread() + { + return java.awt.EventQueue.isDispatchThread(); + } + + /** + * This method paints the given component at the given position and size. + * The component will be reparented to the container given. + * + * @param g The Graphics object to draw with. + * @param c The Component to draw + * @param p The Container to reparent to. + * @param x The x coordinate to draw at. + * @param y The y coordinate to draw at. + * @param w The width of the drawing area. + * @param h The height of the drawing area. + */ + public static void paintComponent(Graphics g, Component c, Container p, + int x, int y, int w, int h) + { + Container parent = c.getParent(); + if (parent != null) + parent.remove(c); + if (p != null) + p.add(c); + + Shape savedClip = g.getClip(); + + g.setClip(x, y, w, h); + g.translate(x, y); + + c.paint(g); + + g.translate(-x, -y); + g.setClip(savedClip); + } + + /** + * This method paints the given component in the given rectangle. + * The component will be reparented to the container given. + * + * @param g The Graphics object to draw with. + * @param c The Component to draw + * @param p The Container to reparent to. + * @param r The rectangle that describes the drawing area. + */ + public static void paintComponent(Graphics g, Component c, + Container p, Rectangle r) + { + paintComponent(g, c, p, r.x, r.y, r.width, r.height); + } + + /** + * This method returns the common Frame owner used in JDialogs or + * JWindow when no owner is provided. + * + * @return The common Frame + */ + static Frame getOwnerFrame() + { + if (ownerFrame == null) + ownerFrame = new OwnerFrame(); + return ownerFrame; + } + + /** + * Checks if left mouse button was clicked. + * + * @param event the event to check + * + * @return true if left mouse was clicked, false otherwise. + */ + public static boolean isLeftMouseButton(MouseEvent event) + { + return ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) + == InputEvent.BUTTON1_DOWN_MASK); + } + + /** + * Checks if middle mouse button was clicked. + * + * @param event the event to check + * + * @return true if middle mouse was clicked, false otherwise. + */ + public static boolean isMiddleMouseButton(MouseEvent event) + { + return ((event.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) + == InputEvent.BUTTON2_DOWN_MASK); + } + + /** + * Checks if right mouse button was clicked. + * + * @param event the event to check + * + * @return true if right mouse was clicked, false otherwise. + */ + public static boolean isRightMouseButton(MouseEvent event) + { + return ((event.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) + == InputEvent.BUTTON3_DOWN_MASK); + } + + /** + * This frame should be used when constructing a Window/JDialog without + * a parent. In this case, we are forced to use this frame as a window's + * parent, because we simply cannot pass null instead of parent to Window + * constructor, since doing it will result in NullPointerException. + */ + private static class OwnerFrame extends Frame + { + public void setVisible(boolean b) + { + // Do nothing here. + } + + public boolean isShowing() + { + return true; + } + } + + public static boolean notifyAction(Action action, + KeyStroke ks, + KeyEvent event, + Object sender, + int modifiers) + { + if (action != null && action.isEnabled()) + { + String name = (String) action.getValue(Action.ACTION_COMMAND_KEY); + if (name == null + && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) + name = new String(new char[] {event.getKeyChar()}); + action.actionPerformed(new ActionEvent(sender, + ActionEvent.ACTION_PERFORMED, + name, modifiers)); + return true; + } + return false; + } + + /** + * <p>Change the shared, UI-managed {@link ActionMap} for a given + * component. ActionMaps are arranged in a hierarchy, in order to + * encourage sharing of common actions between components. The hierarchy + * unfortunately places UI-managed ActionMaps at the <em>end</em> of the + * parent-pointer chain, as illustrated:</p> + * + * <pre> + * [{@link javax.swing.JComponent#getActionMap()}] + * --> [{@link javax.swing.ActionMap}] + * parent --> [{@link javax.swing.text.KeymapActionMap}] + * parent --> [{@link javax.swing.plaf.ActionMapUIResource}] + * </pre> + * + * <p>Our goal with this method is to replace the first ActionMap along + * this chain which is an instance of {@link ActionMapUIResource}, since + * these are the ActionMaps which are supposed to be shared between + * components.</p> + * + * <p>If the provided ActionMap is <code>null</code>, we interpret the + * call as a request to remove the UI-managed ActionMap from the + * component's ActionMap parent chain.</p> + */ + public static void replaceUIActionMap(JComponent component, + ActionMap uiActionMap) + { + ActionMap child = component.getActionMap(); + if (child == null) + component.setActionMap(uiActionMap); + else + { + ActionMap parent = child.getParent(); + while(parent != null) + { + child = parent; + parent = child.getParent(); + } + + if (child != null) + child.setParent(uiActionMap); + } + } + + /** + * <p>Change the shared, UI-managed {@link InputMap} for a given + * component. InputMaps are arranged in a hierarchy, in order to + * encourage sharing of common input mappings between components. The + * hierarchy unfortunately places UI-managed InputMaps at the + * <em>end</em> of the parent-pointer chain, as illustrated:</p> + * + * <pre> + * [{@link javax.swing.JComponent#getInputMap()}] + * --> [{@link javax.swing.InputMap}] + * parent --> [{@link javax.swing.text.KeymapWrapper}] + * parent --> [{@link javax.swing.plaf.InputMapUIResource}] + * </pre> + * + * <p>Our goal with this method is to replace the first InputMap along + * this chain which is an instance of {@link InputMapUIResource}, since + * these are the InputMaps which are supposed to be shared between + * components.</p> + * + * <p>If the provided InputMap is <code>null</code>, we interpret the + * call as a request to remove the UI-managed InputMap from the + * component's InputMap parent chain.</p> + */ + public static void replaceUIInputMap(JComponent component, + int condition, + InputMap uiInputMap) + { + InputMap child = component.getInputMap(condition); + if (child == null) + component.setInputMap(condition, uiInputMap); + else + { + while(child.getParent() != null + && !(child.getParent() instanceof InputMapUIResource)) + child = child.getParent(); + if (child != null) + child.setParent(uiInputMap); + } + } + + /** + * Subtracts a rectangle from another and return the area as an array + * of rectangles. + * Returns the areas of rectA which are not covered by rectB. + * If the rectangles do not overlap, or if either parameter is + * <code>null</code>, a zero-size array is returned. + * @param rectA The first rectangle + * @param rectB The rectangle to subtract from the first + * @return An array of rectangles representing the area in rectA + * not overlapped by rectB + */ + public static Rectangle[] computeDifference(Rectangle rectA, Rectangle rectB) + { + if (rectA == null || rectB == null) + return new Rectangle[0]; + + Rectangle[] r = new Rectangle[4]; + int x1 = rectA.x; + int y1 = rectA.y; + int w1 = rectA.width; + int h1 = rectA.height; + int x2 = rectB.x; + int y2 = rectB.y; + int w2 = rectB.width; + int h2 = rectB.height; + + // (outer box = rectA) + // ------------- + // |_____0_____| + // | |rectB| | + // |_1|_____|_2| + // | 3 | + // ------------- + int H0 = (y2 > y1) ? y2 - y1 : 0; // height of box 0 + int H3 = (y2 + h2 < y1 + h1) ? y1 + h1 - y2 - h2 : 0; // height box 3 + int W1 = (x2 > x1) ? x2 - x1 : 0; // width box 1 + int W2 = (x1 + w1 > x2 + w2) ? x1 + w1 - x2 - w2 : 0; // w. box 2 + int H12 = (H0 + H3 < h1) ? h1 - H0 - H3 : 0; // height box 1 & 2 + + if (H0 > 0) + r[0] = new Rectangle(x1, y1, w1, H0); + else + r[0] = null; + + if (W1 > 0 && H12 > 0) + r[1] = new Rectangle(x1, y1 + H0, W1, H12); + else + r[1] = null; + + if (W2 > 0 && H12 > 0) + r[2] = new Rectangle(x2 + w2, y1 + H0, W2, H12); + else + r[2] = null; + + if (H3 > 0) + r[3] = new Rectangle(x1, y1 + H0 + H12, w1, H3); + else + r[3] = null; + + // sort out null objects + int n = 0; + for (int i = 0; i < 4; i++) + if (r[i] != null) + n++; + Rectangle[] out = new Rectangle[n]; + for (int i = 3; i >= 0; i--) + if (r[i] != null) + out[--n] = r[i]; + + return out; + } + + /** + * Calculates the intersection of two rectangles. + * + * @param x upper-left x coodinate of first rectangle + * @param x upper-left y coodinate of first rectangle + * @param w width of first rectangle + * @param h height of first rectangle + * @param rect a Rectangle object of the second rectangle + * @throws a NullPointerException if rect is null. + * + * @return a rectangle corresponding to the intersection of the + * two rectangles. A zero rectangle is returned if the rectangles + * do not overlap. + */ + public static Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.getX(); + int y2 = (int) rect.getY(); + int w2 = (int) rect.getWidth(); + int h2 = (int) rect.getHeight(); + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + return new Rectangle(dx, dy, dw, dh); + + return new Rectangle(0, 0, 0, 0); + } + + /** + * Calculates the width of a given string. + * + * @param fm the <code>FontMetrics</code> object to use + * @param str the string + * + * @return the width of the the string. + */ + public static int computeStringWidth(FontMetrics fm, String str) + { + return fm.stringWidth(str); + } + + /** + * Calculates the union of two rectangles. + * + * @param x upper-left x coodinate of first rectangle + * @param x upper-left y coodinate of first rectangle + * @param w width of first rectangle + * @param h height of first rectangle + * @param rect a Rectangle object of the second rectangle + * @throws a NullPointerException if rect is null. + * + * @return a rectangle corresponding to the union of the + * two rectangles. A rectangle encompassing both is returned if the + * rectangles do not overlap. + */ + public static Rectangle computeUnion(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = (int) rect.getX(); + int y2 = (int) rect.getY(); + int w2 = (int) rect.getWidth(); + int h2 = (int) rect.getHeight(); + + int dx = (x < x2) ? x : x2; + int dy = (y < y2) ? y : y2; + int dw = (x + w > x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h > y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + return new Rectangle(dx, dy, dw, dh); + + return new Rectangle(0, 0, 0, 0); + } + + /** + * Tests if a rectangle contains another. + * @param a first rectangle + * @param b second rectangle + * @return true if a contains b, false otherwise + * @throws NullPointerException + */ + public static boolean isRectangleContainingRectangle(Rectangle a, Rectangle b) + { + // Note: zero-size rects inclusive, differs from Rectangle.contains() + return b.width >= 0 && b.height >= 0 && b.width >= 0 && b.height >= 0 + && b.x >= a.x && b.x + b.width <= a.x + a.width && b.y >= a.y + && b.y + b.height <= a.y + a.height; + } + + /** + * Returns the InputMap that is provided by the ComponentUI of + * <code>component</code> for the specified condition. + * + * @param component the component for which the InputMap is returned + * @param cond the condition that specifies which of the three input + * maps should be returned, may be + * {@link JComponent#WHEN_IN_FOCUSED_WINDOW}, + * {@link JComponent#WHEN_FOCUSED} or + * {@link JComponent#WHEN_ANCESTOR_OF_FOCUSED_COMPONENT + * + * @return + */ + public static InputMap getUIInputMap(JComponent component, int cond) + { + if (UIManager.getUI(component) != null) + // we assume here that the UI class sets the parent of the component's + // InputMap, which is the correct behaviour. If it's not, then + // this can be considered a bug + return component.getInputMap(cond).getParent(); + else + return null; + } + + /** + * Returns the ActionMap that is provided by the ComponentUI of + * <code>component</code>. + * + * @param component the component for which the ActionMap is returned + */ + public static ActionMap getUIActionMap(JComponent component) + { + if (UIManager.getUI(component) != null) + // we assume here that the UI class sets the parent of the component's + // ActionMap, which is the correct behaviour. If it's not, then + // this can be considered a bug + return component.getActionMap().getParent(); + else + return null; + } +} diff --git a/libjava/classpath/javax/swing/Timer.java b/libjava/classpath/javax/swing/Timer.java new file mode 100644 index 00000000000..87f420a4367 --- /dev/null +++ b/libjava/classpath/javax/swing/Timer.java @@ -0,0 +1,485 @@ +/* Timer.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.EventListenerList; + +/** + * Fires one or more action events after the specified delay. + * @author Ronald Veldema + * @author Audrius Meskauskas (audriusa@Bionformatics.org) - bug fixes + * and documentation comments + */ +public class Timer + implements Serializable +{ + /** + * The timer thread + */ + private class Waker + extends Thread + { + /** + * Fires events, pausing for required intervals. + */ + public void run() + { + running = true; + try + { + sleep(initialDelay); + + queueEvent(); + + while (running) + { + try + { + sleep(delay); + } + catch (InterruptedException e) + { + return; + } + queueEvent(); + + if (logTimers) + System.out.println("javax.swing.Timer -> clocktick"); + + if ( ! repeats) + break; + } + running = false; + } + catch (Exception e) + { + // The timer is no longer running. + running = false; + } + } + } + + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = -1116180831621385484L; + + /** + * The encloding class, used with {@link SwingUtilities#invokeLater} + * to invoke the {@link #drainEvents()}. + */ + private Runnable drainer = new Runnable() + { + public void run() + { + drainEvents(); + } + }; + + /** + * If <code>true</code>, the timer prints a message to + * {@link System#out} when firing each event. + */ + static boolean logTimers; + + /** + * A field to store all listeners who are listening to this timer. + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * <code>true</code> if the timer coalesces events. + */ + boolean coalesce = true; + + /** + * <code>true</code> if the timer is firing repetetive events. + */ + boolean repeats = true; + + /** + * <code>true</code> if the timer is currently active, firing events + * as scheduled. + */ + boolean running; + + /** + * The delay between subsequent repetetive events. + */ + int delay; + + /** + * The initial delay before the first event. + */ + int initialDelay; + + /** + * The number of events that have been already fired by this timer. + * This is used as a numeric identifier for the next event that would + * be fired. + */ + int ticks; + + /** + * Stores the thread that posts events to the queue at required time + * intervals. + */ + private Waker waker; + + /** + * This object manages a "queue" of virtual actionEvents, maintained as a + * simple long counter. When the timer expires, a new event is queued, + * and a dispatcher object is pushed into the system event queue. When + * the system thread runs the dispatcher, it will fire as many + * ActionEvents as have been queued, unless the timer is set to + * coalescing mode, in which case it will fire only one ActionEvent. + */ + private long queue; + + /** + * <code>synchronized(queueLock)</code> replaces + * <code>synchronized(queue)</code> that is not supported by this language. + */ + private Object queueLock = new Object(); + + /** + * Creates a new Timer object. + * + * @param d the default value for both initial and between event delay, in + * milliseconds. + * @param listener the first action listener, can be <code>null</code>. + */ + public Timer(int d, ActionListener listener) + { + delay = d; + initialDelay = d; + + if (listener != null) + addActionListener(listener); + } + + /** + * Get the array of action listeners. + * + * @return the array of action listeners that are listening for the events, + * fired by this timer + * + * @since 1.4 + */ + public ActionListener[] getActionListeners() + { + return (ActionListener[]) listenerList.getListeners(ActionListener.class); + } + + /** + * Sets whether the Timer coalesces multiple pending event firings. + * If the coalescing is enabled, the multiple events that have not been + * fired on time are replaced by the single event. The events may not + * be fired on time if the application is busy. + * + * @param c <code>true</code> (default) to enable the event coalescing, + * <code>false</code> otherwise + */ + public void setCoalesce(boolean c) + { + coalesce = c; + } + + /** + * Checks if the Timer coalesces multiple pending event firings. + * If the coalescing is enabled, the multiple events that have not been + * fired on time are replaced by the single event. The events may not + * be fired on time if the application is busy. + * + * @return <code>true</code> if the coalescing is enabled, + * <code>false</code> otherwise + */ + public boolean isCoalesce() + { + return coalesce; + } + + /** + * Get the event listeners of the given type that are listening for the + * events, fired by this timer. + * + * @param listenerType the listener type (for example, ActionListener.class) + * + * @return the array of event listeners that are listening for the events, + * fired by this timer + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Set the timer logging state. If it is set to <code>true</code>, the + * timer prints a message to {@link System#out} when firing each + * action event. + * + * @param lt <code>true</code> if logging is enabled, <code>false</code> + * (default value) otherwise + */ + public static void setLogTimers(boolean lt) + { + logTimers = lt; + } + + /** + * Return the logging state. + * + * @return <code>true</code> if the timer is printing a message to + * {@link System#out} + * when firing each action event + */ + public static boolean getLogTimers() + { + return logTimers; + } + + /** + * Set the delay between firing the subsequent events. + * This parameter does not change the value of the initial delay before + * firing the first event. + * + * @param d The time gap between the subsequent events, in milliseconds + */ + public void setDelay(int d) + { + delay = d; + } + + /** + * Get the delay between firing the subsequent events. + * + * @return The delay between subsequent events, in milliseconds + */ + public int getDelay() + { + return delay; + } + + /** + * Set the intial delay before firing the first event since calling + * the {@link #start()} method. If the initial delay has not been + * set, it is assumed having the same value as the delay between the + * subsequent events. + * + * @param i the initial delay, in milliseconds + */ + public void setInitialDelay(int i) + { + initialDelay = i; + } + + /** + * Get the intial delay before firing the first event since calling + * the {@link #start()} method. If the initial delay has not been + * set, returns the same value as {@link #getDelay()}. + * + * @return the initial delay before firing the first action event. + */ + public int getInitialDelay() + { + return initialDelay; + } + + /** + * Enable firing the repetetive events. + * + * @param r <code>true</code> (default value) to fire repetetive events. + * <code>false</code> to fire + * only one event after the initial delay + */ + public void setRepeats(boolean r) + { + repeats = r; + } + + /** + * Check is this timer fires repetetive events. + * + * @return <code>true</code> if the timer fires repetetive events, + * <code>false</code> if it fires + * only one event after the initial delay + */ + public boolean isRepeats() + { + return repeats; + } + + /** + * Get the timer state. + * + * @return <code>true</code> if the timer has been started and is firing + * the action events as scheduled. <code>false</code> + * if the timer is inactive. + */ + public boolean isRunning() + { + return running; + } + + /** + * Add the action listener + * + * @param listener the action listener to add + */ + public void addActionListener(ActionListener listener) + { + listenerList.add(ActionListener.class, listener); + } + + /** + * Remove the action listener. + * + * @param listener the action listener to remove + */ + public void removeActionListener(ActionListener listener) + { + listenerList.remove(ActionListener.class, listener); + } + + /** + * Cancel all pending tasks and fire the first event after the initial + * delay. + */ + public void restart() + { + stop(); + start(); + } + + /** + * Start firing the action events. + */ + public void start() + { + if (isRunning()) + return; + waker = new Waker(); + waker.start(); + } + + /** + * Stop firing the action events. + */ + public void stop() + { + running = false; + if (waker != null) + waker.interrupt(); + synchronized (queueLock) + { + queue = 0; + } + } + + /** + * Fire the given action event to the action listeners. + * + * @param event the event to fire + */ + protected void fireActionPerformed(ActionEvent event) + { + ActionListener[] listeners = getActionListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners [ i ].actionPerformed(event); + } + + /** + * Fire the action event, named "Timer" and having the numeric + * identifier, equal to the numer of events that have been + * already fired before. + */ + void fireActionPerformed() + { + fireActionPerformed(new ActionEvent(this, ticks++, "Timer")); + } + + /** + * Fire the queued action events. + * In the coalescing mode, a single event is fired as a replacement + * for all queued events. In non coalescing mode, a series of + * all queued events is fired. + * This is package-private to avoid an accessor method. + */ + void drainEvents() + { + synchronized (queueLock) + { + if (isCoalesce()) + { + if (queue > 0) + fireActionPerformed(); + } + else + { + while (queue > 0) + { + fireActionPerformed(); + queue--; + } + } + queue = 0; + } + } + + /** + * Post a scheduled event to the event queue. + * Package-private to avoid an accessor method. + */ + void queueEvent() + { + synchronized (queueLock) + { + queue++; + if (queue == 1) + SwingUtilities.invokeLater(drainer); + } + } +} diff --git a/libjava/classpath/javax/swing/ToolTipManager.java b/libjava/classpath/javax/swing/ToolTipManager.java new file mode 100644 index 00000000000..61693763898 --- /dev/null +++ b/libjava/classpath/javax/swing/ToolTipManager.java @@ -0,0 +1,646 @@ +/* ToolTipManager.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.LayoutManager; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; + +/** + * This class is responsible for the registration of JToolTips to Components + * and for displaying them when appropriate. + */ +public class ToolTipManager extends MouseAdapter implements MouseMotionListener +{ + /** + * This ActionListener is associated with the Timer that listens to whether + * the JToolTip can be hidden after four seconds. + */ + protected class stillInsideTimerAction implements ActionListener + { + /** + * This method creates a new stillInsideTimerAction object. + */ + protected stillInsideTimerAction() + { + } + + /** + * This method hides the JToolTip when the Timer has finished. + * + * @param event The ActionEvent. + */ + public void actionPerformed(ActionEvent event) + { + hideTip(); + } + } + + /** + * This Actionlistener is associated with the Timer that listens to whether + * the mouse cursor has re-entered the JComponent in time for an immediate + * redisplay of the JToolTip. + */ + protected class outsideTimerAction implements ActionListener + { + /** + * This method creates a new outsideTimerAction object. + */ + protected outsideTimerAction() + { + } + + /** + * This method is called when the Timer that listens to whether the mouse + * cursor has re-entered the JComponent has run out. + * + * @param event The ActionEvent. + */ + public void actionPerformed(ActionEvent event) + { + } + } + + /** + * This ActionListener is associated with the Timer that listens to whether + * it is time for the JToolTip to be displayed after the mouse has entered + * the JComponent. + */ + protected class insideTimerAction implements ActionListener + { + /** + * This method creates a new insideTimerAction object. + */ + protected insideTimerAction() + { + } + + /** + * This method displays the JToolTip when the Mouse has been still for the + * delay. + * + * @param event The ActionEvent. + */ + public void actionPerformed(ActionEvent event) + { + showTip(); + if (insideTimer != null) + insideTimer.start(); + } + } + + /** + * The Timer that determines whether the Mouse has been still long enough + * for the JToolTip to be displayed. + */ + Timer enterTimer; + + /** + * The Timer that determines whether the Mouse has re-entered the JComponent + * quickly enough for the JToolTip to be displayed immediately. + */ + Timer exitTimer; + + /** + * The Timer that determines whether the JToolTip has been displayed long + * enough for it to be hidden. + */ + Timer insideTimer; + + /** A global enabled setting for the ToolTipManager. */ + private transient boolean enabled = true; + + /** lightWeightPopupEnabled */ + protected boolean lightWeightPopupEnabled = true; + + /** heavyWeightPopupEnabled */ + protected boolean heavyWeightPopupEnabled = false; + + /** The shared instance of the ToolTipManager. */ + private static ToolTipManager shared; + + /** The current component the tooltip is being displayed for. */ + private static Component currentComponent; + + /** The current tooltip. */ + private static JToolTip currentTip; + + /** The last known position of the mouse cursor. */ + private static Point currentPoint; + + /** + * The panel that holds the tooltip when the tooltip is displayed fully + * inside the current container. + */ + private static Container containerPanel; + + /** + * The window used when the tooltip doesn't fit inside the current + * container. + */ + private static JWindow tooltipWindow; + + /** + * Creates a new ToolTipManager and sets up the timers. + */ + ToolTipManager() + { + enterTimer = new Timer(750, new insideTimerAction()); + enterTimer.setRepeats(false); + + insideTimer = new Timer(4000, new stillInsideTimerAction()); + insideTimer.setRepeats(false); + + exitTimer = new Timer(500, new outsideTimerAction()); + exitTimer.setRepeats(false); + } + + /** + * This method returns the shared instance of ToolTipManager used by all + * JComponents. + * + * @return The shared instance of ToolTipManager. + */ + public static ToolTipManager sharedInstance() + { + if (shared == null) + shared = new ToolTipManager(); + + return shared; + } + + /** + * This method sets whether ToolTips are enabled or disabled for all + * JComponents. + * + * @param enabled Whether ToolTips are enabled or disabled for all + * JComponents. + */ + public void setEnabled(boolean enabled) + { + if (! enabled) + { + enterTimer.stop(); + exitTimer.stop(); + insideTimer.stop(); + } + + this.enabled = enabled; + } + + /** + * This method returns whether ToolTips are enabled. + * + * @return Whether ToolTips are enabled. + */ + public boolean isEnabled() + { + return enabled; + } + + /** + * This method returns whether LightweightToolTips are enabled. + * + * @return Whether LighweightToolTips are enabled. + */ + public boolean isLightWeightPopupEnabled() + { + return lightWeightPopupEnabled; + } + + /** + * This method sets whether LightweightToolTips are enabled. If you mix + * Lightweight and Heavyweight components, you must set this to false to + * ensure that the ToolTips popup above all other components. + * + * @param enabled Whether LightweightToolTips will be enabled. + */ + public void setLightWeightPopupEnabled(boolean enabled) + { + lightWeightPopupEnabled = enabled; + heavyWeightPopupEnabled = ! enabled; + } + + /** + * This method returns the initial delay before the ToolTip is shown when + * the mouse enters a Component. + * + * @return The initial delay before the ToolTip is shown. + */ + public int getInitialDelay() + { + return enterTimer.getDelay(); + } + + /** + * This method sets the initial delay before the ToolTip is shown when the + * mouse enters a Component. + * + * @param delay The initial delay before the ToolTip is shown. + */ + public void setInitialDelay(int delay) + { + enterTimer.setDelay(delay); + } + + /** + * This method returns the time the ToolTip will be shown before being + * hidden. + * + * @return The time the ToolTip will be shown before being hidden. + */ + public int getDismissDelay() + { + return insideTimer.getDelay(); + } + + /** + * This method sets the time the ToolTip will be shown before being hidden. + * + * @param delay The time the ToolTip will be shown before being hidden. + */ + public void setDismissDelay(int delay) + { + insideTimer.setDelay(delay); + } + + /** + * This method returns the amount of delay where if the mouse re-enters a + * Component, the tooltip will be shown immediately. + * + * @return The reshow delay. + */ + public int getReshowDelay() + { + return exitTimer.getDelay(); + } + + /** + * This method sets the amount of delay where if the mouse re-enters a + * Component, the tooltip will be shown immediately. + * + * @param delay The reshow delay. + */ + public void setReshowDelay(int delay) + { + exitTimer.setDelay(delay); + } + + /** + * This method registers a JComponent with the ToolTipManager. + * + * @param component The JComponent to register with the ToolTipManager. + */ + public void registerComponent(JComponent component) + { + component.addMouseListener(this); + component.addMouseMotionListener(this); + } + + /** + * This method unregisters a JComponent with the ToolTipManager. + * + * @param component The JComponent to unregister with the ToolTipManager. + */ + public void unregisterComponent(JComponent component) + { + component.removeMouseMotionListener(this); + component.removeMouseListener(this); + } + + /** + * This method is called whenever the mouse enters a JComponent registered + * with the ToolTipManager. When the mouse enters within the period of time + * specified by the reshow delay, the tooltip will be displayed + * immediately. Otherwise, it must wait for the initial delay before + * displaying the tooltip. + * + * @param event The MouseEvent. + */ + public void mouseEntered(MouseEvent event) + { + if (currentComponent != null + && getContentPaneDeepestComponent(event) == currentComponent) + return; + currentPoint = event.getPoint(); + currentComponent = (Component) event.getSource(); + + if (exitTimer.isRunning()) + { + exitTimer.stop(); + showTip(); + insideTimer.start(); + return; + } + + // This should always be stopped unless we have just fake-exited. + if (! enterTimer.isRunning()) + enterTimer.start(); + } + + /** + * This method is called when the mouse exits a JComponent registered with + * the ToolTipManager. When the mouse exits, the tooltip should be hidden + * immediately. + * + * @param event The MouseEvent. + */ + public void mouseExited(MouseEvent event) + { + if (getContentPaneDeepestComponent(event) == currentComponent) + return; + + currentPoint = event.getPoint(); + currentComponent = null; + hideTip(); + + if (! enterTimer.isRunning() && insideTimer.isRunning()) + exitTimer.start(); + if (enterTimer.isRunning()) + enterTimer.stop(); + if (insideTimer.isRunning()) + insideTimer.stop(); + } + + /** + * This method is called when the mouse is pressed on a JComponent + * registered with the ToolTipManager. When the mouse is pressed, the + * tooltip (if it is shown) must be hidden immediately. + * + * @param event The MouseEvent. + */ + public void mousePressed(MouseEvent event) + { + currentPoint = event.getPoint(); + if (enterTimer.isRunning()) + enterTimer.restart(); + else if (insideTimer.isRunning()) + { + insideTimer.stop(); + hideTip(); + } + + if (currentComponent == null) + currentComponent = (Component) event.getSource(); + + currentComponent.invalidate(); + currentComponent.validate(); + currentComponent.repaint(); + } + + /** + * This method is called when the mouse is dragged in a JComponent + * registered with the ToolTipManager. + * + * @param event The MouseEvent. + */ + public void mouseDragged(MouseEvent event) + { + currentPoint = event.getPoint(); + if (enterTimer.isRunning()) + enterTimer.restart(); + } + + /** + * This method is called when the mouse is moved in a JComponent registered + * with the ToolTipManager. + * + * @param event The MouseEvent. + */ + public void mouseMoved(MouseEvent event) + { + currentPoint = event.getPoint(); + if (currentTip != null) + { + if (currentComponent == null) + currentComponent = (Component) event.getSource(); + + String text = ((JComponent) currentComponent).getToolTipText(event); + currentTip.setTipText(text); + } + if (enterTimer.isRunning()) + enterTimer.restart(); + } + + /** + * This method displays the ToolTip. It can figure out the method needed to + * show it as well (whether to display it in heavyweight/lightweight panel + * or a window.) This is package-private to avoid an accessor method. + */ + void showTip() + { + if (! enabled || currentComponent == null) + return; + + if (currentTip == null + || currentTip.getComponent() != currentComponent + && currentComponent instanceof JComponent) + currentTip = ((JComponent) currentComponent).createToolTip(); + Point p = currentPoint; + Dimension dims = currentTip.getPreferredSize(); + if (canToolTipFit(currentTip)) + { + JLayeredPane pane = ((JRootPane) SwingUtilities.getAncestorOfClass(JRootPane.class, + currentComponent)) + .getLayeredPane(); + + // This should never happen, but just in case. + if (pane == null) + return; + + if (containerPanel != null) + hideTip(); + if (isLightWeightPopupEnabled()) + { + containerPanel = new Panel(); + JRootPane root = new JRootPane(); + root.getContentPane().add(currentTip); + containerPanel.add(root); + } + else + { + containerPanel = new JPanel(); + containerPanel.add(currentTip); + } + LayoutManager lm = containerPanel.getLayout(); + if (lm instanceof FlowLayout) + { + FlowLayout fm = (FlowLayout) lm; + fm.setVgap(0); + fm.setHgap(0); + } + + p = getGoodPoint(p, pane, currentTip, dims); + + pane.add(containerPanel); + containerPanel.setBounds(p.x, p.y, dims.width, dims.height); + currentTip.setBounds(0, 0, dims.width, dims.height); + + pane.revalidate(); + pane.repaint(); + } + else + { + SwingUtilities.convertPointToScreen(p, currentComponent); + tooltipWindow = new JWindow(); + tooltipWindow.getContentPane().add(currentTip); + tooltipWindow.setFocusable(false); + tooltipWindow.pack(); + tooltipWindow.setBounds(p.x, p.y, dims.width, dims.height); + tooltipWindow.show(); + } + currentTip.setVisible(true); + } + + /** + * This method hides the ToolTip. + * This is package-private to avoid an accessor method. + */ + void hideTip() + { + if (currentTip == null || ! currentTip.isVisible() || ! enabled) + return; + currentTip.setVisible(false); + if (containerPanel != null) + { + Container parent = containerPanel.getParent(); + if (parent == null) + return; + parent.remove(containerPanel); + parent.invalidate(); + parent.validate(); + parent.repaint(); + + parent = currentTip.getParent(); + if (parent == null) + return; + parent.remove(currentTip); + + containerPanel = null; + } + if (tooltipWindow != null) + { + tooltipWindow.hide(); + tooltipWindow.dispose(); + tooltipWindow = null; + } + } + + /** + * This method returns a point in the LayeredPane where the ToolTip can be + * shown. The point returned (if the ToolTip is to be displayed at the + * preferred dimensions) will always place the ToolTip inside the + * currentComponent if possible. + * + * @param p The last known good point for the mouse. + * @param c The JLayeredPane in the first RootPaneContainer up from the + * currentComponent. + * @param tip The ToolTip to display. + * @param dims The ToolTip preferred dimensions (can be null). + * + * @return A good point to place the ToolTip. + */ + private Point getGoodPoint(Point p, JLayeredPane c, JToolTip tip, + Dimension dims) + { + if (dims == null) + dims = tip.getPreferredSize(); + Rectangle bounds = currentComponent.getBounds(); + if (p.x + dims.width > bounds.width) + p.x = bounds.width - dims.width; + if (p.y + dims.height > bounds.height) + p.y = bounds.height - dims.height; + + p = SwingUtilities.convertPoint(currentComponent, p, c); + return p; + } + + /** + * This method returns the deepest component in the content pane for the + * first RootPaneContainer up from the currentComponent. This method is + * used in conjunction with one of the mouseXXX methods. + * + * @param e The MouseEvent. + * + * @return The deepest component in the content pane. + */ + private Component getContentPaneDeepestComponent(MouseEvent e) + { + Component source = (Component) e.getSource(); + Container parent = (Container) SwingUtilities.getAncestorOfClass(JRootPane.class, + currentComponent); + if (parent == null) + return null; + parent = ((JRootPane) parent).getContentPane(); + Point p = e.getPoint(); + p = SwingUtilities.convertPoint(source, p, parent); + Component target = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); + return target; + } + + /** + * This method returns whether the ToolTip can fit in the first + * RootPaneContainer up from the currentComponent. + * + * @param tip The ToolTip. + * + * @return Whether the ToolTip can fit. + */ + private boolean canToolTipFit(JToolTip tip) + { + JRootPane root = (JRootPane) SwingUtilities.getAncestorOfClass(JRootPane.class, + currentComponent); + if (root == null) + return false; + Dimension pref = tip.getPreferredSize(); + Dimension rootSize = root.getSize(); + if (rootSize.width > pref.width && rootSize.height > pref.height) + return true; + return false; + } +} diff --git a/libjava/classpath/javax/swing/TransferHandler.java b/libjava/classpath/javax/swing/TransferHandler.java new file mode 100644 index 00000000000..96cb9d42abf --- /dev/null +++ b/libjava/classpath/javax/swing/TransferHandler.java @@ -0,0 +1,190 @@ +/* TransferHandler.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.io.Serializable; + +public class TransferHandler implements Serializable +{ + static class TransferAction extends AbstractAction + { + private String command; + + public TransferAction(String command) + { + this.command = command; + } + + public void actionPerformed(ActionEvent event) + { + JComponent component = (JComponent) event.getSource(); + TransferHandler transferHandler = component.getTransferHandler(); + Clipboard clipboard = getClipboard(component); + + if (command.equals(COMMAND_COPY)) + transferHandler.exportToClipboard(component, clipboard, COPY); + else if (command.equals(COMMAND_CUT)) + transferHandler.exportToClipboard(component, clipboard, MOVE); + else if (command.equals(COMMAND_PASTE)) + { + Transferable transferable = clipboard.getContents(null); + + if (transferable != null) + transferHandler.importData(component, transferable); + } + } + + private static Clipboard getClipboard(JComponent component) + { + SecurityManager sm = System.getSecurityManager(); + + if (sm != null) + { + try + { + sm.checkSystemClipboardAccess(); + + // We may access system clipboard. + return component.getToolkit().getSystemClipboard(); + } + catch (SecurityException e) + { + // We may not access system clipboard. + } + } + + // Create VM-local clipboard if non exists yet. + if (clipboard == null) + clipboard = new Clipboard("Clipboard"); + + return clipboard; + } + } + + private static final long serialVersionUID = -967749805571669910L; + + private static final String COMMAND_COPY = "copy"; + private static final String COMMAND_CUT = "cut"; + private static final String COMMAND_PASTE = "paste"; + + public static final int NONE = 0; + public static final int COPY = 1; + public static final int MOVE = 2; + public static final int COPY_OR_MOVE = 3; + + private static Action copyAction = new TransferAction(COMMAND_COPY); + private static Action cutAction = new TransferAction(COMMAND_CUT); + private static Action pasteAction = new TransferAction(COMMAND_PASTE); + + /** + * Clipboard if system clipboard may not be used. + * Package-private to avoid an accessor method. + */ + static Clipboard clipboard; + + private int sourceActions; + private Icon visualRepresentation; + + public static Action getCopyAction() + { + return copyAction; + } + + public static Action getCutAction() + { + return cutAction; + } + + public static Action getPasteAction() + { + return pasteAction; + } + + protected TransferHandler() + { + this.sourceActions = NONE; + } + + public TransferHandler(String property) + { + this.sourceActions = property != null ? COPY : NONE; + } + + public boolean canImport (JComponent c, DataFlavor[] flavors) + { + return false; + } + + protected Transferable createTransferable(JComponent c) + { + return null; + } + + public void exportAsDrag (JComponent c, InputEvent e, int action) + { + } + + protected void exportDone (JComponent c, Transferable data, int action) + { + } + + public void exportToClipboard(JComponent c, Clipboard clip, int action) + { + } + + public int getSourceActions (JComponent c) + { + return sourceActions; + } + + public Icon getVisualRepresentation (Transferable t) + { + return visualRepresentation; + } + + public boolean importData (JComponent c, Transferable t) + { + return false; + } +} diff --git a/libjava/classpath/javax/swing/UIDefaults.java b/libjava/classpath/javax/swing/UIDefaults.java new file mode 100644 index 00000000000..06fee05c658 --- /dev/null +++ b/libjava/classpath/javax/swing/UIDefaults.java @@ -0,0 +1,842 @@ +/* UIDefaults.java -- database for all settings and interface bindings. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Insets; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.lang.reflect.Method; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.ListIterator; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; + +/** + * UIDefaults is a database where all settings and interface bindings are + * stored into. A PLAF implementation fills one of these (see for example + * plaf/basic/BasicLookAndFeel.java) with "ButtonUI" -> new BasicButtonUI(). + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public class UIDefaults extends Hashtable +{ + + /** Our ResourceBundles. */ + private LinkedList bundles; + + /** The default locale. */ + private Locale defaultLocale; + + /** We use this for firing PropertyChangeEvents. */ + private PropertyChangeSupport propertyChangeSupport; + + /** + * Used for lazy instantiation of UIDefaults values so that they are not + * all loaded when a Swing application starts up, but only the values that + * are really needed. An <code>ActiveValue</code> is newly instantiated + * every time when the value is requested, as opposed to the normal + * {@link LazyValue} that is only instantiated once. + */ + public static interface ActiveValue + { + Object createValue(UIDefaults table); + } + + public static class LazyInputMap implements LazyValue + { + Object[] bind; + public LazyInputMap(Object[] bindings) + { + bind = bindings; + } + public Object createValue(UIDefaults table) + { + InputMap im = new InputMap (); + for (int i = 0; 2*i+1 < bind.length; ++i) + { + im.put (KeyStroke.getKeyStroke ((String) bind[2*i]), + bind[2*i+1]); + } + return im; + } + } + + /** + * Used for lazy instantiation of UIDefaults values so that they are not + * all loaded when a Swing application starts up, but only the values that + * are really needed. A <code>LazyValue</code> is only instantiated once, + * as opposed to the {@link ActiveValue} that is newly created every time + * it is requested. + */ + public static interface LazyValue + { + Object createValue(UIDefaults table); + } + + public static class ProxyLazyValue implements LazyValue + { + LazyValue inner; + public ProxyLazyValue(String s) + { + final String className = s; + inner = new LazyValue () + { + public Object createValue (UIDefaults table) + { + try + { + return Class + .forName(className) + .getConstructor(new Class[] {}) + .newInstance(new Object[] {}); + } + catch (Exception e) + { + return null; + } + } + }; + } + + public ProxyLazyValue(String c, String m) + { + final String className = c; + final String methodName = m; + inner = new LazyValue () + { + public Object createValue (UIDefaults table) + { + try + { + return Class + .forName (className) + .getMethod (methodName, new Class[] {}) + .invoke (null, new Object[] {}); + } + catch (Exception e) + { + return null; + } + } + }; + } + + public ProxyLazyValue(String c, Object[] os) + { + final String className = c; + final Object[] objs = os; + final Class[] clss = new Class[objs.length]; + for (int i = 0; i < objs.length; ++i) + { + clss[i] = objs[i].getClass(); + } + inner = new LazyValue() + { + public Object createValue(UIDefaults table) + { + try + { + return Class + .forName(className) + .getConstructor(clss) + .newInstance(objs); + } + catch (Exception e) + { + return null; + } + } + }; + } + + public ProxyLazyValue(String c, String m, Object[] os) + { + final String className = c; + final String methodName = m; + final Object[] objs = os; + final Class[] clss = new Class[objs.length]; + for (int i = 0; i < objs.length; ++i) + { + clss[i] = objs[i].getClass(); + } + inner = new LazyValue() + { + public Object createValue(UIDefaults table) + { + try + { + return Class + .forName(className) + .getMethod(methodName, clss) + .invoke(null, objs); + } + catch (Exception e) + { + return null; + } + } + }; + } + + public Object createValue(UIDefaults table) + { + return inner.createValue(table); + } + } + + /** Our serialVersionUID for serialization. */ + private static final long serialVersionUID = 7341222528856548117L; + + /** + * Constructs a new empty UIDefaults instance. + */ + public UIDefaults() + { + bundles = new LinkedList(); + defaultLocale = Locale.getDefault(); + propertyChangeSupport = new PropertyChangeSupport(this); + } + + /** + * Constructs a new UIDefaults instance and loads the specified entries. + * The entries are expected to come in pairs, that means + * <code>entries[0]</code> is a key, <code>entries[1]</code> is a value, + * <code>entries[2]</code> a key and so forth. + * + * @param entries the entries to initialize the UIDefaults instance with + */ + public UIDefaults(Object[] entries) + { + this(); + + for (int i = 0; (2 * i + 1) < entries.length; ++i) + put(entries[2 * i], entries[2 * i + 1]); + } + + /** + * Returns the entry for the specified <code>key</code> in the default + * locale. + * + * @return the entry for the specified <code>key</code> + */ + public Object get(Object key) + { + return this.get(key, getDefaultLocale()); + } + + /** + * Returns the entry for the specified <code>key</code> in the Locale + * <code>loc</code>. + * + * @param key the key for which we return the value + * @param loc the locale + */ + public Object get(Object key, Locale loc) + { + Object obj = null; + + if (super.containsKey(key)) + { + obj = super.get(key); + } + else if (key instanceof String) + { + String keyString = (String) key; + ListIterator i = bundles.listIterator(0); + while (i.hasNext()) + { + String bundle_name = (String) i.next(); + ResourceBundle res = + ResourceBundle.getBundle(bundle_name, loc); + if (res != null) + { + try + { + obj = res.getObject(keyString); + break; + } + catch (MissingResourceException me) + { + // continue, this bundle has no such key + } + } + } + } + + // now we've found the object, resolve it. + // nb: LazyValues aren't supported in resource bundles, so it's correct + // to insert their results in the locale-less hashtable. + + if (obj == null) + return null; + + if (obj instanceof LazyValue) + { + Object resolved = ((LazyValue) obj).createValue(this); + super.remove(key); + super.put(key, resolved); + return resolved; + } + else if (obj instanceof ActiveValue) + { + return ((ActiveValue) obj).createValue(this); + } + + return obj; + } + + /** + * Puts a key and value into this UIDefaults object.<br> + * In contrast to + * {@link java.util.Hashtable}s <code>null</code>-values are accepted + * here and treated like #remove(key). + * <br> + * This fires a PropertyChangeEvent with key as name and the old and new + * values. + * + * @param key the key to put into the map + * @param value the value to put into the map + * + * @return the old value for key or <code>null</code> if <code>key</code> + * had no value assigned + */ + public Object put(Object key, Object value) + { + Object old = checkAndPut(key, value); + + if (key instanceof String && old != value) + firePropertyChange((String) key, old, value); + return old; + } + + /** + * Puts a set of key-value pairs into the map. + * The entries are expected to come in pairs, that means + * <code>entries[0]</code> is a key, <code>entries[1]</code> is a value, + * <code>entries[2]</code> a key and so forth. + * <br> + * If a value is <code>null</code> it is treated like #remove(key). + * <br> + * This unconditionally fires a PropertyChangeEvent with + * <code>'UIDefaults'</code> as name and <code>null</code> for + * old and new value. + * + * @param entries the entries to be put into the map + */ + public void putDefaults(Object[] entries) + { + for (int i = 0; (2 * i + 1) < entries.length; ++i) + { + checkAndPut(entries[2 * i], entries[2 * i + 1]); + } + firePropertyChange("UIDefaults", null, null); + } + + /** + * Checks the value for <code>null</code> and put it into the Hashtable, if + * it is not <code>null</code>. If the value is <code>null</code> then + * remove the corresponding key. + * + * @param key the key to put into this UIDefauls table + * @param value the value to put into this UIDefaults table + * + * @return the old value for <code>key</code> + */ + private Object checkAndPut(Object key, Object value) + { + Object old; + + if (value != null) + old = super.put(key, value); + else + old = super.remove(key); + + return old; + } + + /** + * Returns a font entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the font entry for <code>key</code> or null if no such entry + * exists + */ + public Font getFont(Object key) + { + Object o = get(key); + return o instanceof Font ? (Font) o : null; + } + + /** + * Returns a font entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the font entry for <code>key</code> or null if no such entry + * exists + */ + public Font getFont(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Font ? (Font) o : null; + } + + /** + * Returns a color entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the color entry for <code>key</code> or null if no such entry + * exists + */ + public Color getColor(Object key) + { + Object o = get(key); + return o instanceof Color ? (Color) o : null; + } + + /** + * Returns a color entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the color entry for <code>key</code> or null if no such entry + * exists + */ + public Color getColor(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Color ? (Color) o : null; + } + + /** + * Returns an icon entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the icon entry for <code>key</code> or null if no such entry + * exists + */ + public Icon getIcon(Object key) + { + Object o = get(key); + return o instanceof Icon ? (Icon) o : null; + } + + /** + * Returns an icon entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the icon entry for <code>key</code> or null if no such entry + * exists + */ + public Icon getIcon(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Icon ? (Icon) o : null; + } + + /** + * Returns a border entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the border entry for <code>key</code> or null if no such entry + * exists + */ + public Border getBorder(Object key) + { + Object o = get(key); + return o instanceof Border ? (Border) o : null; + } + + /** + * Returns a border entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the border entry for <code>key</code> or null if no such entry + * exists + */ + public Border getBorder(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Border ? (Border) o : null; + } + + /** + * Returns a string entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the string entry for <code>key</code> or null if no such entry + * exists + */ + public String getString(Object key) + { + Object o = get(key); + return o instanceof String ? (String) o : null; + } + + /** + * Returns a string entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the string entry for <code>key</code> or null if no such entry + * exists + */ + public String getString(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof String ? (String) o : null; + } + + /** + * Returns an integer entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the integer entry for <code>key</code> or null if no such entry + * exists + */ + public int getInt(Object key) + { + Object o = get(key); + return o instanceof Integer ? ((Integer) o).intValue() : 0; + } + + /** + * Returns an integer entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the integer entry for <code>key</code> or null if no such entry + * exists + */ + public int getInt(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Integer ? ((Integer) o).intValue() : 0; + } + + /** + * Returns a boolean entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the boolean entry for <code>key</code> or null if no such entry + * exists + */ + public boolean getBoolean(Object key) + { + return Boolean.TRUE.equals(get(key)); + } + + /** + * Returns a boolean entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the boolean entry for <code>key</code> or null if no such entry + * exists + */ + public boolean getBoolean(Object key, Locale l) + { + return Boolean.TRUE.equals(get(key, l)); + } + + /** + * Returns an insets entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the insets entry for <code>key</code> or null if no such entry + * exists + */ + public Insets getInsets(Object key) + { + Object o = get(key); + return o instanceof Insets ? (Insets) o : null; + } + + /** + * Returns an insets entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the boolean entry for <code>key</code> or null if no such entry + * exists + */ + public Insets getInsets(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Insets ? (Insets) o : null; + } + + /** + * Returns a dimension entry for the default locale. + * + * @param key the key to the requested entry + * + * @return the dimension entry for <code>key</code> or null if no such entry + * exists + */ + public Dimension getDimension(Object key) + { + Object o = get(key); + return o instanceof Dimension ? (Dimension) o : null; + } + + /** + * Returns a dimension entry for a specic locale. + * + * @param key the key to the requested entry + * @param locale the locale to the requested entry + * + * @return the boolean entry for <code>key</code> or null if no such entry + * exists + */ + public Dimension getDimension(Object key, Locale l) + { + Object o = get(key, l); + return o instanceof Dimension ? (Dimension) o : null; + } + + /** + * Returns the ComponentUI class that renders a component. <code>id</code> + * is the ID for which the String value of the classname is stored in + * this UIDefaults map. + * + * @param id the ID of the UI class + * @param loader the ClassLoader to use + * + * @return the UI class for <code>id</code> + */ + public Class getUIClass(String id, ClassLoader loader) + { + String className = (String) get (id); + if (className == null) + return null; + try + { + if (loader != null) + return loader.loadClass (className); + return Class.forName (className); + } + catch (Exception e) + { + return null; + } + } + + /** + * Returns the ComponentUI class that renders a component. <code>id</code> + * is the ID for which the String value of the classname is stored in + * this UIDefaults map. + * + * @param id the ID of the UI class + * + * @return the UI class for <code>id</code> + */ + public Class getUIClass(String id) + { + return getUIClass (id, null); + } + + /** + * If a key is requested in #get(key) that has no value, this method + * is called before returning <code>null</code>. + * + * @param msg the error message + */ + protected void getUIError(String msg) + { + System.err.println ("UIDefaults.getUIError: " + msg); + } + + /** + * Returns the {@link ComponentUI} for the specified {@link JComponent}. + * + * @param target the component for which the ComponentUI is requested + * + * @return the {@link ComponentUI} for the specified {@link JComponent} + */ + public ComponentUI getUI(JComponent target) + { + String classId = target.getUIClassID (); + Class cls = getUIClass (classId); + if (cls == null) + { + getUIError ("failed to locate UI class:" + classId); + return null; + } + + Method factory; + + try + { + factory = cls.getMethod ("createUI", new Class[] { JComponent.class } ); + } + catch (NoSuchMethodException nme) + { + getUIError ("failed to locate createUI method on " + cls.toString ()); + return null; + } + + try + { + return (ComponentUI) factory.invoke (null, new Object[] { target }); + } + catch (java.lang.reflect.InvocationTargetException ite) + { + getUIError ("InvocationTargetException ("+ ite.getTargetException() + +") calling createUI(...) on " + cls.toString ()); + return null; + } + catch (Exception e) + { + getUIError ("exception calling createUI(...) on " + cls.toString ()); + return null; + } + } + + /** + * Adds a {@link PropertyChangeListener} to this UIDefaults map. + * Registered PropertyChangeListener are notified when values + * are beeing put into this UIDefaults map. + * + * @param listener the PropertyChangeListener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + propertyChangeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes a PropertyChangeListener from this UIDefaults map. + * + * @param listener the PropertyChangeListener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + propertyChangeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns an array of all registered PropertyChangeListeners. + * + * @return all registered PropertyChangeListeners + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return propertyChangeSupport.getPropertyChangeListeners(); + } + + /** + * Fires a PropertyChangeEvent. + * + * @param property the property name + * @param oldValue the old value + * @param newValue the new value + */ + protected void firePropertyChange(String property, + Object oldValue, Object newValue) + { + propertyChangeSupport.firePropertyChange(property, oldValue, newValue); + } + + /** + * Adds a ResourceBundle for localized values. + * + * @param name the name of the ResourceBundle to add + */ + public void addResourceBundle(String name) + { + bundles.addFirst(name); + } + + /** + * Removes a ResourceBundle. + * + * @param name the name of the ResourceBundle to remove + */ + public void removeResourceBundle(String name) + { + bundles.remove(name); + } + + /** + * Sets the current locale to <code>loc</code>. + * + * @param loc the Locale to be set + */ + public void setDefaultLocale(Locale loc) + { + defaultLocale = loc; + } + + /** + * Returns the current default locale. + * + * @return the current default locale + */ + public Locale getDefaultLocale() + { + return defaultLocale; + } +} diff --git a/libjava/classpath/javax/swing/UIManager.java b/libjava/classpath/javax/swing/UIManager.java new file mode 100644 index 00000000000..7f6d65e74a6 --- /dev/null +++ b/libjava/classpath/javax/swing/UIManager.java @@ -0,0 +1,491 @@ +/* UIManager.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Insets; +import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Locale; + +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.metal.MetalLookAndFeel; + +public class UIManager implements Serializable +{ + public static class LookAndFeelInfo + { + String name, clazz; + + public LookAndFeelInfo(String name, + String clazz) + { + this.name = name; + this.clazz = clazz; + } + + public String getName() + { + return name; + } + + public String getClassName() + { + return clazz; + } + + /** + * Returns a String representation of the LookAndFeelInfo object. + * + * @return a String representation of the LookAndFeelInfo object + */ + public String toString() + { + StringBuffer s = new StringBuffer(); + s.append(getClass().getName()); + s.append('['); + s.append(getName()); + s.append(' '); + s.append(getClassName()); + s.append(']'); + return s.toString(); + } + } + + private static final long serialVersionUID = -5547433830339189365L; + + static LookAndFeelInfo [] installed = { + new LookAndFeelInfo ("Metal", "javax.swing.plaf.metal.MetalLookAndFeel") + }; + + static LookAndFeel[] aux_installed; + + static LookAndFeel look_and_feel = new MetalLookAndFeel(); + + static + { + String defaultlaf = System.getProperty("swing.defaultlaf"); + try { + if (defaultlaf != null) + { + Class lafClass = Class.forName(defaultlaf); + LookAndFeel laf = (LookAndFeel) lafClass.newInstance(); + setLookAndFeel(laf); + } + } + catch (Exception ex) + { + System.err.println("cannot initialize Look and Feel: " + defaultlaf); + System.err.println("errot: " + ex.getMessage()); + System.err.println("falling back to Metal Look and Feel"); + } + } + + public UIManager() + { + // Do nothing here. + } + + /** + * Add a <code>PropertyChangeListener</code> to the listener list. + * + * @param listener the listener to add + */ + public static void addPropertyChangeListener(PropertyChangeListener listener) + { + // FIXME + } + + /** + * Remove a <code>PropertyChangeListener</code> from the listener list. + * + * @param listener the listener to remove + */ + public static void removePropertyChangeListener(PropertyChangeListener listener) + { + // FIXME + } + + /** + * Returns an array of all added <code>PropertyChangeListener</code> objects. + * + * @return an array of listeners + * + * @since 1.4 + */ + public static PropertyChangeListener[] getPropertyChangeListeners() + { + // FIXME + throw new Error ("Not implemented"); + } + + /** + * Add a LookAndFeel to the list of auxiliary look and feels. + */ + public static void addAuxiliaryLookAndFeel (LookAndFeel l) + { + if (aux_installed == null) + { + aux_installed = new LookAndFeel[1]; + aux_installed[0] = l; + return; + } + + LookAndFeel[] T = new LookAndFeel[ aux_installed.length+1 ]; + System.arraycopy(aux_installed, 0, T, 0, aux_installed.length); + aux_installed = T; + aux_installed[aux_installed.length-1] = l; + } + + public static boolean removeAuxiliaryLookAndFeel(LookAndFeel laf) + { + if (aux_installed == null) + return false; + + for (int i=0;i<aux_installed.length;i++) + { + if (aux_installed[i] == laf) + { + aux_installed[ i ] = aux_installed[aux_installed.length-1]; + LookAndFeel[] T = new LookAndFeel[ aux_installed.length-1 ]; + System.arraycopy (aux_installed, 0, T, 0, aux_installed.length-1); + aux_installed = T; + return true; + } + } + return false; + } + + public static LookAndFeel[] getAuxiliaryLookAndFeels() + { + return aux_installed; + } + + public static Object get(Object key) + { + return getLookAndFeel().getDefaults().get(key); + } + + public static Object get(Object key, Locale locale) + { + return getLookAndFeel().getDefaults().get(key ,locale); + } + + /** + * Returns a boolean value from the defaults table, + * <code>false</code> if key is not present. + * + * @since 1.4 + */ + public static boolean getBoolean(Object key) + { + Boolean value = (Boolean) getLookAndFeel().getDefaults().get(key); + return value != null ? value.booleanValue() : false; + } + + /** + * Returns a boolean value from the defaults table, + * <code>false</code> if key is not present. + * + * @since 1.4 + */ + public static boolean getBoolean(Object key, Locale locale) + { + Boolean value = (Boolean) getLookAndFeel().getDefaults().get(key, locale); + return value != null ? value.booleanValue() : false; + } + + /** + * Returns a border from the defaults table. + */ + public static Border getBorder(Object key) + { + return (Border) getLookAndFeel().getDefaults().get(key); + } + + /** + * Returns a border from the defaults table. + * + * @since 1.4 + */ + public static Border getBorder(Object key, Locale locale) + { + return (Border) getLookAndFeel().getDefaults().get(key, locale); + } + + /** + * Returns a drawing color from the defaults table. + */ + public static Color getColor(Object key) + { + return (Color) getLookAndFeel().getDefaults().get(key); + } + + /** + * Returns a drawing color from the defaults table. + */ + public static Color getColor(Object key, Locale locale) + { + return (Color) getLookAndFeel().getDefaults().get(key); + } + + /** + * this string can be passed to Class.forName() + */ + public static String getCrossPlatformLookAndFeelClassName() + { + return "javax.swing.plaf.metal.MetalLookAndFeel"; + } + + /** + * Returns the default values for this look and feel. + */ + public static UIDefaults getDefaults() + { + return getLookAndFeel().getDefaults(); + } + + /** + * Returns a dimension from the defaults table. + */ + public static Dimension getDimension(Object key) + { + return (Dimension) getLookAndFeel().getDefaults().get(key); + } + + /** + * Returns a dimension from the defaults table. + */ + public static Dimension getDimension(Object key, Locale locale) + { + return (Dimension) getLookAndFeel().getDefaults().get(key, locale); + } + + /** + * Retrieves a font from the defaults table of the current + * LookAndFeel. + * + * @param key an Object that specifies the font. Typically, + * this is a String such as + * <code>TitledBorder.font</code>. + */ + public static Font getFont(Object key) + { + return (Font) getLookAndFeel().getDefaults().get(key); + } + + /** + * Retrieves a font from the defaults table of the current + * LookAndFeel. + * + * @param key an Object that specifies the font. Typically, + * this is a String such as + * <code>TitledBorder.font</code>. + */ + public static Font getFont(Object key, Locale locale) + { + return (Font) getLookAndFeel().getDefaults().get(key ,locale); + } + + /** + * Returns an Icon from the defaults table. + */ + public static Icon getIcon(Object key) + { + return (Icon) getLookAndFeel().getDefaults().get(key); + } + + /** + * Returns an Icon from the defaults table. + */ + public static Icon getIcon(Object key, Locale locale) + { + return (Icon) getLookAndFeel().getDefaults().get(key, locale); + } + + /** + * Returns an Insets object from the defaults table. + */ + public static Insets getInsets(Object key) + { + return (Insets) getLookAndFeel().getDefaults().getInsets(key); + } + + /** + * Returns an Insets object from the defaults table. + */ + public static Insets getInsets(Object key, Locale locale) + { + return (Insets) getLookAndFeel().getDefaults().getInsets(key, locale); + } + + public static LookAndFeelInfo[] getInstalledLookAndFeels() + { + return installed; + } + + public static int getInt(Object key) + { + Integer x = (Integer) getLookAndFeel().getDefaults().get(key); + if (x == null) + return 0; + return x.intValue(); + } + + public static int getInt(Object key, Locale locale) + { + Integer x = (Integer) getLookAndFeel().getDefaults().get(key, locale); + if (x == null) + return 0; + return x.intValue(); + } + + public static LookAndFeel getLookAndFeel() + { + return look_and_feel; + } + + /** + * Returns the <code>UIDefaults</code> table of the currently active + * look and feel. + */ + public static UIDefaults getLookAndFeelDefaults() + { + return getLookAndFeel().getDefaults(); + } + + /** + * Returns a string from the defaults table. + */ + public static String getString(Object key) + { + return (String) getLookAndFeel().getDefaults().get(key); + } + + /** + * Returns a string from the defaults table. + */ + public static String getString(Object key, Locale locale) + { + return (String) getLookAndFeel().getDefaults().get(key, locale); + } + + /** + * Returns the name of the LookAndFeel class that implements the + * native systems look and feel if there is one, otherwise the name + * of the default cross platform LookAndFeel class. + */ + public static String getSystemLookAndFeelClassName() + { + return getCrossPlatformLookAndFeelClassName(); + } + + /** + * Returns the Look and Feel object that renders the target component. + */ + public static ComponentUI getUI(JComponent target) + { + return getDefaults().getUI(target); + } + + /** + * Creates a new look and feel and adds it to the current array. + */ + public static void installLookAndFeel(String name, String className) + { + } + + /** + * Adds the specified look and feel to the current array and then calls + * setInstalledLookAndFeels(javax.swing.UIManager.LookAndFeelInfo[]). + */ + public static void installLookAndFeel(LookAndFeelInfo info) + { + } + + /** + * Stores an object in the defaults table. + */ + public static Object put(Object key, Object value) + { + return getLookAndFeel().getDefaults().put(key,value); + } + + /** + * Replaces the current array of installed LookAndFeelInfos. + */ + public static void setInstalledLookAndFeels(UIManager.LookAndFeelInfo[] infos) + { + } + + /** + * Set the current default look. + */ + public static void setLookAndFeel(LookAndFeel newLookAndFeel) + throws UnsupportedLookAndFeelException + { + if (! newLookAndFeel.isSupportedLookAndFeel()) + throw new UnsupportedLookAndFeelException(newLookAndFeel.getName()); + + if (look_and_feel != null) + look_and_feel.uninitialize(); + + // Set the current default look and feel using a LookAndFeel object. + look_and_feel = newLookAndFeel; + look_and_feel.initialize(); + + //revalidate(); + //repaint(); + } + + /** + * Set the current default look and feel using a class name. + */ + public static void setLookAndFeel (String className) + throws ClassNotFoundException, InstantiationException, IllegalAccessException, + UnsupportedLookAndFeelException + { + Class c = Class.forName(className); + LookAndFeel a = (LookAndFeel) c.newInstance(); // throws class-cast-exception + setLookAndFeel(a); + } +} diff --git a/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java b/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java new file mode 100644 index 00000000000..5abe45fe117 --- /dev/null +++ b/libjava/classpath/javax/swing/UnsupportedLookAndFeelException.java @@ -0,0 +1,47 @@ +/* UnsupportedLookAndFeelException.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + + +public class UnsupportedLookAndFeelException extends Exception +{ + public UnsupportedLookAndFeelException(String a) + { + super(a); + } +} diff --git a/libjava/classpath/javax/swing/ViewportLayout.java b/libjava/classpath/javax/swing/ViewportLayout.java new file mode 100644 index 00000000000..18b49125743 --- /dev/null +++ b/libjava/classpath/javax/swing/ViewportLayout.java @@ -0,0 +1,169 @@ +/* ViewportLayout.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.io.Serializable; + +/** + * ViewportLayout + * @author Andrew Selkirk + * @author Graydon Hoare + */ +public class ViewportLayout implements LayoutManager, Serializable +{ + private static final long serialVersionUID = -788225906076097229L; + + public ViewportLayout() + { + } + public void addLayoutComponent(String name, Component c) + { + } + public void removeLayoutComponent(Component c) + { + } + + public Dimension preferredLayoutSize(Container parent) + { + JViewport vp = (JViewport)parent; + Component view = vp.getView(); + if (view != null) + return view.getPreferredSize(); + else + return new Dimension(); + } + + public Dimension minimumLayoutSize(Container parent) + { + JViewport vp = (JViewport)parent; + Component view = vp.getView(); + if (view != null) + return view.getMinimumSize(); + else + return new Dimension(); + } + + /** + * Layout the view and viewport to respect the following rules. These are + * not precisely the rules described in sun's javadocs, but they are the + * rules which sun's swing implementation follows, if you watch its + * behavior: + * + * <ol> + * + * <li>If the port is larger than the view's minimum size, put the port + * at view position <code>(0,0)</code> and make the view's size equal to + * the port's.</li> + * + * <li>If the port is smaller than the view, leave the view at its + * minimum size. also, do not move the port, <em>unless</em> the port + * extends into space <em>past</em> the edge of the view. If so, move the + * port up or to the left, in view space, by the amount of empty space + * (keep the lower and right edges lined up)</li> + * + * </ol> + * + * @see JViewport#getViewSize + * @see JViewport#setViewSize + * @see JViewport#getViewPosition + * @see JViewport#setViewPosition + */ + + public void layoutContainer(Container parent) + { + // The way to interpret this function is basically to ignore the names + // of methods it calls, and focus on the variable names here. getViewRect + // doesn't, for example, return the view; it returns the port bounds in + // view space. Likwise setViewPosition doesn't reposition the view; it + // positions the port, in view coordinates. + + JViewport port = (JViewport) parent; + Component view = port.getView(); + + if (view == null) + return; + + // These dimensions and positions are in *view space*. Do not mix + // variables in here from port space (eg. parent.getBounds()). This + // function should be entirely in view space, because the methods on + // the viewport require inputs in view space. + + Rectangle portBounds = port.getViewRect(); + Dimension viewPref = view.getPreferredSize(); + Dimension viewMinimum = view.getMinimumSize(); + Point portLowerRight = new Point(portBounds.x + portBounds.width, + portBounds.y + portBounds.height); + + // vertical implementation of the above rules + if (portBounds.height >= viewMinimum.height) + { + portBounds.y = 0; + viewPref.height = portBounds.height; + } + else + { + viewPref.height = viewMinimum.height; + int overextension = portLowerRight.y - viewPref.height; + if (overextension > 0) + portBounds.y -= overextension; + } + + // horizontal implementation of the above rules + if (portBounds.width >= viewMinimum.width) + { + portBounds.x = 0; + viewPref.width = portBounds.width; + } + else + { + viewPref.width = viewMinimum.width; + int overextension = portLowerRight.x - viewPref.width; + if (overextension > 0) + portBounds.x -= overextension; + } + + port.setViewPosition(portBounds.getLocation()); + port.setViewSize(viewPref); + } +} diff --git a/libjava/classpath/javax/swing/WindowConstants.java b/libjava/classpath/javax/swing/WindowConstants.java new file mode 100644 index 00000000000..5e364434484 --- /dev/null +++ b/libjava/classpath/javax/swing/WindowConstants.java @@ -0,0 +1,73 @@ +/* WindowConstants.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing; + +/** + * Defines some constants that are used in Swing's top-level + * containers. + * + * @author Andrew Selkirk + */ +public interface WindowConstants { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * DO_NOTHING_ON_CLOSE + */ + int DO_NOTHING_ON_CLOSE = 0; + + /** + * HIDE_ON_CLOSE + */ + int HIDE_ON_CLOSE = 1; + + /** + * DISPOSE_ON_CLOSE + */ + int DISPOSE_ON_CLOSE = 2; + + /** + * EXIT_ON_CLOSE + */ + int EXIT_ON_CLOSE =3; + + +} // WindowConstants diff --git a/libjava/classpath/javax/swing/border/AbstractBorder.java b/libjava/classpath/javax/swing/border/AbstractBorder.java new file mode 100644 index 00000000000..d755b6779d8 --- /dev/null +++ b/libjava/classpath/javax/swing/border/AbstractBorder.java @@ -0,0 +1,192 @@ +/* AbstractBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.io.Serializable; + + +/** + * An invisible zero-width border, serving as a base class for + * implementing more interesting borders. + * + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Ronald Veldema (rveldema@cs.vu.nl) + */ +public abstract class AbstractBorder + implements Border, Serializable +{ + static final long serialVersionUID = -545885975315191844L; + + + /** + * Constructs a new AbstractBorder. + */ + public AbstractBorder () + { + } + + + /** + * Performs nothing, because the default implementation provided by + * this class is an invisible, zero-width border. Subclasses will + * likely want to override this method, but they are not required + * for doing so. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder (Component c, Graphics g, + int x, int y, int width, int height) + { + /* A previous version of Classpath had emitted a warning when + * this method was called. The warning was removed because it is + * perfectly legal for a subclass to not override the paintBorder + * method. An example would be EmptyBorder. + */ + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge, which is zero + * for the default implementation provided by AbstractButton. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets (Component c) + { + return new Insets (0, 0, 0, 0); + } + + + /** + * Determines the insets of this border. The implementation provided + * by AbstractButton sets the <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields of the passed + * <code>insets</code> parameter to zero. + * + * @param c the component whose border is to be measured. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets (Component c, Insets insets) + { + insets.left = insets.right = insets.top = insets.bottom = 0; + return insets; + } + + + /** + * Determines whether or not this border is opaque. An opaque border + * fills every pixel in its area when painting. Partially + * translucent borders must return <code>false</code>, or ugly + * artifacts can appear on screen. The default implementation + * provided by AbstractBorder always returns <code>false</code>. + * + * @return <code>false</code>. + */ + public boolean isBorderOpaque () + { + return false; + } + + + /** + * Returns a rectangle that covers the specified area minus this + * border. Components that wish to determine an area into which + * they can safely draw without intersecting with a border might + * want to use this helper method. + * + * @param c the component in the center of this border. + * @param x the horizontal position of the border. + * @param y the vertical position of the border. + * @param width the width of the available area for the border. + * @param height the height of the available area for the border. + */ + public Rectangle getInteriorRectangle (Component c, + int x, int y, int width, int height) + { + return getInteriorRectangle (c, this, x, y, width, height); + } + + + /** + * Returns a rectangle that covers the specified area minus a + * border. Components that wish to determine an area into which + * they can safely draw without intersecting with a border might + * want to use this helper method. + * + * @param c the component in the center of this border. + * @param x the horizontal position of the border. + * @param y the vertical position of the border. + * @param width the width of the available area for the border. + * @param height the height of the available area for the border. + */ + public static Rectangle getInteriorRectangle (Component c, Border b, + int x, int y, int width, int height) + { + Insets borderInsets; + + if (b != null) + { + borderInsets = b.getBorderInsets (c); + x += borderInsets.left; + y += borderInsets.top; + width -= borderInsets.left + borderInsets.right; + height -= borderInsets.top + borderInsets.bottom; + } + + return new Rectangle (x, y, width, height); + } +} diff --git a/libjava/classpath/javax/swing/border/BevelBorder.java b/libjava/classpath/javax/swing/border/BevelBorder.java new file mode 100644 index 00000000000..e755fdcc94c --- /dev/null +++ b/libjava/classpath/javax/swing/border/BevelBorder.java @@ -0,0 +1,568 @@ +/* BevelBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + + +/** + * A rectangular, two pixel thick border that causes the enclosed area + * to appear as if it was raising out of or lowered into the screen. Some + * LookAndFeels use this kind of border for rectangular buttons. + * + * <p>A BevelBorder has a highlight and a shadow color. In the raised + * variant, the highlight color is used for the top and left edges, + * and the shadow color is used for the bottom and right edge. For an + * image, see the documentation of the individual constructors. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class BevelBorder + extends AbstractBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -1034942243356299676L; + + + /** + * Indicates that the BevelBorder looks like if the enclosed area was + * raising out of the screen. + */ + public static final int RAISED = 0; + + + /** + * Indicates that the BevelBorder looks like if the enclosed area was + * pressed into the screen. + */ + public static final int LOWERED = 1; + + + /** + * The type of this BevelBorder, which is either {@link #RAISED} + * or {@link #LOWERED}. + */ + protected int bevelType; + + + /** + * The outer highlight color, or <code>null</code> to indicate that + * the color shall be derived from the background of the component + * whose border is being painted. + */ + protected Color highlightOuter; + + + /** + * The inner highlight color, or <code>null</code> to indicate that + * the color shall be derived from the background of the component + * whose border is being painted. + */ + protected Color highlightInner; + + + /** + * The outer shadow color, or <code>null</code> to indicate that the + * color shall be derived from the background of the component whose + * border is being painted. + */ + protected Color shadowOuter; + + + /** + * The inner shadow color, or <code>null</code> to indicate that the + * color shall be derived from the background of the component whose + * border is being painted. + */ + protected Color shadowInner; + + + /** + * Constructs a BevelBorder whose colors will be derived from the + * background of the enclosed component. The background color is + * retrieved each time the border is painted, so a BevelBorder + * constructed by this method will automatically reflect a change + * to the component’s background color. + * + * <p><img src="doc-files/BevelBorder-1.png" width="500" height="150" + * alt="[An illustration showing raised and lowered BevelBorders]" /> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link #RAISED} or {@link #LOWERED}. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + */ + public BevelBorder(int bevelType) + { + if ((bevelType != RAISED) && (bevelType != LOWERED)) + throw new IllegalArgumentException(); + + this.bevelType = bevelType; + } + + + /** + * Constructs a BevelBorder given its appearance type and two colors + * for its highlight and shadow. + * + * <p><img src="doc-files/BevelBorder-2.png" width="500" height="150" + * alt="[An illustration showing BevelBorders that were constructed + * with this method]" /> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link #RAISED} or {@link #LOWERED}. + * + * @param highlight the color that will be used for the inner + * side of the highlighted edges (top and left if + * if <code>bevelType</code> is {@link #RAISED}; bottom + * and right otherwise). The color for the outer side + * is a brightened version of this color. + * + * @param shadow the color that will be used for the outer + * side of the shadowed edges (bottom and right + * if <code>bevelType</code> is {@link #RAISED}; top + * and left otherwise). The color for the inner side + * is a brightened version of this color. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + * + * @throws NullPointerException if <code>highlight</code> or + * <code>shadow</code> is <code>null</code>. + * + * @see java.awt.Color.brighter() + */ + public BevelBorder(int bevelType, Color highlight, Color shadow) + { + this(bevelType, + /* highlightOuter */ highlight.brighter(), + /* highlightInner */ highlight, + /* shadowOuter */ shadow, + /* shadowInner */ shadow.brighter()); + } + + + /** + * Constructs a BevelBorder given its appearance type and all + * colors. + * + * <p><img src="doc-files/BevelBorder-3.png" width="500" height="150" + * alt="[An illustration showing BevelBorders that were constructed + * with this method]" /> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link #RAISED} or {@link #LOWERED}. + * + * @param highlightOuter the color that will be used for the outer + * side of the highlighted edges (top and left if + * <code>bevelType</code> is {@link #RAISED}; bottom and + * right otherwise). + * + * @param highlightInner the color that will be used for the inner + * side of the highlighted edges. + * + * @param shadowOuter the color that will be used for the outer + * side of the shadowed edges (bottom and right + * if <code>bevelType</code> is {@link #RAISED}; top + * and left otherwise). + * + * @param shadowInner the color that will be used for the inner + * side of the shadowed edges. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + * + * @throws NullPointerException if one of the passed colors + * is <code>null</code>. + */ + public BevelBorder(int bevelType, + Color highlightOuter, Color highlightInner, + Color shadowOuter, Color shadowInner) + { + this(bevelType); // checks the validity of bevelType + + if ((highlightOuter == null) || (highlightInner == null) + || (shadowOuter == null) || (shadowInner == null)) + throw new NullPointerException(); + + this.highlightOuter = highlightOuter; + this.highlightInner = highlightInner; + this.shadowOuter = shadowOuter; + this.shadowInner = shadowInner; + } + + + /** + * Paints the border for a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + switch (bevelType) + { + case RAISED: + paintRaisedBevel(c, g, x, y, width, height); + break; + + case LOWERED: + paintLoweredBevel(c, g, x, y, width, height); + break; + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return new Insets(2, 2, 2, 2); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + insets.left = insets.right = insets.top = insets.bottom = 2; + return insets; + } + + + /** + * Determines the color that will be used for the outer side of + * highlighted edges when painting the border. If a highlight color + * has been specified upon constructing the border, that color is + * returned. Otherwise, the inner highlight color is brightened. + * + * @param c the component enclosed by this border. + * + * @see #getHighlightInnerColor(java.awt.Component) + * @see java.awt.Color#brighter() + */ + public Color getHighlightOuterColor(Component c) + { + if (highlightOuter != null) + return highlightOuter; + else + return getHighlightInnerColor(c).brighter(); + } + + + /** + * Determines the color that will be used for the inner side of + * highlighted edges when painting the border. If a highlight color + * has been specified upon constructing the border, that color is + * returned. Otherwise, the background color of the enclosed + * component is brightened. + * + * @param c the component enclosed by this border. + * + * @see java.awt.Component#getBackground() + * @see java.awt.Color#brighter() + */ + public Color getHighlightInnerColor(Component c) + { + if (highlightInner != null) + return highlightInner; + else + return c.getBackground().brighter(); + } + + + /** + * Determines the color that will be used for the inner side of + * shadowed edges when painting the border. If a shadow color has + * been specified upon constructing the border, that color is + * returned. Otherwise, the background color of the enclosed + * component is darkened. + * + * @param c the component enclosed by this border. + * + * @see java.awt.Component#getBackground() + * @see java.awt.Color#darker() + */ + public Color getShadowInnerColor(Component c) + { + if (shadowInner != null) + return shadowInner; + else + return c.getBackground().darker(); + } + + + /** + * Determines the color that will be used for the outer side of + * shadowed edges when painting the border. If a shadow color + * has been specified upon constructing the border, that color is + * returned. Otherwise, the inner shadow color is darkened. + * + * @param c the component enclosed by this border. + * + * @see #getShadowInnerColor(java.awt.Component) + * @see java.awt.Color#darker() + */ + public Color getShadowOuterColor(Component c) + { + if (shadowOuter != null) + return shadowOuter; + else + return getShadowInnerColor(c).darker(); + } + + + /** + * Returns the color that will be used for the outer side of + * highlighted edges when painting the border, or <code>null</code> + * if that color will be derived from the background of the enclosed + * Component. + */ + public Color getHighlightOuterColor() + { + return highlightOuter; + } + + + /** + * Returns the color that will be used for the inner side of + * highlighted edges when painting the border, or <code>null</code> + * if that color will be derived from the background of the enclosed + * Component. + */ + public Color getHighlightInnerColor() + { + return highlightInner; + } + + + /** + * Returns the color that will be used for the inner side of + * shadowed edges when painting the border, or <code>null</code> if + * that color will be derived from the background of the enclosed + * Component. + */ + public Color getShadowInnerColor() + { + return shadowInner; + } + + + /** + * Returns the color that will be used for the outer side of + * shadowed edges when painting the border, or <code>null</code> if + * that color will be derived from the background of the enclosed + * Component. + */ + public Color getShadowOuterColor() + { + return shadowOuter; + } + + + /** + * Returns the appearance of this border, which is either {@link + * #RAISED} or {@link #LOWERED}. + */ + public int getBevelType() + { + return bevelType; + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * <p>If the border colors are derived from the background color of + * the enclosed component, the result is <code>true</code> because + * the derivation method always returns opaque colors. Otherwise, + * the result depends on the opacity of the individual colors. + * + * @return <code>true</code> if the border is fully opaque, or + * <code>false</code> if some pixels of the background + * can shine through the border. + */ + public boolean isBorderOpaque() + { + /* If the colors are to be drived from the enclosed Component's + * background color, the border is guaranteed to be fully opaque + * because Color.brighten() and Color.darken() always return an + * opaque color. + */ + return + ((highlightOuter == null) || (highlightOuter.getAlpha() == 255)) + && ((highlightInner == null) || (highlightInner.getAlpha() == 255)) + && ((shadowInner == null) || (shadowInner.getAlpha() == 255)) + && ((shadowOuter == null) ||(shadowOuter.getAlpha() == 255)); + } + + + /** + * Paints a raised bevel border around a component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + protected void paintRaisedBevel(Component c, Graphics g, + int x, int y, int width, int height) + { + paintBevel(g, x, y, width, height, + getHighlightOuterColor(c), getHighlightInnerColor(c), + getShadowInnerColor(c), getShadowOuterColor(c)); + } + + + /** + * Paints a lowered bevel border around a component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + protected void paintLoweredBevel(Component c, Graphics g, + int x, int y, int width, int height) + { + paintBevel(g, x, y, width, height, + getShadowInnerColor(c), getShadowOuterColor(c), + getHighlightInnerColor(c), getHighlightOuterColor(c)); + } + + + /** + * Paints a two-pixel bevel in four colors. + * + * <pre> + * @@@@@@@@@@@@ + * @..........# @ = color a + * @. X# . = color b + * @. X# X = color c + * @.XXXXXXXXX# # = color d + * ############</pre> + * + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * @param a the color for the outer side of the top and left edges. + * @param b the color for the inner side of the top and left edges. + * @param c the color for the inner side of the bottom and right edges. + * @param d the color for the outer side of the bottom and right edges. + */ + private static void paintBevel(Graphics g, + int x, int y, int width, int height, + Color a, Color b, Color c, Color d) + { + Color oldColor; + + oldColor = g.getColor(); + g.translate(x, y); + width = width - 1; + height = height - 1; + + try + { + /* To understand this code, it might be helpful to look at the + * images that are included with the JavaDoc. They are located + * in the "doc-files" subdirectory. + */ + g.setColor(a); + g.drawLine(0, 0, width, 0); // a, horizontal + g.drawLine(0, 1, 0, height); // a, vertical + + g.setColor(b); + g.drawLine(1, 1, width - 1, 1); // b, horizontal + g.drawLine(1, 2, 1, height - 1); // b, vertical + + g.setColor(c); + g.drawLine(2, height - 1, width - 1, height - 1); // c, horizontal + g.drawLine(width - 1, 2, width - 1, height - 2); // c, vertical + + g.setColor(d); + g.drawLine(1, height, width, height); // d, horizontal + g.drawLine(width, 1, width, height - 1); // d, vertical + } + finally + { + g.translate(-x, -y); + g.setColor(oldColor); + } + } +} + diff --git a/libjava/classpath/javax/swing/border/Border.java b/libjava/classpath/javax/swing/border/Border.java new file mode 100644 index 00000000000..11bddfe78b3 --- /dev/null +++ b/libjava/classpath/javax/swing/border/Border.java @@ -0,0 +1,105 @@ +/* Border.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + + +/** + * An public interface for decorative or spacing borders around a Component. + * + * <p>To reduce memory consumption, several Components may share a + * single Border instance. {@link javax.swing.BorderFactory} is a + * factory class for producing commonly used shared borders. + * + * @see javax.swing.BorderFactory + * @see EmptyBorder + * @see CompoundBorder + * @see BevelBorder + * @see EtchedBorder + * @see LineBorder + * @see MatteBorder + * @see SoftBevelBorder + * @see TitledBorder + * @see AbstractBorder + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + * @author Michael Koch (konqueror@gmx.de) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public interface Border +{ + /** + * Paints the border for a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + void paintBorder(Component c, Graphics g, + int x, int y, int width, int height); + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + */ + Insets getBorderInsets(Component c); + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * @return <code>true</code> if the border is fully opaque, or + * <code>false</code> if some pixels of the background + * can shine through the border. + */ + boolean isBorderOpaque(); +} diff --git a/libjava/classpath/javax/swing/border/CompoundBorder.java b/libjava/classpath/javax/swing/border/CompoundBorder.java new file mode 100644 index 00000000000..2130a0e3447 --- /dev/null +++ b/libjava/classpath/javax/swing/border/CompoundBorder.java @@ -0,0 +1,257 @@ +/* CompoundBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +/** + * A Border that is composed of an interior and an exterior border, + * where the interior border is tightly nested into the exterior. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class CompoundBorder + extends AbstractBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = 9054540377030555103L; + + + /** + * The inside border, which is painted between the bordered + * Component and the outside border. It is valid for + * <code>insideBorder</code> to be <code>null</code>. + */ + protected Border insideBorder; + + + /** + * The outside border, which is painted outside both the + * bordered Component and the inside border. It is valid for + * <code>outsideBorder</code> to be <code>null</code>. + */ + protected Border outsideBorder; + + + /** + * Constructs a CompoundBorder whose inside and outside borders + * are both <code>null</code>. While this does not really make + * any sense (there exists a class EmptyBorder as well, and not + * every Component needs to have a border at all), the API + * specification requires the existence of this constructor. + * + * @see EmptyBorder + */ + public CompoundBorder () + { + this (null, null); + } + + + /** + * Constructs a CompoundBorder with the specified inside and + * outside borders. + * + * @param outsideBorder the outside border, which is painted to the + * outside of both <code>insideBorder</code> and the enclosed + * component. It is acceptable to pass <code>null</code>, in + * which case no outside border is painted. + * + * @param insideBorder the inside border, which is painted to + * between <code>outsideBorder</code> and the enclosed + * component. It is acceptable to pass <code>null</code>, in + * which case no inside border is painted. + */ + public CompoundBorder (Border outsideBorder, Border insideBorder) + { + this.outsideBorder = outsideBorder; + this.insideBorder = insideBorder; + } + + + /** + * Determines whether or not this border is opaque. An opaque + * border fills every pixel in its area when painting. Partially + * translucent borders must return <code>false</code>, or ugly + * artifacts can appear on screen. + * + * @return <code>true</code> if both the inside and outside borders + * are opaque, or <code>false</code> otherwise. + */ + public boolean isBorderOpaque () + { + /* While it would be safe to assume true for the opacity of + * a null border, this behavior would not be according to + * the API specification. Also, it is pathological to have + * null borders anyway. + */ + if ((insideBorder == null) || (outsideBorder == null)) + return false; + + return insideBorder.isBorderOpaque() + && outsideBorder.isBorderOpaque(); + } + + + /** + * Paints the compound border by first painting the outside border, + * then painting the inside border tightly nested into the outside. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + /* If there is an outside border, paint it and reduce the + * bounding box by its insets. + */ + if (outsideBorder != null) + { + Insets outsideInsets; + + outsideBorder.paintBorder(c, g, x, y, width, height); + outsideInsets = outsideBorder.getBorderInsets(c); + + x += outsideInsets.left; + y += outsideInsets.top; + + /* Reduce width and height by the respective extent of the + * outside border. + */ + width -= outsideInsets.left + outsideInsets.right; + height -= outsideInsets.top + outsideInsets.bottom; + } + + if (insideBorder != null) + insideBorder.paintBorder(c, g, x, y, width, height); + } + + + /** + * Changes the specified insets to the insets of this border, + * which is the sum of the insets of the inside and the outside + * border. + * + * @param c the component in the center of this border. + * @param insets an Insets object for holding the added insets. + * + * @return the <code>insets</code> object. + */ + public Insets getBorderInsets(Component c, Insets insets) + { + Insets borderInsets; + + if (insets == null) + insets = new Insets (0,0,0,0); + else + insets.left = insets.right = insets.top = insets.bottom = 0; + + /* If there is an outside border, add it to insets. */ + if (outsideBorder != null) + { + borderInsets = outsideBorder.getBorderInsets(c); + insets.left += borderInsets.left; + insets.right += borderInsets.right; + insets.top += borderInsets.top; + insets.bottom += borderInsets.bottom; + } + + /* If there is an inside border, add it to insets. */ + if (insideBorder != null) + { + borderInsets = insideBorder.getBorderInsets(c); + insets.left += borderInsets.left; + insets.right += borderInsets.right; + insets.top += borderInsets.top; + insets.bottom += borderInsets.bottom; + } + + return insets; + } + + + /** + * Determines the insets of this border, which is the sum of the + * insets of the inside and the outside border. + * + * @param c the component in the center of this border. + */ + public Insets getBorderInsets (Component c) + { + /* It is not clear why CompoundBorder does not simply inherit + * the implementation from AbstractBorder. However, we want + * to be compatible with the API specification, which overrides + * the getBorderInsets(Component) method. + */ + return getBorderInsets (c, null); + } + + + /** + * Returns the outside border, which is painted outside both the + * bordered Component and the inside border. It is valid for the + * result to be <code>null</code>. + */ + public Border getOutsideBorder () + { + return outsideBorder; + } + + + /** + * Returns the inside border, which is painted between the bordered + * Component and the outside border. It is valid for the result to + * be <code>null</code>. + */ + public Border getInsideBorder () + { + return insideBorder; + } +} + diff --git a/libjava/classpath/javax/swing/border/EmptyBorder.java b/libjava/classpath/javax/swing/border/EmptyBorder.java new file mode 100644 index 00000000000..0f3b7b6931c --- /dev/null +++ b/libjava/classpath/javax/swing/border/EmptyBorder.java @@ -0,0 +1,223 @@ +/* EmptyBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + + +/** + * A border for leaving a specifiable number of pixels empty around + * the enclosed component. An EmptyBorder requires some space on each + * edge, but does not perform any drawing. + * + * <p><img src="EmptyBorder-1.png" width="290" height="200" + * alt="[An illustration of EmptyBorder]" /> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class EmptyBorder + extends AbstractBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -8116076291731988694L; + + + /** + * The number of pixels required at the left edge. + */ + protected int left; + + + /** + * The number of pixels required at the right edge. + */ + protected int right; + + + /** + * The number of pixels required at the top edge. + */ + protected int top; + + + /** + * The number of pixels required at the bottom edge. + */ + protected int bottom; + + + /** + * Constructs an empty border given the number of pixels required + * on each side. + * + * @param top the number of pixels that the border will need + * for its top edge. + * + * @param left the number of pixels that the border will need + * for its left edge. + * + * @param bottom the number of pixels that the border will need + * for its bottom edge. + * + * @param right the number of pixels that the border will need + * for its right edge. + */ + public EmptyBorder(int top, int left, int bottom, int right) + { + this.top = top; + this.left = left; + this.bottom = bottom; + this.right = right; + } + + + /** + * Constructs an empty border given the number of pixels required + * on each side, passed in an Insets object. + * + * @param borderInsets the Insets for the new border. + */ + public EmptyBorder(Insets borderInsets) + { + this(borderInsets.top, borderInsets.left, + borderInsets.bottom, borderInsets.right); + } + + + /** + * Performs nothing because an EmptyBorder does not paint any + * pixels. While the inherited implementation provided by + * {@link AbstractBorder#paintBorder} is a no-op as well, + * it is overwritten in order to match the API of the Sun + * reference implementation. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + if (insets == null) + insets = new Insets(0, 0, 0, 0); + + insets.left = left; + insets.right = right; + insets.top = top; + insets.bottom = bottom; + return insets; + } + + + /** + * Measures the width of this border. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets() + { + return getBorderInsets(null, null); + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. Since an empty border does not paint any pixels + * whatsoever, the result is <code>false</code>. + * + * @return <code>false</code>. + */ + public boolean isBorderOpaque() + { + /* The inherited implementation of AbstractBorder.isBorderOpaque() + * would also return false. It is not clear why this is overriden + * in the Sun implementation, at least not from just reading the + * JavaDoc. + */ + return false; + } +} diff --git a/libjava/classpath/javax/swing/border/EtchedBorder.java b/libjava/classpath/javax/swing/border/EtchedBorder.java new file mode 100644 index 00000000000..ea2a61d9e67 --- /dev/null +++ b/libjava/classpath/javax/swing/border/EtchedBorder.java @@ -0,0 +1,411 @@ +/* EtchedBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + + +/** + * A border that looks like an engraving etched into the background + * surface, or (in its raised variant) coming out of the surface + * plane. Using different constructors, it is possible to either + * explicitly specify the border colors, or to let the colors derive + * from the background color of the enclosed Component. + * + * <p><img src="doc-files/EtchedBorder-1.png" width="500" height="200" + * alt="[An illustration of the two EtchedBorder variants]" /> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class EtchedBorder + extends AbstractBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = 4001244046866360638L; + + + /** + * Indicates that the border appears as coming out of the + * background. + */ + public static final int RAISED = 0; + + + /** + * Indicates that the border appears as engraved into the + * background. + */ + public static final int LOWERED = 1; + + + /** + * The type of this EtchedBorder, which is either {@link #RAISED} + * or {@link #LOWERED}. + */ + protected int etchType; + + + /** + * The highlight color, or <code>null</code> to indicate that the + * color shall be derived from the background of the enclosed + * component. + */ + protected Color highlight; + + + /** + * The shadow color, or <code>null</code> to indicate that the + * color shall be derived from the background of the enclosed + * component. + */ + protected Color shadow; + + + /** + * Constructs a lowered EtchedBorder. The colors will be derived + * from the background color of the enclosed Component when the + * border gets painted. + */ + public EtchedBorder() + { + this(LOWERED); + } + + + /** + * Constructs an EtchedBorder with the specified appearance. The + * colors will be derived from the background color of the enclosed + * Component when the border gets painted. + * + * <p><img src="doc-files/EtchedBorder-1.png" width="500" height="200" + * alt="[An illustration of the two EtchedBorder variants]" /> + * + * @param etchType the desired appearance of the border. The value + * must be either {@link #RAISED} or {@link #LOWERED}. + * + * @throws IllegalArgumentException if <code>etchType</code> has + * an unsupported value. + */ + public EtchedBorder(int etchType) + { + if ((etchType != RAISED) && (etchType != LOWERED)) + throw new IllegalArgumentException(); + + this.etchType = etchType; + + /* The highlight and shadow fields already have a null value + * when the constructor gets called, so there is no need to + * assign a value here. + */ + } + + + /** + * Constructs a lowered EtchedBorder, explicitly selecting the + * colors that will be used for highlight and shadow. + * + * @param highlight the color that will be used for painting + * the highlight part of the border. + * + * @param shadow the color that will be used for painting + * the shadow part of the border. + * + * @see #EtchedBorder(int, Color, Color) + */ + public EtchedBorder(Color highlight, Color shadow) + { + this(LOWERED, highlight, shadow); + } + + + /** + * Constructs an EtchedBorder with the specified appearance, + * explicitly selecting the colors that will be used for + * highlight and shadow. + * + * <p><img src="doc-files/EtchedBorder-2.png" width="500" height="200" + * alt="[An illustration that shows which pixels get painted + * in what color]" /> + * + * @param etchType the desired appearance of the border. The value + * must be either {@link #RAISED} or {@link #LOWERED}. + * + * @param highlight the color that will be used for painting + * the highlight part of the border. + * + * @param shadow the color that will be used for painting + * the shadow part of the border. + * + * @throws IllegalArgumentException if <code>etchType</code> has + * an unsupported value. + */ + public EtchedBorder(int etchType, Color highlight, Color shadow) + { + this(etchType); // Checks the validity of the value. + this.highlight = highlight; + this.shadow = shadow; + } + + + /** + * Paints the border for a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + switch (etchType) + { + case RAISED: + paintEtchedBorder(g, x, y, width, height, + getHighlightColor(c), getShadowColor(c)); + break; + + case LOWERED: + paintEtchedBorder(g, x, y, width, height, + getShadowColor(c), getHighlightColor(c)); + break; + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return new Insets(2, 2, 2, 2); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + insets.left = insets.right = insets.top = insets.bottom = 2; + return insets; + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * <p>If the border colors are derived from the background color of + * the enclosed component, the result is <code>true</code> because + * the derivation method always returns opaque colors. Otherwise, + * the result depends on the opacity of the individual colors. + * + * @return <code>true</code> if the border is fully opaque, or + * <code>false</code> if some pixels of the background + * can shine through the border. + */ + public boolean isBorderOpaque() + { + /* If the colors are to be drived from the enclosed Component's + * background color, the border is guaranteed to be fully opaque + * because Color.brighten() and Color.darken() always return an + * opaque color. + */ + return + ((highlight == null) || (highlight.getAlpha() == 255)) + && ((shadow == null) || (shadow.getAlpha() == 255)); + } + + + /** + * Returns the appearance of this EtchedBorder, which is either + * {@link #RAISED} or {@link #LOWERED}. + */ + public int getEtchType() + { + return etchType; + } + + + /** + * Determines the color that will be used for highlighted parts when + * painting the border around a given component. If a highlight + * color has been specified upon constructing the border, that color + * is returned. Otherwise, the background color of the enclosed + * component is brightened. + * + * @param c the component enclosed by this border. + * + * @see java.awt.Component#getBackground() + * @see java.awt.Color#brighter() + */ + public Color getHighlightColor(Component c) + { + if (highlight != null) + return highlight; + else + return c.getBackground().brighter(); + } + + + /** + * Returns the color that will be used for highlighted parts when + * painting the border, or <code>null</code> if that color will be + * derived from the background of the enclosed Component. + */ + public Color getHighlightColor() + { + return highlight; + } + + + /** + * Determines the color that will be used for shadowed parts when + * painting the border around a given component. If a shadow color + * has been specified upon constructing the border, that color is + * returned. Otherwise, the background color of the enclosed + * component is darkened. + * + * @param c the component enclosed by this border. + * + * @see java.awt.Component#getBackground() + * @see java.awt.Color#darker() + */ + public Color getShadowColor(Component c) + { + if (shadow != null) + return shadow; + else + return c.getBackground().darker(); + } + + + /** + * Returns the color that will be used for shadowed parts when + * painting the border, or <code>null</code> if that color will be + * derived from the background of the enclosed Component. + */ + public Color getShadowColor() + { + return shadow; + } + + + /** + * Paints a two-pixel etching in two colors. + * + * <pre> + * @@@@@@@@@@@. + * @.........@. @ = color a + * @. @. . = color b + * @. @. + * @@@@@@@@@@@. + * ............</pre> + * + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * @param a one of the two colors. + * @param b the second of the two colors. + */ + private static void paintEtchedBorder(Graphics g, + int x, int y, int width, int height, + Color a, Color b) + { + Color oldColor; + + oldColor = g.getColor(); + g.translate(x, y); + width = width - 1; + height = height - 1; + + try + { + /* To understand this code, it might be helpful to look at the + * images that are included with the JavaDoc. They are located + * in the "doc-files" subdirectory. EtchedBorder-2.png might + * be especially informative. + */ + g.setColor(a); + g.drawRect(0, 0, width - 1, height - 1); + + g.setColor(b); + g.drawLine(1, 1, width - 2, 1); // top edge + g.drawLine(1, 2, 1, height - 2); // left edge + g.drawLine(0, height, width, height); // bottom edge + g.drawLine(width, 0, width, height - 1); // right edge + } + finally + { + g.translate(-x, -y); + g.setColor(oldColor); + } + } +} + diff --git a/libjava/classpath/javax/swing/border/LineBorder.java b/libjava/classpath/javax/swing/border/LineBorder.java new file mode 100644 index 00000000000..00c16342c96 --- /dev/null +++ b/libjava/classpath/javax/swing/border/LineBorder.java @@ -0,0 +1,343 @@ +/* LineBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + + +/** + * A border that consists of a line whose thickness and color can be + * specified. There also is a variant with rounded corners. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class LineBorder + extends AbstractBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -787563427772288970L; + + + /** + * A shared instance of a black, one pixel thick, plain LineBorder. + * The singleton object is lazily created by {@link + * #createBlackLineBorder()} upon its first invocation. + */ + private static LineBorder blackLineBorder; + + + /** + * A shared instance of a gray, one pixel thick, plain LineBorder. + * The singleton object is lazily created by {@link + * #createBlackGrayBorder()} upon its first invocation. + */ + private static LineBorder grayLineBorder; + + + /** + * The width of the line in pixels. + */ + protected int thickness; + + + /** + * The color of the line. + */ + protected Color lineColor; + + + /** + * Indicates whether the line is drawn with rounded corners + * (<code>true</code>) or not ((<code>false</code>). + */ + protected boolean roundedCorners; + + + /** + * Constructs a LineBorder given its color. The border will be one + * pixel thick and have plain corners. + * + * @param color the color for drawing the border. + * + * @see #LineBorder(java.awt.Color, int, boolean) + */ + public LineBorder(Color color) + { + this(color, /* thickness */ 1, /* roundedCorners */ false); + } + + + /** + * Constructs a LineBorder given its color and thickness. The + * border will have plain corners. + * + * @param color the color for drawing the border. + * @param thickness the width of the line in pixels. + * + * @see #LineBorder(java.awt.Color, int, boolean) + */ + public LineBorder(Color color, int thickness) + { + this (color, thickness, /* roundedCorners */ false); + } + + + /** + * Constructs a LineBorder given its color, thickness, and whether + * it has rounded corners. + * + * <p><img src="doc-files/LineBorder-1.png" width="500" height="200" + * alt="[An illustration of two LineBorders]" /> + * + * <p>Note that the enlarged view in the right-hand picture shows + * that the implementation draws one more pixel than specified, + * provided that <code>roundedCorders</code> is <code>true</code> + * and anti-aliasing is turned on while painting. While this might + * be considered a bug, the Sun reference implementation (at least + * JDK 1.3.1 on Apple MacOS X 10.1.5) can be observed to fill + * exactly the same pixels as shown above. The GNU Classpath + * LineBorder replicates the observed behavior of the Sun + * implementation. + * + * @param color the color for drawing the border. + * @param thickness the width of the line in pixels. + * @param roundedCorners <code>true</code> for rounded corners, + * <code>false</code> for plain corners. + * + * @since 1.3 + */ + // For the bug mentioned in the JavaDoc, please see also the comment + // in the paintBorder method below. + // + public LineBorder(Color color, int thickness, boolean roundedCorners) + { + if ((color == null) || (thickness < 0)) + throw new IllegalArgumentException(); + + this.lineColor = color; + this.thickness = thickness; + this.roundedCorners = roundedCorners; + } + + + /** + * Returns a black, one pixel thick, plain LineBorder. The method + * may always return the same (singleton) LineBorder instance. + */ + public static Border createBlackLineBorder() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (blackLineBorder == null) + blackLineBorder = new LineBorder(Color.black); + + return blackLineBorder; + } + + + /** + * Returns a gray, one pixel thick, plain LineBorder. The method + * may always return the same (singleton) LineBorder instance. + */ + public static Border createGrayLineBorder() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (grayLineBorder == null) + grayLineBorder = new LineBorder(Color.gray); + + return grayLineBorder; + } + + + /** + * Paints the line border around a given Component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + Color oldColor = g.getColor(); + + try + { + g.setColor(lineColor); + + /* If width and height were not adjusted, the border would + * appear one pixel too large in both directions. + */ + width -= 1; + height -= 1; + + /* Blurred, too large appearance + * ----------------------------- + * While Java 2D has introduced line strokes of arbitrary width, + * it seems desirable to keep this code independent of Java 2D. + * Therefore, multiple nested rectangles (or rounded rectangles) + * are drawn in order to simulate a line whose thickness is + * greater than one pixel. + * + * This hack causes a blurred appearance when anti-aliasing is + * on. Interestingly enough, though, the Sun JDK 1.3.1 (at least + * on MacOS X 10.1.5) shows exactly the same appearance under + * this condition. It thus seems likely that Sun does the same + * hack for simulating thick lines. For this reason, the + * blurred appearance seems acceptable -- especially since GNU + * Classpath tries to be compatible with the Sun reference + * implementation. + */ + for (int i = 0; i < thickness; i++) + { + if (roundedCorners) + g.drawRoundRect(x, y, width, height, thickness, thickness); + else + g.drawRect(x, y, width, height); + + x += 1; + y += 1; + width -= 2; + height -= 2; + } + } + finally + { + g.setColor(oldColor); + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge, which is the + * thickness of the line. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return new Insets(thickness, thickness, thickness, thickness); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge, which is the thickness + * of the line. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + insets.left = insets.right = insets.top = insets.bottom = thickness; + return insets; + } + + + /** + * Returns the color of the line. + */ + public Color getLineColor() + { + return lineColor; + } + + + /** + * Returns the thickness of the line in pixels. + */ + public int getThickness() + { + return thickness; + } + + + /** + * Returns whether this LineBorder os drawm with rounded + * or with plain corners. + * + * @return <code>true</code> if the corners are rounded, + * <code>false</code> if the corners are plain. + */ + public boolean getRoundedCorners() + { + return roundedCorners; + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * @return <code>true</code> if the corners are plain and the line + * color is fully opaque; <code>false</code> if the corners + * are rounded or the line color is partially transparent. + */ + public boolean isBorderOpaque() + { + return (!roundedCorners) && (lineColor.getAlpha() == 255); + } +} + diff --git a/libjava/classpath/javax/swing/border/MatteBorder.java b/libjava/classpath/javax/swing/border/MatteBorder.java new file mode 100644 index 00000000000..f7ff1ca01c3 --- /dev/null +++ b/libjava/classpath/javax/swing/border/MatteBorder.java @@ -0,0 +1,404 @@ +/* MatteBorder.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.Icon; + +/** + * A border that is filled with either a solid color or with repeated + * icon tiles. + * + * <p><img src="doc-files/MatteBorder-1.png" width="500" height="150" + * alt="[Two MatteBorders]" /> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class MatteBorder + extends EmptyBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = 4422248989617298224L; + + + /** + * The color that is used for filling the border, or + * <code>null</code> if the border is filled with repetitions of a + * tile icon. + * + * @see #tileIcon + */ + protected Color color; + + + /** + * The icon is used for filling the border with a tile, or + * <code>null</code> if the border is filled with a solid + * color. + * + * @see #color + */ + protected Icon tileIcon; + + + /** + * Constructs a MatteBorder given the width on each side + * and a fill color. + * + * <p><img src="doc-files/MatteBorder-2.png" width="500" height="150" + * alt="[A picture of a MatteBorder made by this constructor]" /> + * + * @param top the width of the border at its top edge. + * @param left the width of the border at its left edge. + * @param bottom the width of the border at its bottom edge. + * @param right the width of the border at its right edge. + * @param matteColor the color for filling the border. + */ + public MatteBorder(int top, int left, int bottom, int right, + Color matteColor) + { + super(top, left, bottom, right); + + if (matteColor == null) + throw new IllegalArgumentException(); + + this.color = matteColor; + } + + + /** + * Constructs a MatteBorder given its insets and fill color. + * + * <p><img src="doc-files/MatteBorder-3.png" width="500" height="150" + * alt="[A picture of a MatteBorder made by this constructor]" /> + * + * @param borderInsets an Insets object whose <code>top</code>, + * <code>left</code>, <code>bottom</code> and <code>right</code> + * fields indicate the with of the border at the respective + * edge. + * + * @param matteColor the color for filling the border. + */ + public MatteBorder(Insets borderInsets, Color matteColor) + { + this(borderInsets.top, borderInsets.left, + borderInsets.bottom, borderInsets.right, + matteColor); + } + + + /** + * Constructs a MatteBorder given the width on each side + * and an icon for tiling the border area. + * + * <p><img src="doc-files/MatteBorder-4.png" width="500" height="150" + * alt="[A picture of a MatteBorder made by this constructor]" /> + * + * @param top the width of the border at its top edge. + * @param left the width of the border at its left edge. + * @param bottom the width of the border at its bottom edge. + * @param right the width of the border at its right edge. + * @param tileIcon an icon for tiling the border area. + */ + public MatteBorder(int top, int left, int bottom, int right, + Icon tileIcon) + { + super(top, left, bottom, right); + + if (tileIcon == null) + throw new IllegalArgumentException(); + + this.tileIcon = tileIcon; + } + + + /** + * Constructs a MatteBorder given its insets and an icon + * for tiling the border area. + * + * <p><img src="doc-files/MatteBorder-5.png" width="500" height="150" + * alt="[A picture of a MatteBorder made by this constructor]" /> + * + * @param borderInsets an Insets object whose <code>top</code>, + * <code>left</code>, <code>bottom</code> and <code>right</code> + * fields indicate the with of the border at the respective + * edge. + * + * @param tileIcon an icon for tiling the border area. + */ + public MatteBorder(Insets borderInsets, Icon tileIcon) + { + this(borderInsets.top, borderInsets.left, + borderInsets.bottom, borderInsets.right, + tileIcon); + } + + + /** + * Constructs a MatteBorder given an icon for tiling the + * border area. The icon width is used for the border insets + * at the left and right edge, the icon height for the top and + * bottom edge. + * + * <p><img src="doc-files/MatteBorder-6.png" width="379" height="150" + * alt="[A picture of a MatteBorder made by this constructor]" /> + * + * @param tileIcon an icon for tiling the border area. + */ + public MatteBorder(Icon tileIcon) + { + this(-1, -1, -1, -1, tileIcon); + } + + + /** + * Paints the border for a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + Insets i = getBorderInsets(); + paintEdge(c, g, x, y, width, i.top, 0, 0); // top edge + paintEdge(c, g, x, y + height - i.bottom, // bottom edge + width, i.bottom, + 0, height - i.bottom); + paintEdge(c, g, x, y + i.top, // left edge + i.left, height - i.top, + 0, i.top); + paintEdge(c, g, x + width - i.right, y + i.top, // right edge + i.right, height - i.bottom, + width - i.right, i.top); + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + /* There is no obvious reason for overriding this method, but we + * try to have exactly the same API as the Sun reference + * implementation. + */ + return this.getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + if (insets == null) + insets = new Insets(0, 0, 0, 0); + + if ((tileIcon != null) + && (top < 0) && (left < 0) + && (right < 0) && (bottom < 0)) + { + insets.left = insets.right = tileIcon.getIconWidth(); + insets.top = insets.bottom = tileIcon.getIconHeight(); + return insets; + } + + /* Copy top, left, bottom and right into the respective + * field of insets. + */ + return super.getBorderInsets(c, insets); + } + + + /** + * Measures the width of this border. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets() + { + /* The inherited implementation of EmptyBorder.isBorderOpaque() + * would do the same. It is not clear why this is overriden in the + * Sun implementation, at least not from just reading the JavaDoc. + */ + return this.getBorderInsets(null, null); + } + + + /** + * Returns the color that is used for filling the border, or + * <code>null</code> if the border is filled with repetitions of a + * tile icon. + */ + public Color getMatteColor() + { + return color; + } + + + /** + * Returns the icon is used for tiling the border, or + * <code>null</code> if the border is filled with a color instead of + * an icon. + */ + public Icon getTileIcon() + { + return tileIcon; + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * @return <code>true</code> if the border is filled with an + * opaque color; <code>false</code> if it is filled with + * a semi-transparent color or with an icon. + */ + public boolean isBorderOpaque() + { + return (color != null) && (color.getAlpha() == 255); + } + + + /** + * Paints a rectangular area of the border. This private helper + * method is called once for each of the border edges + * by {@link #paintBorder}. + * + * @param c the component whose border is being painted. + * @param g the graphics for painting. + * @param x the horizontal position of the rectangular area. + * @param y the vertical position of the rectangular area. + * @param width the width of the rectangular area. + * @param height the height of the rectangular area. + * @param dx the x displacement for repeating the tile. + * @param dy the y displacement for repeating the tile. + */ + private void paintEdge(Component c, Graphics g, + int x, int y, int width, int height, + int dx, int dy) + { + Color oldColor; + int iconWidth, iconHeight; + Graphics clipped; + + if ((width <= 0) || (height <= 0)) + return; + + /* Paint a colored rectangle if desired. */ + if (color != null) + { + oldColor = g.getColor(); + try + { + g.setColor(color); + g.fillRect(x, y, width, height); + } + finally + { + g.setColor(oldColor); + } + return; + } + + /* Determine the width and height of the icon. Some icons return + * -1 if it is an image whose dimensions have not yet been + * retrieved. There is not much we can do about this, but we + * should at least avoid entering the paint loop below + * with negative increments. + */ + iconWidth = tileIcon.getIconWidth(); + iconHeight = tileIcon.getIconHeight(); + if ((iconWidth <= 0) || (iconHeight <= 0)) + return; + + dx = dx % iconWidth; + dy = dy % iconHeight; + + clipped = g.create(); + try + { + clipped.setClip(x, y, width, height); + for (int ty = y - dy; ty < y + height; ty += iconHeight) + for (int tx = x - dx; tx < x + width; tx += iconWidth) + tileIcon.paintIcon(c, clipped, tx, ty); + } + finally + { + clipped.dispose(); + } + } +} + diff --git a/libjava/classpath/javax/swing/border/SoftBevelBorder.java b/libjava/classpath/javax/swing/border/SoftBevelBorder.java new file mode 100644 index 00000000000..fa718e35bac --- /dev/null +++ b/libjava/classpath/javax/swing/border/SoftBevelBorder.java @@ -0,0 +1,329 @@ +/* SoftBevelBorder.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + + +/** + * A rectangular, three pixel thick border that looks like a BevelBorder + * with slightly softened corners. + * + * <p>Like BevelBorder, SoftBevelBorder has a highlight and a shadow + * color. In the raised variant, the highlight color is used for the + * top and left edges, and the shadow color is used for the bottom and + * right edge. In the lowered variant, color usage is reversed. For + * an image, see the documentation of the individual constructors. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class SoftBevelBorder + extends BevelBorder +{ + /** + * Determined using the <code>serialver</code> tool + * of Sun JDK 1.4.1_01 on GNU/Linux 2.4.20. Interestingly, + * the Apple/Sun JDK 1.3.1 on MacOS X 10.1.5 gives a different + * value, namely -6658357140774549493L. + */ + static final long serialVersionUID = 5248789787305979975L; + + + /** + * Constructs a SoftBevelBorder whose colors will be derived from the + * background of the enclosed component. The background color is + * retrieved each time the border is painted, so a SoftBevelBorder + * constructed by this method will automatically reflect a change + * to the component’s background color. + * + * <p><img src="doc-files/SoftBevelBorder-1.png" width="500" height="200" + * alt="[An illustration showing raised and lowered SoftBevelBorders]" /> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link BevelBorder#RAISED} + * or {@link BevelBorder#LOWERED}. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + */ + public SoftBevelBorder(int bevelType) + { + super(bevelType); + } + + + /** + * Constructs a SoftBevelBorder given its appearance type and two + * colors for its highlight and shadow. + * + * <p><img src="doc-files/SoftBevelBorder-2.png" width="500" height="150" + * alt="[An illustration showing SoftBevelBorders that were + * constructed with this method]" /> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link BevelBorder#RAISED} or {@link + * BevelBorder#LOWERED}. + * + * @param highlight the color that will be used for the inner side + * of the highlighted edges (top and left if if + * <code>bevelType</code> is {@link BevelBorder#RAISED}; + * bottom and right otherwise). The color for the outer side + * is a brightened version of this color. + * + * @param shadow the color that will be used for the outer side of + * the shadowed edges (bottom and right if + * <code>bevelType</code> is {@link BevelBorder#RAISED}; top + * and left otherwise). The color for the inner side is a + * brightened version of this color. + * + * @throws IllegalArgumentException if <code>bevelType</code> has an + * unsupported value. + * + * @throws NullPointerException if <code>highlight</code> or + * <code>shadow</code> is <code>null</code>. + * + * @see java.awt.Color.brighter() + */ + public SoftBevelBorder(int bevelType, Color highlight, Color shadow) + { + this(bevelType, + /* highlightOuter */ highlight.brighter(), + /* highlightInner */ highlight, + /* shadowOuter */ shadow, + /* shadowInner */ shadow.brighter()); + } + + + /** + * Constructs a SoftBevelBorder given its appearance type and all + * colors. + * + * <p><img src="doc-files/SoftBevelBorder-3.png" width="500" height="150" + * alt="[An illustration showing SoftBevelBorders that were + * constructed with this method]" /> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link BevelBorder#RAISED} or {@link + * BevelBorder#LOWERED}. + * + * @param highlightOuter the color that will be used for the outer + * side of the highlighted edges (top and left if + * <code>bevelType</code> is {@link BevelBorder#RAISED}; + * bottom and right otherwise). + * + * @param highlightInner the color that will be used for the inner + * side of the highlighted edges. + * + * @param shadowOuter the color that will be used for the outer side + * of the shadowed edges (bottom and right if + * <code>bevelType</code> is {@link BevelBorder#RAISED}; top + * and left otherwise). + * + * @param shadowInner the color that will be used for the inner + * side of the shadowed edges. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + * + * @throws NullPointerException if one of the passed colors + * is <code>null</code>. + */ + public SoftBevelBorder(int bevelType, + Color highlightOuter, Color highlightInner, + Color shadowOuter, Color shadowInner) + { + super(bevelType, + highlightOuter, highlightInner, + shadowOuter, shadowInner); + } + + + /** + * Paints the border for a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + switch (bevelType) + { + case RAISED: + paintSoftBevel(g, x, y, width, height, + getHighlightOuterColor(c), getHighlightInnerColor(c), + getShadowInnerColor(c), getShadowOuterColor(c)); + break; + + case LOWERED: + paintSoftBevel(g, x, y, width, height, + getShadowOuterColor(c), getShadowInnerColor(c), + getHighlightInnerColor(c), getHighlightOuterColor(c)); + break; + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return new Insets(3, 3, 3, 3); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + insets.left = insets.right = insets.top = insets.bottom = 3; + return insets; + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * <p>The enlarged view (see documentation for constructors) shows + * that a SoftBevelBorder does not paint all pixels. Therefore, + * this method always returns <code>false</code>. + * + * @return <code>false</code>. + */ + public boolean isBorderOpaque() + { + return false; + } + + + /** + * Paints a soft bevel in four colors. + * + * <pre> + * @@@@@@@@@@@. + * @@.........# @ = color a + * @.. # . = color b + * @. # X = color c + * .. X# # = color d + * . ##########</pre> + * + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * @param a the color for the outer side of the top and left edges. + * @param b the color for the inner side of the top and left edges. + * @param c the color for the inner side of the bottom and right edges. + * @param d the color for the outer side of the bottom and right edges. + */ + private static void paintSoftBevel(Graphics g, + int x, int y, int width, int height, + Color a, Color b, Color c, Color d) + { + Color oldColor; + + oldColor = g.getColor(); + g.translate(x, y); + width = width - 1; + height = height - 1; + + try + { + /* To understand this code, it might be helpful to look at the + * images that are included with the JavaDoc, especially + * SoftBevelBorder-3.png. They are located in the "doc-files" + * subdirectory. + */ + g.setColor(a); + g.drawLine(0, 0, width - 1, 0); // a, horizontal + g.drawLine(0, 1, 2, 1); // a, horizontal + g.drawLine(0, 2, 0, height - 1); // a, vertical + + g.setColor(b); + g.drawLine(width, 0, width, 0); // b, horizontal + g.drawLine(2, 1, width - 1, 1); // b, horizontal + g.drawLine(1, 2, 2, 2); // b, horizontal + g.drawLine(1, 3, 1, height - 1); // b, vertical + g.drawLine(0, height - 1, 0, height); // b, vertical + + g.setColor(c); + g.drawLine(width - 1, height - 1, // c, one pixel + width - 1, height - 1); + + g.setColor(d); + g.drawLine(2, height, width, height); // d, horizontal + g.drawLine(width, 2, width, height - 1); // d, vertical + } + finally + { + g.translate(-x, -y); + g.setColor(oldColor); + } + } +} + diff --git a/libjava/classpath/javax/swing/border/TitledBorder.java b/libjava/classpath/javax/swing/border/TitledBorder.java new file mode 100644 index 00000000000..30e4bcd6947 --- /dev/null +++ b/libjava/classpath/javax/swing/border/TitledBorder.java @@ -0,0 +1,1155 @@ +/* TitledBorder.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.border; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Shape; + +import javax.swing.UIManager; + + +/** + * A border that paints a title on top of another border. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class TitledBorder + extends AbstractBorder +{ + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text at the default vertical position, which + * is in the middle of the top line of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int DEFAULT_POSITION = 0; + + + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text above the top line of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int ABOVE_TOP = 1; + + + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text at the middle of the top line + * of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int TOP = 2; + + + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text below the top line of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int BELOW_TOP = 3; + + + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text above the bottom line of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int ABOVE_BOTTOM = 4; + + + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text at the center of the bottom line + * of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int BOTTOM = 5; + + + /** + * A value for the <code>titlePosition</code> property that vertically + * positions the title text below the bottom line of the border. + * + * @see #getTitlePosition() + * @see #setTitlePosition(int) + */ + public static final int BELOW_BOTTOM = 6; + + + /** + * A value for the <code>titleJustification</code> property that + * horizontally aligns the title text with either the left or the + * right edge of the border, depending on the orientation of the + * component nested into the border. If the component orientation + * is left-to-right, the title text is aligned with the left edge; + * otherwise, it is aligned with the right edge. This is the same + * behavior as with {@link #LEADING}. + * + * @see #getTitleJustification() + * @see #setTitleJustification(int) + * @see java.awt.ComponentOrientation#isLeftToRight() + */ + public static final int DEFAULT_JUSTIFICATION = 0; + + + /** + * A value for the <code>titleJustification</code> property that + * horizontally aligns the title text with the left-hand edge of + * the border. + * + * @see #getTitleJustification() + * @see #setTitleJustification(int) + */ + public static final int LEFT = 1; + + + /** + * A value for the <code>titleJustification</code> property that + * horizontally aligns the title text with the center of the border. + * + * @see #getTitleJustification() + * @see #setTitleJustification(int) + */ + public static final int CENTER = 2; + + + /** + * A value for the <code>titleJustification</code> property that + * horizontally aligns the title text with the right-hand edge of + * the border. + * + * @see #getTitleJustification() + * @see #setTitleJustification(int) + */ + public static final int RIGHT = 3; + + + /** + * A value for the <code>titleJustification</code> property that + * horizontally aligns the title text with either the left or the + * right edge of the border, depending on the orientation of the + * component nested into the border. If the component orientation + * is left-to-right, the title text is aligned with the left edge; + * otherwise, it is aligned with the right edge. This is the same + * behavior as with {@link #DEFAULT_JUSTIFICATION}. + * + * @see #getTitleJustification() + * @see #setTitleJustification(int) + * @see java.awt.ComponentOrientation#isLeftToRight() + */ + public static final int LEADING = 4; + + + /** + * A value for the <code>titleJustification</code> property that + * horizontally aligns the title text with either the right or the + * left edge of the border, depending on the orientation of the + * component nested into the border. If the component orientation + * is left-to-right, the title text is aligned with the right edge; + * otherwise, it is aligned with the left edge. + * + * @see #getTitleJustification() + * @see #setTitleJustification(int) + * @see java.awt.ComponentOrientation#isLeftToRight() + */ + public static final int TRAILING = 5; + + + /** + * The number of pixels between the inside of {@link #border} + * and the bordered component. + */ + protected static final int EDGE_SPACING = 2; + + + /** + * The number of pixels between the outside of this TitledBorder + * and the beginning (if left-aligned) or end (if right-aligned) + * of the title text. + */ + protected static final int TEXT_INSET_H = 5; + + + /** + * The number of pixels between the title text and {@link #border}. + * This value is only relevant if the title text does not intersect + * {@link #border}. No intersection occurs if {@link #titlePosition} + * is one of {@link #ABOVE_TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, + * or {@link #BELOW_BOTTOM}. + */ + protected static final int TEXT_SPACING = 2; + + + /** + * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1 + * on MacOS X 10.1.5. + */ + static final long serialVersionUID = 8012999415147721601L; + + + /** + * The title, or <code>null</code> to display no title. + */ + protected String title; + + + /** + * The border underneath the title. If this value is + * <code>null</code>, the border will be retrieved from the {@link + * javax.swing.UIManager}’s defaults table using the key + * <code>TitledBorder.border</code>. + */ + protected Border border; + + + /** + * The vertical position of the title text relative to the border, + * which is one of {@link #ABOVE_TOP}, {@link #TOP}, {@link + * #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link + * #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}. + */ + protected int titlePosition; + + + /** + * The horizontal alignment of the title text in relation to the + * border, which is one of {@link #LEFT}, {@link #CENTER}, {@link + * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link + * #DEFAULT_JUSTIFICATION}. + */ + protected int titleJustification; + + + /** + * The font for displaying the title text. If this value is + * <code>null</code>, the font will be retrieved from the {@link + * javax.swing.UIManager}’s defaults table using the key + * <code>TitledBorder.font</code>. + */ + protected Font titleFont; + + + /** + * The color for displaying the title text. If this value is + * <code>null</code>, the color will be retrieved from the {@link + * javax.swing.UIManager}’s defaults table using the key + * <code>TitledBorder.titleColor</code>. + */ + protected Color titleColor; + + + /** + * Constructs a TitledBorder given the text of its title. + * + * @param title the title text, or <code>null</code> to use no title text. + */ + public TitledBorder(String title) + { + this(/* border */ null, + title, DEFAULT_JUSTIFICATION, DEFAULT_POSITION, + /* titleFont */ null, /* titleColor */ null); + } + + + /** + * Constructs an initially untitled TitledBorder given another border. + * + * @param border the border underneath the title, or <code>null</code> + * to use a default from the current look and feel. + */ + public TitledBorder(Border border) + { + this(border, /* title */ "", DEFAULT_JUSTIFICATION, DEFAULT_POSITION, + /* titleFont */ null, /* titleColor */ null); + } + + + /** + * Constructs a TitledBorder given its border and title text. + * + * @param border the border underneath the title, or <code>null</code> + * to use a default from the current look and feel. + * + * @param title the title text, or <code>null</code> to use no title + * text. + */ + public TitledBorder(Border border, String title) + { + this(border, title, DEFAULT_JUSTIFICATION, DEFAULT_POSITION, + /* titleFont */ null, /* titleColor */ null); + } + + + /** + * Constructs a TitledBorder given its border, title text, horizontal + * alignment, and vertical position. + * + * @param border the border underneath the title, or <code>null</code> + * to use a default from the current look and feel. + * + * @param title the title text, or <code>null</code> to use no title + * text. + * + * @param titleJustification the horizontal alignment of the title + * text in relation to the border. The value must be one of + * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, + * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. + + * @param titlePosition the vertical position of the title text + * in relation to the border. The value must be one of + * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP}, + * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM}, + * or {@link #DEFAULT_POSITION}. + * + * @throws IllegalArgumentException if <code>titleJustification</code> + * or <code>titlePosition</code> have an unsupported value. + */ + public TitledBorder(Border border, String title, int titleJustification, + int titlePosition) + { + this(border, title, titleJustification, titlePosition, + /* titleFont */ null, /* titleColor */ null); + } + + + /** + * Constructs a TitledBorder given its border, title text, horizontal + * alignment, vertical position, and font. + * + * @param border the border underneath the title, or <code>null</code> + * to use a default from the current look and feel. + * + * @param title the title text, or <code>null</code> to use no title + * text. + * + * @param titleJustification the horizontal alignment of the title + * text in relation to the border. The value must be one of + * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, + * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. + * + * @param titlePosition the vertical position of the title text + * in relation to the border. The value must be one of + * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP}, + * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM}, + * or {@link #DEFAULT_POSITION}. + * + * @param titleFont the font for the title text, or <code>null</code> + * to use a default from the current look and feel. + * + * @throws IllegalArgumentException if <code>titleJustification</code> + * or <code>titlePosition</code> have an unsupported value. + */ + public TitledBorder(Border border, String title, int titleJustification, + int titlePosition, Font titleFont) + { + this(border, title, titleJustification, titlePosition, titleFont, + /* titleColor */ null); + } + + + /** + * Constructs a TitledBorder given its border, title text, horizontal + * alignment, vertical position, font, and color. + * + * @param border the border underneath the title, or <code>null</code> + * to use a default from the current look and feel. + * + * @param title the title text, or <code>null</code> to use no title + * text. + * + * @param titleJustification the horizontal alignment of the title + * text in relation to the border. The value must be one of + * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, + * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. + * + * @param titlePosition the vertical position of the title text + * in relation to the border. The value must be one of + * {@link #ABOVE_TOP}, {@link #TOP}, {@link #BELOW_TOP}, + * {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, {@link #BELOW_BOTTOM}, + * or {@link #DEFAULT_POSITION}. + * + * @param titleFont the font for the title text, or <code>null</code> + * to use a default from the current look and feel. + * + * @param titleColor the color for the title text, or <code>null</code> + * to use a default from the current look and feel. + * + * @throws IllegalArgumentException if <code>titleJustification</code> + * or <code>titlePosition</code> have an unsupported value. + */ + public TitledBorder(Border border, String title, int titleJustification, + int titlePosition, Font titleFont, Color titleColor) + { + this.border = border; + this.title = title; + + /* Invoking the setter methods ensures that the newly constructed + * TitledBorder has valid property values. + */ + setTitleJustification(titleJustification); + setTitlePosition(titlePosition); + + this.titleFont = titleFont; + this.titleColor = titleColor; + } + + + /** + * Paints the border and the title text. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + Measurements mes = getMeasurements(c); + Font oldFont = g.getFont(); + Color oldColor = g.getColor(); + + /** + * A local helper class for painting the border without changing + * any pixels inside the rectangle of the title text. + */ + class BorderPainter + { + private Component c; + private Border b; + private int x, y, width, height; + + /** + * Constructs a BorderPainter. + * + * @param c the component whose border is being painted. + * @param b the border object. + * @param x the x coordinate of the rectangle delimiting the border. + * @param y the y coordinate of the rectangle delimiting the border. + * @param width the width of the rectangle delimiting the border. + * @param height the width of the rectangle delimiting the border. + */ + public BorderPainter(Component c, Border b, + int x, int y, int width, int height) + { + this.c = c; + this.b = b; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + + /** + * Paints the entire border. + */ + public void paint(Graphics g) + { + if (b != null) + b.paintBorder(c, g, x, y, width - 1, height - 1); + } + + + /** + * Paints the border, clipping the drawing operation to a + * given rectangular area. + */ + private void paint(Graphics g, + int clipX, int clipY, int clipWidth, int clipHeight) + { + Shape oldClip = g.getClip(); + try + { + g.clipRect(clipX, clipY, clipWidth, clipHeight); + paint(g); + } + finally + { + g.setClip(oldClip); + } + } + + + /** + * Paints the border without affecting a given rectangular area. + * This is used for painting the border without drawing anything + * underneath the title text. + * + * <p>Since we do not want to introduce unnecessary dependencies + * on Java 2D, we perform the clipping without constructive geometry + * (provided by java.awt.geom.Area). Instead, the border’s + * bounding rectangle is split into smaller parts, which are then + * clipped and painted individually.: + * + * <p><pre> + * +--------------------+ +--------------------+ + * | | | 1 | + * | +--------+ | +---+--------+-------+ + * | | hole | | |====> | 2 | hole | 3 | + * | +--------+ | |---+--------+-------+ + * | | | 4 | + * +--------------------+ +--------------------+</pre> + * + */ + public void paintExcept(Graphics g, + int holeX, int holeY, int holeWidth, int holeHeight) + { + int stripeHeight; + + stripeHeight = holeY - y; + if (stripeHeight > 0) + paint(g, x, y, width, stripeHeight); // patch #1 in the image above + + stripeHeight = holeHeight; + if (stripeHeight > 0) + { + paint(g, x, holeY, holeX - x, stripeHeight); // patches #2 and #3 + paint(g, holeX + holeWidth, holeY, width - (holeX + holeWidth), stripeHeight); + } + + stripeHeight = height - (holeY - y + holeHeight); + if (stripeHeight > 0) + paint(g, x, y + height - stripeHeight, width, stripeHeight); // #4 + } + }; + + BorderPainter bp; + int textX, textY, borderWidth, borderHeight; + + borderWidth = width - (mes.borderSpacing.left + mes.borderSpacing.right); + borderHeight = height - (mes.borderSpacing.top + mes.borderSpacing.bottom); + bp = new BorderPainter(c, getBorder(), + x + mes.borderSpacing.left, y + mes.borderSpacing.top, + borderWidth, borderHeight); + + switch (getRealTitleJustification(c)) + { + case LEFT: + textX = x + TEXT_INSET_H; + break; + + case CENTER: + textX = x + (borderWidth - mes.textWidth) / 2; + break; + + case RIGHT: + textX = x + borderWidth - (mes.textWidth + TEXT_INSET_H); + break; + + default: + throw new IllegalStateException(); + } + + switch (titlePosition) + { + case ABOVE_TOP: + textY = y; + break; + + case TOP: + case DEFAULT_POSITION: + default: + textY = y + mes.borderSpacing.top + mes.borderInsets.top - mes.textAscent; + break; + + case BELOW_TOP: + textY = y + mes.borderSpacing.top + mes.borderInsets.top + TEXT_SPACING; + break; + + case ABOVE_BOTTOM: + textY = y + height - mes.borderSpacing.bottom - mes.borderInsets.bottom + - TEXT_SPACING - (mes.textAscent + mes.textDescent); + break; + + case BOTTOM: + case BELOW_BOTTOM: + textY = y + height - (mes.textAscent + mes.textDescent); + break; + } + + if (mes.trimmedText == null) + bp.paint(g); + else + { + try + { + g.setFont(mes.font); + g.setColor(getTitleColor()); + g.drawString(mes.trimmedText, textX, textY + mes.textAscent); + } + finally + { + g.setFont(oldFont); + g.setColor(oldColor); + } + bp.paintExcept(g, textX - 2, textY, + mes.textWidth + 2, mes.textAscent + mes.textDescent); + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, new Insets(0, 0, 0, 0)); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets() + */ + public Insets getBorderInsets(Component c, Insets insets) + { + return getMeasurements(c).getContentInsets(insets); + } + + + /** + * Returns <code>false</code>, indicating that there are pixels inside + * the area of this border where the background shines through. + * + * @return <code>false</code>. + */ + public boolean isBorderOpaque() + { + /* Note that the AbstractBorder.isBorderOpaque would also return + * false, so there is actually no need to override the inherited + * implementation. However, GNU Classpath strives for exact + * compatibility with the Sun reference implementation, which + * overrides isBorderOpaque for unknown reasons. + */ + return false; + } + + + /** + * Returns the text of the title. + * + * @return the title text, or <code>null</code> if no title is + * displayed. + */ + public String getTitle() + { + return title; + } + + + /** + * Retrieves the border underneath the title. If no border has been + * set, or if it has been set to<code>null</code>, the current + * {@link javax.swing.LookAndFeel} will be asked for a border + * using the key <code>TitledBorder.border</code>. + * + * @return a border, or <code>null</code> if the current LookAndFeel + * does not provide a border for the key + * <code>TitledBorder.border</code>. + * + * @see javax.swing.UIManager#getBorder(Object) + */ + public Border getBorder() + { + if (border != null) + return border; + + return UIManager.getBorder("TitledBorder.border"); + } + + + /** + * Returns the vertical position of the title text in relation + * to the border. + * + * @return one of the values {@link #ABOVE_TOP}, {@link #TOP}, + * {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, {@link #BOTTOM}, + * {@link #BELOW_BOTTOM}, or {@link #DEFAULT_POSITION}. + */ + public int getTitlePosition() + { + return titlePosition; + } + + + /** + * Returns the horizontal alignment of the title text in relation to + * the border. + * + * @return one of the values {@link #LEFT}, {@link #CENTER}, {@link + * #RIGHT}, {@link #LEADING}, {@link #TRAILING}, or {@link + * #DEFAULT_JUSTIFICATION}. + */ + public int getTitleJustification() + { + return titleJustification; + } + + + /** + * Retrieves the font for displaying the title text. If no font has + * been set, or if it has been set to<code>null</code>, the current + * {@link javax.swing.LookAndFeel} will be asked for a font + * using the key <code>TitledBorder.font</code>. + * + * @return a font, or <code>null</code> if the current LookAndFeel + * does not provide a font for the key + * <code>TitledBorder.font</code>. + * + * @see javax.swing.UIManager#getFont(Object) + */ + public Font getTitleFont() + { + if (titleFont != null) + return titleFont; + + return UIManager.getFont("TitledBorder.font"); + } + + + /** + * Retrieves the color for displaying the title text. If no color has + * been set, or if it has been set to<code>null</code>, the current + * {@link javax.swing.LookAndFeel} will be asked for a color + * using the key <code>TitledBorder.titleColor</code>. + * + * @return a color, or <code>null</code> if the current LookAndFeel + * does not provide a color for the key + * <code>TitledBorder.titleColor</code>. + * + * @see javax.swing.UIManager#getColor(Object) + */ + public Color getTitleColor() + { + if (titleColor != null) + return titleColor; + + return UIManager.getColor("TitledBorder.titleColor"); + } + + + /** + * Sets the text of the title. + * + * @param title the new title text, or <code>null</code> for displaying + * no text at all. + */ + public void setTitle(String title) + { + // Swing borders are not JavaBeans, thus no need to fire an event. + this.title = title; + } + + + /** + * Sets the border underneath the title. + * + * @param border a border, or <code>null</code> to use the + * border that is supplied by the current LookAndFeel. + * + * @see #getBorder() + */ + public void setBorder(Border border) + { + // Swing borders are not JavaBeans, thus no need to fire an event. + this.border = border; + } + + + /** + * Sets the vertical position of the title text in relation + * to the border. + * + * @param titlePosition one of the values {@link #ABOVE_TOP}, + * {@link #TOP}, {@link #BELOW_TOP}, {@link #ABOVE_BOTTOM}, + * {@link #BOTTOM}, {@link #BELOW_BOTTOM}, + * or {@link #DEFAULT_POSITION}. + * + * @throws IllegalArgumentException if an unsupported value is passed + * for <code>titlePosition</code>. + */ + public void setTitlePosition(int titlePosition) + { + if ((titlePosition < DEFAULT_POSITION) || (titlePosition > BELOW_BOTTOM)) + throw new IllegalArgumentException(); + + // Swing borders are not JavaBeans, thus no need to fire an event. + this.titlePosition = titlePosition; + } + + + /** + * Sets the horizontal alignment of the title text in relation to the border. + * + * @param titleJustification the new alignment, which must be one of + * {@link #LEFT}, {@link #CENTER}, {@link #RIGHT}, {@link #LEADING}, + * {@link #TRAILING}, or {@link #DEFAULT_JUSTIFICATION}. + * + * @throws IllegalArgumentException if an unsupported value is passed + * for <code>titleJustification</code>. + */ + public void setTitleJustification(int titleJustification) + { + if ((titleJustification < DEFAULT_JUSTIFICATION) + || (titleJustification > TRAILING)) + throw new IllegalArgumentException(); + + // Swing borders are not JavaBeans, thus no need to fire an event. + this.titleJustification = titleJustification; + } + + + /** + * Sets the font for displaying the title text. + * + * @param titleFont the font, or <code>null</code> to use the font + * provided by the current {@link javax.swing.LookAndFeel}. + * + * @see #getTitleFont() + */ + public void setTitleFont(Font titleFont) + { + // Swing borders are not JavaBeans, thus no need to fire an event. + this.titleFont = titleFont; + } + + + /** + * Sets the color for displaying the title text. + * + * @param titleColor the color, or <code>null</code> to use the color + * provided by the current {@link javax.swing.LookAndFeel}. + * + * @see #getTitleColor() + */ + public void setTitleColor(Color titleColor) + { + // Swing borders are not JavaBeans, thus no need to fire an event. + this.titleColor = titleColor; + } + + + /** + * Calculates the minimum size needed for displaying the border + * and its title. + * + * @param c the Component for which this TitledBorder consitutes + * a border. + */ + public Dimension getMinimumSize(Component c) + { + return getMeasurements(c).getMinimumSize(); + } + + + /** + * Returns the font that is used for displaying the title text for + * a given Component. + * + * @param c the Component for which this TitledBorder is the border. + * + * @return The font returned by {@link #getTitleFont()}, or a fallback + * if {@link #getTitleFont()} returned <code>null</code>. + */ + protected Font getFont(Component c) + { + Font f; + + f = getTitleFont(); + if (f != null) + return f; + + return new Font("Dialog", Font.PLAIN, 12); + } + + + /** + * Returns the horizontal alignment of the title text in relation to + * the border, mapping the component-dependent alignment constants + * {@link #LEADING}, {@link #TRAILING} and {@link #DEFAULT_JUSTIFICATION} + * to the correct value according to the embedded component’s + * orientation. + * + * @param c the Component for which this TitledBorder is the border. + * + * @return one of the values {@link #LEFT}, {@link #CENTER}, or {@link + * #RIGHT}. + */ + private int getRealTitleJustification(Component c) + { + switch (titleJustification) + { + case DEFAULT_JUSTIFICATION: + case LEADING: + if ((c == null) || c.getComponentOrientation().isLeftToRight()) + return LEFT; + else + return RIGHT; + + case TRAILING: + if ((c == null) || c.getComponentOrientation().isLeftToRight()) + return RIGHT; + else + return LEFT; + + default: + return titleJustification; + } + } + + + /** + * Performs various measurements for the current state of this TitledBorder + * and the given Component. + */ + private Measurements getMeasurements(Component c) + { + Measurements m = new Measurements(); + FontMetrics fmet; + + m.font = getFont(c); + fmet = c.getFontMetrics(m.font); + m.border = getBorder(); + if (m.border != null) + m.borderInsets = m.border.getBorderInsets(c); + else + m.borderInsets = new Insets(0, 0, 0, 0); + + if (title != null) + { + m.trimmedText = title.trim(); + if (m.trimmedText.length() == 0) + m.trimmedText = null; + } + + m.textAscent = fmet.getAscent(); + m.textDescent = fmet.getDescent(); + if (m.trimmedText != null) + m.textWidth = fmet.stringWidth(m.trimmedText) + 3; + + m.edgeSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING, EDGE_SPACING); + m.borderSpacing = new Insets(0, 0, 0, 0); + + switch (titlePosition) + { + case ABOVE_TOP: + m.borderSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING; + break; + + case BELOW_TOP: + m.edgeSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING; + break; + + case ABOVE_BOTTOM: + m.edgeSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING; + break; + + case BOTTOM: + m.edgeSpacing.bottom += Math.max(m.textAscent - m.borderInsets.bottom, 0); + m.borderSpacing.bottom += m.textDescent; + break; + + case BELOW_BOTTOM: + m.borderSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING; + break; + + default: + m.borderSpacing.top += m.textAscent; + } + + return m; + } + + + /** + * A private helper class for holding the result of measuring the + * distances of a TitledBorder. While it would be possible to cache + * these objects, it does not seem to be worth the effort. Note that + * invalidating the cache would be tricky, especially since there is + * no notification mechanism that would inform the cache when + * border has changed, so it would return different insets. + */ + private static class Measurements + { + /** + * The font used for displaying the title text. Note that it can + * well be that the TitledBorder’s font is <code>null</code>, + * which means that the font is to be retrieved from the current + * LookAndFeel. In this case, this <code>font</code> field will + * contain the result of the retrieval. Therefore, it is safe + * to assume that his <code>font</code> field will never have + * a <code>null</code> value. + */ + Font font; + + + /** + * The number of pixels between the base line and the top of the + * text box. + */ + int textAscent; + + + /** + * The number of pixels between the base line and the bottom of + * the text box. + */ + int textDescent; + + + /** + * The title text after removing leading and trailing white space + * characters. If the title consists only of white space, the + * value of <code>trimmedText</code> will be <code>null</code>. + */ + String trimmedText; + + + /** + * The width of the trimmed title text in pixels. + */ + int textWidth; + + + /** + * The border that constitues the interior border + * underneath the title text. + */ + Border border; + + + /** + * The distance between the TitledBorder and the interior border. + */ + Insets borderSpacing; + + + /** + * The width of the interior border, as returned by + * <code>border.getBorderInsets()</code>. + */ + Insets borderInsets; + + + /** + * The distance between the interior border and the nested + * Component for which this TitledBorder is a border. + */ + Insets edgeSpacing; + + + /** + * Determines the insets of the nested component when it has a + * TitledBorder as its border. Used by {@link + * TitledBorder#getBorderInsets()}. + * + * @param i an Insets object for storing the results into, or + * <code>null</code> to cause the creation of a + * new instance. + * + * @return the <code>i</code> object, or a new Insets object + * if <code>null</code> was passed for <code>i</code>. + */ + public Insets getContentInsets(Insets i) + { + if (i == null) + i = new Insets(0, 0, 0, 0); + i.left = borderSpacing.left + borderInsets.left + edgeSpacing.left; + i.right = borderSpacing.right + borderInsets.right + edgeSpacing.right; + i.top = borderSpacing.top + borderInsets.top + edgeSpacing.top; + i.bottom = borderSpacing.bottom + borderInsets.bottom + edgeSpacing.bottom; + return i; + } + + + /** + * Calculates the minimum size needed for displaying the border + * and its title. Used by {@link TitledBorder#getMiminumSize()}. + */ + public Dimension getMinimumSize() + { + int width; + Insets insets; + + insets = getContentInsets(null); + width = Math.max(insets.left + insets.right, textWidth + 2 * TEXT_INSET_H); + return new Dimension(width, insets.top + insets.bottom); + } + } +} diff --git a/libjava/classpath/javax/swing/border/doc-files/BevelBorder-1.png b/libjava/classpath/javax/swing/border/doc-files/BevelBorder-1.png Binary files differnew file mode 100644 index 00000000000..8c3e4b27758 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/BevelBorder-1.png diff --git a/libjava/classpath/javax/swing/border/doc-files/BevelBorder-2.png b/libjava/classpath/javax/swing/border/doc-files/BevelBorder-2.png Binary files differnew file mode 100644 index 00000000000..ac52d47a7f3 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/BevelBorder-2.png diff --git a/libjava/classpath/javax/swing/border/doc-files/BevelBorder-3.png b/libjava/classpath/javax/swing/border/doc-files/BevelBorder-3.png Binary files differnew file mode 100644 index 00000000000..dd531ff6831 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/BevelBorder-3.png diff --git a/libjava/classpath/javax/swing/border/doc-files/EmptyBorder-1.png b/libjava/classpath/javax/swing/border/doc-files/EmptyBorder-1.png Binary files differnew file mode 100644 index 00000000000..2f21140b1a5 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/EmptyBorder-1.png diff --git a/libjava/classpath/javax/swing/border/doc-files/EtchedBorder-1.png b/libjava/classpath/javax/swing/border/doc-files/EtchedBorder-1.png Binary files differnew file mode 100644 index 00000000000..6b1085c1b8e --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/EtchedBorder-1.png diff --git a/libjava/classpath/javax/swing/border/doc-files/EtchedBorder-2.png b/libjava/classpath/javax/swing/border/doc-files/EtchedBorder-2.png Binary files differnew file mode 100644 index 00000000000..36b07056c47 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/EtchedBorder-2.png diff --git a/libjava/classpath/javax/swing/border/doc-files/LineBorder-1.png b/libjava/classpath/javax/swing/border/doc-files/LineBorder-1.png Binary files differnew file mode 100644 index 00000000000..45b8afc6118 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/LineBorder-1.png diff --git a/libjava/classpath/javax/swing/border/doc-files/MatteBorder-1.png b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-1.png Binary files differnew file mode 100644 index 00000000000..fc49f4b4387 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-1.png diff --git a/libjava/classpath/javax/swing/border/doc-files/MatteBorder-2.png b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-2.png Binary files differnew file mode 100644 index 00000000000..9c2c8d9556f --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-2.png diff --git a/libjava/classpath/javax/swing/border/doc-files/MatteBorder-3.png b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-3.png Binary files differnew file mode 100644 index 00000000000..62089eab5ea --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-3.png diff --git a/libjava/classpath/javax/swing/border/doc-files/MatteBorder-4.png b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-4.png Binary files differnew file mode 100644 index 00000000000..bffbcc84e47 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-4.png diff --git a/libjava/classpath/javax/swing/border/doc-files/MatteBorder-5.png b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-5.png Binary files differnew file mode 100644 index 00000000000..807eee8df13 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-5.png diff --git a/libjava/classpath/javax/swing/border/doc-files/MatteBorder-6.png b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-6.png Binary files differnew file mode 100644 index 00000000000..2c4ce1e3db8 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/MatteBorder-6.png diff --git a/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-1.png b/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-1.png Binary files differnew file mode 100644 index 00000000000..4404bf98cc1 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-1.png diff --git a/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-2.png b/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-2.png Binary files differnew file mode 100644 index 00000000000..ebd9849e618 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-2.png diff --git a/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-3.png b/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-3.png Binary files differnew file mode 100644 index 00000000000..9f939b7a9e1 --- /dev/null +++ b/libjava/classpath/javax/swing/border/doc-files/SoftBevelBorder-3.png diff --git a/libjava/classpath/javax/swing/border/package.html b/libjava/classpath/javax/swing/border/package.html new file mode 100644 index 00000000000..de8479a6a00 --- /dev/null +++ b/libjava/classpath/javax/swing/border/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.border package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.border</title></head> + +<body> +<p>Provides borders for use by components in the <code>javax.swing</code> +package.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/colorchooser/AbstractColorChooserPanel.java b/libjava/classpath/javax/swing/colorchooser/AbstractColorChooserPanel.java new file mode 100644 index 00000000000..d55346aaf2c --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/AbstractColorChooserPanel.java @@ -0,0 +1,162 @@ +/* AbstractColorChooserPanel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.Icon; +import javax.swing.JColorChooser; +import javax.swing.JPanel; + +/** + * AbstractColorChooserPanel + * + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class AbstractColorChooserPanel extends JPanel +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = -977469671210173863L; + + /** The chooser associated with this panel. */ + private JColorChooser chooser; + + /** + * This is the constructor for the AbstractColorChooserPanel. + */ + public AbstractColorChooserPanel() + { + } // AbstractColorChooserPanel() + + /** + * This method returns the name displayed in the tab for this chooser panel. + * + * @return The name displayed in the JTabbedPane's tabs. + */ + public abstract String getDisplayName(); + + /** + * This method updates the chooser panel when the JColorChooser's color has + * changed. + */ + public abstract void updateChooser(); + + /** + * This method constructs and does any initialization necessary for the + * chooser panel. + */ + protected abstract void buildChooser(); + + /** + * This method sets the small icon used in the JTabbedPane for this chooser + * panel. + * + * @return The small icon used in the JTabbedPane. + */ + public abstract Icon getSmallDisplayIcon(); + + /** + * This method sets the large icon useed in the jTabbedPane for this chooser + * panel. + * + * @return The large icon. + */ + public abstract Icon getLargeDisplayIcon(); + + /** + * This method installs the chooser panel for the given JColorChooser. + * + * @param chooser The JColorChooser that will have this panel installed. + */ + public void installChooserPanel(JColorChooser chooser) + { + this.chooser = chooser; + buildChooser(); + } // installChooserPanel() + + /** + * This method removes the chooser panel from the given JColorChooser and + * does any necessary clean up for the chooser panel. + * + * @param chooser The JColorChooser that is having this panel removed. + */ + public void uninstallChooserPanel(JColorChooser chooser) + { + this.chooser = null; + } // uninstallChooserPanel() + + /** + * This method returns the ColorSelectionModel for the JColorChooser + * associated with this chooser panel. + * + * @return The ColorSelectionModel for the JColorChooser associated with + * this chooser panel. + */ + public ColorSelectionModel getColorSelectionModel() + { + if (chooser != null) + return chooser.getSelectionModel(); + return null; + } // getColorSelectionModel() + + /** + * This method returns the current color stored in the model for this + * chooser panel. + * + * @return The current color. + */ + protected Color getColorFromModel() + { + if (chooser != null) + return chooser.getColor(); + return null; + } // getColorFromModel() + + /** + * This method paints the chooser panel. + * + * @param graphics The Graphics object to paint with. + */ + public void paint(Graphics graphics) + { + super.paint(graphics); + } // paint() +} // AbstractColorChooserPanel diff --git a/libjava/classpath/javax/swing/colorchooser/ColorChooserComponentFactory.java b/libjava/classpath/javax/swing/colorchooser/ColorChooserComponentFactory.java new file mode 100644 index 00000000000..77e319c70e4 --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/ColorChooserComponentFactory.java @@ -0,0 +1,85 @@ +/* ColorChooserComponentFactory.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.colorchooser; + +import javax.swing.JComponent; + + +/** + * ColorChooserComponentFactory + * + * @author Andrew Selkirk + * @version 1.0 + */ +public class ColorChooserComponentFactory +{ + /** + * Constructor ColorChooserComponentFactory + */ + private ColorChooserComponentFactory() + { + } // ColorChooserComponentFactory() + + /** + * This method returns the three default chooser panels to be used in + * JColorChooser. + * + * @return The default chooser panels. + */ + public static AbstractColorChooserPanel[] getDefaultChooserPanels() + { + AbstractColorChooserPanel[] values = + { + new DefaultSwatchChooserPanel(), + new DefaultHSBChooserPanel(), + new DefaultRGBChooserPanel() + }; + return values; + } + + /** + * This method returns the default preview panel to be used with + * JColorChoosers. + * + * @return The default preview panel. + */ + public static JComponent getPreviewPanel() + { + return new DefaultPreviewPanel(); + } // getPreviewPanel() +} // ColorChooserComponentFactory diff --git a/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java b/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java new file mode 100644 index 00000000000..5f3070813ce --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/ColorSelectionModel.java @@ -0,0 +1,81 @@ +/* ColorSelectionModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.Color; + +import javax.swing.event.ChangeListener; + +/** + * ColorSelectionModel + * @author Andrew Selkirk + * @version 1.0 + */ +public interface ColorSelectionModel { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getSelectedColor + * @returns Color + */ + Color getSelectedColor(); + + /** + * setSelectedColor + * @param color TODO + */ + void setSelectedColor(Color color); + + /** + * addChangeListener + * @param listener TODO + */ + void addChangeListener(ChangeListener listener); + + /** + * removeChangeListener + * @param listener TODO + */ + void removeChangeListener(ChangeListener listener); + + +} // ColorSelectionModel diff --git a/libjava/classpath/javax/swing/colorchooser/DefaultColorSelectionModel.java b/libjava/classpath/javax/swing/colorchooser/DefaultColorSelectionModel.java new file mode 100644 index 00000000000..aae2bed68e5 --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/DefaultColorSelectionModel.java @@ -0,0 +1,163 @@ +/* DefaultColorSelectionModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.Color; +import java.io.Serializable; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +/** + * This is the default implementation of the ColorSelectionModel interface + * that JColorChoosers use. + * + * @author Andrew Selkirk + * @version 1.0 + */ +public class DefaultColorSelectionModel implements ColorSelectionModel, + Serializable +{ + /** DOCUMENT ME! */ + private static final long serialVersionUID = -8117143602864778804L; + + /** The currently selected color. */ + private Color selectedColor; + + /** The ChangeEvent fired to all ChangeListeners. */ + protected transient ChangeEvent changeEvent = new ChangeEvent(this); + + /** The list of listeners. */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * Creates a new color selection model with the default white color. + */ + public DefaultColorSelectionModel() + { + this(Color.white); + } + + /** + * Creates a new color selection model with a given selected color. + * + * @param color The initial color. + * + * @throws Error If the color is null. + */ + public DefaultColorSelectionModel(Color color) + { + super(); + if (color == null) + throw new Error("ColorSelectionModel cannot be set to have null color."); + this.selectedColor = color; + } + + /** + * Returns the selected color. + * + * @return The selected color. + */ + public Color getSelectedColor() + { + return selectedColor; + } + + /** + * This method sets the color. + * + * @param color The color to set. + * + * @throws Error If the color is set. + */ + public void setSelectedColor(Color color) + { + if (color == null) + throw new Error("ColorSelectionModel cannot be set to have null color."); + if (color != selectedColor) + { + this.selectedColor = color; + fireStateChanged(); + } + } + + /** + * Adds a listener to this model. + * + * @param listener The listener to add. + */ + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + /** + * Removes a listener from this model. + * + * @param listener The listener to remove. + */ + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + /** + * Returns all currently added <code>ChangeListener</code> objects. + * + * @return Array of <code>ChangeListener</code> objects. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + /** + * Calls all the <code>stateChanged()</code> method of all added + * <code>ChangeListener</code> objects with <code>changeEvent</code> as + * argument. + */ + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners[i].stateChanged(changeEvent); + } +} diff --git a/libjava/classpath/javax/swing/colorchooser/DefaultHSBChooserPanel.java b/libjava/classpath/javax/swing/colorchooser/DefaultHSBChooserPanel.java new file mode 100644 index 00000000000..71d6c75b5f9 --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/DefaultHSBChooserPanel.java @@ -0,0 +1,891 @@ +/* DefaultHSBChooserPanel.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Point; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.awt.image.MemoryImageSource; + +import javax.swing.AbstractButton; +import javax.swing.ButtonGroup; +import javax.swing.Icon; +import javax.swing.JColorChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingConstants; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * This is the Default HSB Panel displayed in the JColorChooser. + */ +class DefaultHSBChooserPanel extends AbstractColorChooserPanel +{ + /** The gradient image displayed. + * This is package-private to avoid an accessor method. */ + transient Image gradientImage; + + /** The Panel that holds the gradient image. */ + private transient JPanel gradientPanel; + + /** The track gradient image. + * This is package-private to avoid an accessor method. */ + transient Image trackImage; + + /** The panel that holds the track. */ + private transient JPanel trackPanel; + + /** The slider for the locked HSB value. + * This is package-private to avoid an accessor method. */ + transient JSlider slider; + + /** The RadioButton that controls the Hue. + * This is package-private to avoid an accessor method. */ + transient JRadioButton hRadio; + + /** The RadioButton that controls the Saturation. + * This is package-private to avoid an accessor method. */ + transient JRadioButton sRadio; + + /** The RadioButton that controls the Brightness. + * This is package-private to avoid an accessor method. */ + transient JRadioButton bRadio; + + /** The JSpinner that controls the Hue. + * This is package-private to avoid an accessor method. */ + transient JSpinner hSpinner; + + /** The JSpinner that controls the Saturation. + * This is package-private to avoid an accessor method. */ + transient JSpinner sSpinner; + + /** The JSpinner that controls the Brightness. + * This is package-private to avoid an accessor method. */ + transient JSpinner bSpinner; + + /** The default width of the gradient image. */ + private static final int imgWidth = 200; + + /** The default height of the gradient image. */ + private static final int imgHeight = 200; + + /** The default width of the track gradient. */ + private static final int trackWidth = 30; + + /** The JLabel for Red. */ + private static final JLabel R = new JLabel("R"); + + /** The JLabel for Green. */ + private static final JLabel G = new JLabel("G"); + + /** The JLabel for Blue. */ + private static final JLabel B = new JLabel("B"); + + // FIXME: Should be textfields. + + /** The JLabel that displays the value of Red. */ + private transient JLabel rFull; + + /** The JLabel that displays the value of Green. */ + private transient JLabel gFull; + + /** The JLabel that displays the value of Blue. */ + private transient JLabel bFull; + + /** The point that is displayed in the gradient image. + * Package-private to avoid an accessor method. + */ + transient Point gradientPoint = new Point(); + + /** + * This indicates that the change to the slider or point is triggered + * internally. + * This is package-private to avoid an accessor method. + */ + transient boolean internalChange = false; + + /** This indicates that the change to the spinner is triggered + * internally. + * This is package-private to avoid an accessor method. */ + transient boolean spinnerTrigger = false; + + /** This int identifies which spinner is currently locked. + * This is package-private to avoid an accessor method. */ + transient int locked = -1; + + /** This value indicates that the Hue spinner is locked. */ + static final int HLOCKED = 0; + + /** This value indicates that the Saturation spinner is locked. */ + static final int SLOCKED = 1; + + /** This value indicates that the Brightness spinner is locked. */ + static final int BLOCKED = 2; + + /** + * This method indicates that the mouse event is in the process of being + * handled. + * This is package-private to avoid an accessor method. + */ + transient boolean handlingMouse; + + /** + * This helper class handles mouse events on the gradient image. + */ + class MainGradientMouseListener extends MouseAdapter + implements MouseMotionListener + { + /** + * This method is called when the mouse is pressed over the gradient + * image. The JColorChooser is then updated with new HSB values. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + gradientPoint = e.getPoint(); + update(e.getPoint()); + } + + /** + * This method is called when the mouse is dragged over the gradient + * image. The JColorChooser is then updated with the new HSB values. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + Point p = e.getPoint(); + if (p.x < 0 || p.y < 0 || p.y > imgHeight || p.x > imgWidth) + return; + + gradientPoint = p; + update(p); + } + + /** + * This method is called when the mouse is moved over the gradient image. + * + * @param e The MouseEvent. + */ + public void mouseMoved(MouseEvent e) + { + // Do nothing. + } + + /** + * This method updates the JColorChooser with the new values. + * + * @param p The Point where the MouseEvent occurred. + */ + private void update(Point p) + { + handlingMouse = true; + if (hSpinner.isEnabled()) + updateH(p); + else if (sSpinner.isEnabled()) + updateS(p); + else + updateB(p); + handlingMouse = false; + } + + /** + * This method updates the SB values if Hue is locked. + * + * @param p The point where the MouseEvent occurred. + */ + private void updateH(Point p) + { + float s = (imgWidth - p.x * 1f) / imgWidth; + float b = (imgHeight - p.y * 1f) / imgHeight; + + // Avoid two changes to the model by changing internalChange to true. + internalChange = true; + sSpinner.setValue(new Integer((int) (s * 100))); + internalChange = false; + bSpinner.setValue(new Integer((int) (b * 100))); + + revalidate(); + } + + /** + * This method updates the HB values if Saturation is locked. + * + * @param p The point where the MouseEvent occurred. + */ + private void updateS(Point p) + { + float h = p.x * 1f / imgWidth; + float b = (imgHeight - p.y * 1f) / imgHeight; + + internalChange = true; + hSpinner.setValue(new Integer((int) (h * 365))); + internalChange = false; + bSpinner.setValue(new Integer((int) (b * 100))); + + revalidate(); + } + + /** + * This method updates the HS values if Brightness is locked. + * + * @param p The point where the MouseEvent occurred. + */ + private void updateB(Point p) + { + float h = p.x * 1f / imgWidth; + float s = (imgHeight - p.y * 1f) / imgHeight; + + internalChange = true; + hSpinner.setValue(new Integer((int) (h * 365))); + internalChange = false; + sSpinner.setValue(new Integer((int) (s * 100))); + + revalidate(); + } + } + + /** + * This method listens for slider value changes. + */ + class SliderChangeListener implements ChangeListener + { + /** + * This method is called when the slider value changes. It should change + * the color of the JColorChooser. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + if (internalChange) + return; + + Integer value = new Integer(slider.getValue()); + + switch (locked) + { + case HLOCKED: + hSpinner.setValue(value); + break; + case SLOCKED: + sSpinner.setValue(value); + break; + case BLOCKED: + bSpinner.setValue(value); + break; + } + } + } + + /** + * This helper class determines the active JSpinner. + */ + class RadioStateListener implements ChangeListener + { + /** + * This method is called when there is a new JRadioButton that was + * selected. As a result, it should activate the associated JSpinner. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + JSpinner change; + if (e.getSource() == hRadio) + { + locked = HLOCKED; + change = hSpinner; + } + else if (e.getSource() == sRadio) + { + locked = SLOCKED; + change = sSpinner; + } + else + { + locked = BLOCKED; + change = bSpinner; + } + + change.setEnabled(((AbstractButton) e.getSource()).isSelected()); + updateSlider(); + updateTrack(); + updateImage(); + repaint(); + } + } + + /** + * This class listens to the JSpinners for changes. + */ + class ImageScrollListener implements ChangeListener + { + /** + * This method is called whenever one of the JSpinner values change. The + * JColorChooser should be updated with the new HSB values. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + if (internalChange) + return; + + float h = ((Number) hSpinner.getValue()).intValue() / 360f; + float s = ((Number) sSpinner.getValue()).intValue() / 100f; + float b = ((Number) bSpinner.getValue()).intValue() / 100f; + + spinnerTrigger = true; + getColorSelectionModel().setSelectedColor(new Color(Color.HSBtoRGB(h, s, + b))); + spinnerTrigger = false; + + if (! handlingMouse && slider != null && ! slider.getValueIsAdjusting()) + { + updateImage(); + updateTrack(); + } + repaint(); + } + } + + /** + * Creates a new DefaultHSBChooserPanel object. + */ + DefaultHSBChooserPanel() + { + super(); + } + + /** + * This method returns the name displayed by the JColorChooser tab that + * holds this panel. + * + * @return The name displayed in the JColorChooser tab. + */ + public String getDisplayName() + { + return "HSB"; + } + + /** + * This method updates the various components inside the HSBPanel (the + * JSpinners, the JSlider, and the gradient image point) with updated + * values when the JColorChooser color value changes. + */ + public void updateChooser() + { + Color c = getColorSelectionModel().getSelectedColor(); + + float[] hsbVals = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), + null); + + internalChange = true; + + if (! spinnerTrigger) + { + hSpinner.setValue(new Integer((int) (hsbVals[0] * 360))); + sSpinner.setValue(new Integer((int) (hsbVals[1] * 100))); + bSpinner.setValue(new Integer((int) (hsbVals[2] * 100))); + } + + switch (locked) + { + case HLOCKED: + if (slider != null) + slider.setValue(((Number) hSpinner.getValue()).intValue()); + if (! handlingMouse) + { + gradientPoint.x = (int) ((1 + - ((Number) sSpinner.getValue()).intValue() / 100f) * imgWidth); + gradientPoint.y = (int) ((1 + - ((Number) bSpinner.getValue()).intValue() / 100f) * imgHeight); + } + break; + case SLOCKED: + if (slider != null) + slider.setValue(((Number) sSpinner.getValue()).intValue()); + if (! handlingMouse) + { + gradientPoint.x = (int) (((Number) hSpinner.getValue()).intValue() / 360f * imgWidth); + gradientPoint.y = (int) ((1 + - ((Number) bSpinner.getValue()).intValue() / 100f) * imgHeight); + } + break; + case BLOCKED: + if (slider != null) + slider.setValue(((Number) bSpinner.getValue()).intValue()); + if (! handlingMouse) + { + gradientPoint.x = (int) (((Number) hSpinner.getValue()).intValue() / 360f * imgWidth); + gradientPoint.y = (int) ((1 + - ((Number) sSpinner.getValue()).intValue() / 100f) * imgHeight); + } + break; + } + internalChange = false; + + if (! handlingMouse && slider != null && ! slider.getValueIsAdjusting()) + updateImage(); + + if (! handlingMouse || locked != HLOCKED) + updateTrack(); + updateTextFields(); + } + + /** + * This method builds the DefaultHSBChooserPanel. + */ + protected void buildChooser() + { + setLayout(new BorderLayout()); + + add(buildRightPanel(), BorderLayout.EAST); + + JPanel container = new JPanel(); + container.setLayout(new BorderLayout()); + + gradientPanel = new JPanel() + { + public Dimension getPreferredSize() + { + return new Dimension(imgWidth, imgHeight); + } + + public void paint(Graphics g) + { + if (gradientImage != null) + g.drawImage(gradientImage, 0, 0, this); + + Color saved = g.getColor(); + g.setColor(Color.WHITE); + g.drawOval(gradientPoint.x - 3, gradientPoint.y - 3, 6, 6); + g.setColor(saved); + } + }; + + MouseAdapter ml = new MainGradientMouseListener(); + gradientPanel.addMouseListener(ml); + gradientPanel.addMouseMotionListener((MouseMotionListener) ml); + + trackPanel = new JPanel() + { + public Dimension getPreferredSize() + { + return new Dimension(trackWidth, imgHeight); + } + + public void paint(Graphics g) + { + if (trackImage != null) + g.drawImage(trackImage, 0, 0, this); + } + }; + + slider = new JSlider(); + slider.setPaintTrack(false); + slider.setPaintTicks(false); + + slider.setOrientation(SwingConstants.VERTICAL); + + updateSlider(); + + container.add(gradientPanel, BorderLayout.WEST); + container.add(slider, BorderLayout.CENTER); + container.add(trackPanel, BorderLayout.EAST); + + add(container, BorderLayout.WEST); + slider.addChangeListener(new SliderChangeListener()); + repaint(); + } + + /** + * This method uninstalls the DefaultHSBPanel. + * + * @param chooser The JColorChooser to remove this panel from. + */ + public void uninstallChooserPanel(JColorChooser chooser) + { + trackImage = null; + gradientImage = null; + gradientPanel = null; + slider = null; + + hSpinner = null; + sSpinner = null; + bSpinner = null; + + hRadio = null; + sRadio = null; + bRadio = null; + + removeAll(); + super.uninstallChooserPanel(chooser); + } + + /** + * This helper method creates the right side panel (the panel with the + * Spinners and TextFields). + * + * @return The right side panel. + */ + private Container buildRightPanel() + { + JPanel container = new JPanel(); + container.setLayout(new GridLayout(6, 2)); + + hRadio = new JRadioButton("H"); + sRadio = new JRadioButton("S"); + bRadio = new JRadioButton("B"); + + ButtonGroup group = new ButtonGroup(); + group.add(hRadio); + group.add(sRadio); + group.add(bRadio); + + hSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 359, 1)); + sSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1)); + bSpinner = new JSpinner(new SpinnerNumberModel(100, 0, 100, 1)); + + hSpinner.setEnabled(false); + sSpinner.setEnabled(false); + bSpinner.setEnabled(false); + + ChangeListener cl = new RadioStateListener(); + ChangeListener scroll = new ImageScrollListener(); + + hRadio.addChangeListener(cl); + sRadio.addChangeListener(cl); + bRadio.addChangeListener(cl); + + hSpinner.addChangeListener(scroll); + sSpinner.addChangeListener(scroll); + bSpinner.addChangeListener(scroll); + + hRadio.setSelected(true); + + container.add(hRadio); + container.add(hSpinner); + + container.add(sRadio); + container.add(sSpinner); + + container.add(bRadio); + container.add(bSpinner); + + rFull = new JLabel("red full"); + gFull = new JLabel("green full"); + bFull = new JLabel("blue full"); + + container.add(R); + container.add(rFull); + + container.add(G); + container.add(gFull); + + container.add(B); + container.add(bFull); + + return container; + } + + /** + * This method returns the small display icon. + * + * @return The small display icon. + */ + public Icon getSmallDisplayIcon() + { + return null; + } + + /** + * This method returns the large display icon. + * + * @return The large display icon. + */ + public Icon getLargeDisplayIcon() + { + return null; + } + + /** + * This method paints the chooser panel. + * + * @param g The graphics object to paint with. + */ + public void paint(Graphics g) + { + super.paint(g); + } + + /** + * This method updates the gradient image with a new one taking the Hue + * value as the constant. + */ + private void updateHLockImage() + { + int index = 0; + int[] pix = new int[imgWidth * imgHeight]; + float hValue = ((Number) hSpinner.getValue()).intValue() / 360f; + + for (int j = 0; j < imgHeight; j++) + for (int i = 0; i < imgWidth; i++) + pix[index++] = Color.HSBtoRGB(hValue, (imgWidth - i * 1f) / imgWidth, + (imgHeight - j * 1f) / imgHeight) + | (255 << 24); + + gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight, + pix, 0, imgWidth)); + } + + /** + * This method updates the gradient image with a new one taking the + * Brightness value as the constant. + */ + private void updateBLockImage() + { + int[] pix = new int[imgWidth * imgHeight]; + float bValue = ((Number) bSpinner.getValue()).intValue() / 100f; + + int index = 0; + for (int j = 0; j < imgHeight; j++) + for (int i = 0; i < imgWidth; i++) + pix[index++] = Color.HSBtoRGB(i * 1f / imgWidth, + (imgHeight - j * 1f) / imgHeight, bValue) + | (255 << 24); + + gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight, + pix, 0, imgWidth)); + } + + /** + * This method updates the gradient image with a new one taking the + * Saturation value as the constant. + */ + private void updateSLockImage() + { + int[] pix = new int[imgWidth * imgHeight]; + float sValue = ((Number) sSpinner.getValue()).intValue() / 100f; + + int index = 0; + for (int j = 0; j < imgHeight; j++) + for (int i = 0; i < imgWidth; i++) + pix[index++] = Color.HSBtoRGB(i * 1f / imgWidth, sValue, + (imgHeight - j * 1f) / imgHeight) + | (255 << 24); + gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight, + pix, 0, imgWidth)); + } + + /** + * This method calls the appropriate method to update the gradient image + * depending on which HSB value is constant. + * This is package-private to avoid an accessor method. + */ + void updateImage() + { + switch (locked) + { + case HLOCKED: + updateHLockImage(); + break; + case SLOCKED: + updateSLockImage(); + break; + case BLOCKED: + updateBLockImage(); + break; + } + } + + /** + * This method updates the TextFields with the correct RGB values. + */ + private void updateTextFields() + { + int c = getColorSelectionModel().getSelectedColor().getRGB(); + + rFull.setText("" + (c >> 16 & 0xff)); + gFull.setText("" + (c >> 8 & 0xff)); + bFull.setText("" + (c & 0xff)); + + repaint(); + } + + /** + * This method updates the slider in response to making a different HSB + * property the constant. + * This is package-private to avoid an accessor method. + */ + void updateSlider() + { + if (slider == null) + return; + + slider.setMinimum(0); + if (locked == HLOCKED) + { + slider.setMaximum(359); + ; + slider.setValue(((Number) hSpinner.getValue()).intValue()); + slider.setInverted(true); + } + else + { + slider.setMaximum(100); + slider.setInverted(false); + if (sRadio.isSelected()) + slider.setValue(((Number) sSpinner.getValue()).intValue()); + else + slider.setValue(((Number) bSpinner.getValue()).intValue()); + } + repaint(); + } + + /** + * This method updates the track gradient image depending on which HSB + * property is constant. + * This is package-private to avoid an accessor method. + */ + void updateTrack() + { + switch (locked) + { + case HLOCKED: + updateHTrack(); + break; + case SLOCKED: + updateSTrack(); + break; + case BLOCKED: + updateBTrack(); + break; + } + } + + /** + * This method updates the track gradient image if the Hue value is allowed + * to change (according to the JRadioButtons). + */ + private void updateHTrack() + { + int trackIndex = 0; + int[] trackPix = new int[trackWidth * imgHeight]; + + for (int j = 0; j < imgHeight; j++) + for (int i = 0; i < trackWidth; i++) + trackPix[trackIndex++] = Color.HSBtoRGB(j * 1f / imgHeight, 1f, 1f) + | (255 << 24); + + trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight, + trackPix, 0, trackWidth)); + } + + /** + * This method updates the track gradient image if the Saturation value is + * allowed to change (according to the JRadioButtons). + */ + private void updateSTrack() + { + int[] trackPix = new int[trackWidth * imgHeight]; + + float hValue = ((Number) hSpinner.getValue()).intValue() / 360f; + float bValue = ((Number) bSpinner.getValue()).intValue() / 100f; + + int trackIndex = 0; + for (int j = 0; j < imgHeight; j++) + for (int i = 0; i < trackWidth; i++) + trackPix[trackIndex++] = Color.HSBtoRGB(hValue, + (imgHeight - j * 1f) / imgHeight, + bValue) | (255 << 24); + + trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight, + trackPix, 0, trackWidth)); + } + + /** + * This method updates the track gradient image if the Brightness value is + * allowed to change (according to the JRadioButtons). + */ + private void updateBTrack() + { + int[] trackPix = new int[trackWidth * imgHeight]; + + float hValue = ((Number) hSpinner.getValue()).intValue() / 360f; + float sValue = ((Number) sSpinner.getValue()).intValue() / 100f; + + int trackIndex = 0; + for (int j = 0; j < imgHeight; j++) + for (int i = 0; i < trackWidth; i++) + trackPix[trackIndex++] = Color.HSBtoRGB(hValue, sValue, + (imgHeight - j * 1f) / imgHeight) + | (255 << 24); + + trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight, + trackPix, 0, trackWidth)); + } + + /** + * This method returns the HSB values for the currently selected color. + * + * @return The HSB values for the currently selected color. + */ + private float[] getHSBValues() + { + Color c = getColorFromModel(); + float[] f = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + return f; + } +} diff --git a/libjava/classpath/javax/swing/colorchooser/DefaultPreviewPanel.java b/libjava/classpath/javax/swing/colorchooser/DefaultPreviewPanel.java new file mode 100644 index 00000000000..2462add3df2 --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/DefaultPreviewPanel.java @@ -0,0 +1,318 @@ +/* DefaultPreviewPanel.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.JColorChooser; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; + +/** + * This is the default preview panel for the JColorChooser. The default + * preview panel is responsible for displaying the currently selected color + * of the JColorChooser. + */ +class DefaultPreviewPanel extends JPanel +{ + /** + * This is the border around the preview panel. + */ + class PreviewBorder implements Border + { + /** This is the value of the top, bottom, top, and right inset. */ + private static final int edge = 20; + + /** + * This is the distance from the top left corner of the border to the + * text. + */ + private static final int lead = 5; + + /** This is the horizontal gap between the text and the border. */ + private static final int gap = 3; + + /** + * This method returns the border insets for the given Component. + * + * @param c The Component to retrieve insets for. + * + * @return The insets for the given Component. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(edge, edge, edge, edge); + } + + /** + * This method returns whether the border is responsible for painting its + * own background. + * + * @return Whether the border is responsible for painting its own + * background. + */ + public boolean isBorderOpaque() + { + return true; + } + + /** + * This method paints the border for the given component with the graphics + * object using the given properties. + * + * @param c The Component to paint the border for. + * @param g The Graphics object to paint with. + * @param x The x location to paint at. + * @param y The y location to paint at. + * @param width The width of the component. + * @param height The height of the component. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) + { + Color saved = g.getColor(); + FontMetrics fm = g.getFontMetrics(); + + g.setColor(Color.BLACK); + g.drawLine(x + edge / 2, y + edge / 2, x + edge / 2, + y + height - edge / 2); + g.drawLine(x + edge / 2, y + height - edge / 2, x + width - edge / 2, + y + height - edge / 2); + g.drawLine(x + width - edge / 2, y + edge / 2, x + width - edge / 2, + y + height - edge / 2); + g.drawLine(x + edge / 2, y + edge / 2, x + edge / 2 + lead, y + edge / 2); + + int strwidth = fm.stringWidth("Preview"); + + g.drawString("Preview", x + edge / 2 + lead + gap, + y + edge / 2 + fm.getAscent() / 2); + + g.drawLine(x + lead + edge / 2 + strwidth + gap * 2, y + edge / 2, + x + width - edge / 2, y + edge / 2); + + g.setColor(saved); + } + } + + /** A standard large gap size. */ + private static int largeGap = 6; + + /** A standard small gap size. */ + private static int smallGap = 2; + + /** The size of each side of the square. */ + private static int squareSize = 36; + + /** This padding between the text and the edge of its box. */ + private static int textPadding = 4; + + /** The width of the right most rectangles. */ + private static int rightSideRectWidth = 60; + + /** The sample text. */ + private static String sample = "Sample Text Sample Text"; + + /** + * Creates a new DefaultPreviewPanel object. + */ + DefaultPreviewPanel() + { + super(); + setBorder(new PreviewBorder()); + } + + /** + * This method paints the default preview panel with the given Graphics + * object. + * + * @param g The Graphics object. + */ + public void paint(Graphics g) + { + super.paint(g); + Color currentColor = null; + JColorChooser chooser = (JColorChooser) SwingUtilities.getAncestorOfClass(JColorChooser.class, + this); + if (chooser != null) + currentColor = chooser.getColor(); + + Color saved = g.getColor(); + Insets insets = getInsets(); + + int down = insets.top + squareSize + largeGap; + int currX = insets.left; + + paintSquare(g, currX, insets.top, Color.WHITE, currentColor, Color.WHITE, + -1, -1, -1); + paintSquare(g, currX, down, currentColor, null, null, -1, -1, -1); + + currX += squareSize + largeGap; + + paintSquare(g, currX, insets.top, Color.BLACK, currentColor, Color.WHITE, + -1, -1, -1); + paintSquare(g, currX, down, Color.WHITE, currentColor, null, -1, -1, -1); + + currX += squareSize + largeGap; + + paintSquare(g, currX, insets.top, Color.WHITE, currentColor, Color.BLACK, + -1, -1, -1); + paintSquare(g, currX, down, Color.BLACK, currentColor, null, -1, -1, -1); + + FontMetrics fm = g.getFontMetrics(); + int strWidth = fm.stringWidth(sample); + int strHeight = fm.getHeight(); + + currX += squareSize + largeGap; + + int boxWidth = 2 * textPadding + strWidth; + int boxHeight = 2 * textPadding + strHeight; + + int first = insets.top + textPadding; + int second = insets.top + boxHeight + smallGap; + int third = insets.top + 2 * (boxHeight + smallGap); + + g.setColor(Color.WHITE); + g.fillRect(currX, third, boxWidth, boxHeight); + + g.setColor(currentColor); + g.drawString(sample, currX + textPadding, + first + textPadding + fm.getAscent()); + + g.fillRect(currX, second, boxWidth, boxHeight); + + g.drawString(sample, currX + textPadding, + third + textPadding + fm.getAscent()); + + g.setColor(Color.BLACK); + g.drawString(sample, currX + textPadding, + second + textPadding + fm.getAscent()); + + currX += boxWidth + largeGap; + + g.setColor(Color.WHITE); + g.fillRect(currX, insets.top, rightSideRectWidth, squareSize + + largeGap / 2); + + g.setColor(currentColor); + g.fillRect(currX, insets.top + squareSize + largeGap / 2, + rightSideRectWidth, squareSize + largeGap / 2); + + g.setColor(saved); + } + + /** + * This method creates and paints a square. The square has two smaller + * squares inside of it. Each of the three squares has their sizes + * determined by the size arguments. If the size is not given (by passing + * in -1), then the size is determined automatically. + * + * @param g The Graphics object to paint with. + * @param x The x location to paint at. + * @param y The y location to paint at. + * @param first The color of the first square. + * @param second The color of the second square. + * @param third The color of the third square. + * @param firstSize The size of the first square. + * @param secondSize The size of the second square. + * @param thirdSize The size of the third square. + */ + private void paintSquare(Graphics g, int x, int y, Color first, + Color second, Color third, int firstSize, + int secondSize, int thirdSize) + { + Color saved = g.getColor(); + if (firstSize == -1) + firstSize = squareSize; + if (secondSize == -1) + secondSize = squareSize * 2 / 3; + if (thirdSize == -1) + thirdSize = squareSize / 3; + int secondOffset = (firstSize - secondSize) / 2; + int thirdOffset = (firstSize - thirdSize) / 2; + + if (first == null) + return; + g.setColor(first); + g.fillRect(x, y, firstSize, firstSize); + if (second == null) + return; + g.setColor(second); + g.fillRect(x + secondOffset, y + secondOffset, secondSize, secondSize); + if (third == null) + return; + g.setColor(third); + g.fillRect(x + thirdOffset, y + thirdOffset, thirdSize, thirdSize); + + g.setColor(saved); + } + + /** + * This method returns the preferred size of the default preview panel. + * + * @return The preferred size of the default preview panel. + */ + public Dimension getPreferredSize() + { + Graphics g = getGraphics(); + FontMetrics fm = g.getFontMetrics(); + g.dispose(); + + int strWidth = fm.stringWidth(sample); + int strHeight = fm.getHeight(); + + int h1 = (strHeight + 2 * textPadding) * 3 + 2 * smallGap; + int h2 = 2 * squareSize + largeGap; + + int height = Math.max(h1, h2); + + int width = 3 * (squareSize + largeGap) + strWidth + 2 * textPadding + + largeGap + rightSideRectWidth; + + Insets insets = getInsets(); + + return new Dimension(width + insets.right + insets.left, + height + insets.top + insets.bottom); + } +} diff --git a/libjava/classpath/javax/swing/colorchooser/DefaultRGBChooserPanel.java b/libjava/classpath/javax/swing/colorchooser/DefaultRGBChooserPanel.java new file mode 100644 index 00000000000..39a1732502d --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/DefaultRGBChooserPanel.java @@ -0,0 +1,402 @@ +/* DefaultRGHChooserPanel.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; + +import javax.swing.Icon; +import javax.swing.JColorChooser; +import javax.swing.JLabel; +import javax.swing.JSlider; +import javax.swing.JSpinner; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingConstants; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * This is the default RGB panel for the JColorChooser. The color is selected + * using three sliders that represent the RGB values. + */ +class DefaultRGBChooserPanel extends AbstractColorChooserPanel +{ + /** + * This class handles the slider value changes for all three sliders. + */ + class SliderHandler implements ChangeListener + { + /** + * This method is called whenever any of the slider values change. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + if (updateChange) + return; + + int color = R.getValue() << 16 | G.getValue() << 8 | B.getValue(); + + sliderChange = true; + getColorSelectionModel().setSelectedColor(new Color(color)); + sliderChange = false; + } + } + + /** + * This class handles the Spinner values changing. + */ + class SpinnerHandler implements ChangeListener + { + /** + * This method is called whenever any of the JSpinners change values. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + if (updateChange) + return; + + int red = ((Number) RSpinner.getValue()).intValue(); + int green = ((Number) GSpinner.getValue()).intValue(); + int blue = ((Number) BSpinner.getValue()).intValue(); + + int color = red << 16 | green << 8 | blue; + + spinnerChange = true; + getColorSelectionModel().setSelectedColor(new Color(color)); + spinnerChange = false; + } + } + + /** Whether the color change was initiated by the spinners. + * This is package-private to avoid an accessor method. */ + transient boolean spinnerChange = false; + + /** Whether the color change was initiated by the sliders. + * This is package-private to avoid an accessor method. */ + transient boolean sliderChange = false; + + /** + * Whether the change was forced by the chooser (meaning the color has + * already been changed). + * This is package-private to avoid an accessor method. + */ + transient boolean updateChange = false; + + /** The ChangeListener for the sliders. */ + private transient ChangeListener colorChanger; + + /** The ChangeListener for the spinners. */ + private transient ChangeListener spinnerHandler; + + /** The slider that handles the red values. + * This is package-private to avoid an accessor method. */ + transient JSlider R; + + /** The slider that handles the green values. + * This is package-private to avoid an accessor method. */ + transient JSlider G; + + /** The slider that handles the blue values. + * This is package-private to avoid an accessor method. */ + transient JSlider B; + + /** The label for the red slider. */ + private transient JLabel RLabel; + + /** The label for the green slider. */ + private transient JLabel GLabel; + + /** The label for the blue slider. */ + private transient JLabel BLabel; + + /** The spinner that handles the red values. + * This is package-private to avoid an accessor method. */ + transient JSpinner RSpinner; + + /** The spinner that handles the green values. + * This is package-private to avoid an accessor method. */ + transient JSpinner GSpinner; + + /** The spinner that handles the blue values. + * This is package-private to avoid an accessor method. */ + transient JSpinner BSpinner; + + /** + * Creates a new DefaultRGBChooserPanel object. + */ + public DefaultRGBChooserPanel() + { + super(); + } + + /** + * This method returns the name displayed in the JTabbedPane. + * + * @return The name displayed in the JTabbedPane. + */ + public String getDisplayName() + { + return "RGB"; + } + + /** + * This method updates the chooser panel with the new color chosen in the + * JColorChooser. + */ + public void updateChooser() + { + Color c = getColorFromModel(); + int rgb = c.getRGB(); + + int red = rgb >> 16 & 0xff; + int green = rgb >> 8 & 0xff; + int blue = rgb & 0xff; + + updateChange = true; + + if (! sliderChange) + { + if (R != null) + R.setValue(red); + if (G != null) + G.setValue(green); + if (B != null) + B.setValue(blue); + } + if (! spinnerChange) + { + if (GSpinner != null) + GSpinner.setValue(new Integer(green)); + if (RSpinner != null) + RSpinner.setValue(new Integer(red)); + if (BSpinner != null) + BSpinner.setValue(new Integer(blue)); + } + + updateChange = false; + + revalidate(); + repaint(); + } + + /** + * This method builds the chooser panel. + */ + protected void buildChooser() + { + setLayout(new GridBagLayout()); + + RLabel = new JLabel("Red"); + RLabel.setDisplayedMnemonic('d'); + GLabel = new JLabel("Green"); + GLabel.setDisplayedMnemonic('n'); + BLabel = new JLabel("Blue"); + BLabel.setDisplayedMnemonic('B'); + + R = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 255); + G = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 255); + B = new JSlider(SwingConstants.HORIZONTAL, 0, 255, 255); + + R.setPaintTicks(true); + R.setSnapToTicks(false); + G.setPaintTicks(true); + G.setSnapToTicks(false); + B.setPaintTicks(true); + B.setSnapToTicks(false); + + R.setLabelTable(R.createStandardLabels(85)); + R.setPaintLabels(true); + G.setLabelTable(G.createStandardLabels(85)); + G.setPaintLabels(true); + B.setLabelTable(B.createStandardLabels(85)); + B.setPaintLabels(true); + + R.setMajorTickSpacing(85); + G.setMajorTickSpacing(85); + B.setMajorTickSpacing(85); + + R.setMinorTickSpacing(17); + G.setMinorTickSpacing(17); + B.setMinorTickSpacing(17); + + RSpinner = new JSpinner(new SpinnerNumberModel(R.getValue(), + R.getMinimum(), + R.getMaximum(), 1)); + GSpinner = new JSpinner(new SpinnerNumberModel(G.getValue(), + G.getMinimum(), + G.getMaximum(), 1)); + BSpinner = new JSpinner(new SpinnerNumberModel(B.getValue(), + B.getMinimum(), + B.getMaximum(), 1)); + + RLabel.setLabelFor(R); + GLabel.setLabelFor(G); + BLabel.setLabelFor(B); + + GridBagConstraints bag = new GridBagConstraints(); + bag.fill = GridBagConstraints.VERTICAL; + + bag.gridx = 0; + bag.gridy = 0; + add(RLabel, bag); + + bag.gridx = 1; + add(R, bag); + + bag.gridx = 2; + add(RSpinner, bag); + + bag.gridx = 0; + bag.gridy = 1; + add(GLabel, bag); + + bag.gridx = 1; + add(G, bag); + + bag.gridx = 2; + add(GSpinner, bag); + + bag.gridx = 0; + bag.gridy = 2; + add(BLabel, bag); + + bag.gridx = 1; + add(B, bag); + + bag.gridx = 2; + add(BSpinner, bag); + + installListeners(); + } + + /** + * This method uninstalls the chooser panel from the JColorChooser. + * + * @param chooser The JColorChooser to remove this chooser panel from. + */ + public void uninstallChooserPanel(JColorChooser chooser) + { + uninstallListeners(); + removeAll(); + + R = null; + G = null; + B = null; + + RSpinner = null; + GSpinner = null; + BSpinner = null; + + super.uninstallChooserPanel(chooser); + } + + /** + * This method uninstalls any listeners that were added by the chooser + * panel. + */ + private void uninstallListeners() + { + R.removeChangeListener(colorChanger); + G.removeChangeListener(colorChanger); + B.removeChangeListener(colorChanger); + + colorChanger = null; + + RSpinner.removeChangeListener(spinnerHandler); + GSpinner.removeChangeListener(spinnerHandler); + BSpinner.removeChangeListener(spinnerHandler); + + spinnerHandler = null; + } + + /** + * This method installs any listeners that the chooser panel needs to + * operate. + */ + private void installListeners() + { + colorChanger = new SliderHandler(); + + R.addChangeListener(colorChanger); + G.addChangeListener(colorChanger); + B.addChangeListener(colorChanger); + + spinnerHandler = new SpinnerHandler(); + + RSpinner.addChangeListener(spinnerHandler); + GSpinner.addChangeListener(spinnerHandler); + BSpinner.addChangeListener(spinnerHandler); + } + + /** + * This method returns the small display icon. + * + * @return The small display icon. + */ + public Icon getSmallDisplayIcon() + { + return null; + } + + /** + * This method returns the large display icon. + * + * @return The large display icon. + */ + public Icon getLargeDisplayIcon() + { + return null; + } + + /** + * This method paints the default RGB chooser panel. + * + * @param g The Graphics object to paint with. + */ + public void paint(Graphics g) + { + super.paint(g); + } +} diff --git a/libjava/classpath/javax/swing/colorchooser/DefaultSwatchChooserPanel.java b/libjava/classpath/javax/swing/colorchooser/DefaultSwatchChooserPanel.java new file mode 100644 index 00000000000..f28af4cac7c --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/DefaultSwatchChooserPanel.java @@ -0,0 +1,893 @@ +/* DefaultSwatchChooserPanel.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.colorchooser; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; + +import javax.swing.Icon; +import javax.swing.JColorChooser; +import javax.swing.JLabel; +import javax.swing.JPanel; + +/** + * This class is the DefaultSwatchChooserPanel. This chooser panel displays a + * set of colors that can be picked. Recently picked items will go into a + * side panel so the user can see the history of the chosen colors. + */ +class DefaultSwatchChooserPanel extends AbstractColorChooserPanel +{ + /** The main panel that holds the set of choosable colors. */ + MainSwatchPanel mainPalette; + + /** A panel that holds the recent colors. */ + RecentSwatchPanel recentPalette; + + /** The mouse handlers for the panels. */ + MouseListener mouseHandler; + + /** + * This the base class for all swatch panels. Swatch panels are panels that + * hold a set of blocks where colors are displayed. + */ + abstract static class SwatchPanel extends JPanel + { + /** The width of each block. */ + protected int cellWidth = 10; + + /** The height of each block. */ + protected int cellHeight = 10; + + /** The gap between blocks. */ + protected int gap = 1; + + /** The number of rows in the swatch panel. */ + protected int numRows; + + /** The number of columns in the swatch panel. */ + protected int numCols; + + /** + * Creates a new SwatchPanel object. + */ + SwatchPanel() + { + super(); + setBackground(Color.WHITE); + } + + /** + * This method returns the preferred size of the swatch panel based on the + * number of rows and columns and the size of each cell. + * + * @return The preferred size of the swatch panel. + */ + public Dimension getPreferredSize() + { + int height = numRows * cellHeight + (numRows - 1) * gap; + int width = numCols * cellWidth + (numCols - 1) * gap; + Insets insets = getInsets(); + + return new Dimension(width + insets.left + insets.right, + height + insets.top + insets.bottom); + } + + /** + * This method returns the color for the given position. + * + * @param x The x coordinate of the position. + * @param y The y coordinate of the position. + * + * @return The color at the given position. + */ + public abstract Color getColorForPosition(int x, int y); + + /** + * This method initializes the colors for the swatch panel. + */ + protected abstract void initializeColors(); + } + + /** + * This is the main swatch panel. This panel sits in the middle and allows a + * set of colors to be picked which will move to the recent swatch panel. + */ + static class MainSwatchPanel extends SwatchPanel + { + /** The color describing (204, 255, 255) */ + public static final Color C204255255 = new Color(204, 204, 255); + + /** The color describing (255, 204, 204) */ + public static final Color C255204204 = new Color(255, 204, 204); + + /** The color describing (204, 255, 204) */ + public static final Color C204255204 = new Color(204, 255, 204); + + /** The color describing (204, 204, 204) */ + public static final Color C204204204 = new Color(204, 204, 204); + + /** The color (153, 153, 255). */ + public static final Color C153153255 = new Color(153, 153, 255); + + /** The color (51, 51, 255). */ + public static final Color C051051255 = new Color(51, 51, 255); + + /** The color (153, 0, 153). */ + public static final Color C153000153 = new Color(153, 0, 153); + + /** The color (0, 51, 51). */ + public static final Color C000051051 = new Color(0, 51, 51); + + /** The color (51, 0, 51). */ + public static final Color C051000051 = new Color(51, 0, 51); + + /** The color (51, 51, 0). */ + public static final Color C051051000 = new Color(51, 51, 0); + + /** The color (102, 102, 0). */ + public static final Color C102102000 = new Color(102, 102, 0); + + /** The color (153, 255, 153). */ + public static final Color C153255153 = new Color(153, 255, 153); + + /** The color (102, 255, 102). */ + public static final Color C102255102 = new Color(102, 255, 102); + + /** The color (0, 102, 102). */ + public static final Color C000102102 = new Color(0, 102, 102); + + /** The color (102, 0, 102). */ + public static final Color C102000102 = new Color(102, 0, 102); + + /** The color (0, 153, 153). */ + public static final Color C000153153 = new Color(0, 153, 153); + + /** The color (153, 153, 0). */ + public static final Color C153153000 = new Color(153, 153, 0); + + /** The color (204, 204, 0). */ + public static final Color C204204000 = new Color(204, 204, 0); + + /** The color (204, 0, 204). */ + public static final Color C204000204 = new Color(204, 0, 204); + + /** The color (0, 204, 204). */ + public static final Color C000204204 = new Color(0, 204, 204); + + /** The color (51, 255, 51). */ + public static final Color C051255051 = new Color(51, 255, 51); + + /** The color (255, 51, 51). */ + public static final Color C255051051 = new Color(255, 51, 51); + + /** The color (255, 102, 102). */ + public static final Color C255102102 = new Color(255, 102, 102); + + /** The color (102, 102, 255). */ + public static final Color C102102255 = new Color(102, 102, 255); + + /** The color (255, 153, 153). */ + public static final Color C255153153 = new Color(255, 153, 153); + static Color[] colors = + { + // Row 1 + Color.WHITE, new Color(204, 255, 255), C204255255, C204255255, C204255255, + C204255255, C204255255, C204255255, C204255255, + C204255255, C204255255, new Color(255, 204, 255), + C255204204, C255204204, C255204204, C255204204, + C255204204, C255204204, C255204204, C255204204, + C255204204, new Color(255, 255, 204), C204255204, + C204255204, C204255204, C204255204, C204255204, + C204255204, C204255204, C204255204, C204255204, + + // Row 2 + C204204204, new Color(153, 255, 255), new Color(153, 204, 255), C153153255, + C153153255, C153153255, C153153255, C153153255, + C153153255, C153153255, new Color(204, 153, 255), + new Color(255, 153, 255), + new Color(255, 153, 204), C255153153, C255153153, + C255153153, C255153153, C255153153, C255153153, + C255153153, new Color(255, 204, 153), + new Color(255, 255, 153), + new Color(204, 255, 153), C153255153, C153255153, + C153255153, C153255153, C153255153, C153255153, + C153255153, new Color(153, 255, 204), + + // Row 3 + C204204204, new Color(102, 255, 255), new Color(102, 204, 255), + new Color(102, 153, 255), C102102255, C102102255, + C102102255, C102102255, C102102255, + new Color(153, 102, 255), + new Color(204, 102, 255), + new Color(255, 102, 255), + new Color(255, 102, 204), + new Color(255, 102, 153), C255102102, C255102102, + C255102102, C255102102, C255102102, + new Color(255, 153, 102), + new Color(255, 204, 102), + new Color(255, 255, 102), + new Color(204, 255, 102), + new Color(153, 255, 102), C102255102, C102255102, + C102255102, C102255102, C102255102, + new Color(102, 255, 153), + new Color(102, 255, 204), + + // Row 4 + new Color(153, 153, 153), new Color(51, 255, 255), new Color(51, 204, 255), + new Color(51, 153, 255), new Color(51, 102, 255), + C051051255, C051051255, C051051255, + new Color(102, 51, 255), new Color(153, 51, 255), + new Color(204, 51, 255), new Color(255, 51, 255), + new Color(255, 51, 204), new Color(255, 51, 153), + new Color(255, 51, 102), C255051051, C255051051, + C255051051, new Color(255, 102, 51), + new Color(255, 153, 51), new Color(255, 204, 51), + new Color(255, 255, 51), new Color(204, 255, 51), + new Color(153, 255, 51), new Color(102, 255, 51), + C051255051, C051255051, C051255051, + new Color(51, 255, 102), new Color(51, 255, 153), + new Color(51, 255, 204), + + // Row 5 + new Color(153, 153, 153), new Color(0, 255, 255), new Color(0, 204, 255), + new Color(0, 153, 255), new Color(0, 102, 255), + new Color(0, 51, 255), new Color(0, 0, 255), + new Color(51, 0, 255), new Color(102, 0, 255), + new Color(153, 0, 255), new Color(204, 0, 255), + new Color(255, 0, 255), new Color(255, 0, 204), + new Color(255, 0, 153), new Color(255, 0, 102), + new Color(255, 0, 51), new Color(255, 0, 0), + new Color(255, 51, 0), new Color(255, 102, 0), + new Color(255, 153, 0), new Color(255, 204, 0), + new Color(255, 255, 0), new Color(204, 255, 0), + new Color(153, 255, 0), new Color(102, 255, 0), + new Color(51, 255, 0), new Color(0, 255, 0), + new Color(0, 255, 51), new Color(0, 255, 102), + new Color(0, 255, 153), new Color(0, 255, 204), + + // Row 6 + new Color(102, 102, 102), C000204204, C000204204, new Color(0, 153, 204), + new Color(0, 102, 204), new Color(0, 51, 204), + new Color(0, 0, 204), new Color(51, 0, 204), + new Color(102, 0, 204), new Color(153, 0, 204), + C204000204, C204000204, C204000204, + new Color(204, 0, 153), new Color(204, 0, 102), + new Color(204, 0, 51), new Color(204, 0, 0), + new Color(204, 51, 0), new Color(204, 102, 0), + new Color(204, 153, 0), C204204000, C204204000, + C204204000, new Color(153, 204, 0), + new Color(102, 204, 0), new Color(51, 204, 0), + new Color(0, 204, 0), new Color(0, 204, 51), + new Color(0, 204, 102), new Color(0, 204, 153), + new Color(0, 204, 204), + + // Row 7 + new Color(102, 102, 102), C000153153, C000153153, C000153153, + new Color(0, 102, 153), new Color(0, 51, 153), + new Color(0, 0, 153), new Color(51, 0, 153), + new Color(102, 0, 153), C153000153, C153000153, + C153000153, C153000153, C153000153, + new Color(153, 0, 102), new Color(153, 0, 51), + new Color(153, 0, 0), new Color(153, 51, 0), + new Color(153, 102, 0), C153153000, C153153000, + C153153000, C153153000, C153153000, + new Color(102, 153, 0), new Color(51, 153, 0), + new Color(0, 153, 0), new Color(0, 153, 51), + new Color(0, 153, 102), C000153153, C000153153, + + // Row 8 + new Color(51, 51, 51), C000102102, C000102102, C000102102, C000102102, + new Color(0, 51, 102), new Color(0, 0, 102), + new Color(51, 0, 102), C102000102, C102000102, + C102000102, C102000102, C102000102, C102000102, + C102000102, new Color(102, 0, 51), + new Color(102, 0, 0), new Color(102, 51, 0), + C102102000, C102102000, C102102000, C102102000, + C102102000, C102102000, C102102000, + new Color(51, 102, 0), new Color(0, 102, 0), + new Color(0, 102, 51), C000102102, C000102102, + C000102102, + + // Row 9. + Color.BLACK, C000051051, C000051051, C000051051, C000051051, C000051051, + new Color(0, 0, 51), C051000051, C051000051, + C051000051, C051000051, C051000051, C051000051, + C051000051, C051000051, C051000051, + new Color(51, 0, 0), C051051000, C051051000, + C051051000, C051051000, C051051000, C051051000, + C051051000, C051051000, new Color(0, 51, 0), + C000051051, C000051051, C000051051, C000051051, + new Color(51, 51, 51) + }; + + /** + * Creates a new MainSwatchPanel object. + */ + MainSwatchPanel() + { + super(); + numCols = 31; + numRows = 9; + initializeColors(); + revalidate(); + } + + /** + * This method returns the color for the given position. + * + * @param x The x location for the position. + * @param y The y location for the position. + * + * @return The color for the given position. + */ + public Color getColorForPosition(int x, int y) + { + if (x % (cellWidth + gap) > cellWidth + || y % (cellHeight + gap) > cellHeight) + // position is located in gap. + return null; + + int row = y / (cellHeight + gap); + int col = x / (cellWidth + gap); + return colors[row * numCols + col]; + } + + /** + * This method initializes the colors for the main swatch panel. + */ + protected void initializeColors() + { + // Unnecessary + } + + /** + * This method paints the main graphics panel with the given Graphics + * object. + * + * @param graphics The Graphics object to paint with. + */ + public void paint(Graphics graphics) + { + int index = 0; + Insets insets = getInsets(); + int currX = insets.left; + int currY = insets.top; + Color saved = graphics.getColor(); + + for (int i = 0; i < numRows; i++) + { + for (int j = 0; j < numCols; j++) + { + graphics.setColor(colors[index++]); + graphics.fill3DRect(currX, currY, cellWidth, cellHeight, true); + currX += gap + cellWidth; + } + currX = insets.left; + currY += gap + cellHeight; + } + graphics.setColor(saved); + } + + /** + * This method returns the tooltip text for the given MouseEvent. + * + * @param e The MouseEvent to find tooltip text for. + * + * @return The tooltip text. + */ + public String getToolTipText(MouseEvent e) + { + Color c = getColorForPosition(e.getX(), e.getY()); + if (c == null) + return null; + return (c.getRed() + "," + c.getGreen() + "," + c.getBlue()); + } + } + + /** + * This class is the recent swatch panel. It holds recently selected colors. + */ + static class RecentSwatchPanel extends SwatchPanel + { + /** The array for storing recently stored colors. */ + Color[] colors; + + /** The default color. */ + public static final Color defaultColor = Color.GRAY; + + /** The index of the array that is the start. */ + int start = 0; + + /** + * Creates a new RecentSwatchPanel object. + */ + RecentSwatchPanel() + { + super(); + numCols = 5; + numRows = 7; + initializeColors(); + revalidate(); + } + + /** + * This method returns the color for the given position. + * + * @param x The x coordinate of the position. + * @param y The y coordinate of the position. + * + * @return The color for the given position. + */ + public Color getColorForPosition(int x, int y) + { + if (x % (cellWidth + gap) > cellWidth + || y % (cellHeight + gap) > cellHeight) + // position is located in gap. + return null; + + int row = y / (cellHeight + gap); + int col = x / (cellWidth + gap); + + return colors[getIndexForCell(row, col)]; + } + + /** + * This method initializes the colors for the recent swatch panel. + */ + protected void initializeColors() + { + colors = new Color[numRows * numCols]; + for (int i = 0; i < colors.length; i++) + colors[i] = defaultColor; + } + + /** + * This method returns the array index for the given row and column. + * + * @param row The row. + * @param col The column. + * + * @return The array index for the given row and column. + */ + private int getIndexForCell(int row, int col) + { + return ((row * numCols) + col + start) % (numRows * numCols); + } + + /** + * This method adds the given color to the beginning of the swatch panel. + * Package-private to avoid an accessor method. + * + * @param c The color to add. + */ + void addColorToQueue(Color c) + { + if (--start == -1) + start = numRows * numCols - 1; + + colors[start] = c; + } + + /** + * This method paints the panel with the given Graphics object. + * + * @param g The Graphics object to paint with. + */ + public void paint(Graphics g) + { + Color saved = g.getColor(); + Insets insets = getInsets(); + int currX = insets.left; + int currY = insets.top; + + for (int i = 0; i < numRows; i++) + { + for (int j = 0; j < numCols; j++) + { + g.setColor(colors[getIndexForCell(i, j)]); + g.fill3DRect(currX, currY, cellWidth, cellHeight, true); + currX += cellWidth + gap; + } + currX = insets.left; + currY += cellWidth + gap; + } + } + + /** + * This method returns the tooltip text for the given MouseEvent. + * + * @param e The MouseEvent. + * + * @return The tooltip text. + */ + public String getToolTipText(MouseEvent e) + { + Color c = getColorForPosition(e.getX(), e.getY()); + if (c == null) + return null; + return c.getRed() + "," + c.getGreen() + "," + c.getBlue(); + } + } + + /** + * This class handles mouse events for the two swatch panels. + */ + class MouseHandler extends MouseAdapter + { + /** + * This method is called whenever the mouse is pressed. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + SwatchPanel panel = (SwatchPanel) e.getSource(); + Color c = panel.getColorForPosition(e.getX(), e.getY()); + recentPalette.addColorToQueue(c); + DefaultSwatchChooserPanel.this.getColorSelectionModel().setSelectedColor(c); + DefaultSwatchChooserPanel.this.repaint(); + } + } + + /** + * This is the layout manager for the main panel. + */ + static class MainPanelLayout implements LayoutManager + { + /** + * This method is called when a new component is added to the container. + * + * @param name The name of the component. + * @param comp The added component. + */ + public void addLayoutComponent(String name, Component comp) + { + } + + /** + * This method is called to set the size and position of the child + * components for the given container. + * + * @param parent The container to lay out. + */ + public void layoutContainer(Container parent) + { + Component[] comps = parent.getComponents(); + Insets insets = parent.getInsets(); + Dimension[] pref = new Dimension[comps.length]; + + int xpos = 0; + int ypos = 0; + int maxHeight = 0; + int totalWidth = 0; + + for (int i = 0; i < comps.length; i++) + { + pref[i] = comps[i].getPreferredSize(); + if (pref[i] == null) + return; + maxHeight = Math.max(maxHeight, pref[i].height); + totalWidth += pref[i].width; + } + + ypos = (parent.getSize().height - maxHeight) / 2 + insets.top; + xpos = insets.left + (parent.getSize().width - totalWidth) / 2; + + for (int i = 0; i < comps.length; i++) + { + if (pref[i] == null) + continue; + comps[i].setBounds(xpos, ypos, pref[i].width, pref[i].height); + xpos += pref[i].width; + } + } + + /** + * This method is called when a component is removed from the container. + * + * @param comp The component that was removed. + */ + public void removeLayoutComponent(Component comp) + { + } + + /** + * This methods calculates the minimum layout size for the container. + * + * @param parent The container. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + /** + * This method returns the preferred layout size for the given container. + * + * @param parent The container. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container parent) + { + int xmax = 0; + int ymax = 0; + + Component[] comps = parent.getComponents(); + Dimension pref; + + for (int i = 0; i < comps.length; i++) + { + pref = comps[i].getPreferredSize(); + if (pref == null) + continue; + xmax += pref.width; + ymax = Math.max(ymax, pref.height); + } + + Insets insets = parent.getInsets(); + + return new Dimension(insets.left + insets.right + xmax, + insets.top + insets.bottom + ymax); + } + } + + /** + * This is the layout manager for the recent swatch panel. + */ + static class RecentPanelLayout implements LayoutManager + { + /** + * This method is called when a component is added to the container. + * + * @param name The name of the component. + * @param comp The added component. + */ + public void addLayoutComponent(String name, Component comp) + { + // Nothing needs to be done. + } + + /** + * This method sets the size and position of the child components of the + * given container. + * + * @param parent The container to lay out. + */ + public void layoutContainer(Container parent) + { + Component[] comps = parent.getComponents(); + Dimension parentSize = parent.getSize(); + Insets insets = parent.getInsets(); + int currY = insets.top; + Dimension pref; + + for (int i = 0; i < comps.length; i++) + { + pref = comps[i].getPreferredSize(); + if (pref == null) + continue; + comps[i].setBounds(insets.left, currY, pref.width, pref.height); + currY += pref.height; + } + } + + /** + * This method calculates the minimum layout size for the given container. + * + * @param parent The container. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + /** + * This method calculates the preferred layout size for the given + * container. + * + * @param parent The container. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container parent) + { + int width = 0; + int height = 0; + Insets insets = parent.getInsets(); + Component[] comps = parent.getComponents(); + Dimension pref; + for (int i = 0; i < comps.length; i++) + { + pref = comps[i].getPreferredSize(); + if (pref != null) + { + width = Math.max(width, pref.width); + height += pref.height; + } + } + + return new Dimension(width + insets.left + insets.right, + height + insets.top + insets.bottom); + } + + /** + * This method is called whenever a component is removed from the + * container. + * + * @param comp The removed component. + */ + public void removeLayoutComponent(Component comp) + { + // Nothing needs to be done. + } + } + + /** + * Creates a new DefaultSwatchChooserPanel object. + */ + DefaultSwatchChooserPanel() + { + super(); + } + + /** + * This method updates the chooser panel with the new value from the + * JColorChooser. + */ + public void updateChooser() + { + } + + /** + * This method builds the chooser panel. + */ + protected void buildChooser() + { + // The structure of the swatch panel is: + // One large panel (minus the insets). + // Inside that panel, there are two panels, one holds the palette. + // The other holds the label and the recent colors palette. + // The two palettes are two custom swatch panels. + setLayout(new MainPanelLayout()); + + JPanel mainPaletteHolder = new JPanel(); + JPanel recentPaletteHolder = new JPanel(); + + mainPalette = new MainSwatchPanel(); + recentPalette = new RecentSwatchPanel(); + JLabel label = new JLabel("Recent:"); + + mouseHandler = new MouseHandler(); + mainPalette.addMouseListener(mouseHandler); + recentPalette.addMouseListener(mouseHandler); + + mainPaletteHolder.setLayout(new BorderLayout()); + mainPaletteHolder.add(mainPalette, BorderLayout.CENTER); + + recentPaletteHolder.setLayout(new RecentPanelLayout()); + recentPaletteHolder.add(label); + recentPaletteHolder.add(recentPalette); + + JPanel main = new JPanel(); + main.add(mainPaletteHolder); + main.add(recentPaletteHolder); + + this.add(main); + } + + /** + * This method removes the chooser panel from the JColorChooser. + * + * @param chooser The JColorChooser this panel is being removed from. + */ + public void uninstallChooserPanel(JColorChooser chooser) + { + recentPalette = null; + mainPalette = null; + + removeAll(); + super.uninstallChooserPanel(chooser); + } + + /** + * This method returns the JTabbedPane displayed name. + * + * @return The name displayed in the JTabbedPane. + */ + public String getDisplayName() + { + return "Swatches"; + } + + /** + * This method returns the small display icon. + * + * @return The small display icon. + */ + public Icon getSmallDisplayIcon() + { + return null; + } + + /** + * This method returns the large display icon. + * + * @return The large display icon. + */ + public Icon getLargeDisplayIcon() + { + return null; + } + + /** + * This method paints the chooser panel with the given Graphics object. + * + * @param g The Graphics object to paint with. + */ + public void paint(Graphics g) + { + super.paint(g); + } + + /** + * This method returns the tooltip text for the given MouseEvent. + * + * @param e The MouseEvent. + * + * @return The tooltip text. + */ + public String getToolTipText(MouseEvent e) + { + return null; + } +} diff --git a/libjava/classpath/javax/swing/colorchooser/package.html b/libjava/classpath/javax/swing/colorchooser/package.html new file mode 100644 index 00000000000..c04e96ebb10 --- /dev/null +++ b/libjava/classpath/javax/swing/colorchooser/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.event package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.colorchooser</title></head> + +<body> +<p>Provides support classes for the {@link javax.swing.JColorChooser} +component.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/event/AncestorEvent.java b/libjava/classpath/javax/swing/event/AncestorEvent.java new file mode 100644 index 00000000000..d06c6e39612 --- /dev/null +++ b/libjava/classpath/javax/swing/event/AncestorEvent.java @@ -0,0 +1,100 @@ +/* AncestorEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.awt.AWTEvent; +import java.awt.Container; + +import javax.swing.JComponent; + +/** + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class AncestorEvent extends AWTEvent +{ + private static final long serialVersionUID = -8079801679695605002L; + + public static final int ANCESTOR_ADDED = 1; + public static final int ANCESTOR_REMOVED = 2; + public static final int ANCESTOR_MOVED = 3; + + private JComponent sourceComponent; + private Container ancestor; + private Container ancestorParent; + + /** + * @param source Source component + * @param id ID + * @param ancestor ancestor + * @param ancestorParent parent ancestor + */ + public AncestorEvent(JComponent source, int id, Container ancestor, + Container ancestorParent) + { + super(source, id); + this.sourceComponent = source; + this.ancestor = ancestor; + this.ancestorParent = ancestorParent; + } + + /** + * Returns the ancestor of this event. + */ + public Container getAncestor() + { + return ancestor; + } + + /** + * Returns the ancester parent of this event. + */ + public Container getAncestorParent() + { + return ancestorParent; + } + + /** + * Returns the source of this event. + */ + public JComponent getComponent() + { + return sourceComponent; + } +} diff --git a/libjava/classpath/javax/swing/event/AncestorListener.java b/libjava/classpath/javax/swing/event/AncestorListener.java new file mode 100644 index 00000000000..61d5aedb7c9 --- /dev/null +++ b/libjava/classpath/javax/swing/event/AncestorListener.java @@ -0,0 +1,69 @@ +/* AncestorListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * AncestorListener Interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface AncestorListener extends EventListener { + + /** + * Ancestor Added + * @param event Ancestor Event + */ + void ancestorAdded(AncestorEvent event); + + /** + * Ancestor Removed + * @param event Ancestor Event + */ + void ancestorRemoved(AncestorEvent event); + + /** + * Ancestor Moved + * @param event Ancestor Event + */ + void ancestorMoved(AncestorEvent event); + + +} // AncestorListener diff --git a/libjava/classpath/javax/swing/event/CaretEvent.java b/libjava/classpath/javax/swing/event/CaretEvent.java new file mode 100644 index 00000000000..c4870a8008f --- /dev/null +++ b/libjava/classpath/javax/swing/event/CaretEvent.java @@ -0,0 +1,79 @@ +/* CaretEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventObject; + +/** + * CaretEvent + * @author Andrew Selkirk + */ +public abstract class CaretEvent extends EventObject { + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * CaretEvent constructor + * @param source Source object + */ + public CaretEvent(Object source) { + super(source); + } // CaretEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * Get caret location + * @returns the dot + */ + public abstract int getDot(); + + /** + * Get mark + * @returns the mark + */ + public abstract int getMark(); + + +} // CaretEvent diff --git a/libjava/classpath/javax/swing/event/CaretListener.java b/libjava/classpath/javax/swing/event/CaretListener.java new file mode 100644 index 00000000000..aeee434e50b --- /dev/null +++ b/libjava/classpath/javax/swing/event/CaretListener.java @@ -0,0 +1,56 @@ +/* CaretListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * CaretListener public interface + * @author Andrew Selkirk + */ +public interface CaretListener extends EventListener { + + /** + * Caret position has been updated + * @param event Caret Event + */ + void caretUpdate(CaretEvent event); + + +} // CaretListener diff --git a/libjava/classpath/javax/swing/event/CellEditorListener.java b/libjava/classpath/javax/swing/event/CellEditorListener.java new file mode 100644 index 00000000000..d2dd5bab8ec --- /dev/null +++ b/libjava/classpath/javax/swing/event/CellEditorListener.java @@ -0,0 +1,62 @@ +/* CellEditorListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * CellEditorListener public interface + * @author Andrew Selkirk + */ +public interface CellEditorListener extends EventListener { + + /** + * Editing has been canceled + * @param event Change Event + */ + void editingCanceled(ChangeEvent event); + + /** + * Editing has been stopped + * @param event Change Event + */ + void editingStopped(ChangeEvent event); + + +} // CellEditorListener diff --git a/libjava/classpath/javax/swing/event/ChangeEvent.java b/libjava/classpath/javax/swing/event/ChangeEvent.java new file mode 100644 index 00000000000..f75c15aac83 --- /dev/null +++ b/libjava/classpath/javax/swing/event/ChangeEvent.java @@ -0,0 +1,59 @@ +/* ChangeEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventObject; + +/** + * ChangeEvent + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class ChangeEvent extends EventObject { + + /** + * ChangeEvent constructor + * @param source Source object + */ + public ChangeEvent(Object source) { + super(source); + } // ChangeEvent() + + +} // ChangeEvent diff --git a/libjava/classpath/javax/swing/event/ChangeListener.java b/libjava/classpath/javax/swing/event/ChangeListener.java new file mode 100644 index 00000000000..1e58b1d82d9 --- /dev/null +++ b/libjava/classpath/javax/swing/event/ChangeListener.java @@ -0,0 +1,57 @@ +/* ChangeListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * ChangeListener interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface ChangeListener extends EventListener { + + /** + * State changed + * @param event Change Event + */ + void stateChanged(ChangeEvent event); + + +} // ChangeListener diff --git a/libjava/classpath/javax/swing/event/DocumentEvent.java b/libjava/classpath/javax/swing/event/DocumentEvent.java new file mode 100644 index 00000000000..6a005ea7a5b --- /dev/null +++ b/libjava/classpath/javax/swing/event/DocumentEvent.java @@ -0,0 +1,166 @@ +/* DocumentEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +import javax.swing.text.Document; +import javax.swing.text.Element; + +/** + * DocumentEvent public interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface DocumentEvent { + + //------------------------------------------------------------- + // Classes ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * ElementChange public interface + */ + public interface ElementChange { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getIndex + * @returns int + */ + int getIndex(); + + /** + * getElement + * @returns Element + */ + Element getElement(); + + /** + * getChildrenRemoved + * @returns Element[] + */ + Element[] getChildrenRemoved(); + + /** + * getChildrenAdded + * @returns Element[] + */ + Element[] getChildrenAdded(); + + + } // ElementChange + + /** + * EventType + */ + class EventType + { + /** + * INSERT + */ + public static final EventType INSERT = new EventType("INSERT"); // TODO + + /** + * REMOVE + */ + public static final EventType REMOVE = new EventType("REMOVE"); // TODO + + /** + * CHANGE + */ + public static final EventType CHANGE = new EventType("CHANGE"); // TODO + + /** + * typeString + */ + private String type; + + /** + * Constructor EventType + * @param type TODO + */ + private EventType(String type) + { + this.type = type; + } + + /** + * toString + * @returns String + */ + public String toString() + { + return type; + } + } + + /** + * getType + * @returns EventType + */ + EventType getType(); + + /** + * getOffset + * @returns int + */ + int getOffset(); + + /** + * getLength + * @returns int + */ + int getLength(); + + /** + * getDocument + * @returns Document + */ + Document getDocument(); + + /** + * getChange + * @param element TODO + * @returns ElementChange + */ + ElementChange getChange(Element element); + + +} // DocumentEvent diff --git a/libjava/classpath/javax/swing/event/DocumentListener.java b/libjava/classpath/javax/swing/event/DocumentListener.java new file mode 100644 index 00000000000..df5e784e40f --- /dev/null +++ b/libjava/classpath/javax/swing/event/DocumentListener.java @@ -0,0 +1,68 @@ +/* DocumentListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +import java.util.EventListener; + +/** + * DocumentListener public interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface DocumentListener extends EventListener { + + /** + * Changed update + * @param event Document Event + */ + void changedUpdate(DocumentEvent event); + + /** + * Insert update + * @param event Document Event + */ + void insertUpdate(DocumentEvent event); + + /** + * Remove update + * @param event Document Event + */ + void removeUpdate(DocumentEvent event); + + +} // DocumentListener diff --git a/libjava/classpath/javax/swing/event/EventListenerList.java b/libjava/classpath/javax/swing/event/EventListenerList.java new file mode 100644 index 00000000000..ea14d4d1474 --- /dev/null +++ b/libjava/classpath/javax/swing/event/EventListenerList.java @@ -0,0 +1,302 @@ +/* EventListenerList.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.EventListener; + + +/** + * A utility class for keeping track of {@link EventListener}s. + * + * <p><b>Example for using this class:</b> + * + * <blockquote><pre> import java.util.EventListener; + * import javax.swing.event.EventListenerList; + * + * class Foo + * { + * protected final EventListenerList listeners = new EventListenerList(); + * protected BarClosedEvent barClosedEvent = null; + * + * public void addBarListener(BarListener l) + * { + * listeners.<a href="#add(java.lang.Class, java.util.EventListener)" + * >add</a>(BarListener.class, l); + * } + * + * public void removeBarListener(BarListener l) + * { + * listeners.<a href="#remove(java.lang.Class, java.util.EventListener)" + * >remove</a>(BarListener.class, l); + * } + * + * protected void fireBarClosedEvent() + * { + * Object[] l = listeners.<a href="#getListenerList()" + * >getListenerList()</a>; + * + * for (int i = l.length - 2; i >= 0; i -= 2) + * if (l[i] == BarListener.class) + * { + * // Create the event on demand, when it is needed the first time. + * if (barClosedEvent == null) + * barClosedEvent = new BarClosedEvent(this); + * + * ((BarClosedListener) l[i + 1]).barClosed(barClosedEvent); + * } + * } + * }</pre></blockquote> + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class EventListenerList + implements Serializable +{ + /** + * An ID for serializing instances of this class; verified with the + * serialver tool of Sun J2SE 1.4.1_01. + */ + static final long serialVersionUID = -5677132037850737084L; + + + /** + * An empty array that is shared by all instances of this class that + * have no listeners. + */ + private static final Object[] NO_LISTENERS = new Object[0]; + + + /** + * An array with all currently registered listeners. The array has + * twice as many elements as there are listeners. For an even + * integer <code>i</code>, <code>listenerList[i]</code> indicates + * the registered class, and <code>listenerList[i+1]</code> is the + * listener. + */ + protected transient Object[] listenerList = NO_LISTENERS; + + + /** + * EventListenerList constructor + */ + public EventListenerList() + { + } + + + /** + * Registers a listener of a specific type. + * + * @param t the type of the listener. + * + * @param listener the listener to add, which must be an instance of + * <code>t</code>, or of a subclass of <code>t</code>. + * + * @throws IllegalArgumentException if <code>listener</code> is not + * an instance of <code>t</code> (or a subclass thereof). + * + * @throws Exception if <code>t</code> is <code>null</code>. + */ + public void add(Class t, EventListener listener) + { + int oldLength; + Object[] newList; + + if (listener == null) + return; + + if (!t.isInstance(listener)) + throw new IllegalArgumentException(); + + oldLength = listenerList.length; + newList = new Object[oldLength + 2]; + if (oldLength > 0) + System.arraycopy(listenerList, 0, newList, 0, oldLength); + + newList[oldLength] = t; + newList[oldLength + 1] = listener; + listenerList = newList; + } + + + /** + * Determines the number of listeners. + */ + public int getListenerCount() + { + return listenerList.length / 2; + } + + + /** + * Determines the number of listeners of a particular class. + * + * @param t the type of listeners to be counted. In order to get + * counted, a subscribed listener must be exactly of class + * <code>t</code>. Thus, subclasses of <code>t</code> will not be + * counted. + */ + public int getListenerCount(Class t) + { + int result = 0; + for (int i = 0; i < listenerList.length; i += 2) + if (t == listenerList[i]) + ++result; + + return result; + } + + + /** + * Get a list of listenerType/listener pairs + * @returns Listener list + */ + public Object[] getListenerList() + { + return listenerList; + } + + + /** + * Retrieves the currently subscribed listeners of a particular + * type. For a listener to be returned, it must have been + * registered with exactly the type <code>c</code>; subclasses are + * not considered equal. + * + * <p>The returned array can always be cast to <code>c[]</code>. + * Since it is a newly allocated copy, the caller may arbitrarily + * modify the array. + * + * @param c the class which was passed to {@link #add}. + * + * @throws ClassCastException if <code>c</code> does not implement + * the {@link EventListener} interface. + * + * @throws NullPointerException if <code>c</code> is + * <code>null</code>. + * + * @returns an array of <code>c</code> whose elements are the + * currently subscribed listeners of the specified type. If there + * are no such listeners, an empty array is returned. + * + * @since 1.3 + */ + public EventListener[] getListeners(Class c) + { + int count, f; + EventListener[] result; + + count = getListenerCount(c); + result = (EventListener[]) Array.newInstance(c, count); + f = 0; + for (int i = 0; i < listenerList.length; i += 2) + if (listenerList[i] == c) + result[f++] = (EventListener) listenerList[i + 1]; + + return result; + } + + + /** + * Removes a listener of a specific type. + * + * @param t the type of the listener. + * + * @param listener the listener to remove, which must be an instance + * of <code>t</code>, or of a subclass of <code>t</code>. + * + * @throws IllegalArgumentException if <code>listener</code> is not + * an instance of <code>t</code> (or a subclass thereof). + * + * @throws Exception if <code>t</code> is <code>null</code>. + */ + public void remove(Class t, EventListener listener) + { + Object[] oldList, newList; + int oldLength; + + if (listener == null) + return; + + if (!t.isInstance(listener)) + throw new IllegalArgumentException(); + + oldList = listenerList; + oldLength = oldList.length; + for (int i = 0; i < oldLength; i += 2) + if (oldList[i] == t && oldList[i + 1] == listener) + { + if (oldLength == 2) + newList = NO_LISTENERS; + else + { + newList = new Object[oldLength - 2]; + if (i > 0) + System.arraycopy(oldList, 0, newList, 0, i); + if (i < oldLength - 2) + System.arraycopy(oldList, i + 2, newList, i, + oldLength - 2 - i); + } + listenerList = newList; + return; + } + } + + + /** + * Returns a string representation of this object that may be useful + * for debugging purposes. + */ + public String toString() + { + StringBuffer buf = new StringBuffer("EventListenerList: "); + buf.append(listenerList.length / 2); + buf.append(" listeners: "); + for (int i = 0; i < listenerList.length; i += 2) + { + buf.append(" type "); + buf.append(((Class) listenerList[i]).getName()); + buf.append(" listener "); + buf.append(listenerList[i + 1]); + } + return buf.toString(); + } +} diff --git a/libjava/classpath/javax/swing/event/HyperlinkEvent.java b/libjava/classpath/javax/swing/event/HyperlinkEvent.java new file mode 100644 index 00000000000..4afa009f4f9 --- /dev/null +++ b/libjava/classpath/javax/swing/event/HyperlinkEvent.java @@ -0,0 +1,162 @@ +/* HyperlinkEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.net.URL; +import java.util.EventObject; + +import javax.swing.text.Element; + +/** + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class HyperlinkEvent extends EventObject +{ + public static final class EventType + { + public static final EventType ENTERED = new EventType("ENTERED"); // TODO + public static final EventType EXITED = new EventType("EXITED"); // TODO + public static final EventType ACTIVATED = new EventType("ACTIVATED"); // TODO + + private String type; + + /** + * Creates a new Event type. + * + * @param type String representing the event type. + */ + private EventType(String type) + { + this.type = type; + } + + /** + * Returns a <code>String</code> of this object. + */ + public String toString() + { + return type; + } + } + + private static final long serialVersionUID = -2054640811732867012L; + + private EventType type; + private URL url; + private String description; + private Element element; + + /** + * Creates a new <code>HyperlinkEvent</code> with the given arguments. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + */ + public HyperlinkEvent(Object source, EventType type, URL url) + { + this (source, type, url, null, null); + } + + /** + * Creates a new <code>HyperlinkEvent</code> with the given arguments. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + * @param description The description for this link. + */ + public HyperlinkEvent(Object source, EventType type, URL url, + String description) + { + this (source, type, url, description, null); + } + + /** + * Creates a new <code>HyperlinkEvent</code> with the given arguments. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + * @param description The description for this link. + * @param element The element in the document representing the anchor. + */ + public HyperlinkEvent(Object source, EventType type, URL url, + String description, Element element) + { + super(source); + this.type = type; + this.url = url; + this.description = description; + this.element = element; + } + + /** + * Returns the element of the document repesenting this anchor. + */ + public Element getSourceElement() + { + return element; + } + + /** + * Returns the URL of this event. + */ + public URL getURL() + { + return url; + } + + /** + * Returns the type of this event. + */ + public EventType getEventType() + { + return type; + } + + /** + * Returns the description of this event. + */ + public String getDescription() + { + return description; + } +} diff --git a/libjava/classpath/javax/swing/event/HyperlinkListener.java b/libjava/classpath/javax/swing/event/HyperlinkListener.java new file mode 100644 index 00000000000..5dede993fc0 --- /dev/null +++ b/libjava/classpath/javax/swing/event/HyperlinkListener.java @@ -0,0 +1,57 @@ +/* HyperlinkListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * HyperlinkListener + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface HyperlinkListener extends EventListener { + + /** + * Hyperlink updated + * @param event Hyperlink Event + */ + void hyperlinkUpdate(HyperlinkEvent event); + + +} // HyperlinkListener diff --git a/libjava/classpath/javax/swing/event/InternalFrameAdapter.java b/libjava/classpath/javax/swing/event/InternalFrameAdapter.java new file mode 100644 index 00000000000..a2878e76e79 --- /dev/null +++ b/libjava/classpath/javax/swing/event/InternalFrameAdapter.java @@ -0,0 +1,113 @@ +/* InternalFrameAdapter.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +/** + * InternalFrameAdapter + * @author Andrew Selkirk + */ +public abstract class InternalFrameAdapter implements InternalFrameListener +{ + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * InternalFrameAdapter constructor + */ + public InternalFrameAdapter() { + } // InternalFrameAdapter() + + + //------------------------------------------------------------- + // Interface: InternalFrameListener --------------------------- + //------------------------------------------------------------- + + /** + * Internal frame activated + * @param event Internal frame event + */ + public void internalFrameActivated(InternalFrameEvent event) { + } // internalFrameActivated() + + /** + * Internal frame closed + * @param event Internal frame event + */ + public void internalFrameClosed(InternalFrameEvent event) { + } // internalFrameClosed() + + /** + * Internal frame closing + * @param event Internal frame event + */ + public void internalFrameClosing(InternalFrameEvent event) { + } // internalFrameClosing() + + /** + * Internal frame deactivated + * @param event Internal frame event + */ + public void internalFrameDeactivated(InternalFrameEvent event) { + } // internalFrameDeactivated() + + /** + * Internal frame deiconified + * @param event Internal frame event + */ + public void internalFrameDeiconified(InternalFrameEvent event) { + } // internalFrameDeiconified() + + /** + * Internal frame iconified + * @param event Internal frame event + */ + public void internalFrameIconified(InternalFrameEvent event) { + } // internalFrameIconified() + + /** + * Internal frame opened + * @param event Internal frame event + */ + public void internalFrameOpened(InternalFrameEvent event) { + } // internalFrameOpened() + + +} // InternalFrameAdapter diff --git a/libjava/classpath/javax/swing/event/InternalFrameEvent.java b/libjava/classpath/javax/swing/event/InternalFrameEvent.java new file mode 100644 index 00000000000..badfa80aca7 --- /dev/null +++ b/libjava/classpath/javax/swing/event/InternalFrameEvent.java @@ -0,0 +1,115 @@ +/* InternalFrameEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.awt.AWTEvent; + +import javax.swing.JInternalFrame; + +/** + * @author Andrew Selkirk + */ +public class InternalFrameEvent extends AWTEvent +{ + private static final long serialVersionUID = -5204823611874873183L; + + /** + * Internal frame activated event + */ + public static final int INTERNAL_FRAME_ACTIVATED = 25554; + + /** + * Internal frame closed event + */ + public static final int INTERNAL_FRAME_CLOSED = 25551; + + /** + * Internal frame closing event + */ + public static final int INTERNAL_FRAME_CLOSING = 25550; + + /** + * Internal frame deactivated event + */ + public static final int INTERNAL_FRAME_DEACTIVATED = 25555; + + /** + * Internal frame deiconifed event + */ + public static final int INTERNAL_FRAME_DEICONIFIED = 25553; + + /** + * Internal frame frame first event + */ + public static final int INTERNAL_FRAME_FIRST = 25549; + + /** + * Internal frame iconified event + */ + public static final int INTERNAL_FRAME_ICONIFIED = 25552; + + /** + * Internal frame last event + */ + public static final int INTERNAL_FRAME_LAST = 25555; + + /** + * Internal frame opened event + */ + public static final int INTERNAL_FRAME_OPENED = 25549; + + /** + * Creates a <code>JInternalFrameEvent</code> object. + * + * @param source The source of this event. + * @param id Then event ID of this event. + */ + public InternalFrameEvent(JInternalFrame source, int id) + { + super(source, id); + } + + /** + * Returns the <code>JInternalFrame</code> object stored in this event. + */ + public JInternalFrame getInternalFrame() + { + return (JInternalFrame) source; + } +} diff --git a/libjava/classpath/javax/swing/event/InternalFrameListener.java b/libjava/classpath/javax/swing/event/InternalFrameListener.java new file mode 100644 index 00000000000..d1b2812a86f --- /dev/null +++ b/libjava/classpath/javax/swing/event/InternalFrameListener.java @@ -0,0 +1,92 @@ +/* InternalFrameListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * InternalFrameListener public interface + * @author Andrew Selkirk + */ +public interface InternalFrameListener extends EventListener { + + /** + * Internal frame activated + * @param event Internal Frame Event + */ + void internalFrameActivated(InternalFrameEvent event); + + /** + * Internal frame closed + * @param event Internal Frame Event + */ + void internalFrameClosed(InternalFrameEvent event); + + /** + * Internal frame closing + * @param event Internal Frame Event + */ + void internalFrameClosing(InternalFrameEvent event); + + /** + * Internal frame deactivated + * @param event Internal Frame Event + */ + void internalFrameDeactivated(InternalFrameEvent event); + + /** + * Internal frame deiconified + * @param event Internal Frame Event + */ + void internalFrameDeiconified(InternalFrameEvent event); + + /** + * Internal frame iconified + * @param event Internal Frame Event + */ + void internalFrameIconified(InternalFrameEvent event); + + /** + * Internal frame opened + * @param event Internal Frame Event + */ + void internalFrameOpened(InternalFrameEvent event); + + +} // InternalFrameListener diff --git a/libjava/classpath/javax/swing/event/ListDataEvent.java b/libjava/classpath/javax/swing/event/ListDataEvent.java new file mode 100644 index 00000000000..2a6e6dbe9f0 --- /dev/null +++ b/libjava/classpath/javax/swing/event/ListDataEvent.java @@ -0,0 +1,98 @@ +/* ListDataEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +/** + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class ListDataEvent extends EventObject +{ + private static final long serialVersionUID = 2510353260071004774L; + + public static final int CONTENTS_CHANGED = 0; + public static final int INTERVAL_ADDED = 1; + public static final int INTERVAL_REMOVED = 2; + + private int type = 0; + private int index0 = 0; + private int index1 = 0; + + /** + * Creates a <code>ListDataEvent</code> object. + * + * @param source The source of the event. + * @param type The type of the event + * @param index0 Bottom of range + * @param index1 Top of range + */ + public ListDataEvent(Object source, int type, int index0, int index1) + { + super(source); + this.type = type; + this.index0 = index0; + this.index1 = index1; + } + + /** + * Returns the bottom index. + */ + public int getIndex0() + { + return index0; + } + + /** + * Returns the top index. + */ + public int getIndex1() + { + return index1; + } + + /** + * Returns the type of this event. + */ + public int getType() + { + return type; + } +} diff --git a/libjava/classpath/javax/swing/event/ListDataListener.java b/libjava/classpath/javax/swing/event/ListDataListener.java new file mode 100644 index 00000000000..7ce17d86fa6 --- /dev/null +++ b/libjava/classpath/javax/swing/event/ListDataListener.java @@ -0,0 +1,69 @@ +/* ListDataListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * ListDataListener public interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface ListDataListener extends EventListener { + + /** + * Contents Changed + * @param event ListDataEvent Event + */ + void contentsChanged(ListDataEvent event); + + /** + * Interval Added + * @param event ListDataEvent Event + */ + void intervalAdded(ListDataEvent event); + + /** + * Interval Removed + * @param event ListDataEvent Event + */ + void intervalRemoved(ListDataEvent event); + + +} // ListDataListener diff --git a/libjava/classpath/javax/swing/event/ListSelectionEvent.java b/libjava/classpath/javax/swing/event/ListSelectionEvent.java new file mode 100644 index 00000000000..e5e4c33bad9 --- /dev/null +++ b/libjava/classpath/javax/swing/event/ListSelectionEvent.java @@ -0,0 +1,126 @@ +/* ListSelectionEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventObject; + +/** + * ListSelectionEvent + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class ListSelectionEvent extends EventObject { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * firstIndex + */ + private int firstIndex = 0; + + /** + * lastIndex + */ + private int lastIndex = 0; + + /** + * isAdjusting + */ + private boolean isAdjusting = false; + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor ListSelectionEvent + * @param source Source + * @param firstIndex First index + * @param lastIndex Last index + * @param isAdjusting Is Adjusting? + */ + public ListSelectionEvent(Object source, int firstIndex, + int lastIndex, boolean isAdjusting) { + super(source); + this.firstIndex = firstIndex; + this.lastIndex = lastIndex; + this.isAdjusting = isAdjusting; + } // ListSelectionEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getFirstIndex + * @returns firstIndex + */ + public int getFirstIndex() { + return firstIndex; + } // getFirstIndex() + + /** + * getLastIndex + * @returns lastIndex + */ + public int getLastIndex() { + return lastIndex; + } // getLastIndex() + + /** + * getValueIsAdjusting + * @returns isAdjusting + */ + public boolean getValueIsAdjusting() { + return isAdjusting; + } // getValueIsAdjusting() + + /** + * String representation + * @returns String representation + */ + public String toString() { + return null; // TODO + } // toString() + + +} // ListSelectionEvent diff --git a/libjava/classpath/javax/swing/event/ListSelectionListener.java b/libjava/classpath/javax/swing/event/ListSelectionListener.java new file mode 100644 index 00000000000..4ebf5830432 --- /dev/null +++ b/libjava/classpath/javax/swing/event/ListSelectionListener.java @@ -0,0 +1,57 @@ +/* ListSelectionListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * ListSelectionListener public interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface ListSelectionListener extends EventListener { + + /** + * Value changed + * @param event List Selection Event + */ + void valueChanged(ListSelectionEvent event); + + +} // ListSelectionListener diff --git a/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java b/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java new file mode 100644 index 00000000000..99761670629 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MenuDragMouseEvent.java @@ -0,0 +1,115 @@ +/* MenuDragMouseEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.awt.Component; +import java.awt.event.MouseEvent; + +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; + +/** + * MenuDragMouseEvent + * @author Andrew Selkirk + */ +public class MenuDragMouseEvent extends MouseEvent { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * path + */ + private MenuElement[] path = null; + + /** + * manager + */ + private MenuSelectionManager manager = null; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor MenuDragMouseEvent + * @param source Source + * @param id MouseEvent type + * @param when Time + * @param modifiers Key modifiers + * @param x Horizontal position + * @param y Vertical position + * @param clickCount Click count + * @param popupTrigger Popup trigger? + * @param path Path + * @param manager MenuSelectionManager + */ + public MenuDragMouseEvent(Component source, int id, long when, int modifiers, + int x, int y, int clickCount, boolean popupTrigger, + MenuElement[] path, MenuSelectionManager manager) { + super(source, id, when, modifiers, x, y, clickCount, popupTrigger); + this.path = path; + this.manager = manager; + } // MenuDragMouseEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * Get path + * @returns path + */ + public MenuElement[] getPath() { + return path; + } // getPath() + + /** + * Get menu selection manager + * @returns manager + */ + public MenuSelectionManager getMenuSelectionManager() { + return manager; + } // getMenuSelectionManager() + + +} // MenuDragMouseEvent diff --git a/libjava/classpath/javax/swing/event/MenuDragMouseListener.java b/libjava/classpath/javax/swing/event/MenuDragMouseListener.java new file mode 100644 index 00000000000..bfca315e333 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MenuDragMouseListener.java @@ -0,0 +1,74 @@ +/* MenuDragMouseListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * MenuDragMouseListener public interface + * @author Andrew Selkirk + */ +public interface MenuDragMouseListener extends EventListener { + + /** + * Menu drag mouse dragged + * @param event Menu Drag Mouse Event + */ + void menuDragMouseDragged(MenuDragMouseEvent event); + + /** + * Menu drag mouse entered + * @param event Menu Drag Mouse Event + */ + void menuDragMouseEntered(MenuDragMouseEvent event); + + /** + * Menu drag mouse exited + * @param event Menu Drag Mouse Event + */ + void menuDragMouseExited(MenuDragMouseEvent event); + + /** + * Menu drag mouse released + * @param event Menu Drag Mouse Event + */ + void menuDragMouseReleased(MenuDragMouseEvent event); + + +} // MenuDragMouseListener diff --git a/libjava/classpath/javax/swing/event/MenuEvent.java b/libjava/classpath/javax/swing/event/MenuEvent.java new file mode 100644 index 00000000000..35bb5b97b43 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MenuEvent.java @@ -0,0 +1,59 @@ +/* MenuEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventObject; + +/** + * MenuEvent + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class MenuEvent extends EventObject { + + /** + * Constructor MenuEvent + * @param source Source object + */ + public MenuEvent(Object source) { + super(source); + } // MenuEvent() + + +} // MenuEvent diff --git a/libjava/classpath/javax/swing/event/MenuKeyEvent.java b/libjava/classpath/javax/swing/event/MenuKeyEvent.java new file mode 100644 index 00000000000..48fcb45b5b3 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MenuKeyEvent.java @@ -0,0 +1,113 @@ +/* MenuKeyEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.awt.Component; +import java.awt.event.KeyEvent; + +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; + +/** + * MenuKeyEvent + * @author Andrew Selkirk + */ +public class MenuKeyEvent extends KeyEvent { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * path + */ + private MenuElement[] path = null; + + /** + * manager + */ + private MenuSelectionManager manager = null; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor MenuKeyEvent + * @param source Source + * @param id KeyEvent ID + * @param when Time + * @param modifiers Modifier keys + * @param keyCode Key code + * @param keyhar Key char + * @param path Path + * @param manager MenuSelectionManager + */ + public MenuKeyEvent(Component source, int id, long when, int modifiers, + int keyCode, char keyChar, MenuElement[] path, + MenuSelectionManager manager) { + super(source, id, when, modifiers, keyCode, keyChar); + this.path = path; + this.manager = manager; + } // MenuKeyEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getPath + * @returns path + */ + public MenuElement[] getPath() { + return path; + } // getPath() + + /** + * getMenuSelectionManager + * @returns MenuSelectionManager + */ + public MenuSelectionManager getMenuSelectionManager() { + return manager; + } // getMenuSelectionManager() + + +} // MenuKeyEvent diff --git a/libjava/classpath/javax/swing/event/MenuKeyListener.java b/libjava/classpath/javax/swing/event/MenuKeyListener.java new file mode 100644 index 00000000000..7a1eb89b428 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MenuKeyListener.java @@ -0,0 +1,68 @@ +/* MenuKeyListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * MenuKeyListener public interface + * @author Andrew Selkirk + */ +public interface MenuKeyListener extends EventListener { + + /** + * Menu key pressed + * @param event Menu Key Event + */ + void menuKeyPressed(MenuKeyEvent event); + + /** + * Menu key released + * @param event Menu Key Event + */ + void menuKeyReleased(MenuKeyEvent event); + + /** + * Menu key typed + * @param event Menu Key Event + */ + void menuKeyTyped(MenuKeyEvent event); + + +} // MenuKeyListener diff --git a/libjava/classpath/javax/swing/event/MenuListener.java b/libjava/classpath/javax/swing/event/MenuListener.java new file mode 100644 index 00000000000..dba704a8ee1 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MenuListener.java @@ -0,0 +1,68 @@ +/* MenuListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * MenuListener public interface + * @author Andrew Selkirk + */ +public interface MenuListener extends EventListener { + + /** + * Menu canceled + * @param event Menu Event + */ + void menuCanceled(MenuEvent event); + + /** + * Menu deselected + * @param event Menu Event + */ + void menuDeselected(MenuEvent event); + + /** + * Menu selected + * @param event Menu Event + */ + void menuSelected(MenuEvent event); + + +} // MenuListener diff --git a/libjava/classpath/javax/swing/event/MouseInputAdapter.java b/libjava/classpath/javax/swing/event/MouseInputAdapter.java new file mode 100644 index 00000000000..2da5543eb91 --- /dev/null +++ b/libjava/classpath/javax/swing/event/MouseInputAdapter.java @@ -0,0 +1,119 @@ +/* MouseInputAdapter.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.awt.event.MouseEvent; + +/** + * MouseInputAdapter + * @author Andrew Selkirk + */ +public abstract class MouseInputAdapter implements MouseInputListener +{ + /** + * Constructor MouseInputAdapter + */ + public MouseInputAdapter() + { + // Do nothing here. + } + + /** + * Mouse clicked + * @param event Mouse event + */ + public void mouseClicked(MouseEvent event) + { + // Do nothing by default. + } + + /** + * Mouse dragged + * @param event Mouse event + */ + public void mouseDragged(MouseEvent event) + { + // Do nothing by default. + } + + /** + * Mouse entered + * @param event Mouse event + */ + public void mouseEntered(MouseEvent event) + { + // Do nothing by default. + } + + /** + * Mouse exited + * @param event Mouse event + */ + public void mouseExited(MouseEvent event) + { + // Do nothing by default. + } + + /** + * Mouse moved + * @param event Mouse event + */ + public void mouseMoved(MouseEvent event) + { + // Do nothing by default. + } + + /** + * Mouse pressed + * @param event Mouse event + */ + public void mousePressed(MouseEvent event) + { + // Do nothing by default. + } + + /** + * Mouse released + * @param event Mouse event + */ + public void mouseReleased(MouseEvent event) + { + // Do nothing by default. + } +} diff --git a/libjava/classpath/javax/swing/event/MouseInputListener.java b/libjava/classpath/javax/swing/event/MouseInputListener.java new file mode 100644 index 00000000000..3c3ca2347fe --- /dev/null +++ b/libjava/classpath/javax/swing/event/MouseInputListener.java @@ -0,0 +1,52 @@ +/* MouseInputListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +/** + * MouseInputListener public interface + * @author Andrew Selkirk + */ +public interface MouseInputListener extends MouseListener, + MouseMotionListener { + +} // MouseInputListener + diff --git a/libjava/classpath/javax/swing/event/PopupMenuEvent.java b/libjava/classpath/javax/swing/event/PopupMenuEvent.java new file mode 100644 index 00000000000..055555086ef --- /dev/null +++ b/libjava/classpath/javax/swing/event/PopupMenuEvent.java @@ -0,0 +1,58 @@ +/* PopupMenuEvent.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventObject; + +/** + * PopupMenuEvent + * @author Andrew Selkirk + */ +public class PopupMenuEvent extends EventObject { + + /** + * Constructor PopupMenuEvent + * @param source Source + */ + public PopupMenuEvent(Object source) { + super(source); + } // PopupMenuEvent() + + +} // PopupMenuEvent diff --git a/libjava/classpath/javax/swing/event/PopupMenuListener.java b/libjava/classpath/javax/swing/event/PopupMenuListener.java new file mode 100644 index 00000000000..dc917d2414c --- /dev/null +++ b/libjava/classpath/javax/swing/event/PopupMenuListener.java @@ -0,0 +1,68 @@ +/* PopupMenuListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * PopupMenuListener public interface + * @author Andrew Selkirk + */ +public interface PopupMenuListener extends EventListener { + + /** + * Popup Menu Canceled + * @param event Popup Menu Event + */ + void popupMenuCanceled(PopupMenuEvent event); + + /** + * Popup Menu will become invisible + * @param event Popup Menu Event + */ + void popupMenuWillBecomeInvisible(PopupMenuEvent event); + + /** + * Popup Menu will become visible + * @param event Popup Menu Event + */ + void popupMenuWillBecomeVisible(PopupMenuEvent event); + + +} // PopupMenuListener diff --git a/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java b/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java new file mode 100644 index 00000000000..ddbb4865883 --- /dev/null +++ b/libjava/classpath/javax/swing/event/SwingPropertyChangeSupport.java @@ -0,0 +1,255 @@ +/* SwingPropertyChangeSupport.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.EventListener; +import java.util.Hashtable; + +/** + * SwingPropertyChangeSupport + * @author Andrew Selkirk +*/ +public final class SwingPropertyChangeSupport + extends PropertyChangeSupport { + + private static final long serialVersionUID = 7162625831330845068L; + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * listeners + */ + private transient EventListenerList listeners; + + /** + * propertyListeners + */ + private Hashtable propertyListeners; + + /** + * source + */ + private Object source; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor SwingPropertyChangeSupport + * @param source TODO + */ + public SwingPropertyChangeSupport(Object source) { + super(source); + this.source = source; + this.listeners = new EventListenerList(); + this.propertyListeners = new Hashtable(); + } // SwingPropertyChangeSupport() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * writeObject + * @param stream TODO + * @exception IOException TODO + */ + private void writeObject(ObjectOutputStream stream) throws IOException { + // TODO + } // writeObject() + + /** + * readObject + * @param stream TODO + * @exception ClassNotFoundException TODO + * @exception IOException TODO + */ + private void readObject(ObjectInputStream stream) throws ClassNotFoundException, IOException { + // TODO + } // readObject() + + /** + * addPropertyChangeListener + * @param listener TODO + */ + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) { + listeners.add(PropertyChangeListener.class, listener); + } // addPropertyChangeListener() + + /** + * addPropertyChangeListener + * @param propertyName TODO + * @param listener TODO + */ + public synchronized void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { + + // Variables + EventListenerList list; + + // Get Listener list + list = (EventListenerList) propertyListeners.get(propertyName); + if (list == null) { + list = new EventListenerList(); + propertyListeners.put(propertyName, list); + } // if + + // Add Listeners + list.add(PropertyChangeListener.class, listener); + + } // addPropertyChangeListener() + + /** + * removePropertyChangeListener + * @param listener TODO + */ + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) { + listeners.remove(PropertyChangeListener.class, listener); + } // removePropertyChangeListener() + + /** + * removePropertyChangeListener + * @param propertyName TODO + * @param listener TODO + */ + public synchronized void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { + + // Variables + EventListenerList list; + + // Get Listener list + list = (EventListenerList) propertyListeners.get(propertyName); + if (list == null) { + return; + } // if + + // Remove Listeners + list.remove(PropertyChangeListener.class, listener); + + // Clean up propertyListeners + if (list.getListenerCount() == 0) { + propertyListeners.remove(propertyName); + } // if + + } // removePropertyChangeListener() + + /** + * firePropertyChange + * @param propertyName TODO + * @param oldValue TODO + * @param newValue TODO + */ + public void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + + // Variables + PropertyChangeEvent event; + + // Create Property Change Event + event = new PropertyChangeEvent(source, propertyName, oldValue, newValue); + + // Fire Event + firePropertyChange(event); + + } // firePropertyChange() + + /** + * firePropertyChange + * @param event TODO + */ + public void firePropertyChange(PropertyChangeEvent event) { + + // Variables + EventListenerList list; + EventListener[] listenerList; + int index; + PropertyChangeListener listener; + + // Check Values if they are equal + if (event.getOldValue() == null && event.getNewValue() == null || + (event.getOldValue() != null && event.getNewValue() != null && + event.getOldValue().equals(event.getNewValue()))) { + return; + } // if + + // Process Main Listener List + listenerList = listeners.getListeners(PropertyChangeListener.class); + for (index = 0; index < listenerList.length; index++) { + listener = (PropertyChangeListener) listenerList[index]; + listener.propertyChange(event); + } // for + + // Process Property Listener List + list = (EventListenerList) propertyListeners.get(event.getPropertyName()); + if (list != null) { + listenerList = list.getListeners(PropertyChangeListener.class); + for (index = 0; index < listenerList.length; index++) { + listener = (PropertyChangeListener) listenerList[index]; + listener.propertyChange(event); + } // for + } // if + + } // firePropertyChange() + + /** + * hasListeners + * @param propertyName TODO + * @returns boolean + */ + public synchronized boolean hasListeners(String propertyName) { + + // Get Listener list + if (propertyListeners.get(propertyName) == null) { + return false; + } // if + + return true; + + } // hasListeners() + + +} // SwingPropertyChangeSupport diff --git a/libjava/classpath/javax/swing/event/TableColumnModelEvent.java b/libjava/classpath/javax/swing/event/TableColumnModelEvent.java new file mode 100644 index 00000000000..2ca4148aadb --- /dev/null +++ b/libjava/classpath/javax/swing/event/TableColumnModelEvent.java @@ -0,0 +1,105 @@ +/* TableColumnModelEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +import javax.swing.table.TableColumnModel; + +/** + * TableColumnModelEvent + * @author Andrew Selkirk + */ +public class TableColumnModelEvent extends EventObject { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * fromIndex + */ + protected int fromIndex = 0; + + /** + * toIndex + */ + protected int toIndex = 0; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor TableColumnModelEvent + * @param source Source TableColumnModel + * @param from From index + * @param to To index + */ + public TableColumnModelEvent(TableColumnModel source, + int from, int to) { + super(source); + fromIndex = from; + toIndex = to; + } // TableColumnModelEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getFromIndex. + * @returns From index + */ + public int getFromIndex() { + return fromIndex; + } // getFromIndex() + + /** + * getToIndex. + * @returns To index + */ + public int getToIndex() { + return toIndex; + } // getToIndex() + + +} // TableColumnModelEvent diff --git a/libjava/classpath/javax/swing/event/TableColumnModelListener.java b/libjava/classpath/javax/swing/event/TableColumnModelListener.java new file mode 100644 index 00000000000..90e1b29cc57 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TableColumnModelListener.java @@ -0,0 +1,80 @@ +/* TableColumnModelListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * TableColumnModelListener public interface + * @author Andrew Selkirk + */ +public interface TableColumnModelListener extends EventListener { + + /** + * Column added + * @param event Table Column Model Event + */ + void columnAdded(TableColumnModelEvent event); + + /** + * Column margin changed + * @param event Change Event + */ + void columnMarginChanged(ChangeEvent event); + + /** + * Column moved + * @param event Table Column Model Event + */ + void columnMoved(TableColumnModelEvent event); + + /** + * Column removed + * @param event Table Column Model Event + */ + void columnRemoved(TableColumnModelEvent event); + + /** + * Column selection changed + * @param event List Selection Event + */ + void columnSelectionChanged(ListSelectionEvent event); + + +} // TableColumnModelListener diff --git a/libjava/classpath/javax/swing/event/TableModelEvent.java b/libjava/classpath/javax/swing/event/TableModelEvent.java new file mode 100644 index 00000000000..e15174cc6c2 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TableModelEvent.java @@ -0,0 +1,220 @@ +/* TableModelEvent.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +import javax.swing.table.TableModel; + +/** + * An event that describes changes to a {@link TableModel}. + * + * @see javax.swing.event.TableModelListener + * + * @author Andrew Selkirk + */ +public class TableModelEvent extends EventObject +{ + private static final long serialVersionUID = -7849342674552212824L; + + /** A column index representing all columns. */ + public static final int ALL_COLUMNS = -1; + + /** + * An event type indicating that one or more rows have been deleted from the + * model. + */ + public static final int DELETE = -1; + + /** A row index representing the header row. */ + public static final int HEADER_ROW = -1; + + /** + * An event type indicating that one or more rows have been inserted into the + * model. + */ + public static final int INSERT = 1; + + /** An event type indicating that data has been updated in the model. */ + public static final int UPDATE = 0; + + /** The column in the table model that the event relates to. */ + protected int column = 0; + + /** The first row in the table model that the event relates to. */ + protected int firstRow = 0; + + /** The last row in the table model that the event relates to. */ + protected int lastRow = 0; + + /** + * The event type (one of {@link #UPDATE}, {@link #INSERT}, {@link #DELETE}). + */ + protected int type = 0; + + /** + * Creates a new <code>TableModelEvent</code> indicating an {@link #UPDATE} + * to the data in all columns and rows. + * + * @param source the source object (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. + */ + public TableModelEvent(TableModel source) + { + this(source, 0, Integer.MAX_VALUE, ALL_COLUMNS, UPDATE); + } + + /** + * Creates a new <code>TableModelEvent</code> indicating an {@link #UPDATE} + * to the data in a single row across all columns. + * + * @param source the source object (<code>null</code> not permitted). + * @param row the updated row. + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. + */ + public TableModelEvent(TableModel source, int row) + { + this(source, row, row, ALL_COLUMNS, UPDATE); + } + + /** + * Creates a new <code>TableModelEvent</code> indicating an {@link #UPDATE} + * to the data in the specified rows across all columns. + * + * @param source the source object (<code>null</code> not permitted). + * @param firstRow the first row of update. + * @param lastRow the last row of update. + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. + */ + public TableModelEvent(TableModel source, int firstRow, int lastRow) + { + this(source, firstRow, lastRow, ALL_COLUMNS, UPDATE); + } + + /** + * Creates a new <code>TableModelEvent</code> indicating an {@link #UPDATE} + * to the data in the specified rows and column. Use {@link #ALL_COLUMNS} + * for the <code>column</code> argument to indicate all columns. + * + * @param source the source object (<code>null</code> not permitted). + * @param firstRow the first row of update. + * @param lastRow the last row of update. + * @param column the affected column. + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. + */ + public TableModelEvent(TableModel source, int firstRow, int lastRow, + int column) + { + this(source, firstRow, lastRow, column, UPDATE); + } + + /** + * Creates a new <code>TableModelEvent</code> indicating an operation of + * the specified <code>type</code> on the data in the specified rows and + * column. The event type is usually one of {@link #UPDATE}, {@link #INSERT}, + * and {@link #DELETE}. + * + * @param source the source object (<code>null</code> not permitted). + * @param firstRow the first row of update. + * @param lastRow the last row of update. + * @param column the affected column. + * @param type the type of change. + * + * @throws IllegalArgumentException if <code>source</code> is + * <code>null</code>. + */ + public TableModelEvent(TableModel source, int firstRow, int lastRow, + int column, int type) + { + super(source); + this.firstRow = firstRow; + this.lastRow = lastRow; + this.column = column; + this.type = type; + } + + /** + * Returns the affected column of this event. + * + * @return The column index. + */ + public int getColumn() + { + return column; + } + + /** + * Returns the first affected row of this event. + * + * @return The row index. + */ + public int getFirstRow() + { + return firstRow; + } + + /** + * Returns the last affected row of this event. + * + * @return The row index. + */ + public int getLastRow() + { + return lastRow; + } + + /** + * Returns the type of change indicated by this event (usually one of + * {@link #UPDATE}, {@link #INSERT}, {@link #DELETE}). + * + * @return The type. + */ + public int getType() + { + return type; + } +} diff --git a/libjava/classpath/javax/swing/event/TableModelListener.java b/libjava/classpath/javax/swing/event/TableModelListener.java new file mode 100644 index 00000000000..c8d6e8f8dbc --- /dev/null +++ b/libjava/classpath/javax/swing/event/TableModelListener.java @@ -0,0 +1,55 @@ +/* TableModelListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +import java.util.EventListener; + +/** + * TableModelListener public interface + * @author Andrew Selkirk + */ +public interface TableModelListener extends EventListener { + + /** + * Table changed + * @param event Table Model Event + */ + void tableChanged(TableModelEvent event); + + +} // TableModelListener diff --git a/libjava/classpath/javax/swing/event/TreeExpansionEvent.java b/libjava/classpath/javax/swing/event/TreeExpansionEvent.java new file mode 100644 index 00000000000..c4b33134694 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeExpansionEvent.java @@ -0,0 +1,89 @@ +/* TreeExpansionEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +import javax.swing.tree.TreePath; + +/** + * TreeExpansionEvent + * @author Andrew Selkirk + */ +public class TreeExpansionEvent extends EventObject { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * path + */ + protected TreePath path = null; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor TreeExpansionEvent + * @param source Source object + * @param path Path + */ + public TreeExpansionEvent(Object source, TreePath path) { + super(source); + this.path = path; + } // TreeExpansionEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getPath + * @returns Tree path + */ + public TreePath getPath() { + return path; + } // getPath() + + +} // TreeExpansionEvent diff --git a/libjava/classpath/javax/swing/event/TreeExpansionListener.java b/libjava/classpath/javax/swing/event/TreeExpansionListener.java new file mode 100644 index 00000000000..08507a0ffe9 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeExpansionListener.java @@ -0,0 +1,62 @@ +/* TreeExpansionListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * TreeExpansionListener public interface + * @author Andrew Selkirk + */ +public interface TreeExpansionListener extends EventListener { + + /** + * Tree collapsed + * @param event Tree Expansion Event + */ + void treeCollapsed(TreeExpansionEvent event); + + /** + * Tree expanded + * @param event Tree Expansion Event + */ + void treeExpanded(TreeExpansionEvent event); + + +} // TreeExpansionListener diff --git a/libjava/classpath/javax/swing/event/TreeModelEvent.java b/libjava/classpath/javax/swing/event/TreeModelEvent.java new file mode 100644 index 00000000000..a217e3b4053 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeModelEvent.java @@ -0,0 +1,171 @@ +/* TreeModelEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +import javax.swing.tree.TreePath; + +/** + * TreeModelEvent + * @author Andrew Selkirk + */ +public class TreeModelEvent extends EventObject { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * childIndices + */ + protected int[] childIndices = new int[0]; + + /** + * children + */ + protected Object[] children = new Object[0]; + + /** + * path + */ + protected TreePath path = null; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path + */ + public TreeModelEvent(Object source, Object[] path) { + super(source); + this.path = new TreePath(path); + } // TreeModelEvent() + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path path + * @param childIndices Child indices + * @param children Children + */ + public TreeModelEvent(Object source, Object[] path, + int[] childIndices, Object[] children) { + super(source); + this.path = new TreePath(path); + this.childIndices = childIndices; + this.children = children; + } // TreeModelEvent() + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path Path + */ + public TreeModelEvent(Object source, TreePath path) { + super(source); + this.path = path; + } // TreeModelEvent() + + /** + * Constructor TreeModelEvent + * @param source Source object + * @param path Path + * @param childIndices Child indices + * @param children Children + */ + public TreeModelEvent(Object source, TreePath path, + int[] childIndices, Object[] children) { + super(source); + this.path = path; + this.childIndices = childIndices; + this.children = children; + } // TreeModelEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getChildIndices + * @returns child indices + */ + public int[] getChildIndices() { + return childIndices; + } // getChildIndices() + + /** + * getChildren + * @returns children + */ + public Object[] getChildren() { + return children; + } // getChildren() + + /** + * getPath + * @returns path + */ + public Object[] getPath() { + return path.getPath(); + } // getPath() + + /** + * getTreePath + * @returns TreePath + */ + public TreePath getTreePath() { + return path; + } // getTreePath() + + /** + * String representation + * @returns String representation + */ + public String toString() { + return null; // TODO + } // toString() + + +} // TreeModelEvent diff --git a/libjava/classpath/javax/swing/event/TreeModelListener.java b/libjava/classpath/javax/swing/event/TreeModelListener.java new file mode 100644 index 00000000000..57b5c511b8b --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeModelListener.java @@ -0,0 +1,74 @@ +/* TreeModelListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * TreeModelListener public interface + * @author Andrew Selkirk + */ +public interface TreeModelListener extends EventListener { + + /** + * Tree nodes changed + * @param event Tree Model Event + */ + void treeNodesChanged(TreeModelEvent event); + + /** + * Tree nodes inserted + * @param event Tree Model Event + */ + void treeNodesInserted(TreeModelEvent event); + + /** + * Tree nodes removed + * @param event Tree Model Event + */ + void treeNodesRemoved(TreeModelEvent event); + + /** + * Tree structured changed + * @param event Tree Model Event + */ + void treeStructureChanged(TreeModelEvent event); + + +} // TreeModelListener diff --git a/libjava/classpath/javax/swing/event/TreeSelectionEvent.java b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java new file mode 100644 index 00000000000..df4e0ff9128 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeSelectionEvent.java @@ -0,0 +1,199 @@ +/* TreeSelectionEvent.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +import javax.swing.tree.TreePath; + +/** + * TreeSelectionEvent + * @author Andrew Selkirk + * @version 1.0 + */ +public class TreeSelectionEvent extends EventObject { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * paths + */ + protected TreePath[] paths; + + /** + * areNew + */ + protected boolean[] areNew; + + /** + * oldLeadSelectionPath + */ + protected TreePath oldLeadSelectionPath; + + /** + * newLeadSelectionPath + */ + protected TreePath newLeadSelectionPath; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor TreeSelectionEvent + * @param source TODO + * @param paths TODO + * @param areNew TODO + * @param oldLeadSelectionPath TODO + * @param newLeadSelectionPath TODO + */ + public TreeSelectionEvent(Object source, TreePath[] paths, + boolean[] areNew, TreePath oldLeadSelectionPath, + TreePath newLeadSelectionPath) + { + super(source); + this.paths = paths; + this.areNew = areNew; + this.oldLeadSelectionPath = oldLeadSelectionPath; + this.newLeadSelectionPath = newLeadSelectionPath; + } // TreeSelectionEvent() + + /** + * Constructor TreeSelectionEvent + * @param source TODO + * @param paths TODO + * @param areNew TODO + * @param oldLeadSelectionPath TODO + * @param newLeadSelectionPath TODO + */ + public TreeSelectionEvent(Object source, TreePath path, + boolean isNew, TreePath oldLeadSelectionPath, + TreePath newLeadSelectionPath) + { + super(source); + this.paths = new TreePath[]{path}; + this.areNew = new boolean[]{isNew}; + this.oldLeadSelectionPath = oldLeadSelectionPath; + this.newLeadSelectionPath = newLeadSelectionPath; + } // TreeSelectionEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * @returns the first path element + */ + public TreePath getPath() + { + return paths[0]; + } // getPath() + + /** + * + * @returns the paths with selection changed + */ + public TreePath[] getPaths() + { + return (TreePath[]) paths.clone(); + } // getPaths() + + /** + * @return true if the first path is added to the selection, false otherwise + */ + public boolean isAddedPath() + { + return areNew[0]; + } // isAddedPath() + + /** + * @param path the path to check + * @return true if the path is added to the selection, false otherwise + */ + public boolean isAddedPath(TreePath path) + { + for (int i = paths.length - 1; i >= 0; i--) + if (paths[i].equals(path)) + return areNew[i]; + + return false; + } // isAddedPath() + + /** + * @param index the index'th path + * @return true if the path is added to the selection, false otherwise + */ + public boolean isAddedPath(int index) + { + return areNew[index]; + } // isAddedPath() + + /** + * @return the previous lead selection path + */ + public TreePath getOldLeadSelectionPath() + { + return oldLeadSelectionPath; + } // getOldLeadSelectionPath() + + /** + * @returns the current lead selection path + */ + public TreePath getNewLeadSelectionPath() + { + return newLeadSelectionPath; + } // getNewLeadSelectionPath() + + /** + * @param source the new event source + * @return a cloned event with another event source + */ + public Object cloneWithSource(Object source) + { + return new TreeSelectionEvent (source, paths, areNew, + oldLeadSelectionPath, + newLeadSelectionPath); + } // cloneWithSource() + + +} // TreeSelectionEvent diff --git a/libjava/classpath/javax/swing/event/TreeSelectionListener.java b/libjava/classpath/javax/swing/event/TreeSelectionListener.java new file mode 100644 index 00000000000..b844a6e0b51 --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeSelectionListener.java @@ -0,0 +1,56 @@ +/* TreeSelectionListener.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +// Imports +import java.util.EventListener; + +/** + * TreeSelectionListener public interface + * @author Andrew Selkirk + */ +public interface TreeSelectionListener extends EventListener { + + /** + * Value changed + * @param event Tree Selection Event + */ + void valueChanged(TreeSelectionEvent event); + + +} // TreeSelectionListener diff --git a/libjava/classpath/javax/swing/event/TreeWillExpandListener.java b/libjava/classpath/javax/swing/event/TreeWillExpandListener.java new file mode 100644 index 00000000000..89d3764f3bd --- /dev/null +++ b/libjava/classpath/javax/swing/event/TreeWillExpandListener.java @@ -0,0 +1,65 @@ +/* TreeWillExpandListener.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventListener; + +import javax.swing.tree.ExpandVetoException; + +/** + * @author Andrew Selkirk + */ +public interface TreeWillExpandListener extends EventListener +{ + /** + * Invoked whenever a node in the tree is about to be collapsed. + * + * @param event The tree expansion Event + */ + void treeWillCollapse(TreeExpansionEvent event) + throws ExpandVetoException; + + /** + * Invoked whenever a node in the tree is about to be expanded. + * + * @param event The tree expansion Event + */ + void treeWillExpand(TreeExpansionEvent event) + throws ExpandVetoException; +} diff --git a/libjava/classpath/javax/swing/event/UndoableEditEvent.java b/libjava/classpath/javax/swing/event/UndoableEditEvent.java new file mode 100644 index 00000000000..147c2e5b1c5 --- /dev/null +++ b/libjava/classpath/javax/swing/event/UndoableEditEvent.java @@ -0,0 +1,92 @@ +/* UndoableEditEvent.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.event; + +import java.util.EventObject; + +import javax.swing.undo.UndoableEdit; + +/** + * UndoableEditEvent + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public class UndoableEditEvent extends EventObject { + + private static final long serialVersionUID = 4418044561759134484L; + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * edit + */ + private UndoableEdit edit; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor UndoableEditEvent + * @param source TODO + * @param edit TODO + */ + public UndoableEditEvent(Object source, UndoableEdit edit) { + super(source); + this.edit = edit; + } // UndoableEditEvent() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getEdit + * @returns UndoableEdit + */ + public UndoableEdit getEdit() { + return edit; + } // getEdit() + + +} // UndoableEditEvent diff --git a/libjava/classpath/javax/swing/event/UndoableEditListener.java b/libjava/classpath/javax/swing/event/UndoableEditListener.java new file mode 100644 index 00000000000..13eecf51afb --- /dev/null +++ b/libjava/classpath/javax/swing/event/UndoableEditListener.java @@ -0,0 +1,56 @@ +/* UndoableEditListener.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.event; + +import java.util.EventListener; + + +/** + * UndoableEditListener public interface + * @author Andrew Selkirk + * @author Ronald Veldema + */ +public interface UndoableEditListener extends EventListener +{ + /** + * Undoable edit has happened + * + * @param event Undoable Edit Event + */ + void undoableEditHappened(UndoableEditEvent event); +} diff --git a/libjava/classpath/javax/swing/event/package.html b/libjava/classpath/javax/swing/event/package.html new file mode 100644 index 00000000000..faef7e15a85 --- /dev/null +++ b/libjava/classpath/javax/swing/event/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.event package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.event</title></head> + +<body> +<p>Provides events and listeners used by components in the +<code>javax.swing</code> package.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/filechooser/FileFilter.java b/libjava/classpath/javax/swing/filechooser/FileFilter.java new file mode 100644 index 00000000000..42770d98186 --- /dev/null +++ b/libjava/classpath/javax/swing/filechooser/FileFilter.java @@ -0,0 +1,80 @@ +/* FileFilter.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.filechooser; + +import java.io.File; + +/** + * FileFilter + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class FileFilter { + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor FileFilter + */ + public FileFilter() { + // TODO + } // FileFilter() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * accept + * @param file TODO + * @returns boolean + */ + public abstract boolean accept(File file); + + /** + * getDescription + * @returns String + */ + public abstract String getDescription(); + + +} // FileFilter diff --git a/libjava/classpath/javax/swing/filechooser/FileSystemView.java b/libjava/classpath/javax/swing/filechooser/FileSystemView.java new file mode 100644 index 00000000000..ffa41ca07de --- /dev/null +++ b/libjava/classpath/javax/swing/filechooser/FileSystemView.java @@ -0,0 +1,361 @@ +/* FileSystemView.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.filechooser; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import javax.swing.Icon; + + +/** + * DOCUMENT ME! + */ +public abstract class FileSystemView +{ + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + * @param filename DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File createFileObject(File dir, String filename) + { + return new File(dir, filename); + } + + /** + * DOCUMENT ME! + * + * @param path DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File createFileObject(String path) + { + return new File(path); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected File createFileSystemRoot(File f) + { + File[] roots = File.listRoots(); + if (roots == null) + return null; + return roots[0]; + } + + /** + * DOCUMENT ME! + * + * @param containingDir DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws IOException DOCUMENT ME! + */ + public abstract File createNewFolder(File containingDir) + throws IOException; + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * @param fileName DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File getChild(File parent, String fileName) + { + // FIXME: Handle the case when parent and child are special folders. + return new File(parent, fileName); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File getDefaultDirectory() + { + return getHomeDirectory(); + } + + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + * @param useFileHiding DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File[] getFiles(File dir, boolean useFileHiding) + { + if (dir == null || dir.listFiles() == null) + return null; + File[] files = dir.listFiles(); + if (! useFileHiding) + return files; + ArrayList trim = new ArrayList(); + for (int i = 0; i < files.length; i++) + if (! files[i].isHidden()) + trim.add(files[i]); + File[] value = (File[]) trim.toArray(new File[0]); + return value; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public static FileSystemView getFileSystemView() + { + if (File.separator.equals("/")) + return new UnixFileSystemView(); + + // else if (File.Separator.equals("\")) + // return new Win32FileSystemView(); + // else + // return new GenericFileSystemView(); + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File getHomeDirectory() + { + return createFileObject(System.getProperty("user.home")); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File getParentDirectory(File f) + { + if (f == null) + return null; + return f.getParentFile(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File[] getRoots() + { + // subclass + return null; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getSystemDisplayName(File f) + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Icon getSystemIcon(File f) + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getSystemTypeDescription(File f) + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isComputerNode(File dir) + { + return false; + } + + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isDrive(File dir) + { + return false; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isFileSystem(File f) + { + return (f.isFile() || f.isDirectory()); + } + + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isFileSystemRoot(File dir) + { + File[] roots = File.listRoots(); + if (roots == null || dir == null) + return false; + String filename = dir.getAbsolutePath(); + for (int i = 0; i < roots.length; i++) + if (roots[i].getAbsolutePath().equals(filename)) + return true; + return false; + } + + /** + * DOCUMENT ME! + * + * @param dir DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isFloppyDrive(File dir) + { + return false; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isHiddenFile(File f) + { + return f.isHidden(); + } + + /** + * DOCUMENT ME! + * + * @param folder DOCUMENT ME! + * @param file DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isParent(File folder, File file) + { + File parent = file.getParentFile(); + if (parent == null) + return false; + return folder.equals(parent); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isRoot(File f) + { + // These are not file system roots. + return false; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Boolean isTraversable(File f) + { + // Tested. A directory where the user has no permission to rwx is still + // traversable. (No files are listed when you traverse the directory) + // My best guess is that as long as it's a directory, the file is + // traversable. + return new Boolean(f.isDirectory()); + } +} diff --git a/libjava/classpath/javax/swing/filechooser/FileView.java b/libjava/classpath/javax/swing/filechooser/FileView.java new file mode 100644 index 00000000000..c431fd46127 --- /dev/null +++ b/libjava/classpath/javax/swing/filechooser/FileView.java @@ -0,0 +1,114 @@ +/* FileView.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.filechooser; + +import java.io.File; + +import javax.swing.Icon; + +/** + * FileView + * @author Andrew Selkirk + * @version 1.0 + */ +public abstract class FileView { + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor FileView + */ + public FileView() { + // TODO + } // FileView() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getName + * @param file TODO + * @returns String + */ + public String getName(File file) { + return null; // TODO + } // getName() + + /** + * getDescription + * @param value0 TODO + * @returns String + */ + public String getDescription(File value0) { + return null; // TODO + } // getDescription() + + /** + * getTypeDescription + * @param value0 TODO + * @returns String + */ + public String getTypeDescription(File value0) { + return null; // TODO + } // getTypeDescription() + + /** + * getIcon + * @param value0 TODO + * @returns Icon + */ + public Icon getIcon(File value0) { + return null; // TODO + } // getIcon() + + /** + * isTraversable + * @param value0 TODO + * @returns Boolean + */ + public Boolean isTraversable(File value0) { + return null; // TODO + } // isTraversable() + + +} // FileView diff --git a/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java b/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java new file mode 100644 index 00000000000..f2360ec52f8 --- /dev/null +++ b/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java @@ -0,0 +1,144 @@ +/* UnixFileSystemView.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.filechooser; + +import java.io.File; +import java.io.IOException; +import javax.swing.Icon; + + +/** + * DOCUMENT ME! + */ +class UnixFileSystemView extends FileSystemView +{ + /** DOCUMENT ME! */ + private static final String NEW_FOLDER_NAME = "NewFolder"; + + /** + * DOCUMENT ME! + * + * @param containingDir DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @throws IOException DOCUMENT ME! + */ + public File createNewFolder(File containingDir) throws IOException + { + int count = 0; + File f = null; + String filename = containingDir.getAbsolutePath() + File.separator + + NEW_FOLDER_NAME; + while (f == null) + { + String full = filename; + if (count > 0) + full += "." + (count++); + f = new File(full); + if (f.isDirectory() || f.isFile()) + { + count++; + f = null; + } + } + f.mkdir(); + return f; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public File[] getRoots() + { + return File.listRoots(); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getSystemDisplayName(File f) + { + // FIXME: Implement; + return null; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Icon getSystemIcon(File f) + { + // FIXME: Implement; + return null; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getSystemTypeDescription(File f) + { + // FIXME: Implement. + return null; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isRoot(File f) + { + return isFileSystemRoot(f); + } +} diff --git a/libjava/classpath/javax/swing/filechooser/package.html b/libjava/classpath/javax/swing/filechooser/package.html new file mode 100644 index 00000000000..bf897abb5bf --- /dev/null +++ b/libjava/classpath/javax/swing/filechooser/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.event package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.filechooser</title></head> + +<body> +<p>Provides support classes for the {@link javax.swing.JFileChooser} +component.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/package.html b/libjava/classpath/javax/swing/package.html new file mode 100644 index 00000000000..30ceb88bf2c --- /dev/null +++ b/libjava/classpath/javax/swing/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing</title></head> + +<body> +<p>Provides a collection of cross-platform user interface +components.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/plaf/ActionMapUIResource.java b/libjava/classpath/javax/swing/plaf/ActionMapUIResource.java new file mode 100644 index 00000000000..f6af0880ddb --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ActionMapUIResource.java @@ -0,0 +1,64 @@ +/* ActionMapUIResource.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +import javax.swing.ActionMap; + + +/** + * An <code>ActionMap</code> that implements the {@link UIResource} + * interface to indicate that it belongs to a pluggable + * LookAndFeel. + * + * @see javax.swing.ActionMap + * + * @author Andrew Selkirk + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class ActionMapUIResource + extends ActionMap + implements UIResource +{ + /** + * Constructs a new ActionMapUIResource. + */ + public ActionMapUIResource() + { + /* The constructor does nothing. */ + } +} diff --git a/libjava/classpath/javax/swing/plaf/BorderUIResource.java b/libjava/classpath/javax/swing/plaf/BorderUIResource.java new file mode 100644 index 00000000000..1bf854033b2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/BorderUIResource.java @@ -0,0 +1,933 @@ +/* BorderUIResource.java + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Insets; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.EtchedBorder; +import javax.swing.border.LineBorder; +import javax.swing.border.MatteBorder; +import javax.swing.border.TitledBorder; + +/** + * A wrapper for {@link javax.swing.border.Border} that also + * implements the {@link UIResource} marker interface. This is useful + * for implementing pluggable look-and-feels: When switching the + * current LookAndFeel, only those borders are replaced that are + * marked as {@link UIResource}. For this reason, a look-and-feel + * should always install borders that implement + * <code>UIResource</code>, such as the borders provided by this + * class. + * + * @serial + * @serialField delegate Border the <code>Border</code> wrapped + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class BorderUIResource + extends Object + implements Border, UIResource, Serializable +{ + /** + * Verified using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -3440553684010079691L; + + + /** + * A shared instance of an {@link EtchedBorderUIResource}, or + * <code>null</code> if the {@link #getEtchedBorderUIResource()} + * method has not yet been called. + */ + private static Border etchedBorderUIResource; + + + /** + * A shared instance of a {@link BevelBorderUIResource} whose + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#LOWERED}, or <code>null</code> if + * the {@link #getLoweredBevelBorderUIResource()} has not yet been + * called. + */ + private static Border loweredBevelBorderUIResource; + + + /** + * A shared instance of a {@link BevelBorderUIResource} whose + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#RAISED}, or <code>null</code> if + * the {@link #getRaisedBevelBorderUIResource()} has not yet been + * called. + */ + private static Border raisedBevelBorderUIResource; + + + /** + * A shared instance of a {@link LineBorderUIResource} for + * a one-pixel thick black line, or <code>null</code> if + * the {@link #getBlackLineBorderUIResource()} has not yet been + * called. + */ + private static Border blackLineBorderUIResource; + + + /** + * Returns a shared instance of an etched border which also + * is marked as an {@link UIResource}. + * + * @see javax.swing.border.EtchedBorder + */ + public static Border getEtchedBorderUIResource() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (etchedBorderUIResource == null) + etchedBorderUIResource = new EtchedBorderUIResource(); + return etchedBorderUIResource; + } + + + /** + * Returns a shared instance of {@link BevelBorderUIResource} whose + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#LOWERED}. + * + * @see javax.swing.border.BevelBorder + */ + public static Border getLoweredBevelBorderUIResource() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (loweredBevelBorderUIResource == null) + loweredBevelBorderUIResource = new BevelBorderUIResource( + BevelBorder.LOWERED); + return loweredBevelBorderUIResource; + } + + + /** + * Returns a shared instance of {@link BevelBorderUIResource} whose + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#RAISED}. + * + * @see javax.swing.border.BevelBorder + */ + public static Border getRaisedBevelBorderUIResource() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (raisedBevelBorderUIResource == null) + raisedBevelBorderUIResource = new BevelBorderUIResource( + BevelBorder.RAISED); + return raisedBevelBorderUIResource; + } + + + /** + * Returns a shared instance of {@link LineBorderUIResource} for + * a black, one-pixel width border. + * + * @see javax.swing.border.LineBorder + */ + public static Border getBlackLineBorderUIResource() + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (blackLineBorderUIResource == null) + blackLineBorderUIResource = new LineBorderUIResource(Color.black); + return blackLineBorderUIResource; + } + + + /** + * The wrapped border. + */ + private Border delegate; + + + /** + * Constructs a <code>BorderUIResource</code> for wrapping + * a <code>Border</code> object. + * + * @param delegate the border to be wrapped. + */ + public BorderUIResource(Border delegate) + { + if (delegate == null) + throw new IllegalArgumentException(); + + this.delegate = delegate; + } + + + /** + * Paints the border around an enclosed component by calling + * the <code>paintBorder</code> method of the wrapped delegate. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + delegate.paintBorder(c, g, x, y, width, height); + } + + + /** + * Measures the width of this border by calling the + * <code>getBorderInsets</code> method of the wrapped + * delegate. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + */ + public Insets getBorderInsets(Component c) + { + return delegate.getBorderInsets(c); + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting by calling the <code>isBorderOpaque</code> + * method of the wrapped delegate. + * + * @return <code>true</code> if the border is fully opaque, or + * <code>false</code> if some pixels of the background + * can shine through the border. + */ + public boolean isBorderOpaque() + { + return delegate.isBorderOpaque(); + } + + + /** + * A {@link javax.swing.border.BevelBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class BevelBorderUIResource + extends BevelBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = -1275542891108351642L; + + /** + * Constructs a BevelBorderUIResource whose colors will be derived + * from the background of the enclosed component. The background + * color is retrieved each time the border is painted, so a border + * constructed by this method will automatically reflect a change + * to the component’s background color. + * + * <p><img src="../border/doc-files/BevelBorder-1.png" + * width="500" height="150" + * alt="[An illustration showing raised and lowered BevelBorders]" /></p> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link javax.swing.border.BevelBorder#RAISED} + * or {@link javax.swing.border.BevelBorder#LOWERED}. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + */ + public BevelBorderUIResource(int bevelType) + { + super(bevelType); + } + + + /** + * Constructs a BevelBorderUIResource given its appearance type + * and two colors for its highlight and shadow. + * + * <p><img src="../border/doc-files/BevelBorder-2.png" width="500" + * height="150" alt="[An illustration showing BevelBorders that were + * constructed with this method]" /></p> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link javax.swing.border.BevelBorder#RAISED} + * or {@link javax.swing.border.BevelBorder#LOWERED}. + * + * @param highlight the color that will be used for the inner side + * of the highlighted edges (top and left if if + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#RAISED}; bottom and right + * otherwise). The color for the outer side is a brightened + * version of this color. + * + * @param shadow the color that will be used for the outer side of + * the shadowed edges (bottom and right if + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#RAISED}; top and left + * otherwise). The color for the inner side is a brightened + * version of this color. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + * + * @throws NullPointerException if <code>highlight</code> or + * <code>shadow</code> is <code>null</code>. + */ + public BevelBorderUIResource(int bevelType, + Color highlight, + Color shadow) + { + super(bevelType, highlight, shadow); + } + + + /** + * Constructs a BevelBorderUIResource given its appearance type + * and all its colors. + * + * <p><img src="../border/doc-files/BevelBorder-3.png" width="500" + * height="150" alt="[An illustration showing BevelBorders that + * were constructed with this method]" /></p> + * + * @param bevelType the desired appearance of the border. The value + * must be either {@link javax.swing.border.BevelBorder#RAISED} + * or {@link javax.swing.border.BevelBorder#LOWERED}. + * + * @param highlightOuter the color that will be used for the outer + * side of the highlighted edges (top and left if + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#RAISED}; bottom and right + * otherwise). + * + * @param highlightInner the color that will be used for the inner + * side of the highlighted edges. + * + * @param shadowOuter the color that will be used for the outer + * side of the shadowed edges (bottom and right if + * <code>bevelType</code> is {@link + * javax.swing.border.BevelBorder#RAISED}; top and left + * otherwise). + * + * @param shadowInner the color that will be used for the inner + * side of the shadowed edges. + * + * @throws IllegalArgumentException if <code>bevelType</code> has + * an unsupported value. + * + * @throws NullPointerException if one of the passed colors + * is <code>null</code>. + */ + public BevelBorderUIResource(int bevelType, + Color highlightOuter, + Color highlightInner, + Color shadowOuter, + Color shadowInner) + { + super(bevelType, + highlightOuter, highlightInner, + shadowOuter, shadowInner); + } + } + + + /** + * A {@link javax.swing.border.CompoundBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class CompoundBorderUIResource + extends CompoundBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = 7550017084975167341L; + + /** + * Constructs a CompoundBorderUIResource with the specified inside + * and outside borders. + * + * @param outsideBorder the outside border, which is painted to the + * outside of both <code>insideBorder</code> and the enclosed + * component. It is acceptable to pass <code>null</code>, in + * which case no outside border is painted. + * + * @param insideBorder the inside border, which is painted to + * between <code>outsideBorder</code> and the enclosed + * component. It is acceptable to pass <code>null</code>, in + * which case no inside border is painted. + */ + public CompoundBorderUIResource(Border outsideBorder, + Border insideBorder) + { + super(outsideBorder, insideBorder); + } + } + + + /** + * An {@link javax.swing.border.EmptyBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * <p><img src="../border/doc-files/EmptyBorder-1.png" + * width="290" height="200" + * alt="[An illustration of EmptyBorder]" /></p> + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class EmptyBorderUIResource + extends EmptyBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = -4914187529340071708L; + + /** + * Constructs an empty border given the number of pixels required + * on each side. + * + * @param top the number of pixels that the border will need + * for its top edge. + * + * @param left the number of pixels that the border will need + * for its left edge. + * + * @param bottom the number of pixels that the border will need + * for its bottom edge. + * + * @param right the number of pixels that the border will need + * for its right edge. + */ + public EmptyBorderUIResource(int top, int left, int bottom, int right) + { + super(top, left, bottom, right); + } + + + /** + * Constructs an empty border given the number of pixels required + * on each side, passed in an Insets object. + * + * @param insets the Insets for the new border. + */ + public EmptyBorderUIResource(Insets insets) + { + super(insets); + } + } + + + /** + * An {@link javax.swing.border.EtchedBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * <p><img src="../border/doc-files/EtchedBorder-1.png" width="500" + * height="200" alt="[An illustration of the two EtchedBorder + * variants]" /></p> + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class EtchedBorderUIResource + extends EtchedBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = -8186391754165296656L; + + /** + * Constructs an EtchedBorderUIResource that appears lowered into + * the surface. The colors will be derived from the background + * color of the enclosed Component when the border gets painted. + */ + public EtchedBorderUIResource() + { + super(); + } + + + /** + * Constructs an EtchedBorderUIResource with the specified + * appearance. The colors will be derived from the background + * color of the enclosed Component when the border gets painted. + * + * <p><img src="../border/doc-files/EtchedBorder-1.png" + * width="500" height="200" alt="[An illustration of the two + * EtchedBorder variants]" /></p> + * + * @param etchType the desired appearance of the border. The value + * must be either {@link javax.swing.border.EtchedBorder#RAISED} + * or {@link javax.swing.border.EtchedBorder#LOWERED}. + * + * @throws IllegalArgumentException if <code>etchType</code> has + * an unsupported value. + */ + public EtchedBorderUIResource(int etchType) + { + super(etchType); + } + + + /** + * Constructs a lowered EtchedBorderUIResource, explicitly + * selecting the colors that will be used for highlight and + * shadow. + * + * @param highlight the color that will be used for painting + * the highlight part of the border. + * + * @param shadow the color that will be used for painting + * the shadow part of the border. + * + * @see #EtchedBorderUIResource(int, Color, Color) + */ + public EtchedBorderUIResource(Color highlight, Color shadow) + { + super(highlight, shadow); + } + + + /** + * Constructs an EtchedBorderUIResource with the specified + * appearance, explicitly selecting the colors that will be used + * for highlight and shadow. + * + * <p><img src="../border/doc-files/EtchedBorder-2.png" width="500" + * height="200" alt="[An illustration that shows which pixels get + * painted in what color]" /></p> + * + * @param etchType the desired appearance of the border. The value + * must be either {@link javax.swing.border.EtchedBorder#RAISED} + * or {@link javax.swing.border.EtchedBorder#LOWERED}. + * + * @param highlight the color that will be used for painting + * the highlight part of the border. + * + * @param shadow the color that will be used for painting + * the shadow part of the border. + * + * @throws IllegalArgumentException if <code>etchType</code> has + * an unsupported value. + */ + public EtchedBorderUIResource(int etchType, + Color highlight, Color shadow) + { + super(etchType, highlight, shadow); + } + } + + + /** + * A {@link javax.swing.border.LineBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * <p><img src="../border/doc-files/LineBorder-1.png" width="500" + * height="200" alt="[An illustration of two LineBorders]" /></p> + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class LineBorderUIResource + extends LineBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = -6171232338180172310L; + + /** + * Constructs a LineBorderUIResource given its color. The border + * will be one pixel thick and have plain corners. + * + * @param color the color for drawing the border. + */ + public LineBorderUIResource(Color color) + { + super(color); + } + + + /** + * Constructs a LineBorder given its color and thickness. The + * border will have plain corners. + * + * @param color the color for drawing the border. + * @param thickness the width of the line in pixels. + */ + public LineBorderUIResource(Color color, int thickness) + { + super(color, thickness); + } + + + /* Note: Since JDK1.3, javax.swing.border.LineBorder also has a + * constructor which accepts a value for the roundedCorners + * property. However, as of JDK1.4.1, the LineBorderUIResource + * subclass does not have a corresponding constructor. + * + * A request for enhancing the Swing API has been filed with Sun: + * http://developer.java.sun.com/developer/bugParade/bugs/4879999.html + */ + } + + + /** + * A {@link javax.swing.border.MatteBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * <p><img src="../border/doc-files/MatteBorder-1.png" width="500" + * height="150" alt="[An illustration of two MatteBorders]" /></p> + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class MatteBorderUIResource + extends MatteBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = -8107923147541851122L; + + /** + * Constructs a MatteBorderUIResource given the width on each side + * and a fill color. + * + * <p><img src="../border/doc-files/MatteBorder-2.png" width="500" + * height="150" alt="[A picture of a MatteBorder made by this + * constructor]" /></p> + * + * @param top the width of the border at its top edge. + * @param left the width of the border at its left edge. + * @param bottom the width of the border at its bottom edge. + * @param right the width of the border at its right edge. + * @param matteColor the color for filling the border. + */ + public MatteBorderUIResource(int top, int left, + int bottom, int right, + Color color) + { + super(top, left, bottom, right, color); + } + + + /** + * Constructs a MatteBorderUIResource given the width on each side + * and an icon for tiling the border area. + * + * <p><img src="../border/doc-files/MatteBorder-4.png" width="500" + * height="150" alt="[A picture of a MatteBorder made by this + * constructor]" /></p> + * + * @param top the width of the border at its top edge. + * @param left the width of the border at its left edge. + * @param bottom the width of the border at its bottom edge. + * @param right the width of the border at its right edge. + * @param tileIcon an icon for tiling the border area. + */ + public MatteBorderUIResource(int top, int left, + int bottom, int right, + Icon tileIcon) + { + super(top, left, bottom, right, tileIcon); + } + + + /** + * Constructs a MatteBorderUIResource given an icon for tiling the + * border area. The icon width is used for the border insets at + * the left and right edge, the icon height for the top and bottom + * edge. + * + * <p><img src="../border/doc-files/MatteBorder-6.png" width="500" + * height="150" alt="[A picture of a MatteBorder made by this + * constructor]" /></p> + * + * @param tileIcon an icon for tiling the border area. + */ + public MatteBorderUIResource(Icon tileIcon) + { + super(tileIcon); + } + } + + + /** + * A {@link javax.swing.border.TitledBorder} that also implements the + * {@link UIResource} marker interface. This is useful for + * implementing pluggable look-and-feels: When switching the current + * LookAndFeel, only those borders are replaced that are marked as + * {@link UIResource}. For this reason, a look-and-feel should + * always install borders that implement <code>UIResource</code>, + * such as the borders provided by this class. + * + * @author Brian Jones (cbj@gnu.org) + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class TitledBorderUIResource + extends TitledBorder + implements UIResource, Serializable + { + private static final long serialVersionUID = 7667113547406407427L; + + /** + * Constructs a TitledBorderUIResource given the text of its title. + * + * @param title the title text, or <code>null</code> to use no + * title text. + */ + public TitledBorderUIResource(String title) + { + super(title); + } + + + /** + * Constructs an initially untitled TitledBorderUIResource + * given another border. + * + * @param border the border underneath the title, or + * <code>null</code> to use a default from + * the current look and feel. + */ + public TitledBorderUIResource(Border border) + { + super(border); + } + + + /** + * Constructs a TitledBorder given its border and title text. + * + * @param border the border underneath the title, or + * <code>null</code> to use a default from + * the current look and feel. + * + * @param title the title text, or <code>null</code> + * to use no title text. + */ + public TitledBorderUIResource(Border border, String title) + { + super(border, title); + } + + + /** + * Constructs a TitledBorderUIResource given its border, title + * text, horizontal alignment, and vertical position. + * + * @param border the border underneath the title, or + * <code>null</code> to use a default + * from the current look and feel. + * + * @param title the title text, or <code>null</code> + * to use no title text. + * + * @param titleJustification the horizontal alignment of the title + * text in relation to the border. The value must be one of + * {@link javax.swing.border.TitledBorder#LEFT}, + * {@link javax.swing.border.TitledBorder#CENTER}, + * {@link javax.swing.border.TitledBorder#RIGHT}, + * {@link javax.swing.border.TitledBorder#LEADING}, + * {@link javax.swing.border.TitledBorder#TRAILING}, or + * {@link javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION}. + * + * @param titlePosition the vertical position of the title text + * in relation to the border. The value must be one of + * {@link javax.swing.border.TitledBorder#ABOVE_TOP}, + * {@link javax.swing.border.TitledBorder#TOP}, + * {@link javax.swing.border.TitledBorder#BELOW_TOP}, + * {@link javax.swing.border.TitledBorder#ABOVE_BOTTOM}, + * {@link javax.swing.border.TitledBorder#BOTTOM}, + * {@link javax.swing.border.TitledBorder#BELOW_BOTTOM}, + * or {@link javax.swing.border.TitledBorder#DEFAULT_POSITION}. + * + * @throws IllegalArgumentException if <code>titleJustification</code> + * or <code>titlePosition</code> have an unsupported value. + */ + public TitledBorderUIResource(Border border, String title, + int titleJustification, + int titlePosition) + { + super(border, title, titleJustification, titlePosition); + } + + + /** + * Constructs a TitledBorder given its border, title text, + * horizontal alignment, vertical position, and font. + * + * @param border the border underneath the title, or + * <code>null</code> to use a default + * from the current look and feel. + * + * @param title the title text, or <code>null</code> + * to use no title text. + * + * @param titleJustification the horizontal alignment of the title + * text in relation to the border. The value must be one of + * {@link javax.swing.border.TitledBorder#LEFT}, + * {@link javax.swing.border.TitledBorder#CENTER}, + * {@link javax.swing.border.TitledBorder#RIGHT}, + * {@link javax.swing.border.TitledBorder#LEADING}, + * {@link javax.swing.border.TitledBorder#TRAILING}, or + * {@link javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION}. + * + * @param titlePosition the vertical position of the title text + * in relation to the border. The value must be one of + * {@link javax.swing.border.TitledBorder#ABOVE_TOP}, + * {@link javax.swing.border.TitledBorder#TOP}, + * {@link javax.swing.border.TitledBorder#BELOW_TOP}, + * {@link javax.swing.border.TitledBorder#ABOVE_BOTTOM}, + * {@link javax.swing.border.TitledBorder#BOTTOM}, + * {@link javax.swing.border.TitledBorder#BELOW_BOTTOM}, + * or {@link javax.swing.border.TitledBorder#DEFAULT_POSITION}. + * + * @param titleFont the font for the title text, or <code>null</code> + * to use a default from the current look and feel. + * + * @throws IllegalArgumentException if <code>titleJustification</code> + * or <code>titlePosition</code> have an unsupported value. + */ + public TitledBorderUIResource(Border border, String title, + int titleJustification, + int titlePosition, + Font titleFont) + { + super(border, title, titleJustification, titlePosition, + titleFont); + } + + + /** + * Constructs a TitledBorder given its border, title text, + * horizontal alignment, vertical position, font, and color. + * + * @param border the border underneath the title, or + * <code>null</code> to use a default + * from the current look and feel. + * + * @param title the title text, or <code>null</code> + * to use no title text. + * + * @param titleJustification the horizontal alignment of the title + * text in relation to the border. The value must be one of + * {@link javax.swing.border.TitledBorder#LEFT}, + * {@link javax.swing.border.TitledBorder#CENTER}, + * {@link javax.swing.border.TitledBorder#RIGHT}, + * {@link javax.swing.border.TitledBorder#LEADING}, + * {@link javax.swing.border.TitledBorder#TRAILING}, or + * {@link javax.swing.border.TitledBorder#DEFAULT_JUSTIFICATION}. + * + * @param titlePosition the vertical position of the title text + * in relation to the border. The value must be one of + * {@link javax.swing.border.TitledBorder#ABOVE_TOP}, + * {@link javax.swing.border.TitledBorder#TOP}, + * {@link javax.swing.border.TitledBorder#BELOW_TOP}, + * {@link javax.swing.border.TitledBorder#ABOVE_BOTTOM}, + * {@link javax.swing.border.TitledBorder#BOTTOM}, + * {@link javax.swing.border.TitledBorder#BELOW_BOTTOM}, + * or {@link javax.swing.border.TitledBorder#DEFAULT_POSITION}. + * + * @param titleFont the font for the title text, or <code>null</code> + * to use a default from the current look and feel. + * + * @param titleColor the color for the title text, or <code>null</code> + * to use a default from the current look and feel. + * + * @throws IllegalArgumentException if <code>titleJustification</code> + * or <code>titlePosition</code> have an unsupported value. + */ + public TitledBorderUIResource(Border border, String title, + int titleJustification, int titlePosition, + Font titleFont, Color titleColor) + { + super(border, title, titleJustification, titlePosition, + titleFont, titleColor); + } + } +} + diff --git a/libjava/classpath/javax/swing/plaf/ButtonUI.java b/libjava/classpath/javax/swing/plaf/ButtonUI.java new file mode 100644 index 00000000000..197299e0c95 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ButtonUI.java @@ -0,0 +1,52 @@ +/* ButtonUI.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JButton</code>. + * + * @see javax.swing.JButton + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ButtonUI + extends ComponentUI +{ +} diff --git a/libjava/classpath/javax/swing/plaf/ColorChooserUI.java b/libjava/classpath/javax/swing/plaf/ColorChooserUI.java new file mode 100644 index 00000000000..68ffd916d21 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ColorChooserUI.java @@ -0,0 +1,60 @@ +/* ColorChooserUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JColorChooser</code>. + * + * @see javax.swing.JColorChooser + * + * @author Andrew Selkirk + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ColorChooserUI + extends ComponentUI +{ + /** + * Constructs a ColorChooserUI. + */ + public ColorChooserUI() + { + /* The constructor does not do anything. */ + } +} + diff --git a/libjava/classpath/javax/swing/plaf/ColorUIResource.java b/libjava/classpath/javax/swing/plaf/ColorUIResource.java new file mode 100644 index 00000000000..33b1676e0fd --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ColorUIResource.java @@ -0,0 +1,123 @@ +/* ColorUIResource.java + Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Color; + + +/** + * A Color that is marked as <code>UIResource</code>, which indicates that + * the color has been installed by a pluggable LookAndFeel. Such colors + * are replaced when the LookAndFeel changes. + * + * @see java.awt.Color + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class ColorUIResource + extends Color + implements UIResource +{ + /** + * Constructs a <code>ColorUIResource</code> using the specified + * red, green, and blue values, which must be given as integers in + * the range of 0-255. The alpha channel value will default to 255, + * meaning that the color is fully opaque. + * + * @param r the red intensity, which must be in the range [0 .. 255]. + * @param g the green intensity, which must be in the range [0 .. 255]. + * @param b the blue intensity, which must be in the range [0 .. 255]. + * + * @throws IllegalArgumentException if any of the values is outside the + * specified range. + */ + public ColorUIResource(int r, int g, int b) + { + super(r, g, b); + } + + + /** + * Constructs a <code>ColorUIResource</code> using the specified + * RGB value. The blue value is in bits 0-7, green in bits 8-15, and + * red in bits 16-23. The other bits are ignored. The alpha value is set + * to 255, meaning that the color is fully opaque. + * + * @param rgb the rgb value, as discussed above. + */ + public ColorUIResource(int rgb) + { + super(rgb); + } + + + /** + * Constructs a <code>ColorUIResource</code> using the specified + * red, green, and blue intensities, which must be given as floats in + * the range of 0-1. The alpha channel value will default to 1.0f, + * meaning that the color is fully opaque. + * + * @param r the red intensity, which must be in the range [0.0 .. 1.0]. + * @param g the green intensity, which must be in the range [0.0 .. 1.0]. + * @param b the blue intensity, which must be in the range [0.0 .. 1.0]. + * + * @throws IllegalArgumentException if any of the values is outside the + * specified range. + */ + public ColorUIResource(float r, float g, float b) + { + super(r, g, b); + } + + + /** + * Constructs a <code>ColorUIResource</code>, using the intensities + * of another color. + * + * @param c the color whose intensities will be considered when + * constructing this <code>ColorUIResource</code> (<code>null</code> + * not permitted). + * + * @throws NullPointerException if <code>c</code> is <code>null</code>. + */ + public ColorUIResource(Color c) + { + super(c.getRGB()); + } +} diff --git a/libjava/classpath/javax/swing/plaf/ComboBoxUI.java b/libjava/classpath/javax/swing/plaf/ComboBoxUI.java new file mode 100644 index 00000000000..9498a48153a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ComboBoxUI.java @@ -0,0 +1,96 @@ +/* ComboBoxUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +import javax.swing.JComboBox; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JButton</code>. + * + * @see javax.swing.JComboBox + * + * @author Andrew Selkirk + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ComboBoxUI + extends ComponentUI +{ + /** + * Constructs a new <code>ComboBoxUI</code>. + */ + public ComboBoxUI() + { + } + + + /** + * Sets the visibility of the popup button. + * + * @param c the <code>JComboBox</code> whose popup + * is shown or hidden. + * + * @param visible <code>true</code> to show the popup, <code>false</code> + * to hide it. + */ + public abstract void setPopupVisible(JComboBox c, boolean visible); + + + /** + * Determines whether the popup button is currently visible. + * + * @param c the <code>JComboBox</code> whose popup visibility + * is retrieved. + * + * @return <code>true</code> if the popup button is currently + * visible, <code>false</code> otherwise. + */ + public abstract boolean isPopupVisible(JComboBox c); + + + /** + * Determines whether the combo box can receive input focus. + * + * @param c <code>JComboBox</code> whose focus traversability + * is to be retrieved. + * + * @returns <code>true</code> if <code>c</code> can receive + * input focus, <code>false</code> otherwise. + */ + public abstract boolean isFocusTraversable(JComboBox c); +} diff --git a/libjava/classpath/javax/swing/plaf/ComponentInputMapUIResource.java b/libjava/classpath/javax/swing/plaf/ComponentInputMapUIResource.java new file mode 100644 index 00000000000..e1418710fb2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ComponentInputMapUIResource.java @@ -0,0 +1,70 @@ +/* ComponentInputMapUIResource.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +import javax.swing.ComponentInputMap; +import javax.swing.JComponent; + + +/** + * A <code>ComponentInputMap</code> that implements the {@link UIResource} + * interface to indicate that it belongs to a pluggable + * LookAndFeel. + * + * @see javax.swing.ComponentInputMap + * @see javax.swing.InputMap + * + * @author Andrew Selkirk + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class ComponentInputMapUIResource + extends ComponentInputMap + implements UIResource +{ + /** + * Constructs a new <code>ComponentInputMapUIResource</code>. + * + * @param component the <code>JComponent</code> associated with + * this <code>InputMap</code>. + */ + public ComponentInputMapUIResource(JComponent component) + { + super(component); + } +} + diff --git a/libjava/classpath/javax/swing/plaf/ComponentUI.java b/libjava/classpath/javax/swing/plaf/ComponentUI.java new file mode 100644 index 00000000000..0e7680542f7 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ComponentUI.java @@ -0,0 +1,326 @@ +/* ComponentUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.accessibility.Accessible; +import javax.swing.JComponent; + +/** + * The abstract base class for all delegates that provide the + * pluggable look and feel for Swing components. User applications + * should not need to access this class; it is internal to Swing + * and the look-and-feel implementations. + * + * <p><img src="doc-files/ComponentUI-1.png" width="700" height="550" + * alt="[UML diagram illustrating the architecture for pluggable + * look and feels]" /></p> + * + * <p>Components such as {@link javax.swing.JSlider} do not directly + * implement operations related to the look and feel of the user + * interface, such as painting or layout. Instead, they use a delegate + * object for all such tasks. In the case of <code>JSlider</code>, the + * user interface would be provided by some concrete subclass of + * {@link javax.swing.plaf.SliderUI}. + * + * <p>Soon after its creation, a <code>ComponentUI</code> will be sent + * an {@link #installUI} message. The <code>ComponentUI</code> will + * react by setting properties such as the border or the background + * color of the <code>JComponent</code> for which it provides its + * services. Soon before the end of its lifecycle, the + * <code>ComponentUI</code> will receive an {@link #uninstallUI} + * message, at which time the <code>ComponentUI</code> is expected to + * undo any changes.</p> + * + * <p>Note that the <code>ui</code> of a <code>JComponent</code> + * changes whenever the user switches between look and feels. For + * example, the <code>ui</code> property of a <code>JSlider</code> + * could change from an instance of <code>MetalSliderUI</code> to an + * instance of <code>FooSliderUI</code>. This switch can happen at any + * time, but it will always be performed from inside the Swing thread.</p> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ComponentUI +{ + /** + * Constructs a new UI delegate. + */ + public ComponentUI() + { + } + + + /** + * Sets up the specified component so it conforms the the design + * guidelines of the implemented look and feel. When the look and + * feel changes, a <code>ComponentUI</code> delegate is created. + * The delegate object then receives an <code>installUI</code> + * message. + * + * <p>This method should perform the following tasks:</p> + * + * <ul> + * <li>Set visual properties such as borders, fonts, colors, or + * icons. However, no change should be performed for those + * properties whose values have been directly set by the client + * application. To allow the distinction, LookAndFeels are expected + * to use values that implement the {@link UIResource} marker + * interface, such as {@link BorderUIResource} or {@link + * ColorUIResource}.</li> + * <li>If necessary, install a {@link java.awt.LayoutManager}.</li> + * <li>Embed custom sub-components. For instance, the UI delegate + * for a {@link javax.swing.JSplitPane} might install a special + * component for the divider.</li> + * <li>Register event listeners.</li> + * <li>Set up properties related to keyborad navigation, such as + * mnemonics or focus traversal policies.</li> + * </ul> + * + * @param c the component for which this delegate will provide + * services. + * + * @see #uninstallUI + * @see javax.swing.JComponent#setUI + * @see javax.swing.JComponent#updateUI + */ + public void installUI(JComponent c) + { + // The default implementation does not change any properties. + } + + + /** + * Puts the specified component into the state it had before + * {@link #installUI} was called. + * + * @param c the component for which this delegate has provided + * services. + * + * @see #installUI + * @see javax.swing.JComponent#setUI + * @see javax.swing.JComponent#updateUI + */ + public void uninstallUI(JComponent c) + { + // The default implementation does not change any properties. + } + + + /** + * Paints the component according to the design guidelines + * of the look and feel. Most subclasses will want to override + * this method. + * + * @param g the graphics for painting. + * + * @param c the component for which this delegate performs + * services. + */ + public void paint(Graphics g, JComponent c) + { + } + + + /** + * Fills the specified component with its background color + * (unless the <code>opaque</code> property is <code>false</code>) + * before calling {@link #paint}. + * + * <p>It is unlikely that a subclass needs to override this method. + * The actual rendering should be performed by the {@link #paint} + * method. + * + * @param g the graphics for painting. + * + * @param c the component for which this delegate performs + * services. + * + * @see #paint + * @see javax.swing.JComponent#paintComponent + */ + public void update(Graphics g, JComponent c) + { + if (c.isOpaque()) + { + g.setColor(c.getBackground()); + g.fillRect(0, 0, c.getWidth(), c.getHeight()); + } + paint(g, c); + } + + + /** + * Determines the preferred size of a component. The default + * implementation returns <code>null</code>, which means that + * <code>c</code>’s layout manager should be asked to + * calculate the preferred size. + * + * @param c the component for which this delegate performs services. + * + * @return the preferred size, or <code>null</code> to indicate that + * <code>c</code>’s layout manager should be asked + * for the preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + return null; + } + + + /** + * Determines the minimum size of a component. The default + * implementation calls {@link #getPreferredSize}, but subclasses + * might want to override this. + * + * @param c the component for which this delegate performs services. + * + * @return the minimum size, or <code>null</code> to indicate that + * <code>c</code>’s layout manager should be asked + * to calculate the minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + + /** + * Determines the maximum size of a component. The default + * implementation calls {@link #getPreferredSize}, but subclasses + * might want to override this. + * + * @param c the component for which this delegate performs services. + * + * @return the maximum size, or <code>null</code> to indicate that + * <code>c</code>’s layout manager should be asked + * to calculate the maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + + /** + * Determines whether a click into the component at a specified + * location is considered as having hit the component. The default + * implementation checks whether the point falls into the + * component’s bounding rectangle. Some subclasses might want + * to override this, for example in the case of a rounded button. + * + * @param c the component for which this delegate performs services. + * + * @param x the x coordinate of the point, relative to the local + * coordinate system of the component. Zero would be be + * component’s left edge, irrespective of the location + * inside its parent. + * + * @param y the y coordinate of the point, relative to the local + * coordinate system of the component. Zero would be be + * component’s top edge, irrespective of the location + * inside its parent. + */ + public boolean contains(JComponent c, int x, int y) + { + /* JComponent.contains calls the ui delegate for hit + * testing. Therefore, endless mutual recursion would result if we + * called c.contains(x, y) here. + * + * The previous Classpath implementation called the deprecated + * method java.awt.Component.inside. In the Sun implementation, it + * can be observed that inside, other than contains, does not call + * the ui delegate. But that inside() behaves different to + * contains() clearly is in violation of the method contract, and + * it is not something that a good implementation should rely upon + * -- even if Classpath ends up being forced to replicate this + * apparent bug of the Sun implementation. + */ + return (x >= 0) && (x < c.getWidth()) + && (y >= 0) && (y < c.getHeight()); + } + + + /** + * Creates a delegate object for the specified component. Users + * should use the <code>createUI</code> method of a suitable + * subclass. The implementation of <code>ComponentUI</code> + * always throws an error. + * + * @param c the component for which a UI delegate is requested. + */ + public static ComponentUI createUI(JComponent c) + { + throw new Error( + "javax.swing.plaf.ComponentUI does not implement createUI; call " + + "createUI on a subclass."); + } + + + /** + * Counts the number of accessible children in the component. The + * default implementation delegates the inquiry to the {@link + * javax.accessibility.AccessibleContext} of <code>c</code>. + * + * @param c the component whose accessible children + * are to be counted. + */ + public int getAccessibleChildrenCount(JComponent c) + { + return c.getAccessibleContext().getAccessibleChildrenCount(); + } + + + /** + * Returns the specified accessible child of the component. The + * default implementation delegates the inquiry to the {@link + * javax.accessibility.AccessibleContext} of <code>c</code>. + * + * @param i the index of the accessible child, starting at zero. + * + * @param c the component whose <code>i</code>-th accessible child + * is requested. + */ + public Accessible getAccessibleChild(JComponent c, int i) + { + return c.getAccessibleContext().getAccessibleChild(i); + } +} diff --git a/libjava/classpath/javax/swing/plaf/DesktopIconUI.java b/libjava/classpath/javax/swing/plaf/DesktopIconUI.java new file mode 100644 index 00000000000..2e44088cadd --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/DesktopIconUI.java @@ -0,0 +1,56 @@ +/* DesktopIconUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a desktop icon. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class DesktopIconUI + extends ComponentUI +{ + /** + * Constructs a new <code>DesktopIconUI</code>. + */ + public DesktopIconUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/DesktopPaneUI.java b/libjava/classpath/javax/swing/plaf/DesktopPaneUI.java new file mode 100644 index 00000000000..de553eaf4de --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/DesktopPaneUI.java @@ -0,0 +1,59 @@ +/* DesktopPaneUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JDesktopPane</code>. + * + * @see javax.swing.JDesktopPane + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class DesktopPaneUI + extends ComponentUI +{ + /** + * Constructs a new <code>DesktopPaneUI</code>. + */ + public DesktopPaneUI() + { + } +} + diff --git a/libjava/classpath/javax/swing/plaf/DimensionUIResource.java b/libjava/classpath/javax/swing/plaf/DimensionUIResource.java new file mode 100644 index 00000000000..63c6838c4d1 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/DimensionUIResource.java @@ -0,0 +1,68 @@ +/* DimensionUIResource.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Dimension; + +/** + * A Dimension that is marked as <code>UIResource</code>, which + * indicates that it has been installed by a pluggable + * LookAndFeel. Such dimensions are replaced when the LookAndFeel + * changes. + * + * @see java.awt.Dimension + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class DimensionUIResource + extends Dimension + implements UIResource +{ + /** + * Constructs a new DimensionUIResource, given its width and height. + * + * @param width the width in pixels. + * @param height the height in pixels. + */ + public DimensionUIResource(int width, int height) + { + super(width, height); + } +} diff --git a/libjava/classpath/javax/swing/plaf/FileChooserUI.java b/libjava/classpath/javax/swing/plaf/FileChooserUI.java new file mode 100644 index 00000000000..87847c44fe1 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/FileChooserUI.java @@ -0,0 +1,138 @@ +/* FileChooserUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.io.File; + +import javax.swing.JFileChooser; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileView; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JFileChooser</code>. + * + * @see javax.swing.JFileChooser + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class FileChooserUI + extends ComponentUI +{ + /** + * Constructs a new <code>FileChooserUI</code>. + */ + public FileChooserUI() + { + } + + + /** + * Returns a <code>FileFilter</code> that accepts every file. While + * the filtering itself is not specific to any look and feel, the + * text returned by <code>FileFilter.getDescription()</code> need + * not be the same across all look and feels. + * + * @param chooser the <code>JFileChooser</code> for which + * a <code>FileFilter</code> is requested. + * + * @see javax.swing.JFileChooser#getAcceptAllFileFilter + * @see javax.swing.filechooser.FileFilter#getDescription + */ + public abstract FileFilter getAcceptAllFileFilter(JFileChooser chooser); + + + /** + * Returns a view to a file, which is able to retrieve its name, + * icon, and other properties that are relevant for presenting + * the file to the user. + * + * @param chooser the <code>JFileChooser</code> for which + * a <code>FileFilter</code> is requested. + */ + public abstract FileView getFileView(JFileChooser chooser); + + + /** + * Determines which text is appropriate for the approve button + * according to the design guidelines of the implemented + * look and feel. + * + * @param chooser the <code>JFileChooser</code> whose + * button text is requested. + * + * @see javax.swing.JFileChoose#getApproveButtonText + */ + public abstract String getApproveButtonText(JFileChooser chooser); + + + /** + * Determines which text is appropriate for the title bar of a + * <code>JFileChooser</code> according to the design guidelines of + * the implemented look and feel. + * + * @param chooser the <code>JFileChooser</code> whose + * dialog title is requested. + * + * @see javax.swing.JFileChoose#getDialogtitle + */ + public abstract String getDialogTitle(JFileChooser chooser); + + + /** + * Refreshes the currently displayed directory. + * + * @param chooser the <code>JFileChooser</code> whose + * dialog title needs re-scanning. + */ + public abstract void rescanCurrentDirectory(JFileChooser chooser); + + + /** + * Ensures that a specified file is visible in the + * <code>JFileChooser</code> + * + * @param chooser the <code>JFileChooser</code> that + * should display the file <code>file</code>. + * + * @param file the file that needs to be made visible. + */ + public abstract void ensureFileIsVisible(JFileChooser chooser, File file); +} diff --git a/libjava/classpath/javax/swing/plaf/FontUIResource.java b/libjava/classpath/javax/swing/plaf/FontUIResource.java new file mode 100644 index 00000000000..1c1731048e8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/FontUIResource.java @@ -0,0 +1,101 @@ +/* FontUIResource.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Font; + + +/** + * A font that is marked as <code>UIResource</code>, which + * indicates that it has been installed by a pluggable + * LookAndFeel. Such dimensions are replaced when the LookAndFeel + * changes. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class FontUIResource + extends Font + implements UIResource +{ + /** + * Constructs a new <code>FontUIResource</code> given + * the name, style and size of the font. + * + * @param name the name of the font. A number of + * “logical” names are supported by any Java + * implementation. These are + * <code>“Dialog”</code>, + * <code>“DialogInput”</code>, + * <code>“Monospaced”</code>, + * <code>“Serif”</code>, and + * <code>“SansSerif”</code>. + * + * @param style the style of the font, for instance {@link + * java.awt.Font#BOLD} or {@link java.awt.Font#PLAIN}. + * + * @param size the size of the font in typographic points, for + * instance 10, 12 or 13. Designers of LookAndFeels should be + * aware that some languages (like Japanese and Chinese) have + * glyphs that are too complex to be legible at small point + * sizes. + */ + public FontUIResource(String name, int style, int size) + { + super(name, style, size); + } + + + /** + * Constructs a new <code>FontUIResource</code> given + * an existing font. + * + * @param f the font that serves as a template. + */ + public FontUIResource(Font f) + { + /* This implementation will get rid of many font properties, + * such as skewing, values of multiple master design axes, + * etc., unless they get encoded into the name. It probably + * is not a problem for LookAndFeels because user interfaces + * are usually not very advanced with respect to typography. + */ + super(f.getName(), f.getStyle(), f.getSize()); + } +} diff --git a/libjava/classpath/javax/swing/plaf/IconUIResource.java b/libjava/classpath/javax/swing/plaf/IconUIResource.java new file mode 100644 index 00000000000..1b09ed31f39 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/IconUIResource.java @@ -0,0 +1,122 @@ +/* IconUIResource.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; + +/** + * An icon that is marked as <code>UIResource</code>, which + * indicates that it has been installed by a pluggable + * LookAndFeel. Such icons are replaced when the LookAndFeel + * changes. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class IconUIResource + implements Icon, UIResource, Serializable +{ + /** + * Verified using the <code>serialver</code> tool of Sun JDK 1.4.1_01 + * on GNU/Linux 2.4.18. + */ + static final long serialVersionUID = 3327049506004830542L; + + + /** + * The icon that is wrapped by this <code>IconUIResource</code>. + */ + private Icon delegate; + + + /** + * Constructs a <code>IconUIResource</code> that wraps another + * icon. All messages are forwarded to the delegate icon. + * + * @param delegate the icon that is wrapped by this + * <code>IconUIResource</code>. + */ + public IconUIResource(Icon delegate) + { + this.delegate = delegate; + } + + + /** + * Paints the icon by asking the delegate icon to paint itself. + * + * @param c the Component whose icon is being painted. Some icons + * use this argument to retrieve properties like the + * background color. + * + * @param g the graphics into which the icon will be painted. + * + * @param x the horizontal position of the icon. + * + * @param y the vertical position of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + delegate.paintIcon(c, g, x, y); + } + + + /** + * Returns the width of the icon in pixels. The implementation + * determines and returns the width of the delegate icon. + */ + public int getIconWidth() + { + return delegate.getIconWidth(); + } + + + /** + * Returns the height of the icon in pixels. The implementation + * determines and returns the height of the delegate icon. + */ + public int getIconHeight() + { + return delegate.getIconHeight(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/InputMapUIResource.java b/libjava/classpath/javax/swing/plaf/InputMapUIResource.java new file mode 100644 index 00000000000..ae032e51fa8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/InputMapUIResource.java @@ -0,0 +1,63 @@ +/* InputMapUIResource.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +import javax.swing.InputMap; + + +/** + * An <code>InputMap</code> that is marked as <code>UIResource</code>, + * which indicates that it has been installed by a pluggable + * LookAndFeel. Such dimensions are replaced when the LookAndFeel + * changes. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class InputMapUIResource + extends InputMap + implements UIResource +{ + /** + * Constructs a new <code>InputMapUIResource</code>. + */ + public InputMapUIResource() + { + } +} + diff --git a/libjava/classpath/javax/swing/plaf/InsetsUIResource.java b/libjava/classpath/javax/swing/plaf/InsetsUIResource.java new file mode 100644 index 00000000000..755d8add1b2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/InsetsUIResource.java @@ -0,0 +1,77 @@ +/* InsetsUIResource.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Insets; +import java.io.Serializable; + + +/** + * An <code>Insets</code> that is marked as <code>UIResource</code>, + * which indicates that it has been installed by a pluggable + * LookAndFeel. Such insets are replaced when the LookAndFeel changes. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class InsetsUIResource + extends Insets + implements Cloneable, UIResource, Serializable +{ + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = 5622110143266315421L; + + + /** + * Constructs a new <code>InsetsUIResource</code> given the + * inset at each edge. + * + * @param top the inset at the top, in pixels. + * @param left the inset at the left, in pixels. + * @param bottom the inset at the bottom, in pixels. + * @param right the inset at the right, in pixels. + */ + public InsetsUIResource(int top, int left, int bottom, int right) + { + super(top, left, bottom, right); + } +} diff --git a/libjava/classpath/javax/swing/plaf/InternalFrameUI.java b/libjava/classpath/javax/swing/plaf/InternalFrameUI.java new file mode 100644 index 00000000000..fd1e3374c13 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/InternalFrameUI.java @@ -0,0 +1,59 @@ +/* InternalFrameUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JInternalFrame</code>. + * + * @see javax.swing.JInternalFrame + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class InternalFrameUI + extends ComponentUI +{ + /** + * Constructs a new <code>InternalFrameUI</code>. + */ + public InternalFrameUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/LabelUI.java b/libjava/classpath/javax/swing/plaf/LabelUI.java new file mode 100644 index 00000000000..8fc1d711b0e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/LabelUI.java @@ -0,0 +1,59 @@ +/* LabelUI.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JLabel</code>. + * + * @see javax.swing.JLabel + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class LabelUI + extends ComponentUI +{ + /** + * Constructs a new <code>LabelUI</code>. + */ + public LabelUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/ListUI.java b/libjava/classpath/javax/swing/plaf/ListUI.java new file mode 100644 index 00000000000..66d5cf588bb --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ListUI.java @@ -0,0 +1,114 @@ +/* ListUI.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Point; +import java.awt.Rectangle; + +import javax.swing.JList; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JList</code>. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ListUI + extends ComponentUI +{ + /** + * Constructs a new <code>ListUI</code>. + */ + public ListUI() + { + } + + + /** + * Determines the cell index which is the closest to the specified + * location. The find out whether the returned cell actually + * contains the location, the caller should also use {@link + * #getCellBounds}. + * + * @param list the <code>JList</code> for which this delegate object + * provides the pluggable user interface. + * + * @param location a point in the <code>JList</code> coordinate + * system. + * + * @return the index of the closest cell, or -1 if the list model + * is empty. + */ + public abstract int locationToIndex(JList list, Point location); + + + /** + * Determines the location of the specified cell. + * + * @param list the <code>JList</code> for which this delegate object + * provides the pluggable user interface. + * + * @param index the zero-based index of the cell whose location shall be + * determined. + * + * @return the position of the top left corner of the cell in the + * <code>JList</code> coordinate system, or <code>null</code> + * if <code>cell</code> does not designate a valid cell. + */ + public abstract Point indexToLocation(JList list, int index); + + + /** + * Determines the bounding box of the rectangle spanned by + * two list indices. + * + * @param list the <code>JList</code> for which this delegate object + * provides the pluggable user interface. + * + * @param index1 the zero-based index of the first cell. + * + * @param index2 the zero-based index of the second cell. + * + * @return the spanned rectangle, or <code>null</code> if either + * <code>index1</code> or <code>index2</code> does not + * designate a valid cell. + */ + public abstract Rectangle getCellBounds(JList list, + int index1, int index2); +} diff --git a/libjava/classpath/javax/swing/plaf/MenuBarUI.java b/libjava/classpath/javax/swing/plaf/MenuBarUI.java new file mode 100644 index 00000000000..8835571ac75 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/MenuBarUI.java @@ -0,0 +1,59 @@ +/* MenuBarUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JMenuBar</code>. + * + * @see javax.swing.JMenuBar + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class MenuBarUI + extends ComponentUI +{ + /** + * Constructs a new <code>MenuBarUI</code>. + */ + public MenuBarUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/MenuItemUI.java b/libjava/classpath/javax/swing/plaf/MenuItemUI.java new file mode 100644 index 00000000000..31d73194a18 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/MenuItemUI.java @@ -0,0 +1,59 @@ +/* MenuItemUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JMenuItem</code>. + * + * @see javax.swing.JMenuItem + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class MenuItemUI + extends ButtonUI +{ + /** + * Constructs a new <code>MenuItemUI</code>. + */ + public MenuItemUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/OptionPaneUI.java b/libjava/classpath/javax/swing/plaf/OptionPaneUI.java new file mode 100644 index 00000000000..13d1caa6ac8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/OptionPaneUI.java @@ -0,0 +1,75 @@ +/* OptionPaneUI.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +import javax.swing.JOptionPane; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JOptionPane</code>. + * + * @see javax.swing.JOptionPane + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class OptionPaneUI + extends ComponentUI +{ + /** + * Gives keyboard input focus to the component that represents + * the default value. + * + * @param pane the <code>JOptionPane</code> for which this delegate + * object provides the pluggable user interface. + */ + public abstract void selectInitialValue(JOptionPane pane); + + + /** + * Determines whether the user has provided custom components + * for the options or the message. + * + * @param pane the <code>JOptionPane</code> for which this delegate + * object provides the pluggable user interface. + * + * @return <code>true</code> if the user has supplied any custom + * components; <code>false</code> if all components are + * provided by Swing or a LookAndFeel. + */ + public abstract boolean containsCustomComponents(JOptionPane pane); +} diff --git a/libjava/classpath/javax/swing/plaf/PanelUI.java b/libjava/classpath/javax/swing/plaf/PanelUI.java new file mode 100644 index 00000000000..b1171b80d30 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/PanelUI.java @@ -0,0 +1,58 @@ +/* PanelUI.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JPanel</code>. + * + * @see javax.swing.JPanel + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class PanelUI + extends ComponentUI +{ + /** + * Constructs a new <code>PanelUI</code>. + */ + public PanelUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/PopupMenuUI.java b/libjava/classpath/javax/swing/plaf/PopupMenuUI.java new file mode 100644 index 00000000000..c70ad2a4e9b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/PopupMenuUI.java @@ -0,0 +1,117 @@ +/* PopupMenuUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.event.MouseEvent; + +import javax.swing.JPopupMenu; +import javax.swing.Popup; +import javax.swing.PopupFactory; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JPopupMenu</code>. + * + * @see javax.swing.JPopupMenu + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class PopupMenuUI + extends ComponentUI +{ + /** + * Constructs a new <code>PopupMenuUI</code>. + */ + public PopupMenuUI() + { + } + + + /** + * Tests whether or not a mouse event triggers a popup menu. + * + * <p>The default implementation calls + * <code>event.isPopupTrigger()</code>, which checks for the gesture + * that is common for the platform on which the application runs. If + * a look and feel wants to employ non-standard conventions for + * triggering a popup menu, it can override this method. + * + * @param event the event to check. + * + * @return <code>true</code> if the event triggers a popup menu; + * <code>false</code> otherwise. + * + * @since 1.3 + */ + public boolean isPopupTrigger(MouseEvent event) + { + return event.isPopupTrigger(); + } + + + /** + * Creates a <code>Popup</code> for displaying the popup menu. The + * default implementation uses the {@link javax.swing.PopupFactory} + * for retrieving a suitable <code>Popup</code>, but subclasses + * might want to override this method if a LookAndFeel needs special + * Popups. + * + * @param popup the <code>JPopupMenu</code> for whose display + * a <code>Popup</code> is needed. + * + * @param x the horizontal position where the popup will be + * displayed. + * + * @param y the vertical position where the popup will be + * displayed. + * + * @return a <code>Popup</code> for showing and hiding + * the menu. + * + * @since 1.4 + */ + public Popup getPopup(JPopupMenu popup, int x, int y) + { + return PopupFactory.getSharedInstance().getPopup( + /* origin/owner of the popup */ popup.getInvoker(), + /* contents */ popup, + x, y); + } +} diff --git a/libjava/classpath/javax/swing/plaf/ProgressBarUI.java b/libjava/classpath/javax/swing/plaf/ProgressBarUI.java new file mode 100644 index 00000000000..79c1b95a34a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ProgressBarUI.java @@ -0,0 +1,59 @@ +/* ProgressBarUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JProgressBar</code>. + * + * @see javax.swing.JProgressBar + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ProgressBarUI + extends ComponentUI +{ + /** + * Constructs a new <code>ProgressBarUI</code>. + */ + public ProgressBarUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/RootPaneUI.java b/libjava/classpath/javax/swing/plaf/RootPaneUI.java new file mode 100644 index 00000000000..ff7d0a6e78a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/RootPaneUI.java @@ -0,0 +1,58 @@ +/* RootPaneUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JRootPane</code>. + * + * @see javax.swing.JRootPane + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class RootPaneUI + extends ComponentUI +{ + /** + * Constructs a new <code>RootPaneUI</code>. + */ + public RootPaneUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/ScrollBarUI.java b/libjava/classpath/javax/swing/plaf/ScrollBarUI.java new file mode 100644 index 00000000000..3cad3932720 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ScrollBarUI.java @@ -0,0 +1,58 @@ +/* ScrollBarUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JScrollBar</code>. + * + * @see javax.swing.JScrollBar + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ScrollBarUI + extends ComponentUI +{ + /** + * Constructs a new <code>ScrollBarUI</code>. + */ + public ScrollBarUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/ScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/ScrollPaneUI.java new file mode 100644 index 00000000000..14d2ac61ef2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ScrollPaneUI.java @@ -0,0 +1,59 @@ +/* ScrollPaneUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JScrollPane</code>. + * + * @see javax.swing.JScrollPane + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ScrollPaneUI + extends ComponentUI +{ + /** + * Constructs a new <code>ScrollPaneUI</code>. + */ + public ScrollPaneUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/SeparatorUI.java b/libjava/classpath/javax/swing/plaf/SeparatorUI.java new file mode 100644 index 00000000000..6855bd0357e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/SeparatorUI.java @@ -0,0 +1,58 @@ +/* SeparatorUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JSeparator</code>. + * + * @see javax.swing.JSeparator + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class SeparatorUI + extends ComponentUI +{ + /** + * Constructs a new <code>SeparatorUI</code>. + */ + public SeparatorUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/SliderUI.java b/libjava/classpath/javax/swing/plaf/SliderUI.java new file mode 100644 index 00000000000..775f19620a8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/SliderUI.java @@ -0,0 +1,59 @@ +/* SliderUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JSlider</code>. + * + * @see javax.swing.JSlider + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class SliderUI + extends ComponentUI +{ + /** + * Constructs a new <code>SliderUI</code>. + */ + public SliderUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/SpinnerUI.java b/libjava/classpath/javax/swing/plaf/SpinnerUI.java new file mode 100644 index 00000000000..fb4a3b13a93 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/SpinnerUI.java @@ -0,0 +1,59 @@ +/* SpinnerUI.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JSpinner</code>. + * + * @since 1.4 + * @see javax.swing.JSpinner + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class SpinnerUI + extends ComponentUI +{ + /** + * Constructs a new <code>SpinnerUI</code>. + */ + public SpinnerUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/SplitPaneUI.java b/libjava/classpath/javax/swing/plaf/SplitPaneUI.java new file mode 100644 index 00000000000..ea9af2b1716 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/SplitPaneUI.java @@ -0,0 +1,133 @@ +/* SplitPaneUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Graphics; + +import javax.swing.JSplitPane; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JSplitPane</code>. + * + * @see javax.swing.JSplitPane + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class SplitPaneUI + extends ComponentUI +{ + /** + * Constructs a new <code>SplitPaneUI</code>. + */ + public SplitPaneUI() + { + } + + + /** + * Moves the divider to the location which best respects + * the preferred sizes of the children. + * + * @param pane the <code>JSplitPane</code> for thich this + * delegate provides the look and feel. + */ + public abstract void resetToPreferredSizes(JSplitPane pane); + + + /** + * Moves the divider to the specified location. + * + * @param pane the <code>JSplitPane</code> for thich this + * delegate provides the look and feel. + * + * @param location the new location of the divider. + */ + public abstract void setDividerLocation(JSplitPane pane, + int location); + + + /** + * Determines the current location of the divider. + * + * @param pane the <code>JSplitPane</code> for thich this + * delegate provides the look and feel. + * + * @return the current location of the divider. + */ + public abstract int getDividerLocation(JSplitPane pane); + + + /** + * Determines the minimum location of the divider. + * + * @param pane the <code>JSplitPane</code> for thich this + * delegate provides the look and feel. + * + * @return the leftmost (or topmost) possible location + * of the divider. + */ + public abstract int getMinimumDividerLocation(JSplitPane pane); + + + /** + * Determines the maximum location of the divider. + * + * @param pane the <code>JSplitPane</code> for thich this + * delegate provides the look and feel. + * + * @return the bottommost (or rightmost) possible location + * of the divider. + */ + public abstract int getMaximumDividerLocation(JSplitPane pane); + + + /** + * Called by the <code>JSplitPane</code> after it has finished + * painting its children. + * + * @param pane the <code>JSplitPane</code> for thich this + * delegate provides the look and feel. + * + * @param g the Graphics used for painting. + */ + public abstract void finishedPaintingChildren(JSplitPane pane, + Graphics g); +} diff --git a/libjava/classpath/javax/swing/plaf/TabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/TabbedPaneUI.java new file mode 100644 index 00000000000..6ab823b50a8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/TabbedPaneUI.java @@ -0,0 +1,111 @@ +/* TabbedPaneUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Rectangle; + +import javax.swing.JTabbedPane; + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JTabbedPane</code>. + * + * @see javax.swing.JTabbedPane + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class TabbedPaneUI + extends ComponentUI +{ + /** + * Constructs a new <code>TabbedPaneUI</code>. + */ + public TabbedPaneUI() + { + } + + + /** + * Determines which tab lies at a given position. + * + * @param pane the <code>JTabbedPane</code> for which this + * delegate object provides the user interface. + * + * @param x the horizontal position, where zero is the left + * edge of <code>pane</code>. + * + * @param y the vertical position, where zero is the top + * edge of <code>pane</code>. + * + * @return the zero-based index of the tab, or -1 if no + * tab is at the specified position. + */ + public abstract int tabForCoordinate(JTabbedPane pane, + int x, int y); + + + /** + * Calculates the bounding box of a tab. + * + * @param pane the <code>JTabbedPane</code> for which this + * delegate object provides the user interface. + * + * @param index the index of the tab, which must be an integer + * in the range <code>[0 .. pane.getTabCount() - 1]</code>. + * + * @return the bounding box of the <code>index</code>-th tab, + * in the coordinate system of <code>pane</code>. + */ + public abstract Rectangle getTabBounds(JTabbedPane pane, int index); + + + /** + * Determines how many runs are used to display tabs. + * + * @param pane the <code>JTabbedPane</code> for which this + * delegate object provides the user interface. + * + * @return the number of tab runs. + * + * @see javax.swing.JTabbedPane#getTabRunCount() + */ + public abstract int getTabRunCount(JTabbedPane pane); +} + diff --git a/libjava/classpath/javax/swing/plaf/TableHeaderUI.java b/libjava/classpath/javax/swing/plaf/TableHeaderUI.java new file mode 100644 index 00000000000..f23ca74d7ed --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/TableHeaderUI.java @@ -0,0 +1,59 @@ +/* TableHeaderUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JTableHeader</code>. + * + * @see javax.swing.table.JTableHeader + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class TableHeaderUI + extends ComponentUI +{ + /** + * Constructs a new <code>TableHeaderUI</code>. + */ + public TableHeaderUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/TableUI.java b/libjava/classpath/javax/swing/plaf/TableUI.java new file mode 100644 index 00000000000..e56bcd13160 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/TableUI.java @@ -0,0 +1,59 @@ +/* TableUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JTable</code>. + * + * @see javax.swing.JTable + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class TableUI + extends ComponentUI +{ + /** + * Constructs a new <code>TableUI</code>. + */ + public TableUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/TextUI.java b/libjava/classpath/javax/swing/plaf/TextUI.java new file mode 100644 index 00000000000..86d1f1f1b80 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/TextUI.java @@ -0,0 +1,284 @@ +/* TextUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Point; +import java.awt.Rectangle; + +import javax.swing.text.BadLocationException; +import javax.swing.text.EditorKit; +import javax.swing.text.JTextComponent; +import javax.swing.text.Position; +import javax.swing.text.View; + +/** + * An abstract base class for delegates that provide the user + * interface for text editors. + * + * @see javax.swing.text.JTextComponent + * + * @author Ronald Veldema (rveldema@cs.vu.nl) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class TextUI + extends ComponentUI +{ + /** + * Constructs a new <code>TextUI</code>. + */ + public TextUI() + { + } + + + /** + * Calculates the geometric extent of the character at the + * given offset. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param pos the zero-based index of the character into the + * document model. + * + * @return the bounding box of the character at index + * <code>pos</code>, in view coordinates. + * + * @throws BadLocationException if <code>pos</code> does not + * designate a valid position in the document model. + * + * @see javax.swing.text.View#modelToView(int, + * javax.swing.text.Position.Bias, int, + * javax.swing.text.position.Bias, java.awt.Shape) + */ + public abstract Rectangle modelToView(JTextComponent tc, int pos) + throws BadLocationException; + + + /** + * Calculates the geometric extent of the character at the + * given offset. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param pos the zero-based index of the character into the + * document model. + * + * @param bias whether to take the character before or after the + * caret position indicated by <code>pos</code>. The value + * must be either {@link + * javax.swing.text.Position.Bias#Backward} or {@link + * javax.swing.text.Position.Bias#Forward}. + * + * @return the bounding box of the character at index + * <code>pos</code>, in view coordinates. + * + * @throws BadLocationException if <code>pos</code> does not + * designate a valid position in the document model. + * + * @see javax.swing.text.View#modelToView(int, + * javax.swing.text.Position.Bias, int, + * javax.swing.text.position.Bias, java.awt.Shape) + */ + public abstract Rectangle modelToView(JTextComponent tc, int pos, + Position.Bias bias) + throws BadLocationException; + + + /** + * Finds the caret position which is closest to the specified visual + * location. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param loc the position in view coordinates. + * + * @return the caret position which is closest to <code>loc</code>. + * + * @see #viewToModel(JTextComponent, Point, Position.Bias[]) + */ + public abstract int viewToModel(JTextComponent t, Point pt); + + + /** + * Finds the caret position which is closest to the specified visual + * location. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param loc the position in view coordinates. + * + * @param outBias an array whose size must be at least one. + * After the call, <code>outBias[0]</code> will indicate + * whether <code>loc</code> is in the glyph before + * (<code>Position.Bias.Backward</code>) or after + * (<code>Position.Bias.Forward</code>) the returned + * caret position. + * + * @return the caret position which is closest to <code>loc</code>. + */ + public abstract int viewToModel(JTextComponent tc, Point loc, + Position.Bias[] outBias); + + + + /** + * Calculates the caret position that is visually next to the given + * position. This is useful to determine where to move the caret + * after the user has pressed an arrow key. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param pos the current caret position, a zero-based index + * into the document model. + * + * @param bias whether to take the character before or after the + * caret position indicated by <code>pos</code>. The value + * must be either {@link + * javax.swing.text.Position.Bias#Backward} or {@link + * javax.swing.text.Position.Bias#Forward}. + * + * @param direction the visual direction. Pass + * {@link javax.swing.SwingConstants#WEST} for the left + * arrow key, {@link javax.swing.SwingConstants#EAST} + * for the right arrow key, {@link + * javax.swing.SwingConstants#NORTH} for the up arrow + * key, or {@link javax.swing.SwingConstants#SOUTH} + * for the down arrow key. + * + * @throws BadLocationException if <code>pos</code> does not + * designate a valid position in the document model. + * + * @throws IllegalArgumentException if <code>direction</code> + * is not one of <code>Position.Bias.Forward</code> + * or <code>Position.Biad.Backward</code>. + */ + public abstract int getNextVisualPositionFrom(JTextComponent tc, + int pos, + Position.Bias bias, + int direction, + Position.Bias[] outBias) + throws BadLocationException; + + + /** + * Repaints a range of characters. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param start the first character in the range that needs + * painting, indicated as an index into the document model. + * + * @param end the last character in the range that needs + * painting, indicated as an index into the document model. + * <code>end</code> must be greater than or equal to + * <code>start</code>. + */ + public abstract void damageRange(JTextComponent tc, int start, int end); + + + /** + * Repaints a range of characters, also specifying the bias for the + * start and end of the range. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param start the first character in the range that needs + * painting, indicated as an index into the document model. + * + * @param end the last character in the range that needs + * painting, indicated as an index into the document model. + * <code>end</code> must be greater than or equal to + * <code>start</code>. + */ + public abstract void damageRange(JTextComponent tc, + int start, int end, + Position.Bias startBias, + Position.Bias endBias); + + + /** + * Retrieves the <code>EditorKit</code> managing policies and + * persistent state. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @return the <code>EditorKit</code> used by <code>tc</code>. + */ + public abstract EditorKit getEditorKit(JTextComponent tc); + + + /** + * Retrieves the root of the view tree that visually presents + * the text. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @return the root <code>View</code> used by <code>tc</code>. + */ + public abstract View getRootView(JTextComponent tc); + + + /** + * Returns a String for presenting a tool tip at the specified + * location. + * + * @param tc the <code>JTextComponent</code> for which this + * delegate object provides the user interface. + * + * @param loc the location for which the tool tip is requested. + * + * @return the text for the tool tip, or <code>null</code> to + * display no tool tip. + * + * @since 1.4 + */ + public String getToolTipText(JTextComponent tc, Point loc) + { + return null; + } +} diff --git a/libjava/classpath/javax/swing/plaf/ToolBarUI.java b/libjava/classpath/javax/swing/plaf/ToolBarUI.java new file mode 100644 index 00000000000..730cf4887db --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ToolBarUI.java @@ -0,0 +1,59 @@ +/* ToolBarUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JToolBar</code>. + * + * @see javax.swing.JToolBar + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ToolBarUI + extends ComponentUI +{ + /** + * Constructs a new <code>ToolBarUI</code>. + */ + public ToolBarUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/ToolTipUI.java b/libjava/classpath/javax/swing/plaf/ToolTipUI.java new file mode 100644 index 00000000000..4383d0edd11 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ToolTipUI.java @@ -0,0 +1,59 @@ +/* ToolTipUI.java -- + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JToolTip</code>. + * + * @see javax.swing.JToolTip + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ToolTipUI + extends ComponentUI +{ + /** + * Constructs a new <code>ToolTipUI</code>. + */ + public ToolTipUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/TreeUI.java b/libjava/classpath/javax/swing/plaf/TreeUI.java new file mode 100644 index 00000000000..e32952de70f --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/TreeUI.java @@ -0,0 +1,211 @@ +/* TreeUI.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +import java.awt.Rectangle; + +import javax.swing.JTree; +import javax.swing.tree.TreePath; + +/** + * An abstract base class for delegates that provide the user + * interface for <code>JTree</code>. + * + * @see javax.swing.JTree + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class TreeUI + extends ComponentUI +{ + /** + * Constructs a new <code>TreeUI</code>. + */ + public TreeUI() + { + } + + + /** + * Determines the geometric extent of the label that is + * drawn for a path. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @param path the path whose label extent is requested. + * + * @return a rectangle enclosing the label, or <code>null</code> + * if <code>path</code> contains invalid nodes. + */ + public abstract Rectangle getPathBounds(JTree tree, TreePath path); + + + /** + * Creates a <code>TreePath</code> for the specified row. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @param row the index of the row, which should be a number + * in the range <code>[0, getRowCount(tree) - 1]</code>. + * + * @return a <code>TreePath</code> for the specified row, or + * <code>null</code> if <code>row</code> is outside + * the valid range. + */ + public abstract TreePath getPathForRow(JTree tree, int row); + + + /** + * Determines in which row a <code>TreePath</code> is currently + * being displayed. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @param path the path for which the caller wants to know + * in which row it is being displayed. + * + * @return a number in the range <code>[0, getRowCount(tree) + * - 1]</code> if the path is currently on display; + * <code>-1</code> if the path is not shown to the + * user. + */ + public abstract int getRowForPath(JTree tree, TreePath path); + + + /** + * Counts how many rows are currently displayed. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @return the number of visible rows. + */ + public abstract int getRowCount(JTree tree); + + + /** + * Finds the path that is closest to the specified position. + * + * <p><img src="doc-files/TreeUI-1.png" width="300" height="250" + * alt="[A screen shot of a JTree]" /> + * + * <p>As shown by the above illustration, the bounds of the + * closest path do not necessarily need to contain the passed + * location. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @param x the horizontal location, relative to the origin + * of <code>tree</code>. + * + * @param y the vertical location, relative to the origin + * of <code>tree</code>. + * + * @return the closest path, or <code>null</code> if the + * tree is currenlty not displaying any paths at all. + */ + public abstract TreePath getClosestPathForLocation(JTree tree, + int x, int y); + + + /** + * Determines whether the user is currently editing a tree cell. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @see #getEditingPath + */ + public abstract boolean isEditing(JTree tree); + + + /** + * Stops editing a tree cell, committing the entered value into the + * tree’s model. If no editing session is active, or if the + * active editor does not agree to stopping, nothing happens. In + * some look and feels, this action happens when the user has + * pressed the enter key. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @return <code>false</code> if the editing still goes on because + * the cell editor has objected to stopping the session; + * <code>true</code> if editing has been stopped. + */ + public abstract boolean stopEditing(JTree tree); + + + /** + * Cancels editing a tree cell, discarding any entered value. + * If no editing session is active, nothing happens. The cell + * editor is not given an opportunity to veto the canceling. + * In some look and feels, this action happens when the user has + * pressed the escape key. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + */ + public abstract void cancelEditing(JTree tree); + + + /** + * Starts a session to edit a tree cell. If the cell editor + * rejects editing the cell, it will just be selected. + * + * @param tree the <code>JTree</code> for which this delegate + * object provides the user interface. + * + * @param path the cell to edit. + */ + public abstract void startEditingAtPath(JTree tree, TreePath path); + + + /** + * Retrieves the tree cell that is currently being edited. + * + * @return the currently edited path, or <code>null</code> + * if no editing session is currently active. + */ + public abstract TreePath getEditingPath(JTree tree); +} diff --git a/libjava/classpath/javax/swing/plaf/UIResource.java b/libjava/classpath/javax/swing/plaf/UIResource.java new file mode 100644 index 00000000000..1e28280e82f --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/UIResource.java @@ -0,0 +1,55 @@ +/* UIResource.java + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + +/** + * This public interface is used to designate which objects were created by + * <code>ComponentUI</code> delegates. When uninstalling the user public interface + * renderer with <code>ComponentUI.uninstallUI()</code> the renderer + * property is set to <code>null</code>. + * <br> + * A comparison against null can be used with all properties except for + * the <code>java.awt.Component</code> properties font, foreground, and + * background. The container can provide the value of the properties if + * they are initialized or set to <code>null</code>. + * + * @author Brian Jones + * @see java.lang.ComponentUI + */ +public interface UIResource { } diff --git a/libjava/classpath/javax/swing/plaf/ViewportUI.java b/libjava/classpath/javax/swing/plaf/ViewportUI.java new file mode 100644 index 00000000000..087938f1ed2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/ViewportUI.java @@ -0,0 +1,60 @@ +/* ViewportUI.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf; + + +/** + * An abstract base class for delegates that implement the pluggable + * look and feel for a <code>JViewport</code>. + * + * @see javax.swing.JViewport + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ViewportUI + extends ComponentUI +{ + /** + * Constructs a new <code>ViewportUI</code>. + */ + public ViewportUI() + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java new file mode 100644 index 00000000000..4da4691f6d8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java @@ -0,0 +1,350 @@ +/* BasicArrowButton.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Polygon; +import java.awt.Rectangle; + +import javax.swing.JButton; +import javax.swing.SwingConstants; +import javax.swing.border.Border; + +/** + * This class draws simple arrow buttons for the Basic Look and Feel. + */ +public class BasicArrowButton extends JButton implements SwingConstants +{ + /** The default size of the Arrow buttons. */ + private static int defaultSize = 10; + + /** The Polygon that points up. */ + private static Polygon upIcon = new Polygon(new int[] { 0, 5, 9 }, + new int[] { 7, 2, 7 }, 3); + + /** The Polygon that points down. */ + private static Polygon downIcon = new Polygon(new int[] { 1, 5, 9 }, + new int[] { 3, 7, 3 }, 3); + + /** The Polygon that points left. */ + private static Polygon leftIcon = new Polygon(new int[] { 7, 3, 7 }, + new int[] { 1, 5, 9 }, 3); + + /** The Polygon that points right. */ + private static Polygon rightIcon = new Polygon(new int[] { 3, 7, 3 }, + new int[] { 1, 5, 9 }, 3); + + /** The direction to point in. */ + protected int direction; + + /** + * The color the arrow is painted in if disabled and the bottom and right + * edges of the button. + * This is package-private to avoid an accessor method. + */ + transient Color shadow = Color.GRAY; + + /** + * The color the arrow is painted in if enabled and the bottom and right + * edges of the button. + * This is package-private to avoid an accessor method. + */ + transient Color darkShadow = Color.DARK_GRAY; + + /** + * The top and left edges of the button. + * This is package-private to avoid an accessor method. + */ + transient Color highlight = Color.WHITE; + + /** The border around the ArrowButton. */ + private transient Border buttonBorder = new Border() + { + public Insets getBorderInsets(Component c) + { + return new Insets(2, 2, 2, 2); + } + + public boolean isBorderOpaque() + { + return true; + } + + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color saved = g.getColor(); + g.setColor(highlight); + + g.drawLine(x + 1, y + 1, x + w - 1, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 1); + + g.setColor(shadow); + + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + + g.setColor(darkShadow); + + g.drawLine(x, y + h, x + w, y + h); + g.drawLine(x + w, y, x + w, y + h); + + g.setColor(saved); + } + }; + + /** + * Creates a new BasicArrowButton object. + * + * @param direction The direction the arrow points in. + */ + public BasicArrowButton(int direction) + { + super(); + setBorder(buttonBorder); + setDirection(direction); + } + + /** + * Creates a new BasicArrowButton object with the given colors and + * direction. + * + * @param direction The direction to point in. + * @param background The background color. + * @param shadow The shadow color. + * @param darkShadow The dark shadow color. + * @param highlight The highlight color. + */ + public BasicArrowButton(int direction, Color background, Color shadow, + Color darkShadow, Color highlight) + { + this(direction); + setBackground(background); + this.shadow = shadow; + this.darkShadow = darkShadow; + this.highlight = highlight; + } + + /** + * This method returns whether the focus can traverse to this component. + * + * @return Whether the focus can traverse to this component. + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * This method returns the direction of the arrow. + * + * @return The direction of the arrow. + */ + public int getDirection() + { + return direction; + } + + /** + * This method changes the direction of the arrow. + * + * @param dir The new direction of the arrow. + */ + public void setDirection(int dir) + { + this.direction = dir; + } + + /** + * This method paints the arrow button. The painting is delegated to the + * paintTriangle method. + * + * @param g The Graphics object to paint with. + */ + public void paint(Graphics g) + { + super.paint(g); + Insets insets = getInsets(); + Rectangle bounds = getBounds(); + int x = insets.left + + (bounds.width - insets.left - insets.right - defaultSize) / 2; + int y = insets.top + + (bounds.height - insets.left - insets.right - defaultSize) / 2; + paintTriangle(g, x, y, defaultSize, direction, isEnabled()); + } + + /** + * This method returns the preferred size of the arrow button. + * + * @return The preferred size. + */ + public Dimension getPreferredSize() + { + Insets insets = getInsets(); + int w = defaultSize + insets.left + insets.right; + int h = defaultSize + insets.top + insets.bottom; + + return new Dimension(w, h); + } + + /** + * This method returns the minimum size of the arrow button. + * + * @return The minimum size. + */ + public Dimension getMinimumSize() + { + return getPreferredSize(); + } + + /** + * This method returns the maximum size of the arrow button. + * + * @return The maximum size. + */ + public Dimension getMaximumSize() + { + return getPreferredSize(); + } + + /** + * The method paints a triangle with the given size and direction at the + * given x and y coordinates. + * + * @param g The Graphics object to paint with. + * @param x The x coordinate to paint at. + * @param y The y coordinate to paint at. + * @param size The size of the icon. + * @param direction The direction of the icon. + * @param isEnabled Whether it is enabled. + */ + public void paintTriangle(Graphics g, int x, int y, int size, int direction, + boolean isEnabled) + { + Polygon arrow = null; + switch (direction) + { + case NORTH: + arrow = upIcon; + break; + case SOUTH: + arrow = downIcon; + break; + case EAST: + case RIGHT: + arrow = rightIcon; + break; + case WEST: + case LEFT: + arrow = leftIcon; + break; + } + + int[] xPoints = arrow.xpoints; + int[] yPoints = arrow.ypoints; + int x1; + int y1; + int x2; + int y2; + x1 = y1 = x2 = y2 = 0; + + if (size != defaultSize) + { + float scale = size * 1f / defaultSize; + for (int i = 0; i < 3; i++) + { + xPoints[i] *= scale; + yPoints[i] *= scale; + } + } + g.translate(x, y); + + switch (direction) + { + case NORTH: + x1 = xPoints[0] + 2; + y1 = yPoints[0]; + y2 = y1; + x2 = xPoints[2] - 1; + break; + case SOUTH: + x1 = xPoints[1]; + y1 = yPoints[1] + 1; + x2 = xPoints[2] - 1; + y2 = yPoints[2]; + break; + case LEFT: + case WEST: + x1 = xPoints[0] + 1; + y1 = yPoints[0] + 1; + x2 = x1; + y2 = yPoints[2] + 1; + break; + case RIGHT: + case EAST: + x1 = xPoints[2]; + y1 = yPoints[2] + 1; + x2 = xPoints[1] - 1; + y2 = yPoints[1] + 1; + break; + } + Color saved = g.getColor(); + + if (isEnabled) + { + g.setColor(Color.DARK_GRAY); + + if (arrow != null) + g.fillPolygon(xPoints, yPoints, 3); + } + else + { + g.setColor(Color.GRAY); + g.fillPolygon(xPoints, yPoints, 3); + g.setColor(Color.WHITE); + g.drawLine(x1, y1, x2, y2); + } + g.setColor(saved); + g.translate(-x, -y); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java new file mode 100644 index 00000000000..e7d6e433877 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java @@ -0,0 +1,1814 @@ +/* BasicBorders.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JPopupMenu; +import javax.swing.JSplitPane; +import javax.swing.JToolBar; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.text.JTextComponent; + +/** + * Provides various borders for the Basic look and feel. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class BasicBorders +{ + /** + * A MarginBorder that gets shared by multiple components. + * Created on demand by the private helper function {@link + * #getMarginBorder()}. + */ + private static MarginBorder sharedMarginBorder; + + + /** + * Returns a border for drawing push buttons. + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“Button.shadow”</code>, + * <code>“Button.darkShadow”</code>, + * <code>“Button.light”</code>, and + * <code>“Button.highlight”</code>. + * + * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300" + * height="170" alt="[A screen shot of the returned border]" /> + * + * @return a {@link + * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} + * whose outer border is a {@link ButtonBorder} and whose + * inner border is a {@link MarginBorder}. + */ + public static Border getButtonBorder() + { + UIDefaults defaults; + Border outer; + + defaults = UIManager.getLookAndFeelDefaults(); + + /* The keys for UIDefaults have been determined by writing a + * test program that dumps the UIDefaults to stdout; that program + * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, + * the key "light" is usually called "highlight", and "highlight" + * is usually called "lightHighlight". + */ + outer = new ButtonBorder(defaults.getColor("Button.shadow"), + defaults.getColor("Button.darkShadow"), + defaults.getColor("Button.light"), + defaults.getColor("Button.highlight")); + + /* While the inner border is shared between multiple buttons, + * we do not share the outer border because ButtonBorders store + * their border colors. We cannot guarantee that the colors + * (which come from UIDefaults) are unchanged between invocations + * of getButtonBorder. We could store the last colors, and share + * the button border if the colors are the same as in the last + * invocation, but it probably is not worth the effort. + */ + return new BorderUIResource.CompoundBorderUIResource( + outer, + /* inner */ getMarginBorder()); + } + + + /** + * Returns a border for drawing radio buttons. + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“RadioButton.shadow”</code>, + * <code>“RadioButton.darkShadow”</code>, + * <code>“RadioButton.light”</code>, and + * <code>“RadioButton.highlight”</code>. + * + * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300" + * height="135" alt="[A screen shot of the returned border]" /> + * + * @return a {@link + * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} + * whose outer border is a {@link RadioButtonBorder} and whose + * inner border is a {@link MarginBorder}. + */ + public static Border getRadioButtonBorder() + { + UIDefaults defaults; + Border outer; + + defaults = UIManager.getLookAndFeelDefaults(); + + /* The keys for UIDefaults have been determined by writing a + * test program that dumps the UIDefaults to stdout; that program + * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, + * the key "light" is usually called "highlight", and "highlight" + * is usually called "lightHighlight". + */ + outer = new RadioButtonBorder( + defaults.getColor("RadioButton.shadow"), + defaults.getColor("RadioButton.darkShadow"), + defaults.getColor("RadioButton.light"), + defaults.getColor("RadioButton.highlight")); + + /* While the inner border is shared between multiple buttons, we + * do not share the outer border because RadioButtonBorders, being + * ButtonBorders, store their border colors. We cannot guarantee + * that the colors (which come from UIDefaults) are unchanged + * between invocations of getButtonBorder. We could store the last + * colors, and share the button border if the colors are the same + * as in the last invocation, but it probably is not worth the + * effort. + */ + return new BorderUIResource.CompoundBorderUIResource( + outer, + /* inner */ getMarginBorder()); + } + + + /** + * Returns a border for drawing toggle buttons. + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“ToggleButton.shadow”</code>, + * <code>“ToggleButton.darkShadow”</code>, + * <code>“ToggleButton.light”</code>, and + * <code>“ToggleButton.highlight”</code>. + * + * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" width="270" + * height="135" alt="[A screen shot of the returned border]" /> + * + * @return a {@link + * javax.swing.plaf.BorderUIResource.CompoundBorderUIResource} + * whose outer border is a {@link ToggleButtonBorder} and whose + * inner border is a {@link MarginBorder}. + */ + public static Border getToggleButtonBorder() + { + UIDefaults defaults; + Border outer; + + defaults = UIManager.getLookAndFeelDefaults(); + + /* The keys for UIDefaults have been determined by writing a + * test program that dumps the UIDefaults to stdout; that program + * was run on a JDK 1.4.1_01 for GNU/Linux. Note that in the API, + * the key "light" is usually called "highlight", and "highlight" + * is usually called "lightHighlight". + */ + outer = new ToggleButtonBorder( + defaults.getColor("ToggleButton.shadow"), + defaults.getColor("ToggleButton.darkShadow"), + defaults.getColor("ToggleButton.light"), + defaults.getColor("ToggleButton.highlight")); + + /* While the inner border is shared between multiple buttons, we + * do not share the outer border because ToggleButtonBorders, being + * ButtonBorders, store their border colors. We cannot guarantee + * that the colors (which come from UIDefaults) are unchanged + * between invocations of getButtonBorder. We could store the last + * colors, and share the button border if the colors are the same + * as in the last invocation, but it probably is not worth the + * effort. + */ + return new BorderUIResource.CompoundBorderUIResource( + outer, + /* inner */ getMarginBorder()); + } + + + /** + * Returns a border for drawing a two-pixel thick separator line + * below menu bars. + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“MenuBar.shadow”</code> and + * <code>“MenuBar.highlight”</code>. + * + * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" + * height="140" alt="[A screen shot of a JMenuBar with this border]" /> + * + * @return a {@link MenuBarBorder}. + * + * @see javax.swing.JMenuBar + */ + public static Border getMenuBarBorder() + { + UIDefaults defaults; + + /* See comment in methods above for why this border is not shared. */ + defaults = UIManager.getLookAndFeelDefaults(); + return new MenuBarBorder(defaults.getColor("MenuBar.shadow"), + defaults.getColor("MenuBar.highlight")); + } + + + /** + * Returns a border for drawing a one-pixel thick border around + * split panes that are interrupted where the divider joins the + * border. + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“SplitPane.darkShadow”</code> and + * <code>“SplitPane.highlight”</code>. + * + * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" + * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> + * + * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" + * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> + * + * @return a {@link SplitPaneBorder}. + * + * @see javax.swing.JSplitPane + * @see #getSplitPaneDividerBorder() + */ + public static Border getSplitPaneBorder() + { + UIDefaults defaults; + + /* See comment in methods above for why this border is not shared. */ + defaults = UIManager.getLookAndFeelDefaults(); + return new SplitPaneBorder(defaults.getColor("SplitPane.highlight"), + defaults.getColor("SplitPane.darkShadow")); + } + + + /** + * Returns a border for drawing a one-pixel thick border around + * the divider of split panes. + * + * <p>The colors of the edges that are adjacent to the child components + * of the <code>JSplitPane</code> are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“SplitPane.darkShadow”</code> and + * <code>“SplitPane.highlight”</code>. The color of the + * other two edges is the background color of the divider. + * + * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" + * width="520" height="200" alt= + * "[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> + * + * @return an instance of <code>SplitPaneDividerBorder</code>, which is + * not a public API class of this package. + * + * @see javax.swing.JSplitPane + * @see javax.swing.plaf.basic.BasicSplitPaneDivider + * @see #getSplitPaneBorder() + * + * @since 1.3 + */ + public static Border getSplitPaneDividerBorder() + { + UIDefaults defaults; + + /* See comment in methods above for why this border is not shared. */ + defaults = UIManager.getLookAndFeelDefaults(); + return new SplitPaneDividerBorder( + defaults.getColor("SplitPane.highlight"), + defaults.getColor("SplitPane.darkShadow")); + } + + + /** + * Returns a border for drawing a border around a text field + * that makes the field appear as etched into the surface. + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“TextField.shadow”</code>, + * <code>“TextField.darkShadow”</code>, + * <code>“TextField.light”</code>, and + * <code>“TextField.highlight”</code>. + * + * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500" + * height="200" alt="[A screen shot of a border returned by + * this method]" /> + * + * @return an instance of {@link FieldBorder}. + * + * @see javax.swing.JTextField + * @see javax.swing.text.JTextComponent + */ + public static Border getTextFieldBorder() + { + UIDefaults defaults; + + /* See comment in methods above for why this border is not shared. */ + defaults = UIManager.getLookAndFeelDefaults(); + return new FieldBorder( + defaults.getColor("TextField.shadow"), + defaults.getColor("TextField.darkShadow"), + defaults.getColor("TextField.light"), + defaults.getColor("TextField.highlight")); + } + + + /** + * Returns a two-pixel thick, green + * <code>LineBorderUIResource</code>. This is so ugly that look and + * feels better use different borders for their progress bars, or + * they will look really terrible. + * + * <p><img src="doc-files/BasicBorders-1.png" width="120" height="80" + * alt="[A screen shot of a border returned by this method]" /> + */ + public static Border getProgressBarBorder() + { + /* There does not seem to exist a way to parametrize the color + * or thickness of the border through UIDefaults. + */ + return new BorderUIResource.LineBorderUIResource(Color.green, 2); + } + + + /** + * Returns a border that is composed of a raised bevel border and a + * one-pixel thick line border. + * + * <p><img src="doc-files/BasicBorders-2.png" width="300" height="200" + * alt="[A screen shot of a border returned by this method]" /> + * + * <p>The colors of the border are retrieved from the + * <code>UIDefaults</code> of the currently active look and feel + * using the keys <code>“InternalFrame.borderShadow”</code>, + * <code>“InternalFrame.borderDarkShadow”</code>, + * <code>“InternalFrame.borderLight”</code>, + * <code>“InternalFrame.borderHighlight”</code>, and + * (for the inner one-pixel thick line) + * <code>“InternalFrame.borderColor”</code>. + */ + public static Border getInternalFrameBorder() + { + UIDefaults defaults; + Color shadow, darkShadow, highlight, lightHighlight, line; + + /* See comment in methods above for why this border is not shared. */ + defaults = UIManager.getLookAndFeelDefaults(); + + shadow = defaults.getColor("InternalFrame.borderShadow"); + darkShadow = defaults.getColor("InternalFrame.borderDarkShadow"); + highlight = defaults.getColor("InternalFrame.borderLight"); + lightHighlight = defaults.getColor("InternalFrame.borderHighlight"); + line = defaults.getColor("InternalFrame.borderColor"); + + return new BorderUIResource.CompoundBorderUIResource( + /* outer border */ + new BorderUIResource.BevelBorderUIResource( + BevelBorder.RAISED, + (highlight != null) ? highlight : Color.lightGray, + (lightHighlight != null) ? lightHighlight : Color.white, + (darkShadow != null) ? darkShadow : Color.black, + (shadow != null) ? shadow : Color.gray), + + /* inner border */ + new BorderUIResource.LineBorderUIResource( + (line != null) ? line : Color.lightGray)); + } + + + /** + * Returns a shared MarginBorder. + */ + static Border getMarginBorder() // intentionally not public + { + /* Swing is not designed to be thread-safe, so there is no + * need to synchronize the access to the global variable. + */ + if (sharedMarginBorder == null) + sharedMarginBorder = new MarginBorder(); + + return sharedMarginBorder; + } + + + /** + * A border whose appearance depends on the state of + * the enclosed button. + * + * <p><img src="doc-files/BasicBorders.ButtonBorder-1.png" width="300" + * height="170" alt="[A screen shot of this border]" /> + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class ButtonBorder + extends AbstractBorder + implements Serializable, UIResource + { + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -157053874580739687L; + + + /** + * The color for drawing the shaded parts of the border. + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + protected Color shadow; + + + /** + * The color for drawing the dark shaded parts of the border. + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + protected Color darkShadow; + + + /** + * The color for drawing the highlighted parts of the border. + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + protected Color highlight; + + + /** + * The color for drawing the bright highlighted parts of the border. + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + protected Color lightHighlight; + + + /** + * Constructs a new border for drawing a button in the Basic + * look and feel. + * + * @param shadow the shadow color. + * @param darkShadow a darker variant of the shadow color. + * @param highlight the highlight color. + * @param lightHighlight a brighter variant of the highlight color. + */ + public ButtonBorder(Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + /* These colors usually come from the UIDefaults of the current + * look and feel. Use fallback values if the colors are not + * supplied. The API specification is silent about what + * behavior is expected for null colors, so users should not + * rely on this fallback (which is why it is not documented in + * the above Javadoc). + */ + this.shadow = (shadow != null) ? shadow : Color.gray; + this.darkShadow = (darkShadow != null) ? darkShadow : Color.black; + this.highlight = (highlight != null) ? highlight : Color.lightGray; + this.lightHighlight = (lightHighlight != null) + ? lightHighlight + : Color.white; + } + + + /** + * Paints the ButtonBorder around a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + ButtonModel bmodel = null; + + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + + BasicGraphicsUtils.drawBezel( + g, x, y, width, height, + /* pressed */ (bmodel != null) + && /* mouse button pressed */ bmodel.isPressed() + && /* mouse inside */ bmodel.isArmed(), + /* default */ (c instanceof JButton) + && ((JButton) c).isDefaultButton(), + shadow, darkShadow, highlight, lightHighlight); + } + + + /** + * Measures the width of this border. + * + * <p>Although the thickness of the actually painted border + * depends on the state of the enclosed component, this + * measurement always returns the same amount of pixels. Indeed, + * it would be rather confusing if a button was appearing to + * change its size depending on whether it is pressed or not. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + /* There is no obvious reason for overriding this method, but we + * try to have exactly the same API as the Sun reference + * implementation. + */ + return getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * <p>Although the thickness of the actually painted border + * depends on the state of the enclosed component, this + * measurement always returns the same amount of pixels. Indeed, + * it would be rather confusing if a button was appearing to + * change its size depending on whether it is pressed or not. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets(Component) + */ + public Insets getBorderInsets(Component c, Insets insets) + { + /* The exact amount has been determined using a test program + * that was run on the Sun reference implementation. With + * Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, the result is + * [3, 3, 3, 3]. With Sun JDK 1.4.1_01 on Linux/x86, the + * result is [2, 3, 3, 3]. We use the values from the 1.4.1_01 + * release. + */ + if (insets == null) + return new Insets(2, 3, 3, 3); + + insets.top = 2; + insets.bottom = insets.left = insets.right = 3; + return insets; + } + } + + + /** + * A border that makes its enclosed component appear as lowered + * into the surface. Typically used for text fields. + * + * <p><img src="doc-files/BasicBorders.FieldBorder-1.png" width="500" + * height="200" alt="[A screen shot of this border]" /> + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class FieldBorder + extends AbstractBorder + implements UIResource + { + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = 949220756998454908L; + + + /** + * The color for drawing the outer half of the top and left + * edges. + */ + protected Color shadow; + + + /** + * The color for drawing the inner half of the top and left + * edges. + */ + protected Color darkShadow; + + + /** + * The color for drawing the inner half of the bottom and right + * edges. + */ + protected Color highlight; + + + /** + * The color for drawing the outer half of the bottom and right + * edges. + */ + protected Color lightHighlight; + + + /** + * Constructs a new border for drawing a text field in the Basic + * look and feel. + * + * @param shadow the color for drawing the outer half + * of the top and left edges. + * + * @param darkShadow the color for drawing the inner half + * of the top and left edges. + * + * @param highlight the color for drawing the inner half + * of the bottom and right edges. + * + * @param lightHighlight the color for drawing the outer half + * of the bottom and right edges. + */ + public FieldBorder(Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + /* These colors usually come from the UIDefaults of the current + * look and feel. Use fallback values if the colors are not + * supplied. The API specification is silent about what + * behavior is expected for null colors, so users should not + * rely on this fallback (which is why it is not documented in + * the above Javadoc). + */ + this.shadow = (shadow != null) ? shadow : Color.gray; + this.darkShadow = (darkShadow != null) ? darkShadow : Color.black; + this.highlight = (highlight != null) ? highlight : Color.lightGray; + this.lightHighlight = (lightHighlight != null) + ? lightHighlight : Color.white; + } + + + /** + * Paints the FieldBorder around a given component. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawEtchedRect + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height, + shadow, darkShadow, + highlight, lightHighlight); + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * If <code>c</code> is an instance of {@link + * javax.swing.text.JTextComponent}, its margin is + * added to the border size. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param c the component whose border is to be measured. + * If <code>c</code> is an instance of {@link + * javax.swing.text.JTextComponent}, its margin is + * added to the border size. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets(Component) + */ + public Insets getBorderInsets(Component c, Insets insets) + { + if (insets == null) + insets = new Insets(2, 2, 2, 2); + else + insets.top = insets.left = insets.bottom = insets.right = 2; + + if (c instanceof JTextComponent) + { + Insets margin = ((JTextComponent) c).getMargin(); + insets.top += margin.top; + insets.left += margin.left; + insets.bottom += margin.bottom; + insets.right += margin.right; + } + + return insets; + } + } + + + /** + * An invisible, but spacing border whose margin is determined + * by calling the <code>getMargin()</code> method of the enclosed + * component. If the enclosed component has no such method, + * this border will not occupy any space. + * + * <p><img src="doc-files/BasicBorders.MarginBorder-1.png" width="325" + * height="200" alt="[An illustration that shows how MarginBorder + * determines its borders]" /> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class MarginBorder + extends AbstractBorder + implements Serializable, UIResource + { + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -3035848353448896090L; + + + /** + * Constructs a new MarginBorder. + */ + public MarginBorder() + { + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, <code>right</code>, + * <code>top</code> and <code>bottom</code> fields indicate the + * width of the border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, new Insets(0, 0, 0, 0)); + } + + + /** + * Determines the insets of this border by calling the + * <code>getMargin()</code> method of the enclosed component. The + * resulting margin will be stored into the the <code>left</code>, + * <code>right</code>, <code>top</code> and <code>bottom</code> + * fields of the passed <code>insets</code> parameter. + * + * <p>Unfortunately, <code>getMargin()</code> is not a method of + * {@link javax.swing.JComponent} or some other common superclass + * of things with margins. While reflection could be used to + * determine the existence of this method, this would be slow on + * many virtual machines. Therefore, the current implementation + * knows about {@link javax.swing.AbstractButton#getMargin()}, + * {@link javax.swing.JPopupMenu#getMargin()}, {@link + * javax.swing.JToolBar#getMargin()}, and {@link + * javax.swing.text.JTextComponent}. If <code>c</code> is an + * instance of a known class, the respective + * <code>getMargin()</code> method is called to determine the + * correct margin. Otherwise, a zero-width margin is returned. + * + * @param c the component whose border is to be measured. + * + * @return the same object that was passed for <code>insets</code>, + * but with changed fields. + */ + public Insets getBorderInsets(Component c, Insets insets) + { + Insets margin = null; + + /* This is terrible object-oriented design. See the above Javadoc + * for an excuse. + */ + if (c instanceof AbstractButton) + margin = ((AbstractButton) c).getMargin(); + else if (c instanceof JPopupMenu) + margin = ((JPopupMenu) c).getMargin(); + else if (c instanceof JToolBar) + margin = ((JToolBar) c).getMargin(); + else if (c instanceof JTextComponent) + margin = ((JTextComponent) c).getMargin(); + + if (margin == null) + insets.top = insets.left = insets.bottom = insets.right = 0; + else + { + insets.top = margin.top; + insets.left = margin.left; + insets.bottom = margin.bottom; + insets.right = margin.right; + } + + return insets; + } + } + + + /** + * A border for drawing a separator line below JMenuBar. + * + * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" + * height="140" alt="[A screen shot of a JMenuBar with this border]" /> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class MenuBarBorder + extends AbstractBorder + implements UIResource + { + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -6909056571935227506L; + + + /** + * The shadow color, which is used for the upper line of the + * two-pixel thick bottom edge. + */ + private Color shadow; + + + /** + * The highlight color, which is used for the lower line of the + * two-pixel thick bottom edge. + */ + private Color highlight; + + + /** + * Constructs a new MenuBarBorder for drawing a JMenuBar in + * the Basic look and feel. + * + * <p><img src="doc-files/BasicBorders.MenuBarBorder-1.png" width="500" + * height="140" alt="[A screen shot of a JMenuBar with this + * border]" /> + * + * @param shadow the shadow color, which is used for the upper + * line of the two-pixel thick bottom edge. + * + * @param highlight the shadow color, which is used for the lower + * line of the two-pixel thick bottom edge. + */ + public MenuBarBorder(Color shadow, Color highlight) + { + /* These colors usually come from the UIDefaults of the current + * look and feel. Use fallback values if the colors are not + * supplied. The API specification is silent about what + * behavior is expected for null colors, so users should not + * rely on this fallback (which is why it is not documented in + * the above Javadoc). + */ + this.shadow = (shadow != null) ? shadow : Color.gray; + this.highlight = (highlight != null) ? highlight : Color.white; + } + + + /** + * Paints the MenuBarBorder around a given component. + * + * @param c the component whose border is to be painted, usually + * an instance of {@link javax.swing.JMenuBar}. + * + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + Color oldColor; + + /* To understand this code, it might be helpful to look at the + * image "BasicBorders.MenuBarBorder-1.png" that is included + * with the JavaDoc. It is located in the "doc-files" + * subdirectory. + */ + oldColor = g.getColor(); + y = y + height - 2; + try + { + g.setColor(shadow); + g.drawLine(x, y, x + width - 2, y); + g.drawLine(x, y + 1, x, y + 1); + g.drawLine(x + width - 2, y + 1, x + width - 2, y + 1); + + g.setColor(highlight); + g.drawLine(x + 1, y + 1, x + width - 3, y + 1); + g.drawLine(x + width - 1, y, x + width - 1, y + 1); + } + finally + { + g.setColor(oldColor); + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + /* There is no obvious reason for overriding this method, but we + * try to have exactly the same API as the Sun reference + * implementation. + */ + return getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets(Component) + */ + public Insets getBorderInsets(Component c, Insets insets) + { + /* The exact amount has been determined using a test program + * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the + * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [0,0,2,0], + * which was expected from looking at the screen shot. + */ + if (insets == null) + return new Insets(0, 0, 2, 0); + + insets.left = insets.right = insets.top = 0; + insets.bottom = 2; + return insets; + } + } + + + /** + * A border for drawing radio buttons in the Basic look and feel. + * + * <p><img src="doc-files/BasicBorders.RadioButtonBorder-1.png" width="300" + * height="135" alt="[A screen shot of this border]" /> + * + * <p>Note about the screen shot: Normally, the + * <code>borderPainted</code> property is <code>false</code> for + * JRadioButtons. For this screen shot, it has been set to + * <code>true</code> so the borders get drawn. Also, a + * concretization of the Basic look and would typically provide + * icons for the various states of radio buttons. + * + * <p>Note that the focus rectangle is invisible If the radio button + * is currently selected. While it might be debatable whether this + * makes a lot of sense, this behavior can be observed in the Sun + * reference implementation (in JDK 1.3.1 and 1.4.1). The Classpath + * implementation tries to exactly replicate the JDK appearance. + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class RadioButtonBorder + extends ButtonBorder + { + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = 1596945751743747369L; + + + /** + * Constructs a new border for drawing a JRadioButton in + * the Basic look and feel. + * + * @param shadow the shadow color. + * @param darkShadow a darker variant of the shadow color. + * @param highlight the highlight color. + * @param lightHighlight a brighter variant of the highlight color. + */ + public RadioButtonBorder(Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + /* The superclass ButtonBorder substitutes null arguments + * with fallback colors. + */ + super(shadow, darkShadow, highlight, lightHighlight); + } + + + /** + * Paints the RadioButtonBorder around a given component. + * + * <p>The Sun implementation always seems to draw exactly + * the same border, irrespective of the state of the button. + * This is rather surprising, but GNU Classpath emulates the + * observable behavior. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + AbstractButton button = null; + ButtonModel bmodel = null; + boolean lowered = false; + boolean focused = false; + + if (c instanceof AbstractButton) + { + button = (AbstractButton) c; + bmodel = button.getModel(); + } + + if (bmodel != null) + { + lowered = button.isSelected() + || (/* mouse inside */ bmodel.isArmed() && bmodel.isPressed()); + focused = button.hasFocus() && button.isFocusPainted(); + } + + if (lowered) + BasicGraphicsUtils.drawLoweredBezel(g, x, y, width, height, + shadow, darkShadow, + highlight, lightHighlight); + else + BasicGraphicsUtils.drawBezel(g, x, y, width, height, + /* isPressed */ false, + /* isPefault */ focused, + shadow, darkShadow, + highlight, lightHighlight); + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + /* There is no obvious reason for overriding this method, but we + * try to have exactly the same API as the Sun reference + * implementation. + */ + return getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets(Component) + */ + public Insets getBorderInsets(Component c, Insets insets) + { + /* The exact amount has been determined using a test program + * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the + * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2]. + */ + if (insets == null) + return new Insets(2, 2, 2, 2); + + insets.left = insets.right = insets.top = insets.bottom = 2; + return insets; + } + } + + + /** + * A one-pixel thick border for rollover buttons, for example in + * tool bars. + * + * @since 1.4 + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class RolloverButtonBorder + extends ButtonBorder + { + /** + * Determined using the <code>serialver</code> tool + * of Sun JDK 1.4.1_01 on GNU/Linux 2.4.20 for x86. + */ + static final long serialVersionUID = 1976364864896996846L; + + + /** + * Constructs a new border for drawing a roll-over button + * in the Basic look and feel. + * + * @param shadow the shadow color. + * @param darkShadow a darker variant of the shadow color. + * @param highlight the highlight color. + * @param lightHighlight a brighter variant of the highlight color. + */ + public RolloverButtonBorder(Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + super(shadow, darkShadow, highlight, lightHighlight); + } + + + /** + * Paints the border around a rollover button. If <code>c</code> + * is not an {@link javax.swing.AbstractButton} whose model + * returns <code>true</code> for {@link + * javax.swing.ButtonModel#isRollover}, nothing gets painted at + * all. + * + * @param c the button whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + ButtonModel bmodel = null; + boolean drawPressed; + Color oldColor = g.getColor(); + int x2, y2; + + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + + /* Draw nothing if c is not a rollover button. */ + if ((bmodel == null) || !bmodel.isRollover()) + return; + + /* Draw nothing if the mouse is pressed, but outside the button. */ + if (bmodel.isPressed() && !bmodel.isArmed()) + return; + + drawPressed = bmodel.isSelected() || bmodel.isPressed(); + x2 = x + width - 1; + y2 = y + height - 1; + + try + { + g.setColor(drawPressed ? shadow : lightHighlight); + g.drawLine(x, y, x2 - 1, y); // top edge + g.drawLine(x, y + 1, x, y2 - 1); // left edge + + g.setColor(drawPressed ? lightHighlight : shadow); + g.drawLine(x, y2, x2, y2); // bottom edge + g.drawLine(x2, y, x2, y2 - 1); // right edge + } + finally + { + g.setColor(oldColor); + } + } + } + + + /** + * A border for JSplitPanes in the Basic look and feel. The divider + * in the middle of the JSplitPane has its own border class, of which + * an instance can be obtained with {@link #getSplitPaneDividerBorder()}. + * + * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" + * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> + * + * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" + * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> + * + * <p>In contrast to the other borders of the Basic look and feel, + * this class is not serializable. While this might be unintended, + * GNU Classpath follows the specification in order to be fully + * compatible with the Sun reference implementation. + * + * <p>In the Sun JDK, the bottom edge of the divider also gets + * painted if the orientation of the enclosed JSplitPane is + * <code>JSplitPane.VERTICAL_SPLIT</code> (at least in versions + * 1.3.1 and 1.4.1). GNU Classpath does not replicate this bug. A + * report has been filed with Sun (bug ID 4885629). + * + * <p>Note that the bottom left pixel of the border has a different + * color depending on the orientation of the enclosed JSplitPane. + * Although this is visually inconsistent, Classpath replicates the + * appearance of the Sun reference implementation. A bug report has + * been filed with Sun (review ID 188774). + * + * @see #getSplitPaneBorder() + * @see #getSplitPaneDividerBorder() + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class SplitPaneBorder + implements Border, UIResource + { + /** + * Indicates that the top edge shall be not be painted + * by {@link #paintRect(java.awt.Graphics, int, int, int, int, int)}. + */ + private static final int SUPPRESS_TOP = 1; + + + /** + * Indicates that the left edge shall be not be painted + * by {@link #paintRect(java.awt.Graphics, int, int, int, int, int)}. + */ + private static final int SUPPRESS_LEFT = 2; + + + /** + * Indicates that the bottom edge shall be not be painted + * by {@link #paintRect(java.awt.Graphics, int, int, int, int, int)}. + */ + private static final int SUPPRESS_BOTTOM = 4; + + + /** + * Indicates that the right edge shall be not be painted + * by {@link #paintRect(java.awt.Graphics, int, int, int, int, int)}. + */ + private static final int SUPPRESS_RIGHT = 8; + + + /** + * The color for drawing the bottom and right edges of the border. + */ + protected Color highlight; + + + /** + * The color for drawing the top and left edges of the border. + */ + protected Color shadow; + + + /** + * Constructs a new border for drawing a JSplitPane in the Basic + * look and feel. The divider in the middle of the JSplitPane has + * its own border class, <code>SplitPaneDividerBorder</code>. + * + * @param shadow the shadow color. + * @param highlight the highlight color. + */ + public SplitPaneBorder(Color highlight, Color shadow) + { + /* These colors usually come from the UIDefaults of the current + * look and feel. Use fallback values if the colors are not + * supplied. The API specification is silent about what + * behavior is expected for null colors, so users should not + * rely on this fallback (which is why it is not documented in + * the above Javadoc). + */ + this.shadow = (shadow != null) ? shadow : Color.black; + this.highlight = (highlight != null) ? highlight : Color.white; + } + + + /** + * Paints the border around a <code>JSplitPane</code>. + * + * <p><img src="doc-files/BasicBorders.SplitPaneBorder-1.png" width="520" + * height="200" alt="[A screen shot for JSplitPane.HORIZONTAL_SPLIT]" /> + * + * <p><img src="doc-files/BasicBorders.SplitPaneBorder-2.png" width="520" + * height="200" alt="[A screen shot for JSplitPane.VERTICAL_SPLIT]" /> + * + * @param c the <code>JSplitPane</code> whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + JSplitPane splitPane; + Component content; + + if (!(c instanceof JSplitPane)) + return; + + splitPane = (JSplitPane) c; + switch (splitPane.getOrientation()) + { + case JSplitPane.HORIZONTAL_SPLIT: + if ((content = splitPane.getLeftComponent()) != null) + paintRect(g, SUPPRESS_RIGHT, true, x, y, content.getBounds()); + if ((content = splitPane.getRightComponent()) != null) + paintRect(g, SUPPRESS_LEFT, true, x, y, content.getBounds()); + break; + + case JSplitPane.VERTICAL_SPLIT: + if ((content = splitPane.getTopComponent()) != null) + paintRect(g, SUPPRESS_BOTTOM, false, x, y, content.getBounds()); + if ((content = splitPane.getBottomComponent()) != null) + paintRect(g, SUPPRESS_TOP, false, x, y, content.getBounds()); + break; + } + } + + + /** + * Paints a border around a child of a <code>JSplitPane</code>, + * omitting some of the edges. + * + * @param g the graphics for painting. + * + * @param suppress a bit mask indicating the set of suppressed + * edges, for example <code>SUPPRESS_TOP | SUPPRESS_RIGHT</code>. + * + * @param x the x coordinate of the SplitPaneBorder. + * + * @param y the y coordinate of the SplitPaneBorder. + * + * @param shadeBottomLeftPixel <code>true</code> to paint the + * bottom left pixel in the shadow color, + * <code>false</code> for the highlight color. The Basic + * look and feel uses the highlight color for the bottom + * left pixel of the border of a JSplitPane whose + * orientation is VERTICAL_SPLIT, and the shadow color + * otherwise. While this might be a strange distinction, + * Classpath tries to look identical to the reference + * implementation. A bug report has been filed with Sun; + * its review ID is 188774. We currently replicate the + * Sun behavior. + * + * @param rect the bounds of the child of JSplitPane whose + * border is to be painted. + */ + private void paintRect(Graphics g, int suppress, + boolean shadeBottomLeftPixel, + int x, int y, + Rectangle rect) + { + if (rect == null) + return; + + /* On each edge, the border exceeds the enclosed child by one + * pixel. See the image "BasicBorders.SplitPaneBorder-1.png" in + * the directory "doc-files". + */ + x += rect.x - 1; + y += rect.y - 1; + int right = x + rect.width + 1; + int bottom = y + rect.height + 1; + + Color oldColor = g.getColor(); + try + { + g.setColor(shadow); + if ((suppress & SUPPRESS_TOP) == 0) + g.drawLine(x, y, right, y); + if ((suppress & SUPPRESS_LEFT) == 0) + g.drawLine(x, y, x, bottom); + else + g.drawLine(x, bottom, x, bottom); // one pixel + + g.setColor(highlight); + if ((suppress & SUPPRESS_BOTTOM) == 0) + g.drawLine(x + (shadeBottomLeftPixel ? 1 : 0), bottom, right, bottom); + else if (!shadeBottomLeftPixel) + g.drawLine(x, bottom, x, bottom); // one pixel + + if ((suppress & SUPPRESS_RIGHT) == 0) + g.drawLine(right, y, right, bottom); + } + finally + { + g.setColor(oldColor); + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured, usually + * an instance of {@link javax.swing.JSplitPane}. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(1, 1, 1, 1); + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * @return <code>false</code> because this border does not + * paint over the pixels where the divider joins + * the border. + */ + public boolean isBorderOpaque() + { + /* Strangely, the Sun implementation (tested with JDK 1.3.1 and + * 1.4.1_01) seems to always return true. It could be a bug, + * but without knowing the details of their implementation, it is + * hard to decide. + */ + return false; + } + } + + + /** + * A border for the divider inside a JSplitPane. + * + * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" + * width="520" height="200" alt="[A screen shot of this border]" /> + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static class SplitPaneDividerBorder + implements Border, UIResource, Serializable + { + /** + * The highlight color, which is drawn on the left or top edge + * depending on the orientation of the JSplitPanel. + */ + protected Color highlight; + + + /** + * The highlight color, which is drawn on the right or bottom edge + * depending on the orientation of the JSplitPanel. + */ + protected Color shadow; + + + /** + * Constructs a new border for drawing the divider of a JSplitPane + * in the Basic look and feel. The outer parts of the JSplitPane have + * their own border class, <code>SplitPaneBorder</code>. + * + * @param shadow the shadow color. + * @param highlight the highlight color. + */ + public SplitPaneDividerBorder(Color highlight, Color shadow) + { + this.highlight = (highlight != null) ? highlight : Color.white; + this.shadow = (shadow != null) ? shadow : Color.black; + } + + + /** + * Paints the border around the divider of a <code>JSplitPane</code>. + * + * <p><img src="doc-files/BasicBorders.SplitPaneDividerBorder-1.png" + * width="520" height="200" alt="[A picture that shows which pixels + * get painted in what color]" /> + * + * @param c the <code>JSplitPane</code> whose divider’s border + * is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + Color oldColor, dcol; + int x2, y2; + JSplitPane sp; + + sp = getSplitPane(c); + if (sp == null) + return; + + x2 = x + width - 1; + y2 = y + height - 1; + oldColor = g.getColor(); + dcol = c.getBackground(); + try + { + switch (sp.getOrientation()) + { + case JSplitPane.HORIZONTAL_SPLIT: + g.setColor(dcol); + g.drawLine(x + 1, y, x2 - 1, y); + g.drawLine(x + 1, y2, x2 - 1, y2); + g.setColor(sp.getLeftComponent() != null ? highlight : dcol); + g.drawLine(x, y, x, y2); + g.setColor(sp.getRightComponent() != null ? shadow : dcol); + g.drawLine(x2, y, x2, y2); + break; + + case JSplitPane.VERTICAL_SPLIT: + g.setColor(dcol); + g.drawLine(x, y + 1, x, y2 - 1); + g.drawLine(x2, y + 1, x2, y2 - 1); + g.setColor(sp.getTopComponent() != null ? highlight : dcol); + g.drawLine(x, y, x2, y); + g.setColor(sp.getBottomComponent() != null ? shadow : dcol); + g.drawLine(x, y2, x2, y2); + break; + } + } + finally + { + g.setColor(oldColor); + } + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured, usually + * an instance of {@link javax.swing.JSplitPane}. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(1, 1, 1, 1); + } + + + /** + * Determines whether this border fills every pixel in its area + * when painting. + * + * @return <code>true</code> if both highlight and shadow + * color are fully opaque. + */ + public boolean isBorderOpaque() + { + return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255); + } + + + /** + * Determines the JSplitPane whose divider is being painted. + * + * @param c an instance of BasicSplitPaneDivider. + * + * @return a <code>JSplitPane</code>, or <code>null</code> if + * <code>c</code> is not an instance of {@link + * javax.swing.plaf.basic.BasicSplitPaneDivider}. + */ + private JSplitPane getSplitPane(Component c) + { + if (c instanceof BasicSplitPaneDivider) + return (((BasicSplitPaneDivider) c).getBasicSplitPaneUI()) + .getSplitPane(); + else + return null; + } + } + + + /** + * A border for toggle buttons in the Basic look and feel. + * + * <p><img src="doc-files/BasicBorders.ToggleButtonBorder-1.png" + * width="270" height="135" alt="[A screen shot of this border]" /> + * + * <p>The Sun implementation always seems to draw exactly + * the same border, irrespective of the state of the button. + * This is rather surprising, but GNU Classpath emulates the + * observable behavior. + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + public static class ToggleButtonBorder + extends ButtonBorder + { + /** + * Determined using the <code>serialver</code> tool + * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5. + */ + static final long serialVersionUID = -3528666548001058394L; + + + /** + * Constructs a new border for drawing a JToggleButton in + * the Basic look and feel. + * + * @param shadow the shadow color. + * @param darkShadow a darker variant of the shadow color. + * @param highlight the highlight color. + * @param lightHighlight a brighter variant of the highlight color. + */ + public ToggleButtonBorder(Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + /* The superclass ButtonBorder substitutes null arguments + * with fallback colors. + */ + super(shadow, darkShadow, highlight, lightHighlight); + } + + + /** + * Paints the ToggleButtonBorder around a given component. + * + * <p>The Sun implementation always seems to draw exactly + * the same border, irrespective of the state of the button. + * This is rather surprising, but GNU Classpath emulates the + * observable behavior. + * + * @param c the component whose border is to be painted. + * @param g the graphics for painting. + * @param x the horizontal position for painting the border. + * @param y the vertical position for painting the border. + * @param width the width of the available area for painting the border. + * @param height the height of the available area for painting the border. + * + * @see javax.swing.plaf.basic.BasicGraphicsUtils#drawBezel + */ + public void paintBorder(Component c, Graphics g, + int x, int y, int width, int height) + { + /* The author of this code tried various variants for setting + * the state of the enclosed JToggleButton, but it seems that + * the drawn border is always identical. Weird, because this + * means that the user does not see whether the JToggleButton + * is selected or not. + */ + BasicGraphicsUtils.drawBezel(g, x, y, width, height, + /* pressed */ false, + /* default */ false, + shadow, darkShadow, + highlight, lightHighlight); + } + + + /** + * Measures the width of this border. + * + * @param c the component whose border is to be measured. + * + * @return an Insets object whose <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @see #getBorderInsets(java.awt.Component, java.awt.Insets) + */ + public Insets getBorderInsets(Component c) + { + /* There is no obvious reason for overriding this method, but we + * try to have exactly the same API as the Sun reference + * implementation. + */ + return getBorderInsets(c, null); + } + + + /** + * Measures the width of this border, storing the results into a + * pre-existing Insets object. + * + * @param insets an Insets object for holding the result values. + * After invoking this method, the <code>left</code>, + * <code>right</code>, <code>top</code> and + * <code>bottom</code> fields indicate the width of the + * border at the respective edge. + * + * @return the same object that was passed for <code>insets</code>. + * + * @see #getBorderInsets(Component) + */ + public Insets getBorderInsets(Component c, Insets insets) + { + /* The exact amount has been determined using a test program + * that was run on the Apple/Sun JDK 1.3.1 on MacOS X, and the + * Sun JDK 1.4.1_01 on GNU/Linux for x86. Both gave [2,2,2,2]. + */ + if (insets == null) + return new Insets(2, 2, 2, 2); + + insets.left = insets.right = insets.top = insets.bottom = 2; + return insets; + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java new file mode 100644 index 00000000000..5349f524049 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java @@ -0,0 +1,231 @@ +/* BasicButtonListener.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.event.ActionEvent; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.AbstractAction; +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +public class BasicButtonListener + implements MouseListener, MouseMotionListener, FocusListener, + ChangeListener, PropertyChangeListener +{ + public BasicButtonListener(AbstractButton b) + { + // Do nothing here. + } + + public void propertyChange(PropertyChangeEvent e) + { + } + + protected void checkOpacity(AbstractButton b) + { + } + + public void focusGained(FocusEvent e) + { + if (e.getSource() instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) e.getSource(); + if (button.isFocusPainted()) + button.repaint(); + } + } + + public void focusLost(FocusEvent e) + { + if (e.getSource() instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) e.getSource(); + if (button.isFocusPainted()) + button.repaint(); + } + } + + public void installKeyboardActions(JComponent c) + { + c.getActionMap().put("pressed", + new AbstractAction() + { + public void actionPerformed(ActionEvent e) + { + AbstractButton button = (AbstractButton) e.getSource(); + ButtonModel model = button.getModel(); + // It is important that these transitions happen in this order. + model.setArmed(true); + model.setPressed(true); + } + }); + + c.getActionMap().put("released", + new AbstractAction() + { + public void actionPerformed(ActionEvent e) + { + AbstractButton button = (AbstractButton) e.getSource(); + ButtonModel model = button.getModel(); + // It is important that these transitions happen in this order. + model.setPressed(false); + model.setArmed(false); + } + }); + } + + public void uninstallKeyboardActions(JComponent c) + { + c.getActionMap().put("pressed", null); + c.getActionMap().put("released", null); + } + + public void stateChanged(ChangeEvent e) + { + } + + public void mouseMoved(MouseEvent e) + { + } + + public void mouseDragged(MouseEvent e) + { + } + + public void mouseClicked(MouseEvent e) + { + } + + /** + * Accept a mouse press event and arm the button. + * + * @param e The mouse press event to accept + */ + public void mousePressed(MouseEvent e) + { + if (e.getSource() instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) e.getSource(); + ButtonModel model = button.getModel(); + if (e.getButton() == MouseEvent.BUTTON1) + { + // It is important that these transitions happen in this order. + model.setArmed(true); + model.setPressed(true); + } + } + } + + /** + * Accept a mouse release event and set the button's + * "pressed" property to <code>true</code>, if the model + * is armed. If the model is not armed, ignore the event. + * + * @param e The mouse release event to accept + */ + public void mouseReleased(MouseEvent e) + { + if (e.getSource() instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) e.getSource(); + ButtonModel model = button.getModel(); + if (e.getButton() == MouseEvent.BUTTON1) + { + // It is important that these transitions happen in this order. + model.setPressed(false); + model.setArmed(false); + } + } + } + + /** + * Accept a mouse enter event and set the button's "rollover" property to + * <code>true</code>, if the button's "rolloverEnabled" property is + * <code>true</code>. If the button is currently armed and the mouse + * button is not held down, this enter event will also disarm the model. + * + * @param e The mouse enter event to accept + */ + public void mouseEntered(MouseEvent e) + { + if (e.getSource() instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) e.getSource(); + ButtonModel model = button.getModel(); + if (button.isRolloverEnabled()) + model.setRollover(true); + + if (model.isPressed() + && (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0) + model.setArmed(true); + else + model.setArmed(false); + } + } + + /** + * Accept a mouse exit event and set the button's model's "rollover" + * property to <code>false</code>, if it's "rolloverEnabled" property is + * <code>true</code>. Also disarm the button. + * + * @param e The mouse exit event to accept + */ + public void mouseExited(MouseEvent e) + { + if (e.getSource() instanceof AbstractButton) + { + AbstractButton button = (AbstractButton) e.getSource(); + ButtonModel model = button.getModel(); + if (button.isRolloverEnabled()) + model.setRollover(false); + model.setArmed(false); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java new file mode 100644 index 00000000000..d893c5d0a1b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java @@ -0,0 +1,421 @@ +/* BasicButtonUI.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ButtonUI; +import javax.swing.plaf.ComponentUI; + +public class BasicButtonUI extends ButtonUI +{ + /** + * A constant used to pad out elements in the button's layout and + * preferred size calculations. + */ + protected int defaultTextIconGap = 4; + + /** + * A constant added to the defaultTextIconGap to adjust the text + * within this particular button. + */ + protected int defaultTextShiftOffset = 0; + + private int textShiftOffset; + + private Color focusColor; + + /** + * Factory method to create an instance of BasicButtonUI for a given + * {@link JComponent}, which should be an {@link AbstractButton}. + * + * @param c The component to create a UI got + * + * @return A new UI capable of drawing the component + */ + public static ComponentUI createUI(final JComponent c) + { + return new BasicButtonUI(); + } + + public int getDefaultTextIconGap(AbstractButton b) + { + return defaultTextIconGap; + } + + protected void clearTextShiftOffset() + { + textShiftOffset = 0; + } + + protected int getTextShiftOffset() + { + return textShiftOffset; + } + + protected void setTextShiftOffset() + { + textShiftOffset = defaultTextShiftOffset; + } + + /** + * Returns the prefix for the UI defaults property for this UI class. + * This is 'Button' for this class. + * + * @return the prefix for the UI defaults property + */ + protected String getPropertyPrefix() + { + return "Button"; + } + + protected void installDefaults(AbstractButton b) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + String prefix = getPropertyPrefix(); + focusColor = defaults.getColor(prefix + ".focus"); + b.setForeground(defaults.getColor(prefix + ".foreground")); + b.setBackground(defaults.getColor(prefix + ".background")); + b.setMargin(defaults.getInsets(prefix + ".margin")); + b.setBorder(defaults.getBorder(prefix + ".border")); + b.setIconTextGap(defaults.getInt(prefix + ".textIconGap")); + b.setInputMap(JComponent.WHEN_FOCUSED, + (InputMap) defaults.get(prefix + ".focusInputMap")); + b.setOpaque(true); + } + + protected void uninstallDefaults(AbstractButton b) + { + b.setForeground(null); + b.setBackground(null); + b.setBorder(null); + b.setIconTextGap(defaultTextIconGap); + b.setMargin(null); + } + + protected BasicButtonListener listener; + + protected BasicButtonListener createButtonListener(AbstractButton b) + { + return new BasicButtonListener(b); + } + + protected void installListeners(AbstractButton b) + { + listener = createButtonListener(b); + b.addChangeListener(listener); + b.addPropertyChangeListener(listener); + b.addFocusListener(listener); + b.addMouseListener(listener); + b.addMouseMotionListener(listener); + } + + protected void uninstallListeners(AbstractButton b) + { + b.removeChangeListener(listener); + b.removePropertyChangeListener(listener); + b.removeFocusListener(listener); + b.removeMouseListener(listener); + b.removeMouseMotionListener(listener); + } + + protected void installKeyboardActions(AbstractButton b) + { + listener.installKeyboardActions(b); + } + + protected void uninstallKeyboardActions(AbstractButton b) + { + listener.uninstallKeyboardActions(b); + } + + /** + * Install the BasicButtonUI as the UI for a particular component. + * This means registering all the UI's listeners with the component, + * and setting any properties of the button which are particular to + * this look and feel. + * + * @param c The component to install the UI into + */ + public void installUI(final JComponent c) + { + super.installUI(c); + if (c instanceof AbstractButton) + { + AbstractButton b = (AbstractButton) c; + installDefaults(b); + installListeners(b); + installKeyboardActions(b); + } + } + + /** + * Calculate the preferred size of this component, by delegating to + * {@link BasicGraphicsUtils#getPreferredButtonSize}. + * + * @param c The component to measure + * + * @return The preferred dimensions of the component + */ + public Dimension getPreferredSize(JComponent c) + { + AbstractButton b = (AbstractButton)c; + Dimension d = + BasicGraphicsUtils.getPreferredButtonSize + (b, defaultTextIconGap + defaultTextShiftOffset); + return d; + } + + private static Icon currentIcon(AbstractButton b) + { + Icon i = b.getIcon(); + ButtonModel model = b.getModel(); + + if (model.isPressed() && b.getPressedIcon() != null) + i = b.getPressedIcon(); + + else if (model.isRollover()) + { + if (b.isSelected() && b.getRolloverSelectedIcon() != null) + i = b.getRolloverSelectedIcon(); + else if (b.getRolloverIcon() != null) + i = b.getRolloverIcon(); + } + + else if (b.isSelected()) + { + if (b.isEnabled() && b.getSelectedIcon() != null) + i = b.getSelectedIcon(); + else if (b.getDisabledSelectedIcon() != null) + i = b.getDisabledSelectedIcon(); + } + + else if (! b.isEnabled() && b.getDisabledIcon() != null) + i = b.getDisabledIcon(); + + return i; + } + + /** + * Paint the component, which is an {@link AbstractButton}, according to + * its current state. + * + * @param g The graphics context to paint with + * @param c The component to paint the state of + */ + public void paint(Graphics g, JComponent c) + { + AbstractButton b = (AbstractButton) c; + + Rectangle tr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle vr = new Rectangle(); + + Font f = c.getFont(); + + g.setFont(f); + + SwingUtilities.calculateInnerArea(b, vr); + String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f), + b.getText(), + currentIcon(b), + b.getVerticalAlignment(), + b.getHorizontalAlignment(), + b.getVerticalTextPosition(), + b.getHorizontalTextPosition(), + vr, ir, tr, + b.getIconTextGap() + + defaultTextShiftOffset); + + if ((b.getModel().isArmed() && b.getModel().isPressed()) + || b.isSelected()) + paintButtonPressed(g, b); + else + paintButtonNormal(g, vr, c); + + paintIcon(g, c, ir); + if (text != null) + paintText(g, b, tr, text); + paintFocus(g, b, vr, tr, ir); + } + + /** + * Paint any focus decoration this {@link JComponent} might have. The + * component, which in this case will be an {@link AbstractButton}, + * should only have focus decoration painted if it has the focus, and its + * "focusPainted" property is <code>true</code>. + * + * @param g Graphics context to paint with + * @param b Button to paint the focus of + * @param vr Visible rectangle, the area in which to paint + * @param tr Text rectangle, contained in visible rectangle + * @param ir Icon rectangle, contained in visible rectangle + * + * @see AbstractButton#isFocusPainted() + * @see JComponent#hasFocus() + */ + protected void paintFocus(Graphics g, AbstractButton b, Rectangle vr, + Rectangle tr, Rectangle ir) + { + if (b.hasFocus() && b.isFocusPainted()) + { + Color saved_color = g.getColor(); + g.setColor(focusColor); + Rectangle focusRect = ir.union(tr); + g.drawRect(focusRect.x, focusRect.y, + focusRect.width, focusRect.height); + g.setColor(saved_color); + } + } + + /** + * Paint the icon for this component. Depending on the state of the + * component and the availability of the button's various icon + * properties, this might mean painting one of several different icons. + * + * @param g Graphics context to paint with + * @param c Component to paint the icon of + * @param iconRect Rectangle in which the icon should be painted + */ + protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect) + { + AbstractButton b = (AbstractButton) c; + Icon i = currentIcon(b); + + if (i != null) + i.paintIcon(c, g, iconRect.x, iconRect.y); + } + + /** + * Paints the background area of an {@link AbstractButton} in the pressed + * state. This means filling the supplied area with the {@link + * pressedBackgroundColor}. + * + * @param g The graphics context to paint with + * @param b The button to paint the state of + */ + protected void paintButtonPressed(Graphics g, AbstractButton b) + { + if (b.isContentAreaFilled()) + { + Rectangle area = new Rectangle(); + SwingUtilities.calculateInnerArea(b, area); + g.setColor(b.getBackground().darker()); + g.fillRect(area.x, area.y, area.width, area.height); + } + } + + /** + * Paints the background area of an {@link AbstractButton} in the normal, + * non-pressed state. This means filling the supplied area with the + * {@link normalBackgroundColor}. + * + * @param g The graphics context to paint with + * @param area The area in which to paint + * @param b The component to paint the state of + */ + private void paintButtonNormal(Graphics g, Rectangle area, JComponent b) + { + if (((AbstractButton)b).isContentAreaFilled() && b.isOpaque()) + { + g.setColor(b.getBackground()); + g.fillRect(area.x, area.y, area.width, area.height); + } + } + + /** + * Paints the "text" property of an {@link AbstractButton}, using the + * {@link textColor} color. + * + * @param g The graphics context to paint with + * @param c The component to paint the state of + * @param textRect The area in which to paint the text + * @param text The text to paint + */ + protected void paintText(Graphics g, JComponent c, Rectangle textRect, + String text) + { + paintText(g, (AbstractButton) c, textRect, text); + } + + /** + * Paints the "text" property of an {@link AbstractButton}, using the + * {@link textColor} color. + * + * @param g The graphics context to paint with + * @param b The button to paint the state of + * @param textRect The area in which to paint the text + * @param text The text to paint + * + * @since 1.4 + */ + protected void paintText(Graphics g, AbstractButton b, Rectangle textRect, + String text) + { + Font f = b.getFont(); + g.setFont(f); + FontMetrics fm = g.getFontMetrics(f); + + if (b.isEnabled()) + { + g.setColor(b.getForeground()); + g.drawString(text, textRect.x, textRect.y + fm.getAscent()); + } + else + { + g.setColor(b.getBackground().brighter()); + g.drawString(text, textRect.x, textRect.y + fm.getAscent()); + g.setColor(b.getBackground().darker()); + g.drawString(text, textRect.x + 1, textRect.y + fm.getAscent() + 1); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java new file mode 100644 index 00000000000..da11898bf0b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java @@ -0,0 +1,104 @@ +/* BasicCheckBoxMenuItemUI.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.event.MouseEvent; + +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; + +/** + * DOCUMENT ME! + */ +public class BasicCheckBoxMenuItemUI extends BasicMenuItemUI +{ + /** + * Factory method to create a BasicCheckBoxMenuItemUI for the given {@link + * JComponent}, which should be a JCheckBoxMenuItem + * + * @param c The {@link JComponent} a UI is being created for. + * + * @return A BasicCheckBoxMenuItemUI for the {@link JComponent}. + */ + public static ComponentUI createUI(final JComponent c) + { + return new BasicCheckBoxMenuItemUI(); + } + + /** + * DOCUMENT ME! + * + * @return $returnType$ DOCUMENT ME! + */ + protected String getPropertyPrefix() + { + return null; + } + + /** + * This method installs the defaults that are defined in the Basic look and + * feel for this JRadioButtonMenuItem + */ + protected void installDefaults() + { + super.installDefaults(); + + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + checkIcon = defaults.getIcon("CheckBoxMenuItem.checkIcon"); + } + + /** + * DOCUMENT ME! + * + * @param item DOCUMENT ME! + * @param e DOCUMENT ME! + * @param path DOCUMENT ME! + * @param manager DOCUMENT ME! + */ + public void processMouseEvent(JMenuItem item, MouseEvent e, + MenuElement[] path, + MenuSelectionManager manager) + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java new file mode 100644 index 00000000000..e3167327c3a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java @@ -0,0 +1,73 @@ +/* BasicCheckBoxUI.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; + +public class BasicCheckBoxUI extends BasicRadioButtonUI +{ + + public static ComponentUI createUI(final JComponent c) { + return new BasicCheckBoxUI(); + } + + public Icon getDefaultIcon() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + return defaults.getIcon("CheckBox.icon"); + } + + public void installUI(final JComponent c) { + super.installUI(c); + } + + // Overridden to change method access. + public String getPropertyPrefix() + { + return super.getPropertyPrefix(); + } +} + + + + diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java new file mode 100644 index 00000000000..4e6d3815453 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java @@ -0,0 +1,339 @@ +/* BasicColorChooserUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JColorChooser; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.colorchooser.AbstractColorChooserPanel; +import javax.swing.colorchooser.ColorChooserComponentFactory; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ColorChooserUI; +import javax.swing.plaf.ComponentUI; + +/** + * This is the UI Class for the JColorChooser in the Basic Look and Feel. + */ +public class BasicColorChooserUI extends ColorChooserUI +{ + /** + * This helper class handles property changes from the JColorChooser. + */ + public class PropertyHandler implements PropertyChangeListener + { + /** + * This method is called when any of the properties of the JColorChooser + * change. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName() == JColorChooser.CHOOSER_PANELS_PROPERTY) + makeTabs(chooser.getChooserPanels()); + else if (e.getPropertyName() == JColorChooser.PREVIEW_PANEL_PROPERTY) + updatePreviewPanel(chooser.getPreviewPanel()); + else if (e.getPropertyName() == JColorChooser.SELECTION_MODEL_PROPERTY) + ((AbstractColorChooserPanel) pane.getSelectedComponent()) + .updateChooser(); + + chooser.repaint(); + } + } + + /** + * This is a helper class that listens to the Model of the JColorChooser for + * color change events so it can update the preview panel. + */ + private class PreviewListener implements ChangeListener + { + /** + * This method is called whenever the JColorChooser's color changes. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + if (pane != null) + { + AbstractColorChooserPanel panel = (AbstractColorChooserPanel) pane + .getSelectedComponent(); + if (panel != null) + panel.updateChooser(); + } + chooser.repaint(); + } + } + + /** + * This helper class listens to the JTabbedPane that is used for tab + * changes. + */ + private class TabPaneListener implements ChangeListener + { + /** + * This method is called whenever a different tab is selected in the + * JTabbedPane. + * + * @param e The ChangeEvent. + */ + public void stateChanged(ChangeEvent e) + { + // Need to do this because we don't update all the tabs when they're not + // visible, so they are not informed of new colors when they're hidden. + AbstractColorChooserPanel comp = (AbstractColorChooserPanel) pane + .getSelectedComponent(); + comp.updateChooser(); + } + } + + /** An array of default choosers to use in the JColorChooser. */ + protected AbstractColorChooserPanel[] defaultChoosers; + + /** The listener for the preview panel. */ + protected ChangeListener previewListener; + + /** The PropertyChangeListener for the JColorChooser. */ + protected PropertyChangeListener propertyChangeListener; + + /** + * The JColorChooser. + * This is package-private to avoid an accessor method. + */ + JColorChooser chooser; + + /** The JTabbedPane that is used. */ + JTabbedPane pane; + + /** The Container that holds the preview panel. */ + private Container prevContainer; + + /** + * Creates a new BasicColorChooserUI object. + */ + public BasicColorChooserUI() + { + super(); + } + + /** + * This method creates a new UI Component for the given JComponent. + * + * @param c The JComponent to create an UI for. + * + * @return A new BasicColorChooserUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicColorChooserUI(); + } + + /** + * This method creates the default chooser panels for the JColorChooser. + * + * @return The default chooser panels. + */ + protected AbstractColorChooserPanel[] createDefaultChoosers() + { + return ColorChooserComponentFactory.getDefaultChooserPanels(); + } + + /** + * This method installs the UI Component for the given JComponent. + * + * @param c The JComponent to install this UI for. + */ + public void installUI(JComponent c) + { + if (c instanceof JColorChooser) + { + chooser = (JColorChooser) c; + chooser.setLayout(new BorderLayout()); + + // Do this first, so we avoid doing work for property change events. + defaultChoosers = createDefaultChoosers(); + chooser.setChooserPanels(defaultChoosers); + pane = new JTabbedPane(); + + pane.addChangeListener(new ChangeListener() + { + public void stateChanged(ChangeEvent e) + { + pane.repaint(); + } + }); + + makeTabs(defaultChoosers); + + chooser.add(pane, BorderLayout.NORTH); + + installPreviewPanel(); + + installDefaults(); + installListeners(); + } + } + + /** + * This method adds tabs to the JTabbedPane for the chooserPanels defined in + * the JColorChooser. + * This is package-private to avoid an accessor method. + * + * @param panels The Panels that need tabs to be made for them. + */ + void makeTabs(AbstractColorChooserPanel[] panels) + { + pane.removeAll(); + for (int i = 0; i < panels.length; i++) + pane.addTab(panels[i].getDisplayName(), panels[i].getSmallDisplayIcon(), + panels[i]); + } + + /** + * This method uninstalls this UI for the given JComponent. + * + * @param c The JComponent that will have this UI removed. + */ + public void uninstallUI(JComponent c) + { + uninstallListeners(); + uninstallDefaults(); + + pane = null; + chooser = null; + } + + /** + * This method installs the preview panel for the JColorChooser. + */ + protected void installPreviewPanel() + { + updatePreviewPanel(ColorChooserComponentFactory.getPreviewPanel()); + } + + /** + * This is a helper method that swaps the existing preview panel with the + * given panel. + * This is package-private to avoid an accessor method. + * + * @param preview The new preview panel. + */ + void updatePreviewPanel(JComponent preview) + { + if (prevContainer == null) + { + prevContainer = new JPanel(); + prevContainer.setLayout(new BorderLayout()); + chooser.add(prevContainer, BorderLayout.CENTER); + } + prevContainer.removeAll(); + prevContainer.add(preview, BorderLayout.CENTER); + } + + /** + * This method installs the default properties given by the Basic Look and + * Feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + chooser.setFont(defaults.getFont("ColorChooser.font")); + chooser.setForeground(defaults.getColor("ColorChooser.foreground")); + chooser.setBackground(defaults.getColor("ColorChooser.background")); + } + + /** + * This method uninstalls the default properties given by the Basic Look and + * Feel. + */ + protected void uninstallDefaults() + { + chooser.setBackground(null); + chooser.setForeground(null); + chooser.setFont(null); + } + + /** + * This method installs any listeners required for this UI to function. + */ + protected void installListeners() + { + propertyChangeListener = createPropertyChangeListener(); + previewListener = new PreviewListener(); + + chooser.addPropertyChangeListener(propertyChangeListener); + chooser.getSelectionModel().addChangeListener(previewListener); + + pane.addChangeListener(new TabPaneListener()); + } + + /** + * This method creates the PropertyChangeListener used for listening to the + * JColorChooser. + * + * @return A PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyHandler(); + } + + /** + * This method uninstalls any listeners that were previously installed by + * the UI. + */ + protected void uninstallListeners() + { + chooser.removePropertyChangeListener(propertyChangeListener); + chooser.getSelectionModel().removeChangeListener(previewListener); + + previewListener = null; + propertyChangeListener = null; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java new file mode 100644 index 00000000000..04296df0a85 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java @@ -0,0 +1,170 @@ +/* BasicComboBoxEditor.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Component; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +import javax.swing.ComboBoxEditor; +import javax.swing.JTextField; +import javax.swing.border.EmptyBorder; + +/** + * This is a component that is responsible for displaying/editting selected + * item in comboBox. By default, the JTextField is returned as + * BasicComboBoxEditor. + * + * @author Olga Rodimina + */ +public class BasicComboBoxEditor extends Object implements ComboBoxEditor, + FocusListener +{ + protected JTextField editor; + + /** + * Creates a new BasicComboBoxEditor object. + */ + public BasicComboBoxEditor() + { + editor = new JTextField(); + editor.setBorder(new EmptyBorder(1, 1, 1, 1)); + } + + /** + * This method returns textfield that will be used by the combo box to + * display/edit currently selected item in the combo box. + * + * @return textfield that will be used by the combo box to display/edit + * currently selected item + */ + public Component getEditorComponent() + { + return editor; + } + + /** + * Sets item that should be edited when any editing operation is performed + * by the user. The value is always equal to the currently selected value + * in the combo box. Thus whenever a different value is selected from the + * combo box list then this method should be called to change editing + * item to the new selected item. + * + * @param item item that is currently selected in the combo box + */ + public void setItem(Object item) + { + editor.setText(item.toString()); + } + + /** + * This method returns item that is currently editable. + * + * @return item in the combo box that is currently editable + */ + public Object getItem() + { + return editor.getText(); + } + + public void selectAll() + { + editor.selectAll(); + } + + /** + * This method is called when textfield gains focus. This will enable + * editing of the selected item. + * + * @param e the FocusEvent describing change in focus. + */ + public void focusGained(FocusEvent e) + { + // FIXME: Need to implement + } + + /** + * This method is called when textfield loses focus. If during this time any + * editting operation was performed by the user, then it will be cancelled + * and selected item will not be changed. + * + * @param e the FocusEvent describing change in focus + */ + public void focusLost(FocusEvent e) + { + // FIXME: Need to implement + } + + /** + * This method adds actionListener to the editor. If the user will edit + * currently selected item in the textfield and pressEnter, then action + * will be performed. The actionPerformed of this ActionListener should + * change the selected item of the comboBox to the newly editted selected + * item. + * + * @param l the ActionListener responsible for changing selected item of the + * combo box when it is editted by the user. + */ + public void addActionListener(ActionListener l) + { + // FIXME: Need to implement + } + + /** + * This method removes actionListener from the textfield. + * + * @param l the ActionListener to remove from the textfield. + */ + public void removeActionListener(ActionListener l) + { + // FIXME: Need to implement + } + + public static class UIResource extends BasicComboBoxEditor + implements javax.swing.plaf.UIResource + { + /** + * Creates a new UIResource object. + */ + public UIResource() + { + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java new file mode 100644 index 00000000000..e4fbb8352a9 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java @@ -0,0 +1,142 @@ +/* BasicComboBoxRenderer.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Component; +import java.awt.Dimension; +import java.io.Serializable; + +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.SwingConstants; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; + +/** + * This class is renderer for the combo box. + * + * @author Olga Rodimina + */ +public class BasicComboBoxRenderer extends JLabel implements ListCellRenderer, + Serializable +{ + /** + * This border is used whenever renderer doesn't have a focus. + */ + protected static Border noFocusBorder = new EmptyBorder(0, 0, 0, 0); + + /** + * Creates a new BasicComboBoxRenderer object. + */ + public BasicComboBoxRenderer() + { + setHorizontalAlignment(SwingConstants.LEFT); + } + + /** + * Returns preferredSize of the renderer + * + * @return preferredSize of the renderer + */ + public Dimension getPreferredSize() + { + return super.getPreferredSize(); + } + + /** + * getListCellRendererComponent + * + * @param list List of items for which to the background and foreground + * colors + * @param value object that should be rendered in the cell + * @param index index of the cell in the list of items. + * @param isSelected draw cell highlighted if isSelected is true + * @param cellHasFocus draw focus rectangle around cell if the cell has + * focus + * + * @return Component that will be used to draw the desired cell. + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, + boolean cellHasFocus) + { + String s = value.toString(); + setText(s); + setOpaque(true); + + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + if (isSelected) + { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } + else + { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + setEnabled(list.isEnabled()); + setFont(list.getFont()); + + // Use focusCellHighlightBorder when renderer has focus and + // noFocusBorder otherwise + if (cellHasFocus) + setBorder(UIManager.getBorder("List.focusCellHighlightBorder")); + else + setBorder(noFocusBorder); + + return this; + } + + public static class UIResource extends BasicComboBoxRenderer + implements javax.swing.plaf.UIResource + { + /** + * Creates a new UIResource object. + */ + public UIResource() + { + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java new file mode 100644 index 00000000000..68e18a6ab01 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -0,0 +1,1243 @@ +/* BasicComboBoxUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.accessibility.Accessible; +import javax.swing.CellRendererPane; +import javax.swing.ComboBoxEditor; +import javax.swing.ComboBoxModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.plaf.ComboBoxUI; +import javax.swing.plaf.ComponentUI; + +/** + * UI Delegate for JComboBox + * + * @author Olga Rodimina + * @author Robert Schuster + */ +public class BasicComboBoxUI extends ComboBoxUI +{ + /** + * This arrow button that is displayed in the rigth side of JComboBox. This + * button is used to hide and show combo box's list of items + */ + protected JButton arrowButton; + + /** + * The combo box for which this UI delegate is for + */ + protected JComboBox comboBox; + + /** + * Component that is responsible for displaying/editting selected item of + * the combo box. By default JTextField is used as an editor for the + * JComboBox + */ + protected Component editor; + + /** + * Listener listening to focus events occuring in the JComboBox + */ + protected FocusListener focusListener; + + /** + * tells whether JComboBox currently has focus + */ + protected boolean hasFocus; + + /** + * Listener listening to item events fired by the JComboBox + */ + protected ItemListener itemListener; + + /** + * KeyListener listening to key events that occur while JComboBox has focus + */ + protected KeyListener keyListener; + + /** + * MouseListener listening to mouse events occuring in the combo box + */ + private MouseListener mouseListener; + + /** + * List used when rendering selected item of the combo box. The selection + * and foreground colors for combo box renderer are configured from this + * list + */ + protected JList listBox; + + /** + * ListDataListener listening to JComboBox model + */ + protected ListDataListener listDataListener; + + /** + * Popup list containing combo box's menu items + */ + protected ComboPopup popup; + protected KeyListener popupKeyListener; + protected MouseListener popupMouseListener; + protected MouseMotionListener popupMouseMotionListener; + + /** + * Listener listening to changes in the bound properties of JComboBox + */ + protected PropertyChangeListener propertyChangeListener; + + /** + * Colors that are used to render selected item in the combo box. + */ + private Color shadow; + private Color darkShadow; + private Color highlight; + private Color lightHighlight; + + /* Size of the largest item in the comboBox + * This is package-private to avoid an accessor method. + */ + Dimension largestItemSize; + + // It seems that JComboBox doesn't have a border set explicitely. So we just + // paint the border everytime combo box is displayed. + + /* border insets for this JComboBox + * This is package-private to avoid an accessor method. */ + static final Insets borderInsets = new Insets(2, 2, 2, 2); + + // Width of the arrow button + // This is package-private to avoid an accessor method. + // FIXME: has wrong name for a constant. + static final int arrowButtonWidth = 15; + + // FIXME: This fields aren't used anywhere at this moment. + protected Dimension cachedMinimumSize; + protected CellRendererPane currentValuePane; + protected boolean isMinimumSizeDirty; + + /** + * Creates a new BasicComboBoxUI object. + */ + public BasicComboBoxUI() + { + } + + /** + * Factory method to create a BasicComboBoxUI for the given {@link + * JComponent}, which should be a {@link JComboBox}. + * + * @param c The {@link JComponent} a UI is being created for. + * + * @return A BasicComboBoxUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicComboBoxUI(); + } + + /** + * This method installs the UI for the given JComponent. + * + * @param c The JComponent to install a UI for. + */ + public void installUI(JComponent c) + { + super.installUI(c); + + if (c instanceof JComboBox) + { + comboBox = (JComboBox) c; + comboBox.setOpaque(true); + comboBox.setLayout(createLayoutManager()); + installDefaults(); + installComponents(); + installListeners(); + installKeyboardActions(); + } + } + + /** + * This method uninstalls the UI. + * + * @param c The JComponent that is having this UI removed. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallComponents(); + uninstallDefaults(); + comboBox = null; + } + + /** + * This method installs the defaults that are defined in the Basic look and + * feel for this {@link JComboBox}. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + comboBox.setBackground(defaults.getColor("ComboBox.background")); + comboBox.setFont(defaults.getFont("ComboBox.font")); + comboBox.setForeground(defaults.getColor("ComboBox.foreground")); + + // Set default color that should be used to to render selected item + // of the combo box. + shadow = defaults.getColor("Button.shadow"); + darkShadow = defaults.getColor("Button.darkShadow"); + lightHighlight = defaults.getColor("Button.light"); + highlight = defaults.getColor("Button.highlight"); + } + + /** + * This method creates and installs the listeners for this UI. + */ + protected void installListeners() + { + // install combo box's listeners + propertyChangeListener = createPropertyChangeListener(); + comboBox.addPropertyChangeListener(propertyChangeListener); + + focusListener = createFocusListener(); + comboBox.addFocusListener(focusListener); + + itemListener = createItemListener(); + comboBox.addItemListener(itemListener); + + keyListener = createKeyListener(); + comboBox.addKeyListener(keyListener); + + mouseListener = createMouseListener(); + comboBox.addMouseListener(mouseListener); + + // install listeners that listen to combo box model + listDataListener = createListDataListener(); + comboBox.getModel().addListDataListener(listDataListener); + + configureArrowButton(); + } + + /** + * This method uninstalls the defaults and sets any objects created during + * install to null + */ + protected void uninstallDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + comboBox.setBackground(null); + comboBox.setFont(null); + comboBox.setForeground(null); + + shadow = null; + darkShadow = null; + lightHighlight = null; + highlight = null; + } + + /** + * Detaches all the listeners we attached in {@link #installListeners}. + */ + protected void uninstallListeners() + { + comboBox.removePropertyChangeListener(propertyChangeListener); + propertyChangeListener = null; + + comboBox.removeFocusListener(focusListener); + focusListener = null; + + comboBox.removeItemListener(itemListener); + itemListener = null; + + comboBox.removeKeyListener(keyListener); + keyListener = null; + + comboBox.removeMouseListener(mouseListener); + mouseListener = null; + + comboBox.getModel().removeListDataListener(listDataListener); + listDataListener = null; + + unconfigureArrowButton(); + } + + /** + * This method creates popup that will contain list of combo box's items + * + * @return popup containing list of combo box's items + */ + protected ComboPopup createPopup() + { + return new BasicComboPopup(comboBox); + } + + /** + * Creates KeyListener to listen to key events. + * + * @return KeyListener that listens to key events. + */ + protected KeyListener createKeyListener() + { + return new KeyHandler(); + } + + /** + * This method create MouseListener that will listen to mouse event occuring + * in combo box. + * + * @return the MouseListener + */ + private MouseListener createMouseListener() + { + return new MouseHandler(); + } + + /** + * This method create FocusListener that will listen to changes in this + * JComboBox's focus. + * + * @return theFocusListener + */ + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + + /** + * This method create ListDataListener to listen to ComboBox's data model + * + * @return ListDataListener + */ + protected ListDataListener createListDataListener() + { + return new ListDataHandler(); + } + + /** + * This method creates ItemListener that will listen to to the changes in + * the JComboBox's selection. + * + * @return the ItemListener + */ + protected ItemListener createItemListener() + { + return new ItemHandler(); + } + + /** + * This method creates PropertyChangeListener to listen to the changes in + * the JComboBox's bound properties. + * + * @return the PropertyChangeListener + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * This method returns layout manager for the combo box. + * + * @return layout manager for the combo box + */ + protected LayoutManager createLayoutManager() + { + return new ComboBoxLayoutManager(); + } + + /** + * This method creates component that will be responsible for rendering the + * selected component in the combo box. + * + * @return render for the combo box + */ + protected ListCellRenderer createRenderer() + { + return new BasicComboBoxRenderer(); + } + + /** + * Creates component that will be responsible for displaying/editting + * selected item in the combo box. This editor is used only when combo box + * is editable. + * + * @return component that will be responsible for displaying/editting + * selected item in the combo box. + */ + protected ComboBoxEditor createEditor() + { + return new BasicComboBoxEditor(); + } + + /** + * This method installs components for this JComboBox. ArrowButton, main + * part of combo box (upper part) and popup list of items are created and + * configured here. + */ + protected void installComponents() + { + // create and install arrow button + arrowButton = createArrowButton(); + + comboBox.add(arrowButton); + + // Set list that will be used by BasicComboBoxRender + // in order to determine the right colors when rendering + listBox = new JList(); + + Color background = arrowButton.getBackground(); + listBox.setBackground(background); + listBox.setSelectionBackground(background.darker()); + + Color foreground = arrowButton.getForeground(); + listBox.setForeground(foreground); + listBox.setSelectionForeground(foreground); + + // set editor and renderer for the combo box. Editor is used + // only if combo box becomes editable, otherwise renderer is used + // to paint the selected item; combobox is not editable by default. + comboBox.setRenderer(createRenderer()); + + comboBox.setEditor(createEditor()); + editor = comboBox.getEditor().getEditorComponent(); + + // create drop down list of items + popup = createPopup(); + + comboBox.revalidate(); + } + + /** + * This method uninstalls components from this JComboBox + */ + protected void uninstallComponents() + { + // uninstall arrow button + unconfigureArrowButton(); + comboBox.remove(arrowButton); + arrowButton = null; + + listBox = null; + popup = null; + + comboBox.setRenderer(null); + + comboBox.setEditor(null); + editor = null; + } + + /** + * This method adds editor to the combo box + */ + public void addEditor() + { + comboBox.add(editor); + } + + /** + * This method removes editor from the combo box + */ + public void removeEditor() + { + comboBox.remove(editor); + } + + /** + * This method configures editor for this combo box. + */ + protected void configureEditor() + { + // FIXME: Need to implement. Set font and add listeners. + } + + /** + * This method removes all the listeners for the editor. + */ + protected void unconfigureEditor() + { + // FIXME: Need to implement + } + + /** + * This method adds listeners to the arrow button part of the combo box. + */ + public void configureArrowButton() + { + arrowButton.addMouseListener(mouseListener); + } + + /** + * This method removes listeners from the arrow button part of the combo + * box. + */ + public void unconfigureArrowButton() + { + arrowButton.removeMouseListener(mouseListener); + } + + /** + * This method create arrow button for this JComboBox. Arrow button is + * responsible for displaying / hiding drop down list of items when it is + * clicked. + * + * @return JButton arrow button for this JComboBox. + */ + protected JButton createArrowButton() + { + return new BasicArrowButton(BasicArrowButton.SOUTH); + } + + /** + * This method checks if popup part of the combo box is visible on the + * screen + * + * @param c The JComboBox to check + * + * @return true if popup part of the JComboBox is visible and false + * otherwise. + */ + public boolean isPopupVisible(JComboBox c) + { + return popup.isVisible(); + } + + /** + * Displays/Hides JComboBox's list of items on the screen. + * + * @param c The combo box, for which list of items should be + * displayed/hidden + * @param v true if show popup part of the jcomboBox and false to hide. + */ + public void setPopupVisible(JComboBox c, boolean v) + { + if (v) + popup.show(); + else + popup.hide(); + } + + /** + * JComboBox is focus traversable if it is editable and not otherwise. + * + * @param c combo box for which to check whether it is focus traversable + * + * @return true if focus tranversable and false otherwise + */ + public boolean isFocusTraversable(JComboBox c) + { + if (comboBox.isEditable()) + return true; + + return false; + } + + /** + * Paints given menu item using specified graphics context + * + * @param g The graphics context used to paint this combo box + * @param c comboBox which needs to be painted. + */ + public void paint(Graphics g, JComponent c) + { + if (c instanceof JComboBox) + { + JComboBox cb = (JComboBox) c; + + paintBorder(g, comboBox.getBounds(), hasFocus); + + Rectangle rect = rectangleForCurrentValue(); + paintCurrentValueBackground(g, rect, hasFocus); + paintCurrentValue(g, rect, hasFocus); + } + } + + private void paintBorder(Graphics g, Rectangle bounds, boolean hasFocus) + { + int x = 0; + int y = 0; + int width = bounds.width; + int height = bounds.height; + + Color oldColor = g.getColor(); + + if (! arrowButton.getModel().isPressed()) + BasicGraphicsUtils.drawEtchedRect(g, x, y, width, height, Color.gray, + Color.white, Color.gray, Color.white); + else + { + g.setColor(darkShadow); + g.drawRect(x, y, width, height); + g.setColor(shadow); + g.drawRect(x + 1, y + 1, width - 3, height - 3); + } + g.setColor(oldColor); + } + + /** + * Returns preferred size for the given menu item. + * + * @param c comboBox for which to get preferred size + * + * @return $Dimension$ preferred size for the given combo box + */ + public Dimension getPreferredSize(JComponent c) + { + // return null to indicate that combo box's layout will determin its + // preferred size + return null; + } + + /** + * This method returns the minimum size for this {@link JComboBox} for this + * look and feel. + * + * @param c The {@link JComponent} to find the minimum size for. + * + * @return The dimensions of the minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return null; + } + + /** + * This method returns the maximum size for this {@link JComboBox} for this + * look and feel. + * + * @param c The {@link JComponent} to find the maximum size for + * + * @return The dimensions of the minimum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return null; + } + + public int getAccessibleChildrenCount(JComponent c) + { + // FIXME: Need to implement + return 0; + } + + public Accessible getAccessibleChild(JComponent c, int i) + { + // FIXME: Need to implement + return null; + } + + /** + * Returns true if the specified key is a navigation key and false otherwise + * + * @param keyCode a key for which to check whether it is navigation key or + * not. + * + * @return true if the specified key is a navigation key and false otherwis + */ + protected boolean isNavigationKey(int keyCode) + { + return false; + } + + /** + * This method selects next possible item relative to the current selection + * to be next selected item in the combo box. + */ + protected void selectNextPossibleValue() + { + int index = comboBox.getSelectedIndex(); + if (index != comboBox.getItemCount() - 1) + comboBox.setSelectedIndex(index + 1); + } + + /** + * This method selects previous item relative to current selection to be + * next selected item. + */ + protected void selectPreviousPossibleValue() + { + int index = comboBox.getSelectedIndex(); + if (index != 0) + comboBox.setSelectedIndex(index - 1); + } + + /** + * This method displays combo box popup if the popup is not currently shown + * on the screen and hides it if it is currently shown + */ + protected void toggleOpenClose() + { + setPopupVisible(comboBox, ! isPopupVisible(comboBox)); + } + + /** + * This method returns bounds in which comboBox's selected Item will be + * displayed + * + * @return rectangle bounds in which comboBox's selected Item will be + * displayed + */ + protected Rectangle rectangleForCurrentValue() + { + Rectangle cbBounds = comboBox.getBounds(); + + // Subtract width or the arrow button and border insets + Rectangle rectForCurrentValue = new Rectangle(cbBounds.x + + borderInsets.left, + cbBounds.y + + borderInsets.top, + cbBounds.width + - arrowButtonWidth + - borderInsets.left + - borderInsets.right, + cbBounds.height + - borderInsets.top + - borderInsets.bottom); + + return rectForCurrentValue; + } + + /** + * This method returns insets of the current border. + * + * @return Insets representing space between combo box and its border + */ + protected Insets getInsets() + { + return new Insets(0, 0, 0, 0); + } + + /** + * This method paints currently selected value in the main part of the combo + * box (part without popup). + * + * @param g graphics context + * @param bounds Rectangle representing the size of the area in which + * selected item should be drawn + * @param hasFocus true if combo box has focus and false otherwise + */ + public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus) + { + if (! comboBox.isEditable()) + { + Object currentValue = comboBox.getSelectedItem(); + boolean isPressed = arrowButton.getModel().isPressed(); + + /* Gets the component to be drawn for the current value. + * If there is currently no selected item we will take an empty + * String as replacement. + */ + Component comp = comboBox.getRenderer() + .getListCellRendererComponent(listBox, + (currentValue != null ? currentValue : ""), + -1, + isPressed, + hasFocus); + if (! comboBox.isEnabled()) + comp.setEnabled(false); + + g.translate(borderInsets.left, borderInsets.top); + comp.setBounds(0, 0, bounds.width, bounds.height); + comp.paint(g); + g.translate(-borderInsets.left, -borderInsets.top); + + comboBox.revalidate(); + } + else + comboBox.getEditor().setItem(comboBox.getSelectedItem()); + } + + /** + * This method paints background of part of the combo box, where currently + * selected value is displayed. If the combo box has focus this method + * should also paint focus rectangle around the combo box. + * + * @param g graphics context + * @param bounds Rectangle representing the size of the largest item in the + * comboBox + * @param hasFocus true if combo box has fox and false otherwise + */ + public void paintCurrentValueBackground(Graphics g, Rectangle bounds, + boolean hasFocus) + { + // background is painted by renderer, so it seems that nothing + // should be done here. + } + + /** + * Returns default size for the combo box that doesn't contain any elements + * in it + * + * @return Default size of the combo box with no elements in it. + */ + protected Dimension getDefaultSize() + { + return new Dimension(6, 17); + } + + /** + * Returns size of the largest item in the combo box. This size will be the + * size of the combo box, not including the arrowButton. + * + * @return dimensions of the largest item in the combo box. + */ + protected Dimension getLargestItemSize() + { + ComboBoxModel model = comboBox.getModel(); + int numItems = model.getSize(); + + // if combo box doesn't have any items then simply + // return its default size + if (numItems == 0) + { + largestItemSize = getDefaultSize(); + return largestItemSize; + } + + Dimension size = new Dimension(0, 0); + + // ComboBox's display size should be equal to the + // size of the largest item in the combo box. + ListCellRenderer renderer = comboBox.getRenderer(); + + for (int i = 0; i < numItems; i++) + { + Object item = model.getElementAt(i); + String s = item.toString(); + Component comp = renderer.getListCellRendererComponent(listBox, item, + -1, false, false); + + if (comp.getPreferredSize().getWidth() > size.getWidth()) + size = comp.getPreferredSize(); + } + + largestItemSize = size; + return largestItemSize; + } + + /** + * This method installs the keyboard actions for the JComboBox as specified + * by the look and feel. + */ + protected void installKeyboardActions() + { + // FIXME: Need to implement. + } + + /** + * This method uninstalls the keyboard actions for the JComboBox there were + * installed by in {@link #installListeners}. + */ + protected void uninstallKeyboardActions() + { + // FIXME: Need to implement. + } + + /** + * This class is Layout Manager for this combo box. + */ + public class ComboBoxLayoutManager extends Object implements LayoutManager + { + /** + * Creates a new ComboBoxLayoutManager object. + */ + public ComboBoxLayoutManager() + { + } + + public void addLayoutComponent(String name, Component comp) + { + // Do nothing + } + + public void removeLayoutComponent(Component comp) + { + // Do nothing + } + + /** + * Returns preferred layout size of the JComboBox. + * + * @param parent Container for which preferred size should be calculated + * + * @return preferred size for the given container + */ + public Dimension preferredLayoutSize(Container parent) + { + Dimension d = new Dimension(0, 0); + + if (largestItemSize == null) + largestItemSize = getLargestItemSize(); + + // add size for the area that will display selected item + d.width += largestItemSize.getWidth(); + d.height += largestItemSize.getHeight(); + + // add size of the arrow button + d.width += arrowButtonWidth; + + // add width and height of the border + d.width += borderInsets.left + borderInsets.right; + d.height += borderInsets.left + borderInsets.right; + + // Add combo box's insets + Insets insets = parent.getInsets(); + d.width += insets.left + insets.right; + d.width += insets.left + insets.right; + + return d; + } + + public Dimension minimumLayoutSize(Container parent) + { + return preferredLayoutSize(parent); + } + + /** + * This method layouts out the components in the container. It puts arrow + * button right end part of the comboBox. If the comboBox is editable + * then editor is placed to the left of arrow button, starting from the + * beginning. + * + * @param parent Container that should be layed out. + */ + public void layoutContainer(Container parent) + { + // Position editor component to the left of arrow button if combo box is + // editable + int editorWidth = comboBox.getBounds().width - arrowButtonWidth - 2; + + if (comboBox.isEditable()) + editor.setBounds(borderInsets.left, borderInsets.top, editorWidth, + comboBox.getBounds().height - borderInsets.left + - borderInsets.top); + + arrowButton.setBounds(editorWidth, 2, arrowButtonWidth, + comboBox.getBounds().height - 4); + comboBox.revalidate(); + } + } + + /** + * This class handles focus changes occuring in the combo box. This class is + * responsible for repainting combo box whenever focus is gained or lost + * and also for hiding popup list of items whenever combo box loses its + * focus. + */ + public class FocusHandler extends Object implements FocusListener + { + /** + * Creates a new FocusHandler object. + */ + public FocusHandler() + { + } + + /** + * This mehtod is invoked when combo box gains focus. It repaints main + * part of combo box accordingally. + * + * @param e the FocusEvent + */ + public void focusGained(FocusEvent e) + { + hasFocus = true; + comboBox.repaint(); + } + + /** + * This method is invoked when combo box loses focus It repaint main part + * of combo box accordingally and hides popup list of items. + * + * @param e the FocusEvent + */ + public void focusLost(FocusEvent e) + { + hasFocus = false; + comboBox.repaint(); + popup.hide(); + } + } + + /** + * This class handles ItemEvent fired by the JComboBox when its selected + * item changes. + */ + public class ItemHandler extends Object implements ItemListener + { + /** + * Creates a new ItemHandler object. + */ + public ItemHandler() + { + } + + /** + * This method is invoked when selected item becomes deselected or when + * new item becomes selected. + * + * @param e the ItemEvent representing item's state change. + */ + public void itemStateChanged(ItemEvent e) + { + comboBox.repaint(); + } + } + + /** + * KeyHandler handles key events occuring while JComboBox has focus. + */ + public class KeyHandler extends KeyAdapter + { + public KeyHandler() + { + } + + /* + * This method is invoked whenever key is pressed while JComboBox is in + * focus. + */ + public void keyPressed(KeyEvent e) + { + // FIXME: This method calls JComboBox.selectWithKeyChar if the key that was + // pressed is not a navigation key. + } + } + + /** + * This class handles to the changes occuring in the JComboBox's data model + */ + public class ListDataHandler extends Object implements ListDataListener + { + /** + * Creates a new ListDataHandler object. + */ + public ListDataHandler() + { + } + + /** + * This method is invoked content's of JComboBox's data model are changed + * + * @param e ListDataEvent describing the change. + */ + public void contentsChanged(ListDataEvent e) + { + // if the item is selected or deselected + } + + /** + * This method is invoked when items were added to the JComboBox's data + * model. + * + * @param e ListDataEvent describing the change. + */ + public void intervalAdded(ListDataEvent e) + { + // must determine if the size of the combo box should change + int start = e.getIndex0(); + int end = e.getIndex1(); + + ComboBoxModel model = comboBox.getModel(); + ListCellRenderer renderer = comboBox.getRenderer(); + + if (largestItemSize == null) + largestItemSize = new Dimension(0, 0); + + for (int i = start; i < end; i++) + { + Object item = model.getElementAt(i); + Component comp = renderer.getListCellRendererComponent(new JList(), + item, -1, + false, false); + if (comp.getPreferredSize().getWidth() > largestItemSize.getWidth()) + largestItemSize = comp.getPreferredSize(); + } + } + + /** + * This method is invoked when items were removed from the JComboBox's + * data model. + * + * @param e ListDataEvent describing the change. + */ + public void intervalRemoved(ListDataEvent e) + { + // recalculate display size of the JComboBox. + largestItemSize = getLargestItemSize(); + comboBox.repaint(); + } + } + + /** + * This class handles PropertyChangeEvents fired by JComboBox. + */ + public class PropertyChangeHandler extends Object + implements PropertyChangeListener + { + public PropertyChangeHandler() + { + } + + /** + * This method is invoked whenever bound property of JComboBox changes. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals("enabled")) + { + arrowButton.setEnabled(comboBox.isEnabled()); + + if (comboBox.isEditable()) + comboBox.getEditor().getEditorComponent().setEnabled(comboBox + .isEnabled()); + } + else if (e.getPropertyName().equals("editable")) + { + if (comboBox.isEditable()) + { + configureEditor(); + addEditor(); + } + else + { + unconfigureEditor(); + removeEditor(); + } + + comboBox.revalidate(); + comboBox.repaint(); + } + else if (e.getPropertyName().equals("dataModel")) + { + // remove ListDataListener from old model and add it to new model + ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue(); + if (oldModel != null) + oldModel.removeListDataListener(listDataListener); + + if ((ComboBoxModel) e.getNewValue() != null) + comboBox.getModel().addListDataListener(listDataListener); + } + + // FIXME: Need to handle changes in other bound properties. + } + } + + /** + * MouseHandler listens to mouse events occuring in the combo box. This + * class is responsible for repainting this JComboBox whenever the mouse is + * being pressed or released over it. + */ + private class MouseHandler extends MouseAdapter + { + /** + * This method is invoked when mouse is pressed over the combo box. It + * repaints the combo box accordinglly + * + * @param e the MouseEvent + */ + public void mousePressed(MouseEvent e) + { + if (comboBox.isEnabled()) + { + if (e.getSource() instanceof JComboBox) + { + arrowButton.getModel().setPressed(true); + arrowButton.getModel().setArmed(true); + } + + comboBox.repaint(); + + if (e.getSource() instanceof BasicArrowButton) + toggleOpenClose(); + } + } + + /** + * This method is invoked when mouse is released over the combo box. It + * repaints the combo box accordinglly + * + * @param e the MouseEvent + */ + public void mouseReleased(MouseEvent e) + { + if (comboBox.isEnabled()) + { + if (e.getSource() instanceof JComboBox) + { + arrowButton.getModel().setPressed(false); + arrowButton.getModel().setArmed(false); + } + + comboBox.repaint(); + } + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java new file mode 100644 index 00000000000..73aac8d4e65 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java @@ -0,0 +1,1055 @@ +/* BasicComboPopup.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.ComboBoxModel; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPopupMenu; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.ListCellRenderer; +import javax.swing.ListSelectionModel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; + +/** + * UI Delegate for ComboPopup + * + * @author Olga Rodimina + */ +public class BasicComboPopup extends JPopupMenu implements ComboPopup +{ + /* Timer for autoscrolling */ + protected Timer autoscrollTimer; + + /** ComboBox associated with this popup */ + protected JComboBox comboBox; + + /** FIXME: Need to document */ + protected boolean hasEntered; + + /** + * Indicates whether the scroll bar located in popup menu with comboBox's + * list of items is currently autoscrolling. This happens when mouse event + * originated in the combo box and is dragged outside of its bounds + */ + protected boolean isAutoScrolling; + + /** ItemListener listening to the selection changes in the combo box */ + protected ItemListener itemListener; + + /** This listener is not used */ + protected KeyListener keyListener; + + /** JList which is used to display item is the combo box */ + protected JList list; + + /** This listener is not used */ + protected ListDataListener listDataListener; + + /** + * MouseListener listening to mouse events occuring in the combo box's + * list. + */ + protected MouseListener listMouseListener; + + /** + * MouseMotionListener listening to mouse motion events occuring in the + * combo box's list + */ + protected MouseMotionListener listMouseMotionListener; + + /** This listener is not used */ + protected ListSelectionListener listSelectionListener; + + /** MouseListener listening to mouse events occuring in the combo box */ + protected MouseListener mouseListener; + + /** + * MouseMotionListener listening to mouse motion events occuring in the + * combo box + */ + protected MouseMotionListener mouseMotionListener; + + /** + * PropertyChangeListener listening to changes occuring in the bound + * properties of the combo box + */ + protected PropertyChangeListener propertyChangeListener; + + /** direction for scrolling down list of combo box's items */ + protected static final int SCROLL_DOWN = 1; + + /** direction for scrolling up list of combo box's items */ + protected static final int SCROLL_UP = 0; + + /** Indicates auto scrolling direction */ + protected int scrollDirection; + + /** JScrollPane that contains list portion of the combo box */ + protected JScrollPane scroller; + + /** This field is not used */ + protected boolean valueIsAdjusting; + + /** + * Creates a new BasicComboPopup object. + * + * @param comboBox the combo box with which this popup should be associated + */ + public BasicComboPopup(JComboBox comboBox) + { + this.comboBox = comboBox; + installComboBoxListeners(); + configurePopup(); + setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); + } + + /** + * This method displays drow down list of combo box items on the screen. + */ + public void show() + { + Rectangle cbBounds = comboBox.getBounds(); + + // popup should have same width as the comboBox and should be hight anough + // to display number of rows equal to 'maximumRowCount' property + int popupHeight = getPopupHeightForRowCount(comboBox.getMaximumRowCount()); + + list.setPreferredSize(new Dimension(cbBounds.width, popupHeight)); + super.setPopupSize(cbBounds.width, popupHeight); + + // Highlight selected item in the combo box's drop down list + if (comboBox.getSelectedIndex() != -1) + list.setSelectedIndex(comboBox.getSelectedIndex()); + + //scroll scrollbar s.t. selected item is visible + JScrollBar scrollbar = scroller.getVerticalScrollBar(); + int selectedIndex = comboBox.getSelectedIndex(); + if (selectedIndex > comboBox.getMaximumRowCount()) + scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); + + // location specified is relative to comboBox + super.show(comboBox, 0, cbBounds.height); + } + + /** + * This method hides drop down list of items + */ + public void hide() + { + super.setVisible(false); + } + + /** + * Return list cointaining JComboBox's items + * + * @return list cointaining JComboBox's items + */ + public JList getList() + { + return list; + } + + /** + * Returns MouseListener that is listening to mouse events occuring in the + * combo box. + * + * @return MouseListener + */ + public MouseListener getMouseListener() + { + return mouseListener; + } + + /** + * Returns MouseMotionListener that is listening to mouse motion events + * occuring in the combo box. + * + * @return MouseMotionListener + */ + public MouseMotionListener getMouseMotionListener() + { + return mouseMotionListener; + } + + /** + * Returns KeyListener listening to key events occuring in the combo box. + * This method returns null because KeyHandler is not longer used. + * + * @return KeyListener + */ + public KeyListener getKeyListener() + { + return keyListener; + } + + /** + * This method uninstalls the UI for the given JComponent. + */ + public void uninstallingUI() + { + uninstallComboBoxModelListeners(comboBox.getModel()); + + uninstallListeners(); + uninstallKeyboardActions(); + } + + /** + * This method uninstalls listeners that were listening to changes occuring + * in the comb box's data model + * + * @param model data model for the combo box from which to uninstall + * listeners + */ + protected void uninstallComboBoxModelListeners(ComboBoxModel model) + { + model.removeListDataListener(listDataListener); + } + + /** + * This method uninstalls keyboard actions installed by the UI. + */ + protected void uninstallKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * This method fires PopupMenuEvent indicating that combo box's popup list + * of items will become visible + */ + protected void firePopupMenuWillBecomeVisible() + { + PopupMenuListener[] ll = comboBox.getPopupMenuListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].popupMenuWillBecomeVisible(new PopupMenuEvent(comboBox)); + } + + /** + * This method fires PopupMenuEvent indicating that combo box's popup list + * of items will become invisible. + */ + protected void firePopupMenuWillBecomeInvisible() + { + PopupMenuListener[] ll = comboBox.getPopupMenuListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].popupMenuWillBecomeInvisible(new PopupMenuEvent(comboBox)); + } + + /** + * This method fires PopupMenuEvent indicating that combo box's popup list + * of items was closed without selection. + */ + protected void firePopupMenuCanceled() + { + PopupMenuListener[] ll = comboBox.getPopupMenuListeners(); + + for (int i = 0; i < ll.length; i++) + ll[i].popupMenuCanceled(new PopupMenuEvent(comboBox)); + } + + /** + * Creates MouseListener to listen to mouse events occuring in the combo + * box. Note that this listener doesn't listen to mouse events occuring in + * the popup portion of the combo box, it only listens to main combo box + * part. + * + * @return new MouseMotionListener that listens to mouse events occuring in + * the combo box + */ + protected MouseListener createMouseListener() + { + return new InvocationMouseHandler(); + } + + /** + * Create Mouse listener that listens to mouse dragging events occuring in + * the combo box. This listener is responsible for changing the selection + * in the combo box list to the component over which mouse is being + * currently dragged + * + * @return new MouseMotionListener that listens to mouse dragging events + * occuring in the combo box + */ + protected MouseMotionListener createMouseMotionListener() + { + return new InvocationMouseMotionHandler(); + } + + /** + * KeyListener created in this method is not used anymore. + * + * @return KeyListener that does nothing + */ + protected KeyListener createKeyListener() + { + return new InvocationKeyHandler(); + } + + /** + * ListSelectionListener created in this method is not used anymore + * + * @return ListSelectionListener that does nothing + */ + protected ListSelectionListener createListSelectionListener() + { + return new ListSelectionHandler(); + } + + /** + * Creates ListDataListener. This method returns null, because + * ListDataHandler class is obsolete and is no longer used. + * + * @return null + */ + protected ListDataListener createListDataListener() + { + return null; + } + + /** + * This method creates ListMouseListener to listen to mouse events occuring + * in the combo box's item list. + * + * @return MouseListener to listen to mouse events occuring in the combo + * box's items list. + */ + protected MouseListener createListMouseListener() + { + return new ListMouseHandler(); + } + + /** + * Creates ListMouseMotionlistener to listen to mouse motion events occuring + * in the combo box's list. This listener is responsible for highlighting + * items in the list when mouse is moved over them. + * + * @return MouseMotionListener that handles mouse motion events occuring in + * the list of the combo box. + */ + protected MouseMotionListener createListMouseMotionListener() + { + return new ListMouseMotionHandler(); + } + + /** + * Creates PropertyChangeListener to handle changes in the JComboBox's bound + * properties. + * + * @return PropertyChangeListener to handle changes in the JComboBox's bound + * properties. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * Creates new ItemListener that will listen to ItemEvents occuring in the + * combo box. + * + * @return ItemListener to listen to ItemEvents occuring in the combo box. + */ + protected ItemListener createItemListener() + { + return new ItemHandler(); + } + + /** + * Creates JList that will be used to display items in the combo box. + * + * @return JList that will be used to display items in the combo box. + */ + protected JList createList() + { + JList l = new JList(comboBox.getModel()); + l.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); + return l; + } + + /** + * This method configures the list of comboBox's items by setting default + * properties and installing listeners. + */ + protected void configureList() + { + list.setModel(comboBox.getModel()); + list.setVisibleRowCount(comboBox.getMaximumRowCount()); + installListListeners(); + } + + /** + * This method installs list listeners. + */ + protected void installListListeners() + { + // mouse listener listening to mouse events occuring in the + // combo box's list of items. + listMouseListener = createListMouseListener(); + list.addMouseListener(listMouseListener); + + // mouse listener listening to mouse motion events occuring in the + // combo box's list of items + listMouseMotionListener = createListMouseMotionListener(); + list.addMouseMotionListener(listMouseMotionListener); + + listSelectionListener = createListSelectionListener(); + list.addListSelectionListener(listSelectionListener); + } + + /** + * This method creates scroll pane that will contain the list of comboBox's + * items inside of it. + * + * @return JScrollPane + */ + protected JScrollPane createScroller() + { + return new JScrollPane(); + } + + /** + * This method configures scroll pane to contain list of comboBox's items + */ + protected void configureScroller() + { + scroller.getViewport().setView(list); + scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + } + + /** + * This method configures popup menu that will be used to display Scrollpane + * with list of items inside of it. + */ + protected void configurePopup() + { + // initialize list that will be used to display combo box's items + this.list = createList(); + ((JLabel) list.getCellRenderer()).setHorizontalAlignment(SwingConstants.LEFT); + configureList(); + + // initialize scroller. Add list to the scroller. + scroller = createScroller(); + configureScroller(); + + // add scroller with list inside of it to JPopupMenu + super.add(scroller); + } + + /* + * This method installs listeners that will listen to changes occuring + * in the combo box. + */ + protected void installComboBoxListeners() + { + // mouse listener that listens to mouse event in combo box + mouseListener = createMouseListener(); + comboBox.addMouseListener(mouseListener); + + // mouse listener that listens to mouse dragging events in the combo box + mouseMotionListener = createMouseMotionListener(); + comboBox.addMouseMotionListener(mouseMotionListener); + + // item listener listenening to selection events in the combo box + itemListener = createItemListener(); + comboBox.addItemListener(itemListener); + + propertyChangeListener = createPropertyChangeListener(); + comboBox.addPropertyChangeListener(propertyChangeListener); + } + + /** + * This method installs listeners that will listen to changes occuring in + * the comb box's data model + * + * @param model data model for the combo box for which to install listeners + */ + protected void installComboBoxModelListeners(ComboBoxModel model) + { + // list data listener to listen for ListDataEvents in combo box. + // This listener is now obsolete and nothing is done here + listDataListener = createListDataListener(); + comboBox.getModel().addListDataListener(listDataListener); + } + + /** + * DOCUMENT ME! + */ + protected void installKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * This method always returns false to indicate that items in the combo box + * list are not focus traversable. + * + * @return false + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * This method start scrolling combo box's list of items either up or down + * depending on the specified 'direction' + * + * @param direction of the scrolling. + */ + protected void startAutoScrolling(int direction) + { + // FIXME: add timer + isAutoScrolling = true; + + if (direction == SCROLL_UP) + autoScrollUp(); + else + autoScrollDown(); + } + + /** + * This method stops scrolling the combo box's list of items + */ + protected void stopAutoScrolling() + { + // FIXME: add timer + isAutoScrolling = false; + } + + /** + * This method scrolls up list of combo box's items up and highlights that + * just became visible. + */ + protected void autoScrollUp() + { + // scroll up the scroll bar to make the item above visible + JScrollBar scrollbar = scroller.getVerticalScrollBar(); + int scrollToNext = list.getScrollableUnitIncrement(super.getBounds(), + SwingConstants.VERTICAL, + SCROLL_UP); + + scrollbar.setValue(scrollbar.getValue() - scrollToNext); + + // If we haven't reached the begging of the combo box's list of items, + // then highlight next element above currently highlighted element + if (list.getSelectedIndex() != 0) + list.setSelectedIndex(list.getSelectedIndex() - 1); + } + + /** + * This method scrolls down list of combo box's and highlights item in the + * list that just became visible. + */ + protected void autoScrollDown() + { + // scroll scrollbar down to make next item visible + JScrollBar scrollbar = scroller.getVerticalScrollBar(); + int scrollToNext = list.getScrollableUnitIncrement(super.getBounds(), + SwingConstants.VERTICAL, + SCROLL_DOWN); + scrollbar.setValue(scrollbar.getValue() + scrollToNext); + + // If we haven't reached the end of the combo box's list of items + // then highlight next element below currently highlighted element + if (list.getSelectedIndex() + 1 != comboBox.getItemCount()) + list.setSelectedIndex(list.getSelectedIndex() + 1); + } + + /** + * This method helps to delegate focus to the right component in the + * JComboBox. If the comboBox is editable then focus is sent to + * ComboBoxEditor, otherwise it is delegated to JComboBox. + * + * @param e MouseEvent + */ + protected void delegateFocus(MouseEvent e) + { + // FIXME: Need to implement + } + + /** + * This method displays combo box popup if the popup is not currently shown + * on the screen and hides it if it is currently visible + */ + protected void togglePopup() + { + if (BasicComboPopup.this.isVisible()) + hide(); + else + show(); + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected MouseEvent convertMouseEvent(MouseEvent e) + { + return null; + } + + /** + * Returns required height of the popup such that number of items visible in + * it are equal to the maximum row count. By default + * comboBox.maximumRowCount=8 + * + * @param maxRowCount number of maximum visible rows in the combo box's + * popup list of items + * + * @return height of the popup required to fit number of items equal to + * JComboBox.maximumRowCount. + */ + protected int getPopupHeightForRowCount(int maxRowCount) + { + int totalHeight = 0; + ListCellRenderer rend = list.getCellRenderer(); + + if (comboBox.getItemCount() < maxRowCount) + maxRowCount = comboBox.getItemCount(); + + for (int i = 0; i < maxRowCount; i++) + { + Component comp = rend.getListCellRendererComponent(list, + comboBox.getModel() + .getElementAt(i), + -1, false, false); + Dimension dim = comp.getPreferredSize(); + totalHeight += dim.height; + } + + return totalHeight; + } + + /** + * DOCUMENT ME! + * + * @param px DOCUMENT ME! + * @param py DOCUMENT ME! + * @param pw DOCUMENT ME! + * @param ph DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected Rectangle computePopupBounds(int px, int py, int pw, int ph) + { + return new Rectangle(px, py, pw, ph); + } + + /** + * This method changes the selection in the list to the item over which the + * mouse is currently located. + * + * @param anEvent MouseEvent + * @param shouldScroll DOCUMENT ME! + */ + protected void updateListBoxSelectionForEvent(MouseEvent anEvent, + boolean shouldScroll) + { + // FIXME: Need to implement + } + + /** + * InvocationMouseHandler is a listener that listens to mouse events + * occuring in the combo box. Note that this listener doesn't listen to + * mouse events occuring in the popup portion of the combo box, it only + * listens to main combo box part(area that displays selected item). This + * listener is responsible for showing and hiding popup portion of the + * combo box. + */ + protected class InvocationMouseHandler extends MouseAdapter + { + /** + * Creates a new InvocationMouseHandler object. + */ + protected InvocationMouseHandler() + { + } + + /** + * This method is invoked whenever mouse is being pressed over the main + * part of the combo box. This method will show popup if the popup is + * not shown on the screen right now, and it will hide popup otherwise. + * + * @param e MouseEvent that should be handled + */ + public void mousePressed(MouseEvent e) + { + if (comboBox.isEnabled()) + togglePopup(); + } + + /** + * This method is invoked whenever mouse event was originated in the combo + * box and released either in the combBox list of items or in the combo + * box itself. + * + * @param e MouseEvent that should be handled + */ + public void mouseReleased(MouseEvent e) + { + // Get component over which mouse was released + Component src = (Component) e.getSource(); + int x = e.getX(); + int y = e.getY(); + Component releasedComponent = SwingUtilities.getDeepestComponentAt(src, + x, y); + + // if mouse was released inside the bounds of combo box then do nothing, + // Otherwise if mouse was released inside the list of combo box items + // then change selection and close popup + if (! (releasedComponent instanceof JComboBox)) + { + // List model contains the item over which mouse is released, + // since it is updated every time the mouse is moved over a different + // item in the list. Now that the mouse is released we need to + // update model of the combo box as well. + comboBox.setSelectedIndex(list.getSelectedIndex()); + + if (isAutoScrolling) + stopAutoScrolling(); + hide(); + } + } + } + + /** + * InvocationMouseMotionListener is a mouse listener that listens to mouse + * dragging events occuring in the combo box. + */ + protected class InvocationMouseMotionHandler extends MouseMotionAdapter + { + /** + * Creates a new InvocationMouseMotionHandler object. + */ + protected InvocationMouseMotionHandler() + { + } + + /** + * This method is responsible for highlighting item in the drop down list + * over which the mouse is currently being dragged. + */ + public void mouseDragged(MouseEvent e) + { + // convert point of the drag event relative to combo box list component + // figure out over which list cell the mouse is currently being dragged + // and highlight the cell. The list model is changed but the change has + // no effect on combo box's data model. The list model is changed so + // that the appropriate item would be highlighted in the combo box's + // list. + if (BasicComboPopup.this.isVisible()) + { + int cbHeight = (int) comboBox.getPreferredSize().getHeight(); + int popupHeight = BasicComboPopup.this.getSize().height; + + // if mouse is dragged inside the the combo box's items list. + if (e.getY() > cbHeight && ! (e.getY() - cbHeight >= popupHeight)) + { + int index = list.locationToIndex(new Point(e.getX(), + (int) (e.getY() + - cbHeight))); + + int firstVisibleIndex = list.getFirstVisibleIndex(); + + // list.locationToIndex returns item's index that would + // be located at the specified point if the first item that + // is visible is item 0. However in the JComboBox it is not + // necessarily the case since list is contained in the + // JScrollPane so we need to adjust the index returned. + if (firstVisibleIndex != 0) + // FIXME: adjusted index here is off by one. I am adding one + // here to compensate for that. This should be + // index += firstVisibleIndex. Remove +1 once the bug is fixed. + index += firstVisibleIndex + 1; + + list.setSelectedIndex(index); + } + else + { + // if mouse is being dragged at the bottom of combo box's list + // of items or at the very top then scroll the list in the + // desired direction. + boolean movingUP = e.getY() < cbHeight; + boolean movingDown = e.getY() > cbHeight; + + if (movingUP) + { + scrollDirection = SCROLL_UP; + startAutoScrolling(SCROLL_UP); + } + else if (movingDown) + { + scrollDirection = SCROLL_DOWN; + startAutoScrolling(SCROLL_DOWN); + } + } + } + } + } + + /** + * ItemHandler is an item listener that listens to selection events occuring + * in the combo box. FIXME: should specify here what it does when item is + * selected or deselected in the combo box list. + */ + protected class ItemHandler extends Object implements ItemListener + { + /** + * Creates a new ItemHandler object. + */ + protected ItemHandler() + { + } + + /** + * This method responds to the selection events occuring in the combo box. + * + * @param e ItemEvent specifying the combo box's selection + */ + public void itemStateChanged(ItemEvent e) + { + } + } + + /** + * ListMouseHandler is a listener that listens to mouse events occuring in + * the combo box's list of items. This class is responsible for hiding + * popup portion of the combo box if the mouse is released inside the combo + * box's list. + */ + protected class ListMouseHandler extends MouseAdapter + { + protected ListMouseHandler() + { + } + + public void mousePressed(MouseEvent e) + { + } + + public void mouseReleased(MouseEvent anEvent) + { + int index = list.locationToIndex(anEvent.getPoint()); + comboBox.setSelectedIndex(index); + hide(); + } + } + + /** + * ListMouseMotionHandler listens to mouse motion events occuring in the + * combo box's list. This class is responsible for highlighting items in + * the list when mouse is moved over them + */ + protected class ListMouseMotionHandler extends MouseMotionAdapter + { + protected ListMouseMotionHandler() + { + } + + public void mouseMoved(MouseEvent anEvent) + { + // Highlight list cells over which the mouse is located. + // This changes list model, but has no effect on combo box's data model + int index = list.locationToIndex(anEvent.getPoint()); + list.setSelectedIndex(index); + list.repaint(); + } + } + + /** + * This class listens to changes occuring in the bound properties of the + * combo box + */ + protected class PropertyChangeHandler extends Object + implements PropertyChangeListener + { + protected PropertyChangeHandler() + { + } + + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals("renderer")) + { + list.setCellRenderer((ListCellRenderer) e.getNewValue()); + revalidate(); + repaint(); + } + if (e.getPropertyName().equals("dataModel")) + { + list.setModel((ComboBoxModel) e.getNewValue()); + revalidate(); + repaint(); + } + } + } + + // ------ private helper methods -------------------- + + /** + * This method uninstalls listeners installed by the UI + */ + private void uninstallListeners() + { + uninstallListListeners(); + uninstallComboBoxListeners(); + uninstallComboBoxModelListeners(comboBox.getModel()); + } + + /** + * This method uninstalls Listeners registered with combo boxes list of + * items + */ + private void uninstallListListeners() + { + list.removeMouseListener(listMouseListener); + listMouseListener = null; + + list.removeMouseMotionListener(listMouseMotionListener); + listMouseMotionListener = null; + } + + /** + * This method uninstalls listeners listening to combo box associated with + * this popup menu + */ + private void uninstallComboBoxListeners() + { + comboBox.removeMouseListener(mouseListener); + mouseListener = null; + + comboBox.removeMouseMotionListener(mouseMotionListener); + mouseMotionListener = null; + + comboBox.removeItemListener(itemListener); + itemListener = null; + + comboBox.removePropertyChangeListener(propertyChangeListener); + propertyChangeListener = null; + } + + // -------------------------------------------------------------------- + // The following classes are here only for backwards API compatibility + // They aren't used. + // -------------------------------------------------------------------- + + /** + * This class is not used any more. + */ + public class ListDataHandler extends Object implements ListDataListener + { + public ListDataHandler() + { + } + + public void contentsChanged(ListDataEvent e) + { + } + + public void intervalAdded(ListDataEvent e) + { + } + + public void intervalRemoved(ListDataEvent e) + { + } + } + + /** + * This class is not used anymore + */ + protected class ListSelectionHandler extends Object + implements ListSelectionListener + { + protected ListSelectionHandler() + { + } + + public void valueChanged(ListSelectionEvent e) + { + } + } + + /** + * This class is not used anymore + */ + public class InvocationKeyHandler extends KeyAdapter + { + public InvocationKeyHandler() + { + } + + public void keyReleased(KeyEvent e) + { + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDesktopIconUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicDesktopIconUI.java new file mode 100644 index 00000000000..561b497f1c3 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicDesktopIconUI.java @@ -0,0 +1,590 @@ +/* BasicDesktopIconUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; + +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDesktopPane; +import javax.swing.JInternalFrame; +import javax.swing.JInternalFrame.JDesktopIcon; +import javax.swing.SwingConstants; +import javax.swing.border.Border; +import javax.swing.event.MouseInputAdapter; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.DesktopIconUI; + +/** + * This class acts as the UI delegate for JDesktopIcons for the Basic look and feel. + */ +public class BasicDesktopIconUI extends DesktopIconUI +{ + /** + * This helper class handles mouse events that occur on the JDesktopIcon. + */ + public class MouseInputHandler extends MouseInputAdapter + { + /** The x offset from the MouseEvent coordinates to the top left corner. */ + private transient int xOffset; + + /** The y offset fromt he MouseEvent coordinates to the top left corner. */ + private transient int yOffset; + + /** A cached value of the JDesktopPane that parents this JDesktopIcon. */ + private transient JDesktopPane pane; + + /** + * This method is called when the mouse is dragged in the JDesktopIcon. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + Rectangle b = desktopIcon.getBounds(); + + moveAndRepaint(desktopIcon, b.x + e.getX() - xOffset, + b.y + e.getY() - yOffset, b.width, b.height); + } + + /** + * This method is called when the mouse is moved in the JDesktopIcon. + * + * @param e The MouseEvent. + */ + public void mouseMoved(MouseEvent e) + { + // Nothing to do. + } + + /** + * This method is called when the mouse is pressed in the JDesktopIcon. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + xOffset = e.getX(); + yOffset = e.getY(); + pane = frame.getDesktopPane(); + if (pane != null) + pane.getDesktopManager().beginDraggingFrame(desktopIcon); + } + + /** + * This method is called when the mouse is released in the JDesktopIcon. + * + * @param e The MouseEvent. + */ + public void mouseReleased(MouseEvent e) + { + if (pane != null) + pane.getDesktopManager().endDraggingFrame(desktopIcon); + xOffset = 0; + yOffset = 0; + } + + /** + * This method moves and repaints the JDesktopIcon to the given bounds. + * + * @param f The JComponent to move and repaint. + * @param newX The new x coordinate. + * @param newY The new y coordinate. + * @param newWidth The new width. + * @param newHeight The new height. + */ + public void moveAndRepaint(JComponent f, int newX, int newY, int newWidth, + int newHeight) + { + if (pane != null) + pane.getDesktopManager().dragFrame(f, newX, newY); + else + desktopIcon.setBounds(newX, newY, newWidth, newHeight); + } + } + + /** + * This class acts as the border for the JDesktopIcon. + */ + private class DesktopIconBorder implements Border + { + /** The left inset value. */ + int left = 10; + + /** The top inset value. */ + int top = 4; + + /** The right inset value. */ + int right = top; + + /** The bottom inset value. */ + int bottom = top; + + /** + * This method returns the insets of the border. + * + * @param c The Component to find border insets for. + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(top, left, bottom, right); + } + + /** + * This method returns whether the border is opaque. + * + * @return Whether the border is opaque. + */ + public boolean isBorderOpaque() + { + return true; + } + + /** + * This method paints the border. + * + * @param c The Component the border is in. + * @param g The Graphics object to paint with. + * @param x The x coordinate of the Component. + * @param y The y coordinate of the Component. + * @param width The width of the Component. + * @param height The height of the Component. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) + { + g.translate(x, y); + Color saved = g.getColor(); + + g.setColor(Color.LIGHT_GRAY); + + g.fillRect(0, 0, left, height); + g.fillRect(0, 0, width, top); + g.fillRect(0, height - bottom, width, bottom); + g.fillRect(width - right, 0, right, height); + + g.setColor(Color.BLACK); + g.drawRect(0, 0, width - 1, height - 1); + + int fHeight = height / 4; + int hLeft = left / 2; + + g.setColor(Color.BLACK); + g.fillRect(hLeft, fHeight, 2, 2); + g.fillRect(hLeft, fHeight * 2, 2, 2); + g.fillRect(hLeft, fHeight * 3, 2, 2); + + g.setColor(saved); + g.translate(-x, -y); + } + } + + /** The static width and height of the iconSize. */ + private static final int iconSize = 16; + + /** + * This class represents the default frame icon when none + * is supplied by the JInternalFrame. + */ + static class InternalFrameDefaultMenuIcon implements Icon + { + /** + * This returns the icon height. + * + * @return The icon height. + */ + public int getIconHeight() + { + return iconSize; + } + + /** + * This returns the icon width. + * + * @return The icon width. + */ + public int getIconWidth() + { + return iconSize; + } + + /** + * This method paints the icon. + * + * @param c The Component this icon belongs to. + * @param g The Graphics object to paint with. + * @param x The x coordinate to paint at. + * @param y The y coordinate to paint at. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.translate(x, y); + Color saved = g.getColor(); + + g.setColor(Color.BLUE); + g.fillRect(0, 0, iconSize, (int) ((double) iconSize / 3) + 1); + + g.setColor(Color.WHITE); + g.fillRect(0, (int) ((double) iconSize / 3), iconSize, iconSize * 5 / 6); + + g.setColor(Color.GRAY); + g.drawRect(0, 0, iconSize, iconSize); + + g.setColor(saved); + g.translate(-x, -y); + } + } + + /** The default JDesktopIcon width. */ + private static final int iconWidth = 160; + + /** The default JDesktopIcon height */ + private static final int iconHeight = 35; + + /** The JDesktopIcon this UI delegate represents. */ + protected JDesktopIcon desktopIcon; + + /** The JInternalFrame associated with the JDesktopIcon. */ + protected JInternalFrame frame; + + /** The MouseListener responsible for reacting to MouseEvents on the JDesktopIcon. */ + private transient MouseInputListener mouseHandler; + + /** The Button in the JDesktopIcon responsible for deiconifying it. + * This is package-private to avoid an accessor method. */ + transient BoundButton button; + + /** The PropertyChangeListener listening to the JDesktopIcon. */ + private transient PropertyChangeListener propertyHandler; + + /** The default icon used when no frame icon is given by the JInternalFrame. */ + static Icon defaultIcon = new InternalFrameDefaultMenuIcon(); + + /** + * This is a helper class that is used in JDesktopIcon and gives the Button a predetermined size. + */ + private class BoundButton extends JButton + { + /** + * Creates a new BoundButton object. + * + * @param title The title of the button. + */ + public BoundButton(String title) + { + super(title); + } + + /** + * This method returns a standard size (based on the defaults of the JDesktopIcon) and the insets. + * + * @return The preferred size of the JDesktopIcon. + */ + public Dimension getPreferredSize() + { + Insets insets = desktopIcon.getInsets(); + return new Dimension(iconWidth - insets.left - insets.right, + iconHeight - insets.top - insets.bottom); + } + + /** + * This method returns the minimum size of the button. + * + * @return The minimum size of the button. + */ + public Dimension getMinimumSize() + { + return getPreferredSize(); + } + + /** + * This method returns the maximum size of the button. + * + * @return The maximum size of the button. + */ + public Dimension getMaximumSize() + { + return getPreferredSize(); + } + } + + /** + * Creates a new BasicDesktopIconUI object. + */ + public BasicDesktopIconUI() + { + } + + /** + * This method creates a new BasicDesktopIconUI for the given JComponent. + * + * @param c The JComponent to create a UI for. + * + * @return A new BasicDesktopIconUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicDesktopIconUI(); + } + + /** + * This method installs the UI for the given JComponent. + * + * @param c The JComponent to install this UI for. + */ + public void installUI(JComponent c) + { + if (c instanceof JDesktopIcon) + { + desktopIcon = (JDesktopIcon) c; + desktopIcon.setLayout(new BorderLayout()); + frame = desktopIcon.getInternalFrame(); + + installDefaults(); + installComponents(); + installListeners(); + + desktopIcon.setOpaque(true); + } + } + + /** + * This method uninstalls the UI for the given JComponent. + * + * @param c The JComponent to uninstall this UI for. + */ + public void uninstallUI(JComponent c) + { + desktopIcon.setOpaque(false); + + uninstallListeners(); + uninstallComponents(); + uninstallDefaults(); + + frame = null; + desktopIcon.setLayout(null); + desktopIcon = null; + } + + /** + * This method installs the necessary sub components for the JDesktopIcon. + */ + protected void installComponents() + { + // Try to create a button based on what the frame's + // state is currently + button = new BoundButton(frame.getTitle()); + button.setHorizontalAlignment(SwingConstants.LEFT); + button.setHorizontalTextPosition(SwingConstants.TRAILING); + + Icon use = frame.getFrameIcon(); + if (use == null) + use = defaultIcon; + button.setIcon(use); + + desktopIcon.add(button, SwingConstants.CENTER); + } + + /** + * This method uninstalls the sub components for the JDesktopIcon. + */ + protected void uninstallComponents() + { + desktopIcon.remove(button); + + button = null; + } + + /** + * This method installs the listeners needed by this UI. + */ + protected void installListeners() + { + mouseHandler = createMouseInputListener(); + + desktopIcon.addMouseMotionListener(mouseHandler); + desktopIcon.addMouseListener(mouseHandler); + + propertyHandler = new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JInternalFrame.TITLE_PROPERTY)) + button.setText(desktopIcon.getInternalFrame().getTitle()); + else if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY)) + { + Icon use = desktopIcon.getInternalFrame().getFrameIcon(); + if (use == null) + use = defaultIcon; + button.setIcon(use); + } + desktopIcon.revalidate(); + desktopIcon.repaint(); + } + }; + frame.addPropertyChangeListener(propertyHandler); + + button.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + deiconize(); + } + }); + } + + /** + * This method uninstalls the listeners needed by the UI. + */ + protected void uninstallListeners() + { + // button is nulled so no need to remove it. + + frame.removePropertyChangeListener(propertyHandler); + propertyHandler = null; + + desktopIcon.removeMouseMotionListener(mouseHandler); + desktopIcon.removeMouseListener(mouseHandler); + } + + /** + * This method installs the defaults for the JDesktopIcon. + */ + protected void installDefaults() + { + // FIXME: Move border to defaults. + desktopIcon.setBorder(new DesktopIconBorder()); + } + + /** + * This method uninstalls the defaults for the JDesktopIcon. + */ + protected void uninstallDefaults() + { + desktopIcon.setBorder(null); + } + + /** + * This method creates a new MouseInputListener for the JDesktopIcon. + * + * @return A new MouseInputListener. + */ + protected MouseInputListener createMouseInputListener() + { + return new MouseInputHandler(); + } + + /** + * This method returns the preferred size for the given JComponent. + * + * @param c The JComponent to find a preferred size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + return new Dimension(iconWidth, iconHeight); + } + + /** + * This method returns the minimum size for the given JComponent. + * + * @param c The JComponent to find a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum size for the given JComponent. + * + * @param c The JComponent to find a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the insets of the given JComponent. + * + * @param c The JComponent to find insets for. + * + * @return The insets of the given JComponent. + */ + public Insets getInsets(JComponent c) + { + return c.getInsets(); + } + + /** + * This method deiconizes the JInternalFrame associated with the JDesktopIcon. + */ + public void deiconize() + { + try + { + frame.setIcon(false); + } + catch (PropertyVetoException pve) + { + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java new file mode 100644 index 00000000000..b15700d6fc8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java @@ -0,0 +1,464 @@ +/* BasicDesktopPaneUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.beans.PropertyVetoException; + +import javax.swing.AbstractAction; +import javax.swing.DefaultDesktopManager; +import javax.swing.DesktopManager; +import javax.swing.JComponent; +import javax.swing.JDesktopPane; +import javax.swing.JInternalFrame; +import javax.swing.KeyStroke; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.DesktopPaneUI; + +/** + * This class is the UI delegate for JDesktopPane for the Basic look and feel. + */ +public class BasicDesktopPaneUI extends DesktopPaneUI +{ + /** + * This helper class is used to handle key events that cause JInternalFrames + * to be closed. + */ + protected class CloseAction extends AbstractAction + { + /** + * This method is called when the action is performed. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + if (desktop.getSelectedFrame() != null) + { + try + { + desktop.getSelectedFrame().setClosed(true); + } + catch (PropertyVetoException pve) + { + } + } + } + + /** + * This method returns whether the action is enabled. + * + * @return Whether the action is enabled. + */ + public boolean isEnabled() + { + if (desktop.getSelectedFrame() != null) + return desktop.getSelectedFrame().isClosable(); + return false; + } + } + + /** + * This helper class is used to handle key events that cause JInternalFrames + * to be maximized. + */ + protected class MaximizeAction extends AbstractAction + { + /** + * This method is called when the action is performed. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + if (desktop.getSelectedFrame() != null) + { + try + { + desktop.getSelectedFrame().setMaximum(true); + } + catch (PropertyVetoException pve) + { + } + } + } + + /** + * This method returns whether the action is enabled. + * + * @return Whether the action is enabled. + */ + public boolean isEnabled() + { + if (desktop.getSelectedFrame() != null) + return desktop.getSelectedFrame().isMaximizable(); + return false; + } + } + + /** + * This helper class is used to handle key events that cause JInternalFrames + * to be minimized. + */ + protected class MinimizeAction extends AbstractAction + { + /** + * This method is called when the action is performed. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + if (desktop.getSelectedFrame() != null) + { + try + { + desktop.getSelectedFrame().setIcon(true); + } + catch (PropertyVetoException pve) + { + } + } + } + + /** + * This method returns whether the action is enabled. + * + * @return Whether the action is enabled. + */ + public boolean isEnabled() + { + if (desktop.getSelectedFrame() != null) + return desktop.getSelectedFrame().isIconifiable(); + return false; + } + } + + /** + * This helper class is used to handle key events that pass the SELECTED + * property to the next JInternalFrame in the JDesktopPane's list of + * children. + */ + protected class NavigateAction extends AbstractAction + { + /** + * This method is called when the action is performed. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + // This is supposed to set the next selected frame. + JInternalFrame[] frames = desktop.getAllFrames(); + if (frames.length == 0) + return; + + JInternalFrame sFrame = frames[0]; + if (desktop.getSelectedFrame() != null) + sFrame = desktop.getSelectedFrame(); + + int i = 0; + for (; i < frames.length; i++) + if (frames[i] == sFrame) + break; + + // FIXME: Navigate actions go reverse too. + if (i == frames.length) + i = 0; + + desktop.setSelectedFrame(frames[i]); + } + + /** + * This method returns whether the action is enabled. + * + * @return Whether this action is enabled. + */ + public boolean isEnabled() + { + // Always true. + return true; + } + } + + /** + * This helper class is used to restore the JInternalFrame to its original + * size before maximizing or iconifying. + */ + protected class OpenAction extends AbstractAction + { + /** + * This method is called when the action is performed. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + JInternalFrame frame = desktop.getSelectedFrame(); + if (frame != null) + { + try + { + if (frame.isIcon()) + frame.setIcon(false); + else if (frame.isMaximum()) + frame.setMaximum(false); + } + catch (PropertyVetoException pve) + { + } + } + } + + /** + * This method returns whether the action is enabled. + * + * @return Whether this action is enabled. + */ + public boolean isEnabled() + { + // JInternalFrames are always restorable. + return true; + } + } + + /** + * The KeyStroke associated with closing JInternalFrames. + * @deprecated + */ + protected KeyStroke closeKey; + + /** + * The KeyStroke associated with maximizing JInternalFrames. + * @deprecated + */ + protected KeyStroke maximizeKey; + + /** + * The KeyStroke associated with minimizing JInternalFrames. + * @deprecated + */ + protected KeyStroke minimizeKey; + + /** + * The KeyStroke associated with navigating (forward?) through + * JInternalFrames. + * @deprecated + */ + protected KeyStroke navigateKey; + + /** + * The KeyStroke associated with navigating (backward?) through + * JInternalFrames. + * @deprecated + */ + protected KeyStroke navigateKey2; + + /** The default desktop manager used with JDesktopPane. */ + protected DesktopManager desktopManager; + + /** The JDesktopPane this UI is used with. */ + protected JDesktopPane desktop; + + /** + * Creates a new BasicDesktopPaneUI object. + */ + public BasicDesktopPaneUI() + { + } + + /** + * This method creates a BasicDesktopPaneUI for the given JComponent. + * + * @param c The JComponent to create a UI for. + * + * @return A new BasicDesktopPaneUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicDesktopPaneUI(); + } + + /** + * This method returns the maximum size for the given JComponent. + * + * @param c The JComponent to find a maximum size for. + * + * @return The maximum size for the given JComponent. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum size for the given JComponent. + * + * @param c The JComponent to find a minimum size for. + * + * @return The minimum size for the given JComponent. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size for the given JComponent. + * + * @param c The JComponent to find a preferred size for. + * + * @return The preferred size for the given JComponent. + */ + public Dimension getPreferredSize(JComponent c) + { + // return null because JDesktopPanes don't have preferred sizes. + return null; + } + + /** + * This method installs the defaults for the JDesktopPane provided by the + * current look and feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + desktop.setBackground(defaults.getColor("Desktop.background")); + } + + /** + * This method installs the desktop manager for the JDesktopPane. + */ + protected void installDesktopManager() + { + desktopManager = new DefaultDesktopManager(); + desktop.setDesktopManager(desktopManager); + } + + /** + * This method installs the keyboard actions for the JDesktopPane. + */ + protected void installKeyboardActions() + { + // FIXME: create actions and keystrokes. + registerKeyboardAction(); + } + + /** + * This method installs the UI for the given JComponent. + * + * @param c The JComponent to install this UI for. + */ + public void installUI(JComponent c) + { + if (c instanceof JDesktopPane) + { + desktop = (JDesktopPane) c; + + installDefaults(); + installDesktopManager(); + installKeyboardActions(); + } + } + + /** + * This method registers the actions to the appropriate Action and Input + * maps. + */ + protected void registerKeyboardAction() + { + // FIXME: Do the binding. + // XXX: the gtk windows tend to intercept a lot of the + // key events for themselves. must figure a way past that + // before binding + } + + /** + * This method reverses the work done by the installDefaults method. + */ + protected void uninstallDefaults() + { + desktop.setBackground(null); + } + + /** + * This method reverses the work done by the installDesktopManager method. + */ + protected void uninstallDesktopManager() + { + desktopManager = null; + desktop.setDesktopManager(null); + } + + /** + * This method reverses the work done by the installKeyboardActions method. + */ + protected void uninstallKeyboardActions() + { + unregisterKeyboardActions(); + // FIXME: null the actions and keystrokes. + } + + /** + * This method reverses the work done by the registerKeyboardActions method. + */ + protected void unregisterKeyboardActions() + { + // FIXME: unmap the keystrokes + } + + /** + * This method uninstalls the UI for the given JComponent. It should reverse + * all the work done by the installUI method. + * + * @param c The JComponent to uninstall this UI for. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallDesktopManager(); + uninstallDefaults(); + + desktop = null; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java new file mode 100644 index 00000000000..a694f328049 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -0,0 +1,313 @@ +/* BasicDirectoryModel.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.Vector; +import javax.swing.AbstractListModel; +import javax.swing.JFileChooser; +import javax.swing.event.ListDataEvent; +import javax.swing.filechooser.FileSystemView; + + +/** + * DOCUMENT ME! + */ +public class BasicDirectoryModel extends AbstractListModel + implements PropertyChangeListener +{ + /** DOCUMENT ME! */ + private Vector contents; + + /** DOCUMENT ME! */ + private int directories; + + /** DOCUMENT ME! */ + private int listingMode; + + /** DOCUMENT ME! */ + private JFileChooser filechooser; + + /** DOCUMENT ME! */ + private Comparator comparator = new Comparator() + { + public int compare(Object o1, Object o2) + { + if (lt((File) o1, (File) o2)) + return -1; + else + return 1; + } + }; + + /** + * Creates a new BasicDirectoryModel object. + * + * @param filechooser DOCUMENT ME! + */ + public BasicDirectoryModel(JFileChooser filechooser) + { + this.filechooser = filechooser; + filechooser.addPropertyChangeListener(this); + listingMode = filechooser.getFileSelectionMode(); + contents = new Vector(); + } + + /** + * DOCUMENT ME! + * + * @param o DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean contains(Object o) + { + return contents.contains(o); + } + + /** + * DOCUMENT ME! + */ + public void fireContentsChanged() + { + fireContentsChanged(this, 0, getSize() - 1); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Vector getDirectories() + { + Vector tmp = new Vector(); + for (int i = 0; i < directories; i++) + tmp.add(contents.get(i)); + return tmp; + } + + /** + * DOCUMENT ME! + * + * @param index DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Object getElementAt(int index) + { + if (index > getSize() - 1) + return null; + if (listingMode == JFileChooser.FILES_ONLY) + return contents.get(directories + index); + else + return contents.elementAt(index); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Vector getFiles() + { + Vector tmp = new Vector(); + for (int i = directories; i < getSize(); i++) + tmp.add(contents.get(i)); + return tmp; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getSize() + { + if (listingMode == JFileChooser.DIRECTORIES_ONLY) + return directories; + else if (listingMode == JFileChooser.FILES_ONLY) + return contents.size() - directories; + return contents.size(); + } + + /** + * DOCUMENT ME! + * + * @param o DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int indexOf(Object o) + { + if (listingMode == JFileChooser.FILES_ONLY) + return contents.indexOf(o) - directories; + return contents.indexOf(o); + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void intervalAdded(ListDataEvent e) + { + // obsoleted + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void intervalRemoved(ListDataEvent e) + { + // obsoleted + } + + /** + * DOCUMENT ME! + */ + public void invalidateFileCache() + { + // obsoleted + } + + /** + * DOCUMENT ME! + * + * @param a DOCUMENT ME! + * @param b DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected boolean lt(File a, File b) + { + boolean aTrav = filechooser.isTraversable(a); + boolean bTrav = filechooser.isTraversable(b); + + if (aTrav == bTrav) + { + String aname = a.getName().toLowerCase(); + String bname = b.getName().toLowerCase(); + return ((aname.compareTo(bname) < 0) ? true : false); + } + else + { + if (aTrav) + return true; + else + return false; + } + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) + listingMode = filechooser.getFileSelectionMode(); + } + + /** + * DOCUMENT ME! + * + * @param oldFile DOCUMENT ME! + * @param newFile DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean renameFile(File oldFile, File newFile) + { + // FIXME: implement + return false; + } + + /** + * DOCUMENT ME! + * + * @param v DOCUMENT ME! + */ + protected void sort(Vector v) + { + Collections.sort(v, comparator); + Enumeration e = Collections.enumeration(v); + Vector tmp = new Vector(); + for (; e.hasMoreElements();) + tmp.add(e.nextElement()); + + contents = tmp; + } + + /** + * DOCUMENT ME! + */ + public void validateFileCache() + { + contents.clear(); + directories = 0; + FileSystemView fsv = filechooser.getFileSystemView(); + File[] list = fsv.getFiles(filechooser.getCurrentDirectory(), + filechooser.isFileHidingEnabled()); + + if (list == null) + return; + + for (int i = 0; i < list.length; i++) + { + if (list[i] == null) + continue; + if (filechooser.accept(list[i])) + { + contents.add(list[i]); + if (filechooser.isTraversable(list[i])) + directories++; + } + } + sort(contents); + filechooser.revalidate(); + filechooser.repaint(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java new file mode 100644 index 00000000000..6dd15a8f982 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java @@ -0,0 +1,68 @@ +/* BasicEditorPaneUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.Element; +import javax.swing.text.PlainView; +import javax.swing.text.View; + +public class BasicEditorPaneUI extends BasicTextUI +{ + public static ComponentUI createUI(JComponent comp) + { + return new BasicEditorPaneUI(); + } + + public BasicEditorPaneUI() + { + // Do nothing here. + } + + public View create(Element elem) + { + return new PlainView(elem); + } + + protected String getPropertyPrefix() + { + return "EditorPane"; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java new file mode 100644 index 00000000000..fd34fbd6227 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java @@ -0,0 +1,1921 @@ +/* BasicFileChooserUI.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Hashtable; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.ListCellRenderer; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.filechooser.FileFilter; +import javax.swing.filechooser.FileSystemView; +import javax.swing.filechooser.FileView; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.FileChooserUI; + + +/** + * DOCUMENT ME! + */ +public class BasicFileChooserUI extends FileChooserUI +{ + /** + * DOCUMENT ME! + */ + protected class AcceptAllFileFilter extends FileFilter + { + public AcceptAllFileFilter() + { + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean accept(File f) + { + return true; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getDescription() + { + return acceptAllFileFilterText; + } + } + + /** + * DOCUMENT ME! + */ + protected class ApproveSelectionAction extends AbstractAction + { + /** + * Creates a new ApproveSelectionAction object. + */ + protected ApproveSelectionAction() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void actionPerformed(ActionEvent e) + { + Object obj = filelist.getSelectedValue(); + if (obj != null) + { + File f = filechooser.getFileSystemView().createFileObject(obj + .toString()); + if (filechooser.isTraversable(f) && + filechooser.getFileSelectionMode() == JFileChooser.FILES_ONLY) + filechooser.setCurrentDirectory(f); + else + { + filechooser.setSelectedFile(f); + filechooser.approveSelection(); + closeDialog(); + } + } + } + } + + /** + * DOCUMENT ME! + */ + protected class BasicFileView extends FileView + { + /** DOCUMENT ME! */ + protected Hashtable iconCache = new Hashtable(); + + public BasicFileView() + { + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * @param i DOCUMENT ME! + */ + public void cacheIcon(File f, Icon i) + { + iconCache.put(f, i); + } + + /** + * DOCUMENT ME! + */ + public void clearIconCache() + { + iconCache.clear(); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Icon getCachedIcon(File f) + { + return (Icon) iconCache.get(f); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getDescription(File f) + { + return getName(f); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Icon getIcon(File f) + { + Icon val = getCachedIcon(f); + if (val != null) + return val; + if (filechooser.isTraversable(f)) + val = directoryIcon; + else + val = fileIcon; + cacheIcon(f, val); + return val; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getName(File f) + { + return f.getName(); + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getTypeDescription(File f) + { + if (filechooser.isTraversable(f)) + return dirDescText; + else + return fileDescText; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Boolean isHidden(File f) + { + return new Boolean(filechooser.getFileSystemView().isHiddenFile(f)); + } + } + + /** + * DOCUMENT ME! + */ + protected class CancelSelectionAction extends AbstractAction + { + /** + * Creates a new CancelSelectionAction object. + */ + protected CancelSelectionAction() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void actionPerformed(ActionEvent e) + { + filechooser.cancelSelection(); + closeDialog(); + } + } + + /** + * DOCUMENT ME! + */ + protected class ChangeToParentDirectoryAction extends AbstractAction + { + /** + * Creates a new ChangeToParentDirectoryAction object. + */ + protected ChangeToParentDirectoryAction() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void actionPerformed(ActionEvent e) + { + filechooser.changeToParentDirectory(); + filechooser.revalidate(); + filechooser.repaint(); + } + } + + /** + * DOCUMENT ME! + */ + protected class DoubleClickListener extends MouseAdapter + { + /** DOCUMENT ME! */ + private Timer timer = null; + + /** DOCUMENT ME! */ + private Object lastSelected = null; + + /** DOCUMENT ME! */ + private JList list = null; + + /** + * Creates a new DoubleClickListener object. + * + * @param list DOCUMENT ME! + */ + public DoubleClickListener(JList list) + { + this.list = list; + timer = new Timer(1000, null); + timer.setRepeats(false); + lastSelected = list.getSelectedValue(); + setDirectorySelected(false); + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void mouseClicked(MouseEvent e) + { + if (list.getSelectedValue() == null) + return; + FileSystemView fsv = filechooser.getFileSystemView(); + if (timer.isRunning() + && list.getSelectedValue().toString().equals(lastSelected.toString())) + { + File f = fsv.createFileObject(lastSelected.toString()); + timer.stop(); + if (filechooser.isTraversable(f)) + { + filechooser.setCurrentDirectory(f); + filechooser.rescanCurrentDirectory(); + } + else + { + filechooser.setSelectedFile(f); + filechooser.approveSelection(); + closeDialog(); + } + } + else + { + File f = fsv.createFileObject(list.getSelectedValue().toString()); + if (filechooser.isTraversable(f)) + { + setDirectorySelected(true); + setDirectory(f); + } + else + { + setDirectorySelected(false); + setDirectory(null); + } + lastSelected = list.getSelectedValue().toString(); + timer.restart(); + } + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void mouseEntered(MouseEvent e) + { + // FIXME: Implement + } + } + + /** + * DOCUMENT ME! + */ + protected class GoHomeAction extends AbstractAction + { + /** + * Creates a new GoHomeAction object. + */ + protected GoHomeAction() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void actionPerformed(ActionEvent e) + { + filechooser.setCurrentDirectory(filechooser.getFileSystemView() + .getHomeDirectory()); + filechooser.revalidate(); + filechooser.repaint(); + } + } + + /** + * DOCUMENT ME! + */ + protected class NewFolderAction extends AbstractAction + { + /** + * Creates a new NewFolderAction object. + */ + protected NewFolderAction() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void actionPerformed(ActionEvent e) + { + try + { + filechooser.getFileSystemView().createNewFolder(filechooser + .getCurrentDirectory()); + } + catch (IOException ioe) + { + return; + } + filechooser.rescanCurrentDirectory(); + filechooser.repaint(); + } + } + + /** + * DOCUMENT ME! + */ + protected class SelectionListener implements ListSelectionListener + { + /** + * Creates a new SelectionListener object. + */ + protected SelectionListener() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void valueChanged(ListSelectionEvent e) + { + Object f = filelist.getSelectedValue(); + if (f == null) + return; + File file = filechooser.getFileSystemView().createFileObject(f.toString()); + if (! filechooser.isTraversable(file)) + filechooser.setSelectedFile(file); + else + filechooser.setSelectedFile(null); + } + } + + /** + * DOCUMENT ME! + */ + protected class UpdateAction extends AbstractAction + { + /** + * Creates a new UpdateAction object. + */ + protected UpdateAction() + { + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void actionPerformed(ActionEvent e) + { + } + } + + /** DOCUMENT ME! */ + protected int cancelButtonMnemonic; + + /** DOCUMENT ME! */ + protected String cancelButtonText; + + /** DOCUMENT ME! */ + protected String cancelButtonToolTipText; + + /** DOCUMENT ME! */ + protected Icon computerIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + } + }; + + /** DOCUMENT ME! */ + protected Icon detailsViewIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + g.setColor(Color.GRAY); + g.drawRect(1, 1, 15, 20); + g.drawLine(17, 6, 23, 6); + g.drawLine(17, 12, 23, 12); + g.drawLine(17, 18, 23, 18); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** DOCUMENT ME! */ + protected Icon directoryIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + Point ap = new Point(3, 7); + Point bp = new Point(3, 21); + Point cp = new Point(21, 21); + Point dp = new Point(21, 12); + Point ep = new Point(16, 12); + Point fp = new Point(13, 7); + + Polygon dir = new Polygon(new int[] { ap.x, bp.x, cp.x, dp.x, ep.x, fp.x }, + new int[] { ap.y, bp.y, cp.y, dp.y, ep.y, fp.y }, + 6); + + g.setColor(new Color(153, 204, 255)); + g.fillPolygon(dir); + g.setColor(Color.BLACK); + g.drawPolygon(dir); + + g.translate(-x, -y); + g.setColor(saved); + } + }; + + /** DOCUMENT ME! */ + protected int directoryOpenButtonMnemonic; + + /** DOCUMENT ME! */ + protected String directoryOpenButtonText; + + /** DOCUMENT ME! */ + protected String directoryOpenButtonToolTipText; + + /** DOCUMENT ME! */ + protected Icon fileIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + Point a = new Point(5, 4); + Point b = new Point(5, 20); + Point d = new Point(19, 20); + Point e = new Point(19, 7); + Point f = new Point(16, 4); + + Polygon p = new Polygon(new int[] { a.x, b.x, d.x, e.x, f.x, }, + new int[] { a.y, b.y, d.y, e.y, f.y }, 5); + + g.setColor(Color.WHITE); + g.fillPolygon(p); + g.setColor(Color.BLACK); + g.drawPolygon(p); + + g.drawLine(16, 4, 14, 6); + g.drawLine(14, 6, 19, 7); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** DOCUMENT ME! */ + protected Icon floppyDriveIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + } + }; + + /** DOCUMENT ME! */ + protected Icon hardDriveIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + } + }; + + /** DOCUMENT ME! */ + protected int helpButtonMnemonic; + + /** DOCUMENT ME! */ + protected String helpButtonText; + + /** DOCUMENT ME! */ + protected String helpButtonToolTipText; + + /** DOCUMENT ME! */ + protected Icon homeFolderIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + Point a = new Point(12, 3); + Point b = new Point(4, 10); + Point d = new Point(20, 10); + + Polygon p = new Polygon(new int[] { a.x, b.x, d.x }, + new int[] { a.y, b.y, d.y }, 3); + + g.setColor(new Color(104, 51, 0)); + g.fillPolygon(p); + g.setColor(Color.BLACK); + g.drawPolygon(p); + + g.setColor(Color.WHITE); + g.fillRect(8, 10, 8, 10); + g.setColor(Color.BLACK); + g.drawRect(8, 10, 8, 10); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** DOCUMENT ME! */ + protected Icon listViewIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + // Not needed. Only simplifies things until we get real icons. + private void paintPartial(Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + g.setColor(Color.GRAY); + g.drawRect(1, 1, 7, 10); + g.drawLine(8, 6, 11, 6); + + g.setColor(saved); + g.translate(-x, -y); + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + paintPartial(g, 0, 0); + paintPartial(g, 12, 0); + paintPartial(g, 0, 12); + paintPartial(g, 12, 12); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** DOCUMENT ME! */ + protected Icon newFolderIcon = directoryIcon; + + /** DOCUMENT ME! */ + protected int openButtonMnemonic; + + /** DOCUMENT ME! */ + protected String openButtonText; + + /** DOCUMENT ME! */ + protected String openButtonToolTipText; + + /** DOCUMENT ME! */ + protected int saveButtonMnemonic; + + /** DOCUMENT ME! */ + protected String saveButtonText; + + /** DOCUMENT ME! */ + protected String saveButtonToolTipText; + + /** DOCUMENT ME! */ + protected int updateButtonMnemonic; + + /** DOCUMENT ME! */ + protected String updateButtonText; + + /** DOCUMENT ME! */ + protected String updateButtonToolTipText; + + /** DOCUMENT ME! */ + protected Icon upFolderIcon = new Icon() + { + public int getIconHeight() + { + return ICON_SIZE; + } + + public int getIconWidth() + { + return ICON_SIZE; + } + + public void paintIcon(Component comp, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.translate(x, y); + + Point a = new Point(3, 7); + Point b = new Point(3, 21); + Point c = new Point(21, 21); + Point d = new Point(21, 12); + Point e = new Point(16, 12); + Point f = new Point(13, 7); + + Polygon dir = new Polygon(new int[] { a.x, b.x, c.x, d.x, e.x, f.x }, + new int[] { a.y, b.y, c.y, d.y, e.y, f.y }, 6); + + g.setColor(new Color(153, 204, 255)); + g.fillPolygon(dir); + g.setColor(Color.BLACK); + g.drawPolygon(dir); + + a = new Point(12, 15); + b = new Point(9, 18); + c = new Point(15, 18); + + Polygon arrow = new Polygon(new int[] { a.x, b.x, c.x }, + new int[] { a.y, b.y, c.y }, 3); + + g.fillPolygon(arrow); + + g.drawLine(12, 15, 12, 22); + + g.translate(-x, -y); + g.setColor(saved); + } + }; + + // -- begin private, but package local since used in inner classes -- + + JFileChooser filechooser; + + /** DOCUMENT ME! */ + JList filelist; + + /** DOCUMENT ME! */ + JComboBox filters; + + /** DOCUMENT ME! */ + BasicDirectoryModel model; + + /** DOCUMENT ME! */ + FileFilter acceptAll = new AcceptAllFileFilter(); + + /** DOCUMENT ME! */ + FileView fv = new BasicFileView(); + + /** DOCUMENT ME! */ + static final int ICON_SIZE = 24; + + /** DOCUMENT ME! */ + JComboBox parents; + + /** DOCUMENT ME! */ + String filename; + + /** DOCUMENT ME! */ + JButton accept; + + /** DOCUMENT ME! */ + JButton cancel; + + /** DOCUMENT ME! */ + JButton upFolderButton; + + /** DOCUMENT ME! */ + JButton newFolderButton; + + /** DOCUMENT ME! */ + JButton homeFolderButton; + + /** DOCUMENT ME! */ + JPanel accessoryPanel; + + /** DOCUMENT ME! */ + PropertyChangeListener propertyChangeListener; + + /** DOCUMENT ME! */ + String acceptAllFileFilterText; + + /** DOCUMENT ME! */ + String dirDescText; + + /** DOCUMENT ME! */ + String fileDescText; + + /** DOCUMENT ME! */ + boolean dirSelected = false; + + /** DOCUMENT ME! */ + File currDir = null; + + JPanel bottomPanel; + + /** DOCUMENT ME! */ + JPanel closePanel; + + // -- end private -- + private class ListLabelRenderer + extends JLabel + implements ListCellRenderer + { + /** DOCUMENT ME! */ + final Color selected = new Color(153, 204, 255); + + /** + * Creates a new ListLabelRenderer object. + */ + public ListLabelRenderer() + { + super(); + setOpaque(true); + } + + /** + * DOCUMENT ME! + * + * @param list DOCUMENT ME! + * @param value DOCUMENT ME! + * @param index DOCUMENT ME! + * @param isSelected DOCUMENT ME! + * @param cellHasFocus DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + setHorizontalAlignment(SwingConstants.LEFT); + File file = (File) value; + setText(filechooser.getName(file)); + setIcon(filechooser.getIcon(file)); + setBackground(isSelected ? selected : Color.WHITE); + setForeground(Color.BLACK); + + return this; + } + } + + /** + * DOCUMENT ME! + */ + public class CBLabelRenderer extends JLabel implements ListCellRenderer + { + /** + * Creates a new CBLabelRenderer object. + */ + public CBLabelRenderer() + { + super(); + setOpaque(true); + } + + /** + * DOCUMENT ME! + * + * @param list DOCUMENT ME! + * @param value DOCUMENT ME! + * @param index DOCUMENT ME! + * @param isSelected DOCUMENT ME! + * @param cellHasFocus DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + setHorizontalAlignment(SwingConstants.LEFT); + setIcon(directoryIcon); + setText(value.toString()); + setForeground(Color.BLACK); + setBackground(Color.WHITE); + + return this; + } + } + + void closeDialog() + { + Window owner = SwingUtilities.windowForComponent(filechooser); + if (owner instanceof JDialog) + ((JDialog) owner).dispose(); + } + + /** + * Creates a new BasicFileChooserUI object. + * + * @param b DOCUMENT ME! + */ + public BasicFileChooserUI(JFileChooser b) + { + this.filechooser = b; + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicFileChooserUI((JFileChooser) c); + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + */ + public void installUI(JComponent c) + { + if (c instanceof JFileChooser) + { + JFileChooser fc = (JFileChooser) c; + fc.resetChoosableFileFilters(); + createModel(); + clearIconCache(); + installDefaults(fc); + installComponents(fc); + installListeners(fc); + } + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + */ + public void uninstallUI(JComponent c) + { + model = null; + uninstallListeners(filechooser); + uninstallComponents(filechooser); + uninstallDefaults(filechooser); + filechooser = null; + } + + // FIXME: Indent the entries in the combobox + private void boxEntries() + { + ArrayList parentFiles = new ArrayList(); + File parent = filechooser.getCurrentDirectory(); + if (parent == null) + parent = filechooser.getFileSystemView().getDefaultDirectory(); + while (parent != null) + { + String name = parent.getName(); + if (name.equals("")) + name = parent.getAbsolutePath(); + + parentFiles.add(parentFiles.size(), name); + parent = parent.getParentFile(); + } + + if (parentFiles.size() == 0) + return; + + if (parents.getItemCount() > 0) + parents.removeAllItems(); + for (int i = parentFiles.size() - 1; i >= 0; i--) + parents.addItem(parentFiles.get(i)); + parents.setSelectedIndex(parentFiles.size() - 1); + parents.revalidate(); + parents.repaint(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + private ItemListener createBoxListener() + { + return new ItemListener() + { + public void itemStateChanged(ItemEvent e) + { + if (parents.getItemCount() - 1 == parents.getSelectedIndex()) + return; + StringBuffer dir = new StringBuffer(); + for (int i = 0; i <= parents.getSelectedIndex(); i++) + { + dir.append(parents.getItemAt(i)); + dir.append(File.separatorChar); + } + filechooser.setCurrentDirectory(filechooser.getFileSystemView() + .createFileObject(dir + .toString())); + } + }; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + private ItemListener createFilterListener() + { + return new ItemListener() + { + public void itemStateChanged(ItemEvent e) + { + int index = filters.getSelectedIndex(); + if (index == -1) + return; + filechooser.setFileFilter(filechooser.getChoosableFileFilters()[index]); + } + }; + } + + void filterEntries() + { + FileFilter[] list = filechooser.getChoosableFileFilters(); + if (filters.getItemCount() > 0) + filters.removeAllItems(); + + int index = -1; + String selected = filechooser.getFileFilter().getDescription(); + for (int i = 0; i < list.length; i++) + { + if (selected.equals(list[i].getDescription())) + index = i; + filters.addItem(list[i].getDescription()); + } + filters.setSelectedIndex(index); + filters.revalidate(); + filters.repaint(); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + public void installComponents(JFileChooser fc) + { + JLabel look = new JLabel("Look In:"); + + parents = new JComboBox(); + parents.setRenderer(new CBLabelRenderer()); + boxEntries(); + look.setLabelFor(parents); + JPanel parentsPanel = new JPanel(); + parentsPanel.add(look); + parentsPanel.add(parents); + JPanel buttonPanel = new JPanel(); + + upFolderButton = new JButton(); + upFolderButton.setIcon(upFolderIcon); + buttonPanel.add(upFolderButton); + + homeFolderButton = new JButton(); + homeFolderButton = new JButton(homeFolderIcon); + buttonPanel.add(homeFolderButton); + + newFolderButton = new JButton(); + newFolderButton.setIcon(newFolderIcon); + buttonPanel.add(newFolderButton); + + ButtonGroup toggles = new ButtonGroup(); + JToggleButton listViewButton = new JToggleButton(); + listViewButton.setIcon(listViewIcon); + toggles.add(listViewButton); + buttonPanel.add(listViewButton); + + JToggleButton detailsViewButton = new JToggleButton(); + detailsViewButton.setIcon(detailsViewIcon); + toggles.add(detailsViewButton); + buttonPanel.add(detailsViewButton); + + JPanel topPanel = new JPanel(); + topPanel.setLayout(new java.awt.FlowLayout()); + topPanel.add(parentsPanel); + topPanel.add(buttonPanel); + + accessoryPanel = new JPanel(); + if (filechooser.getAccessory() != null) + accessoryPanel.add(filechooser.getAccessory(), BorderLayout.CENTER); + + filelist = new JList(model); + filelist.setVisibleRowCount(6); + JScrollPane scrollp = new JScrollPane(filelist); + scrollp.setPreferredSize(new Dimension(400, 175)); + filelist.setBackground(Color.WHITE); + + filelist.setLayoutOrientation(JList.VERTICAL_WRAP); + filelist.setCellRenderer(new ListLabelRenderer()); + + GridBagConstraints c = new GridBagConstraints(); + c.gridx = 0; + c.gridy = 0; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1; + c.weighty = 1; + + JPanel centrePanel = new JPanel(); + centrePanel.setLayout(new GridBagLayout()); + centrePanel.add(scrollp, c); + + c.gridx = 1; + centrePanel.add(accessoryPanel, c); + + JLabel fileNameLabel = new JLabel("File Name:"); + JLabel fileTypesLabel = new JLabel("Files of Type:"); + + JTextField entry = new JTextField(); + filters = new JComboBox(); + filterEntries(); + + fileNameLabel.setLabelFor(entry); + fileNameLabel.setHorizontalTextPosition(SwingConstants.LEFT); + fileTypesLabel.setLabelFor(filters); + fileTypesLabel.setHorizontalTextPosition(SwingConstants.LEFT); + + closePanel = new JPanel(); + accept = getApproveButton(filechooser); + cancel = new JButton(cancelButtonText); + cancel.setMnemonic(cancelButtonMnemonic); + cancel.setToolTipText(cancelButtonToolTipText); + closePanel.add(accept); + closePanel.add(cancel); + + c.anchor = GridBagConstraints.WEST; + c.weighty = 0; + c.weightx = 0; + c.gridx = 0; + + bottomPanel = new JPanel(); + bottomPanel.setLayout(new GridBagLayout()); + bottomPanel.add(fileNameLabel, c); + + c.gridy = 1; + bottomPanel.add(fileTypesLabel, c); + c.gridx = 1; + c.gridy = 0; + c.weightx = 1; + c.weighty = 1; + bottomPanel.add(entry, c); + + c.gridy = 1; + bottomPanel.add(filters, c); + + c.fill = GridBagConstraints.NONE; + c.gridy = 2; + c.anchor = GridBagConstraints.EAST; + bottomPanel.add(closePanel, c); + + filechooser.setLayout(new BorderLayout()); + filechooser.add(topPanel, BorderLayout.NORTH); + filechooser.add(centrePanel, BorderLayout.CENTER); + filechooser.add(bottomPanel, BorderLayout.SOUTH); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + public void uninstallComponents(JFileChooser fc) + { + parents = null; + + accept = null; + cancel = null; + upFolderButton = null; + homeFolderButton = null; + newFolderButton = null; + + filelist = null; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void installListeners(JFileChooser fc) + { + propertyChangeListener = createPropertyChangeListener(filechooser); + filechooser.addPropertyChangeListener(propertyChangeListener); + + //parents.addItemListener(createBoxListener()); + accept.addActionListener(getApproveSelectionAction()); + cancel.addActionListener(getCancelSelectionAction()); + upFolderButton.addActionListener(getChangeToParentDirectoryAction()); + homeFolderButton.addActionListener(getGoHomeAction()); + newFolderButton.addActionListener(getNewFolderAction()); + filters.addItemListener(createFilterListener()); + + filelist.addMouseListener(createDoubleClickListener(filechooser, filelist)); + filelist.addListSelectionListener(createListSelectionListener(filechooser)); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void uninstallListeners(JFileChooser fc) + { + filechooser.removePropertyChangeListener(propertyChangeListener); + propertyChangeListener = null; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void installDefaults(JFileChooser fc) + { + installIcons(fc); + installStrings(fc); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void uninstallDefaults(JFileChooser fc) + { + uninstallStrings(fc); + uninstallIcons(fc); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void installIcons(JFileChooser fc) + { + // FIXME: Implement. + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void uninstallIcons(JFileChooser fc) + { + // FIXME: Implement. + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void installStrings(JFileChooser fc) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + acceptAllFileFilterText = defaults.getString("FileChooser.acceptAllFileFilterText"); + cancelButtonMnemonic = defaults.getInt("FileChooser.cancelButtonMnemonic"); + cancelButtonText = defaults.getString("FileChooser.cancelButtonText"); + cancelButtonToolTipText = defaults.getString("FileChooser.cancelButtonToolTipText"); + + dirDescText = defaults.getString("FileChooser.directoryDescriptionText"); + fileDescText = defaults.getString("FileChooser.fileDescriptionText"); + + helpButtonMnemonic = defaults.getInt("FileChooser.helpButtonMnemonic"); + helpButtonText = defaults.getString("FileChooser.helpButtonText"); + helpButtonToolTipText = defaults.getString("FileChooser.helpButtonToolTipText"); + + openButtonMnemonic = defaults.getInt("FileChooser.openButtonMnemonic"); + openButtonText = defaults.getString("FileChooser.openButtonText"); + openButtonToolTipText = defaults.getString("FileChooser.openButtonToolTipText"); + + saveButtonMnemonic = defaults.getInt("FileChooser.saveButtonMnemonic"); + saveButtonText = defaults.getString("FileChooser.saveButtonText"); + saveButtonToolTipText = defaults.getString("FileChooser.saveButtonToolTipText"); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + protected void uninstallStrings(JFileChooser fc) + { + acceptAllFileFilterText = null; + cancelButtonMnemonic = 0; + cancelButtonText = null; + cancelButtonToolTipText = null; + + dirDescText = null; + fileDescText = null; + + helpButtonMnemonic = 0; + helpButtonText = null; + helpButtonToolTipText = null; + + openButtonMnemonic = 0; + openButtonText = null; + openButtonToolTipText = null; + + saveButtonMnemonic = 0; + saveButtonText = null; + saveButtonToolTipText = null; + } + + /** + * DOCUMENT ME! + */ + protected void createModel() + { + model = new BasicDirectoryModel(filechooser); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public BasicDirectoryModel getModel() + { + return model; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) + { + return new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent e) + { + // FIXME: Multiple file selection waiting on JList multiple selection bug. + if (e.getPropertyName().equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) + { + if (filechooser.getSelectedFile() == null) + setFileName(null); + else + setFileName(filechooser.getSelectedFile().toString()); + int index = -1; + File file = filechooser.getSelectedFile(); + for (index = 0; index < model.getSize(); index++) + if (((File) model.getElementAt(index)).equals(file)) + break; + if (index == -1) + return; + filelist.setSelectedIndex(index); + filelist.ensureIndexIsVisible(index); + filelist.revalidate(); + filelist.repaint(); + } + else if (e.getPropertyName().equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) + { + //boxEntries(); + filelist.clearSelection(); + filelist.revalidate(); + filelist.repaint(); + setDirectorySelected(false); + setDirectory(filechooser.getCurrentDirectory()); + } + else if (e.getPropertyName().equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) + || e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) + filterEntries(); + else if (e.getPropertyName().equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY) + || e.getPropertyName().equals(JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY)) + { + Window owner = SwingUtilities.windowForComponent(filechooser); + if (owner instanceof JDialog) + ((JDialog) owner).setTitle(getDialogTitle(filechooser)); + accept.setText(getApproveButtonText(filechooser)); + accept.setToolTipText(getApproveButtonToolTipText(filechooser)); + accept.setMnemonic(getApproveButtonMnemonic(filechooser)); + } + else if (e.getPropertyName().equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY)) + accept.setText(getApproveButtonText(filechooser)); + else if (e.getPropertyName().equals(JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY)) + accept.setToolTipText(getApproveButtonToolTipText(filechooser)); + else if (e.getPropertyName().equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) + accept.setMnemonic(getApproveButtonMnemonic(filechooser)); + else if (e.getPropertyName().equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) + { + if (filechooser.getControlButtonsAreShown()) + { + GridBagConstraints c = new GridBagConstraints(); + c.gridy = 1; + bottomPanel.add(filters, c); + + c.fill = GridBagConstraints.BOTH; + c.gridy = 2; + c.anchor = GridBagConstraints.EAST; + bottomPanel.add(closePanel, c); + bottomPanel.revalidate(); + bottomPanel.repaint(); + bottomPanel.doLayout(); + } + else + bottomPanel.remove(closePanel); + } + else if (e.getPropertyName().equals(JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY)) + { + if (filechooser.isAcceptAllFileFilterUsed()) + filechooser.addChoosableFileFilter(getAcceptAllFileFilter(filechooser)); + else + filechooser.removeChoosableFileFilter(getAcceptAllFileFilter(filechooser)); + } + else if (e.getPropertyName().equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) + { + JComponent old = (JComponent) e.getOldValue(); + if (old != null) + getAccessoryPanel().remove(old); + JComponent newval = (JComponent) e.getNewValue(); + if (newval != null) + getAccessoryPanel().add(newval); + } + if (e.getPropertyName().equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY) + || e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY) + || e.getPropertyName().equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY)) + rescanCurrentDirectory(filechooser); + + filechooser.revalidate(); + filechooser.repaint(); + } + }; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getFileName() + { + return filename; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getDirectoryName() + { + // XXX: I don't see a case where the thing returns something non-null.. + return null; + } + + /** + * DOCUMENT ME! + * + * @param filename DOCUMENT ME! + */ + public void setFileName(String filename) + { + this.filename = filename; + } + + /** + * DOCUMENT ME! + * + * @param dirname DOCUMENT ME! + */ + public void setDirectoryName(String dirname) + { + // FIXME: Implement + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + */ + public void rescanCurrentDirectory(JFileChooser fc) + { + getModel().validateFileCache(); + filelist.revalidate(); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * @param f DOCUMENT ME! + */ + public void ensureFileIsVisible(JFileChooser fc, File f) + { + // XXX: Not sure what this does. + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JFileChooser getFileChooser() + { + return filechooser; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JPanel getAccessoryPanel() + { + return accessoryPanel; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public JButton getApproveButton(JFileChooser fc) + { + accept = new JButton(getApproveButtonText(fc)); + accept.setMnemonic(getApproveButtonMnemonic(fc)); + accept.setToolTipText(getApproveButtonToolTipText(fc)); + return accept; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getApproveButtonToolTipText(JFileChooser fc) + { + if (fc.getApproveButtonToolTipText() != null) + return fc.getApproveButtonToolTipText(); + else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) + return saveButtonToolTipText; + else + return openButtonToolTipText; + } + + /** + * DOCUMENT ME! + */ + public void clearIconCache() + { + if (fv instanceof BasicFileView) + ((BasicFileView) fv).clearIconCache(); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public ListSelectionListener createListSelectionListener(JFileChooser fc) + { + return new SelectionListener(); + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * @param list DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected MouseListener createDoubleClickListener(JFileChooser fc, JList list) + { + return new DoubleClickListener(list); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected boolean isDirectorySelected() + { + return dirSelected; + } + + /** + * DOCUMENT ME! + * + * @param selected DOCUMENT ME! + */ + protected void setDirectorySelected(boolean selected) + { + dirSelected = selected; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected File getDirectory() + { + return currDir; + } + + /** + * DOCUMENT ME! + * + * @param f DOCUMENT ME! + */ + protected void setDirectory(File f) + { + currDir = f; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileFilter getAcceptAllFileFilter(JFileChooser fc) + { + return acceptAll; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public FileView getFileView(JFileChooser fc) + { + if (fc.getFileView() != null) + return fc.getFileView(); + return fv; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getDialogTitle(JFileChooser fc) + { + String ret = fc.getDialogTitle(); + if (ret != null) + return ret; + switch (fc.getDialogType()) + { + case JFileChooser.OPEN_DIALOG: + ret = openButtonText; + break; + case JFileChooser.SAVE_DIALOG: + ret = saveButtonText; + break; + default: + ret = fc.getApproveButtonText(); + break; + } + if (ret == null) + ret = openButtonText; + return ret; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public int getApproveButtonMnemonic(JFileChooser fc) + { + if (fc.getApproveButtonMnemonic() != 0) + return fc.getApproveButtonMnemonic(); + else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) + return saveButtonMnemonic; + else + return openButtonMnemonic; + } + + /** + * DOCUMENT ME! + * + * @param fc DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getApproveButtonText(JFileChooser fc) + { + if (fc.getApproveButtonText() != null) + return fc.getApproveButtonText(); + else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) + return saveButtonText; + else + return openButtonText; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Action getNewFolderAction() + { + return new NewFolderAction(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Action getGoHomeAction() + { + return new GoHomeAction(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Action getChangeToParentDirectoryAction() + { + return new ChangeToParentDirectoryAction(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Action getApproveSelectionAction() + { + return new ApproveSelectionAction(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Action getCancelSelectionAction() + { + return new CancelSelectionAction(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Action getUpdateAction() + { + return new UpdateAction(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java new file mode 100644 index 00000000000..3abd76fe2d3 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicFormattedTextFieldUI.java @@ -0,0 +1,62 @@ +/* BasicFormattedTextFieldUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +/** + * @since 1.4 + */ +public class BasicFormattedTextFieldUI extends BasicTextFieldUI +{ + public BasicFormattedTextFieldUI() + { + } + + public static ComponentUI createUI(JComponent c) + { + return new BasicFormattedTextFieldUI(); + } + + protected String getPropertyPrefix() + { + return "FormattedTextField"; + } +}
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java new file mode 100644 index 00000000000..78ee62f95f8 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java @@ -0,0 +1,641 @@ +/* BasicGraphicsUtils.java + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.font.FontRenderContext; +import java.awt.font.LineMetrics; +import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; + + +/** + * A utility class providing commonly used drawing and measurement + * routines. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class BasicGraphicsUtils +{ + /** + * Constructor. It is utterly unclear why this class should + * be constructable, but this is what the API specification + * says. + */ + public BasicGraphicsUtils() + { + } + + + /** + * Draws a rectangle that appears etched into the surface, given + * four colors that are used for drawing. + * + * <p><img src="doc-files/BasicGraphicsUtils-1.png" width="360" + * height="200" alt="[An illustration that shows which pixels + * get painted in what color]" /> + * + * @param g the graphics into which the rectangle is drawn. + * @param x the x coordinate of the rectangle. + * @param y the y coordinate of the rectangle. + * @param width the width of the rectangle in pixels. + * @param height the height of the rectangle in pixels. + * + * @param shadow the color that will be used for painting + * the outer side of the top and left edges. + * + * @param darkShadow the color that will be used for painting + * the inner side of the top and left edges. + * + * @param highlight the color that will be used for painting + * the inner side of the bottom and right edges. + * + * @param lightHighlight the color that will be used for painting + * the outer side of the bottom and right edges. + * + * @see #getEtchedInsets() + * @see javax.swing.border.EtchedBorder + */ + public static void drawEtchedRect(Graphics g, + int x, int y, int width, int height, + Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + Color oldColor; + int x2, y2; + + oldColor = g.getColor(); + x2 = x + width - 1; + y2 = y + height - 1; + + try + { + /* To understand this code, it might be helpful to look at the + * image "BasicGraphicsUtils-1.png" that is included with the + * JavaDoc. The file is located in the "doc-files" subdirectory. + * + * (x2, y2) is the coordinate of the most right and bottom pixel + * to be painted. + */ + g.setColor(shadow); + g.drawLine(x, y, x2 - 1, y); // top, outer + g.drawLine(x, y + 1, x, y2 - 1); // left, outer + + g.setColor(darkShadow); + g.drawLine(x + 1, y + 1, x2 - 2, y + 1); // top, inner + g.drawLine(x + 1, y + 2, x + 1, y2 - 2); // left, inner + + g.setColor(highlight); + g.drawLine(x + 1, y2 - 1, x2 - 1, y2 - 1); // bottom, inner + g.drawLine(x2 - 1, y + 1, x2 - 1, y2 - 2); // right, inner + + g.setColor(lightHighlight); + g.drawLine(x, y2, x2, y2); // bottom, outer + g.drawLine(x2, y, x2, y2 - 1); // right, outer + } + finally + { + g.setColor(oldColor); + } + } + + + /** + * Determines the width of the border that gets painted by + * {@link #drawEtchedRect}. + * + * @return an <code>Insets</code> object whose <code>top</code>, + * <code>left</code>, <code>bottom</code> and + * <code>right</code> field contain the border width at the + * respective edge in pixels. + */ + public static Insets getEtchedInsets() + { + return new Insets(2, 2, 2, 2); + } + + + /** + * Draws a rectangle that appears etched into the surface, given + * two colors that are used for drawing. + * + * <p><img src="doc-files/BasicGraphicsUtils-2.png" width="360" + * height="200" alt="[An illustration that shows which pixels + * get painted in what color]" /> + * + * @param g the graphics into which the rectangle is drawn. + * @param x the x coordinate of the rectangle. + * @param y the y coordinate of the rectangle. + * @param width the width of the rectangle in pixels. + * @param height the height of the rectangle in pixels. + * + * @param shadow the color that will be used for painting the outer + * side of the top and left edges, and for the inner side of + * the bottom and right ones. + * + * @param highlight the color that will be used for painting the + * inner side of the top and left edges, and for the outer + * side of the bottom and right ones. + * + * @see #getGrooveInsets() + * @see javax.swing.border.EtchedBorder + */ + public static void drawGroove(Graphics g, + int x, int y, int width, int height, + Color shadow, Color highlight) + { + /* To understand this, it might be helpful to look at the image + * "BasicGraphicsUtils-2.png" that is included with the JavaDoc, + * and to compare it with "BasicGraphicsUtils-1.png" which shows + * the pixels painted by drawEtchedRect. These image files are + * located in the "doc-files" subdirectory. + */ + drawEtchedRect(g, x, y, width, height, + /* outer topLeft */ shadow, + /* inner topLeft */ highlight, + /* inner bottomRight */ shadow, + /* outer bottomRight */ highlight); + } + + + /** + * Determines the width of the border that gets painted by + * {@link #drawGroove}. + * + * @return an <code>Insets</code> object whose <code>top</code>, + * <code>left</code>, <code>bottom</code> and + * <code>right</code> field contain the border width at the + * respective edge in pixels. + */ + public static Insets getGrooveInsets() + { + return new Insets(2, 2, 2, 2); + } + + + /** + * Draws a border that is suitable for buttons of the Basic look and + * feel. + * + * <p><img src="doc-files/BasicGraphicsUtils-3.png" width="500" + * height="300" alt="[An illustration that shows which pixels + * get painted in what color]" /> + * + * @param g the graphics into which the rectangle is drawn. + * @param x the x coordinate of the rectangle. + * @param y the y coordinate of the rectangle. + * @param width the width of the rectangle in pixels. + * @param height the height of the rectangle in pixels. + * + * @param isPressed <code>true</code> to draw the button border + * with a pressed-in appearance; <code>false</code> for + * normal (unpressed) appearance. + * + * @param isDefault <code>true</code> to draw the border with + * the appearance it has when hitting the enter key in a + * dialog will simulate a click to this button; + * <code>false</code> for normal appearance. + * + * @param shadow the shadow color. + * @param darkShadow a darker variant of the shadow color. + * @param highlight the highlight color. + * @param lightHighlight a brighter variant of the highlight color. + */ + public static void drawBezel(Graphics g, + int x, int y, int width, int height, + boolean isPressed, boolean isDefault, + Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + Color oldColor = g.getColor(); + + /* To understand this, it might be helpful to look at the image + * "BasicGraphicsUtils-3.png" that is included with the JavaDoc, + * and to compare it with "BasicGraphicsUtils-1.png" which shows + * the pixels painted by drawEtchedRect. These image files are + * located in the "doc-files" subdirectory. + */ + try + { + if ((isPressed == false) && (isDefault == false)) + { + drawEtchedRect(g, x, y, width, height, + lightHighlight, highlight, + shadow, darkShadow); + } + + if ((isPressed == true) && (isDefault == false)) + { + g.setColor(shadow); + g.drawRect(x + 1, y + 1, width - 2, height - 2); + } + + if ((isPressed == false) && (isDefault == true)) + { + g.setColor(darkShadow); + g.drawRect(x, y, width - 1, height - 1); + drawEtchedRect(g, x + 1, y + 1, width - 2, height - 2, + lightHighlight, highlight, + shadow, darkShadow); + } + + if ((isPressed == true) && (isDefault == true)) + { + g.setColor(darkShadow); + g.drawRect(x, y, width - 1, height - 1); + g.setColor(shadow); + g.drawRect(x + 1, y + 1, width - 3, height - 3); + } + } + finally + { + g.setColor(oldColor); + } + } + + + /** + * Draws a rectangle that appears lowered into the surface, given + * four colors that are used for drawing. + * + * <p><img src="doc-files/BasicGraphicsUtils-4.png" width="360" + * height="200" alt="[An illustration that shows which pixels + * get painted in what color]" /> + * + * <p><strong>Compatibility with the Sun reference + * implementation:</strong> The Sun reference implementation seems + * to ignore the <code>x</code> and <code>y</code> arguments, at + * least in JDK 1.3.1 and 1.4.1_01. The method always draws the + * rectangular area at location (0, 0). A bug report has been filed + * with Sun; its “bug ID” is 4880003. The GNU Classpath + * implementation behaves correctly, thus not replicating this bug. + * + * @param g the graphics into which the rectangle is drawn. + * @param x the x coordinate of the rectangle. + * @param y the y coordinate of the rectangle. + * @param width the width of the rectangle in pixels. + * @param height the height of the rectangle in pixels. + * + * @param shadow the color that will be used for painting + * the inner side of the top and left edges. + * + * @param darkShadow the color that will be used for painting + * the outer side of the top and left edges. + * + * @param highlight the color that will be used for painting + * the inner side of the bottom and right edges. + * + * @param lightHighlight the color that will be used for painting + * the outer side of the bottom and right edges. + */ + public static void drawLoweredBezel(Graphics g, + int x, int y, int width, int height, + Color shadow, Color darkShadow, + Color highlight, Color lightHighlight) + { + /* Like drawEtchedRect, but swapping darkShadow and shadow. + * + * To understand this, it might be helpful to look at the image + * "BasicGraphicsUtils-4.png" that is included with the JavaDoc, + * and to compare it with "BasicGraphicsUtils-1.png" which shows + * the pixels painted by drawEtchedRect. These image files are + * located in the "doc-files" subdirectory. + */ + drawEtchedRect(g, x, y, width, height, + darkShadow, shadow, + highlight, lightHighlight); + } + + + /** + * Draws a String at the given location, underlining the first + * occurence of a specified character. The algorithm for determining + * the underlined position is not sensitive to case. If the + * character is not part of <code>text</code>, the text will be + * drawn without underlining. Drawing is performed in the current + * color and font of <code>g</code>. + * + * <p><img src="doc-files/BasicGraphicsUtils-5.png" width="500" + * height="100" alt="[An illustration showing how to use the + * method]" /> + * + * @param g the graphics into which the String is drawn. + * + * @param text the String to draw. + * + * @param underlinedChar the character whose first occurence in + * <code>text</code> will be underlined. It is not clear + * why the API specification declares this argument to be + * of type <code>int</code> instead of <code>char</code>. + * While this would allow to pass Unicode characters outside + * Basic Multilingual Plane 0 (U+0000 .. U+FFFE), at least + * the GNU Classpath implementation does not underline + * anything if <code>underlinedChar</code> is outside + * the range of <code>char</code>. + * + * @param x the x coordinate of the text, as it would be passed to + * {@link java.awt.Graphics#drawString(java.lang.String, + * int, int)}. + * + * @param y the y coordinate of the text, as it would be passed to + * {@link java.awt.Graphics#drawString(java.lang.String, + * int, int)}. + */ + public static void drawString(Graphics g, String text, + int underlinedChar, int x, int y) + { + int index = -1; + + /* It is intentional that lower case is used. In some languages, + * the set of lowercase characters is larger than the set of + * uppercase ones. Therefore, it is good practice to use lowercase + * for such comparisons (which really means that the author of this + * code can vaguely remember having read some Unicode techreport + * with this recommendation, but is too lazy to look for the URL). + */ + if ((underlinedChar >= 0) || (underlinedChar <= 0xffff)) + index = text.toLowerCase().indexOf( + Character.toLowerCase((char) underlinedChar)); + + drawStringUnderlineCharAt(g, text, index, x, y); + } + + + /** + * Draws a String at the given location, underlining the character + * at the specified index. Drawing is performed in the current color + * and font of <code>g</code>. + * + * <p><img src="doc-files/BasicGraphicsUtils-5.png" width="500" + * height="100" alt="[An illustration showing how to use the + * method]" /> + * + * @param g the graphics into which the String is drawn. + * + * @param text the String to draw. + * + * @param underlinedIndex the index of the underlined character in + * <code>text</code>. If <code>underlinedIndex</code> falls + * outside the range <code>[0, text.length() - 1]</code>, the + * text will be drawn without underlining anything. + * + * @param x the x coordinate of the text, as it would be passed to + * {@link java.awt.Graphics#drawString(java.lang.String, + * int, int)}. + * + * @param y the y coordinate of the text, as it would be passed to + * {@link java.awt.Graphics#drawString(java.lang.String, + * int, int)}. + * + * @since 1.4 + */ + public static void drawStringUnderlineCharAt(Graphics g, String text, + int underlinedIndex, + int x, int y) + { + Graphics2D g2; + Rectangle2D.Double underline; + FontRenderContext frc; + FontMetrics fmet; + LineMetrics lineMetrics; + Font font; + TextLayout layout; + double underlineX1, underlineX2; + boolean drawUnderline; + int textLength; + + textLength = text.length(); + if (textLength == 0) + return; + + drawUnderline = (underlinedIndex >= 0) && (underlinedIndex < textLength); + + // FIXME: unfortunately pango and cairo can't agree on metrics + // so for the time being we continue to *not* use TextLayouts. + if (true || !(g instanceof Graphics2D)) + { + /* Fall-back. This is likely to produce garbage for any text + * containing right-to-left (Hebrew or Arabic) characters, even + * if the underlined character is left-to-right. + */ + g.drawString(text, x, y); + if (drawUnderline) + { + fmet = g.getFontMetrics(); + g.fillRect( + /* x */ x + fmet.stringWidth(text.substring(0, underlinedIndex)), + /* y */ y + fmet.getDescent() - 1, + /* width */ fmet.charWidth(text.charAt(underlinedIndex)), + /* height */ 1); + } + + return; + } + + g2 = (Graphics2D) g; + font = g2.getFont(); + frc = g2.getFontRenderContext(); + lineMetrics = font.getLineMetrics(text, frc); + layout = new TextLayout(text, font, frc); + + /* Draw the text. */ + layout.draw(g2, x, y); + if (!drawUnderline) + return; + + underlineX1 = x + layout.getLogicalHighlightShape( + underlinedIndex, underlinedIndex).getBounds2D().getX(); + underlineX2 = x + layout.getLogicalHighlightShape( + underlinedIndex + 1, underlinedIndex + 1).getBounds2D().getX(); + + underline = new Rectangle2D.Double(); + if (underlineX1 < underlineX2) + { + underline.x = underlineX1; + underline.width = underlineX2 - underlineX1; + } + else + { + underline.x = underlineX2; + underline.width = underlineX1 - underlineX2; + } + + + underline.height = lineMetrics.getUnderlineThickness(); + underline.y = lineMetrics.getUnderlineOffset(); + if (underline.y == 0) + { + /* Some fonts do not specify an underline offset, although they + * actually should do so. In that case, the result of calling + * lineMetrics.getUnderlineOffset() will be zero. Since it would + * look very ugly if the underline was be positioned immediately + * below the baseline, we check for this and move the underline + * below the descent, as shown in the following ASCII picture: + * + * ##### ##### # + * # # # # + * # # # # + * # # # # + * ##### ###### ---- baseline (0) + * # + * # + * ------------------###----------- lineMetrics.getDescent() + */ + underline.y = lineMetrics.getDescent(); + } + + underline.y += y; + g2.fill(underline); + } + + + /** + * Draws a rectangle, simulating a dotted stroke by painting only + * every second pixel along the one-pixel thick edge. The color of + * those pixels is the current color of the Graphics <code>g</code>. + * Any other pixels are left unchanged. + * + * <p><img src="doc-files/BasicGraphicsUtils-7.png" width="360" + * height="200" alt="[An illustration that shows which pixels + * get painted]" /> + * + * @param g the graphics into which the rectangle is drawn. + * @param x the x coordinate of the rectangle. + * @param y the y coordinate of the rectangle. + * @param width the width of the rectangle in pixels. + * @param height the height of the rectangle in pixels. + */ + public static void drawDashedRect(Graphics g, + int x, int y, int width, int height) + { + int right = x + width - 1; + int bottom = y + height - 1; + + /* Draw the top and bottom edge of the dotted rectangle. */ + for (int i = x; i <= right; i += 2) + { + g.drawLine(i, y, i, y); + g.drawLine(i, bottom, i, bottom); + } + + /* Draw the left and right edge of the dotted rectangle. */ + for (int i = y; i <= bottom; i += 2) + { + g.drawLine(x, i, x, i); + g.drawLine(right, i, right, i); + } + } + + + /** + * Determines the preferred width and height of an AbstractButton, + * given the gap between the button’s text and icon. + * + * @param b the button whose preferred size is determined. + * + * @param textIconGap the gap between the button’s text and + * icon. + * + * @return a <code>Dimension</code> object whose <code>width</code> + * and <code>height</code> fields indicate the preferred + * extent in pixels. + * + * @see javax.swing.SwingUtilities#layoutCompoundLabel(JComponent, + * FontMetrics, String, Icon, int, int, int, int, Rectangle, Rectangle, + * Rectangle, int) + */ + public static Dimension getPreferredButtonSize(AbstractButton b, + int textIconGap) + { + Rectangle contentRect; + Rectangle viewRect; + Rectangle iconRect = new Rectangle(); + Rectangle textRect = new Rectangle(); + Insets insets = b.getInsets(); + + viewRect = new Rectangle(); + + /* java.awt.Toolkit.getFontMetrics is deprecated. However, it + * seems not obvious how to get to the correct FontMetrics object + * otherwise. The real problem probably is that the method + * javax.swing.SwingUtilities.layoutCompundLabel should take a + * LineMetrics, not a FontMetrics argument. But fixing this that + * would change the public API. + */ + SwingUtilities.layoutCompoundLabel( + b, // for the component orientation + b.getToolkit().getFontMetrics(b.getFont()), // see comment above + b.getText(), + b.getIcon(), + b.getVerticalAlignment(), + b.getHorizontalAlignment(), + b.getVerticalTextPosition(), + b.getHorizontalTextPosition(), + viewRect, iconRect, textRect, + textIconGap); + + /* +------------------------+ +------------------------+ + * | | | | + * | ICON | | CONTENTCONTENTCONTENT | + * | TEXTTEXTTEXT | --> | CONTENTCONTENTCONTENT | + * | TEXTTEXTTEXT | | CONTENTCONTENTCONTENT | + * +------------------------+ +------------------------+ + */ + + contentRect = textRect.union(iconRect); + + return new Dimension(insets.left + + contentRect.width + + insets.right, + insets.top + + contentRect.height + + insets.bottom); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java b/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java new file mode 100644 index 00000000000..e7aad8964ba --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java @@ -0,0 +1,238 @@ +/* BasicIconFactory.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Polygon; +import java.io.Serializable; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.UIDefaults; +import javax.swing.UIManager; + +/** + * STUBBED + */ +public class BasicIconFactory implements Serializable +{ + static final long serialVersionUID = 5605588811185324383L; + + private static class DummyIcon + implements Icon + { + public int getIconHeight() { return 10; } + public int getIconWidth() { return 10; } + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color save = g.getColor(); + g.setColor(c.getForeground()); + g.drawRect(x, y, 10, 10); + g.setColor(save); + } + } + + + public BasicIconFactory() + { + } + public static Icon getMenuItemCheckIcon() + { + return new DummyIcon(); + } + public static Icon getMenuItemArrowIcon() + { + return new DummyIcon(); + } + public static Icon getMenuArrowIcon() + { + return new Icon() + { + public int getIconHeight() + { + return 12; + } + + public int getIconWidth() + { + return 12; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.translate(x, y); + + Color saved = g.getColor(); + + g.setColor(Color.BLACK); + + g.fillPolygon(new Polygon(new int[] { 3, 9, 3 }, + new int[] { 2, 6, 10 }, + 3)); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + } + + public static Icon getCheckBoxIcon() + { + return new Icon() + { + public int getIconHeight() + { + return 10; + } + public int getIconWidth() + { + return 10; + } + public void paintIcon(Component c, Graphics g, int x, int y) + { + if (c instanceof AbstractButton) + { + UIDefaults defaults; + defaults = UIManager.getLookAndFeelDefaults(); + Color hi = defaults.getColor("CheckBox.highlight"); + Color low = defaults.getColor("CheckBox.darkShadow"); + Color sel = defaults.getColor("CheckBox.foreground"); + Color dim = defaults.getColor("CheckBox.shadow"); + Polygon check = new Polygon(new int[] {x+3, x+3, x+8}, + new int[] {y+5, y+9, y+3}, 3); + AbstractButton b = (AbstractButton) c; + Color saved = g.getColor(); + if (b.isEnabled()) + { + g.setColor(low); + g.drawRect(x, y, 10, 10); + g.setColor(hi); + g.drawRect(x+1, y+1, 10, 10); + if (b.isSelected()) + { + g.setColor(sel); + if (b.isSelected()) + { + g.drawLine(x+3, y+5, x+3, y+8); + g.drawLine(x+4, y+5, x+4, y+8); + g.drawLine(x+3, y+8, x+8, y+3); + g.drawLine(x+4, y+8, x+8, y+3); + } + } + } + else + { + g.setColor(hi); + g.drawRect(x, y, 10, 10); + if (b.isSelected()) + { + g.drawLine(x+3, y+5, x+3, y+9); + g.drawLine(x+3, y+9, x+8, y+3); + } + } + g.setColor(saved); + } + } + }; + } + + public static Icon getRadioButtonIcon() + { + return new Icon() + { + public int getIconHeight() + { + return 12; + } + public int getIconWidth() + { + return 12; + } + public void paintIcon(Component c, Graphics g, int x, int y) + { + UIDefaults defaults; + defaults = UIManager.getLookAndFeelDefaults(); + Color hi = defaults.getColor("RadioButton.highlight"); + Color low = defaults.getColor("RadioButton.darkShadow"); + Color sel = defaults.getColor("RadioButton.foreground"); + Color dim = defaults.getColor("RadioButton.shadow"); + + if (c instanceof AbstractButton) + { + AbstractButton b = (AbstractButton) c; + Color saved = g.getColor(); + if (b.isEnabled()) + { + g.setColor(low); + g.drawOval(x, y, 12, 12); + g.setColor(hi); + g.drawOval(x+1, y+1, 12, 12); + if (b.isSelected()) + { + g.setColor(sel); + g.fillOval(x+4, y+4, 6, 6); + } + } + else + { + g.setColor(hi); + g.drawOval(x, y, 12, 12); + if (b.isSelected()) + g.fillOval(x+4, y+4, 6, 6); + } + g.setColor(saved); + } + } + }; + } + public static Icon getCheckBoxMenuItemIcon() + { + return getCheckBoxIcon(); + } + public static Icon getRadioButtonMenuItemIcon() + { + return getRadioButtonIcon(); + } + public static Icon createEmptyFrameIcon() + { + return new DummyIcon(); + } +} // class BasicIconFactory diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java new file mode 100644 index 00000000000..91db0cbeb7c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java @@ -0,0 +1,940 @@ +/* BasicInternalFrameTitlePane.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; + +/** + * This class acts as a titlebar for JInternalFrames. + */ +public class BasicInternalFrameTitlePane extends JComponent +{ + /** + * The Action responsible for closing the JInternalFrame. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class CloseAction extends AbstractAction + { + /** + * This method is called when something closes the JInternalFrame. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + if (frame.isClosable()) + { + try + { + frame.setClosed(true); + } + catch (PropertyVetoException pve) + { + } + } + } + } + + /** + * This Action is responsible for iconifying the JInternalFrame. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class IconifyAction extends AbstractAction + { + /** + * This method is called when the user wants to iconify the + * JInternalFrame. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + if (frame.isIconifiable() && ! frame.isIcon()) + { + try + { + frame.setIcon(true); + } + catch (PropertyVetoException pve) + { + } + } + } + } + + /** + * This Action is responsible for maximizing the JInternalFrame. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class MaximizeAction extends AbstractAction + { + /** + * This method is called when the user wants to maximize the + * JInternalFrame. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + try + { + if (frame.isMaximizable() && ! frame.isMaximum()) + frame.setMaximum(true); + else if (frame.isMaximum()) + frame.setMaximum(false); + } + catch (PropertyVetoException pve) + { + } + } + } + + /** + * This Action is responsible for dragging the JInternalFrame. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class MoveAction extends AbstractAction + { + /** + * This method is called when the user wants to drag the JInternalFrame. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + // FIXME: Implement keyboard driven? move actions. + } + } + + /** + * This Action is responsible for restoring the JInternalFrame. Restoring + * the JInternalFrame is the same as setting the maximum property to false. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class RestoreAction extends AbstractAction + { + /** + * This method is called when the user wants to restore the + * JInternalFrame. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + if (frame.isMaximum()) + { + try + { + frame.setMaximum(false); + } + catch (PropertyVetoException pve) + { + } + } + } + } + + /** + * This action is responsible for sizing the JInternalFrame. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class SizeAction extends AbstractAction + { + /** + * This method is called when the user wants to resize the JInternalFrame. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + // FIXME: Not sure how size actions should be handled. + } + } + + /** + * This class is responsible for handling property change events from the + * JInternalFrame and adjusting the Title Pane as necessary. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * This method is called when a PropertyChangeEvent is received by the + * Title Pane. + * + * @param evt The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent evt) + { + String propName = evt.getPropertyName(); + if (propName.equals("closable")) + { + if (evt.getNewValue().equals(Boolean.TRUE)) + closeButton.setVisible(true); + else + closeButton.setVisible(false); + } + else if (propName.equals("iconifiable")) + { + if (evt.getNewValue().equals(Boolean.TRUE)) + iconButton.setVisible(true); + else + iconButton.setVisible(false); + } + else if (propName.equals("maximizable")) + { + if (evt.getNewValue().equals(Boolean.TRUE)) + maxButton.setVisible(true); + else + maxButton.setVisible(false); + } + + } + } + + /** + * This class acts as the MenuBar for the TitlePane. Clicking on the Frame + * Icon in the top left corner will activate it. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class SystemMenuBar extends JMenuBar + { + /** + * This method returns true if it can receive focus. + * + * @return True if this Component can receive focus. + */ + public boolean isFocusTransversable() + { + return true; + } + + /** + * This method returns true if this Component is expected to paint all of + * itself. + * + * @return True if this Component is expect to paint all of itself. + */ + public boolean isOpaque() + { + return true; + } + + /** + * This method paints this Component. + * + * @param g The Graphics object to paint with. + */ + public void paint(Graphics g) + { + Icon frameIcon = frame.getFrameIcon(); + if (frameIcon == null) + frameIcon = BasicDesktopIconUI.defaultIcon; + frameIcon.paintIcon(this, g, 0, 0); + } + + /** + * This method requests that focus be given to this Component. + */ + public void requestFocus() + { + super.requestFocus(); + } + } + + /** + * This class acts as the Layout Manager for the TitlePane. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class TitlePaneLayout implements LayoutManager + { + /** + * Creates a new <code>TitlePaneLayout</code> object. + */ + public TitlePaneLayout() + { + // Do nothing. + } + + /** + * This method is called when adding a Component to the Container. + * + * @param name The name to reference the added Component by. + * @param c The Component to add. + */ + public void addLayoutComponent(String name, Component c) + { + // Do nothing. + } + + /** + * This method is called to lay out the children of the Title Pane. + * + * @param c The Container to lay out. + */ + public void layoutContainer(Container c) + { + Dimension size = c.getSize(); + Insets insets = c.getInsets(); + int width = size.width - insets.left - insets.right; + int height = size.height - insets.top - insets.bottom; + + // MenuBar is always present and located at the top left corner. + Dimension menupref = menuBar.getPreferredSize(); + menuBar.setBounds(insets.left, insets.top, menupref.width, height); + + int loc = width + insets.left - 1; + int top = insets.top + 1; + int buttonWidth = height - 2; + int buttonHeight = height - 4; + if (closeButton.isVisible()) + { + loc -= buttonWidth + 2; + closeButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (maxButton.isVisible()) + { + loc -= buttonWidth + 2; + maxButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (iconButton.isVisible()) + { + loc -= buttonWidth + 2; + iconButton.setBounds(loc, top, buttonWidth, buttonHeight); + } + + if (title != null) + title.setBounds(insets.left + menupref.width, insets.top, + loc - menupref.width - insets.left, height); + } + + /** + * This method returns the minimum size of the given Container given the + * children that it has. + * + * @param c The Container to get a minimum size for. + * + * @return The minimum size of the Container. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * This method returns the preferred size of the given Container taking + * into account the children that it has. + * + * @param c The Container to lay out. + * + * @return The preferred size of the Container. + */ + public Dimension preferredLayoutSize(Container c) + { + return new Dimension(22, 18); + } + + /** + * This method is called when removing a Component from the Container. + * + * @param c The Component to remove. + */ + public void removeLayoutComponent(Component c) + { + } + } + + /** + * This helper class is used to create the minimize, maximize and close + * buttons in the top right corner of the Title Pane. These buttons are + * special since they cannot be given focus and have no border. + */ + private class PaneButton extends JButton + { + /** + * Creates a new PaneButton object with the given Action. + * + * @param a The Action that the button uses. + */ + public PaneButton(Action a) + { + super(a); + setMargin(new Insets(0, 0, 0, 0)); + } + + /** + * This method returns true if the Component can be focused. + * + * @return false. + */ + public boolean isFocusable() + { + // These buttons cannot be given focus. + return false; + } + } + + /** The action command for the Close action. */ + protected static final String CLOSE_CMD = "Close"; + + /** The action command for the Minimize action. */ + protected static final String ICONIFY_CMD = "Minimize"; + + /** The action command for the Maximize action. */ + protected static final String MAXIMIZE_CMD = "Maximize"; + + /** The action command for the Move action. */ + protected static final String MOVE_CMD = "Move"; + + /** The action command for the Restore action. */ + protected static final String RESTORE_CMD = "Restore"; + + /** The action command for the Size action. */ + protected static final String SIZE_CMD = "Size"; + + /** The action associated with closing the JInternalFrame. */ + protected Action closeAction; + + /** The action associated with iconifying the JInternalFrame. */ + protected Action iconifyAction; + + /** The action associated with maximizing the JInternalFrame. */ + protected Action maximizeAction; + + /** The action associated with moving the JInternalFrame. */ + protected Action moveAction; + + /** The action associated with restoring the JInternalFrame. */ + protected Action restoreAction; + + /** The action associated with resizing the JInternalFrame. */ + protected Action sizeAction; + + /** The button that closes the JInternalFrame. */ + protected JButton closeButton; + + /** The button that iconifies the JInternalFrame. */ + protected JButton iconButton; + + /** The button that maximizes the JInternalFrame. */ + protected JButton maxButton; + + /** Active background color. */ + protected Color activeBGColor; + + /** Active foreground color. */ + protected Color activeFGColor; + + /** Inactive background color. */ + protected Color inactiveBGColor; + + /** Inactive foreground color. */ + protected Color inactiveFGColor; + + /** The icon displayed in the restore button. */ + protected Icon minIcon = BasicIconFactory.createEmptyFrameIcon(); + + /** The icon displayed in the maximize button. */ + protected Icon maxIcon = BasicIconFactory.createEmptyFrameIcon(); + + /** The icon displayed in the iconify button. */ + protected Icon iconIcon = BasicIconFactory.createEmptyFrameIcon(); + + /** The JInternalFrame that this TitlePane is used in. */ + protected JInternalFrame frame; + + /** The JMenuBar that is located at the top left of the Title Pane. */ + protected JMenuBar menuBar; + + /** The JMenu inside the menuBar. */ + protected JMenu windowMenu; + + /** + * The text color of the TitlePane when the JInternalFrame is not selected. + */ + protected Color notSelectedTextColor; + + /** + * The background color of the TitlePane when the JInternalFrame is not + * selected. + */ + protected Color notSelectedTitleColor; + + /** The text color of the titlePane when the JInternalFrame is selected. */ + protected Color selectedTextColor; + + /** + * The background color of the TitlePane when the JInternalFrame is + * selected. + */ + protected Color selectedTitleColor; + + /** The Property Change listener that listens to the JInternalFrame. */ + protected PropertyChangeListener propertyChangeListener; + + /** + * The label used to display the title. This label is not added to the + * TitlePane. + * This is package-private to avoid an accessor method. + */ + transient JLabel title; + + /** + * Creates a new BasicInternalFrameTitlePane object that is used in the + * given JInternalFrame. + * + * @param f The JInternalFrame this BasicInternalFrameTitlePane will be used + * in. + */ + public BasicInternalFrameTitlePane(JInternalFrame f) + { + frame = f; + setLayout(createLayout()); + title = new JLabel(); + title.setHorizontalAlignment(SwingConstants.LEFT); + title.setHorizontalTextPosition(SwingConstants.LEFT); + title.setOpaque(false); + setOpaque(true); + + setBackground(Color.LIGHT_GRAY); + + installTitlePane(); + } + + /** + * This method installs the TitlePane onto the JInternalFrameTitlePane. It + * also creates any children components that need to be created and adds + * listeners to the appropriate components. + */ + protected void installTitlePane() + { + installDefaults(); + installListeners(); + createActions(); + + assembleSystemMenu(); + + createButtons(); + setButtonIcons(); + addSubComponents(); + enableActions(); + } + + /** + * This method adds the sub components to the TitlePane. + */ + protected void addSubComponents() + { + add(menuBar); + + add(closeButton); + add(iconButton); + add(maxButton); + } + + /** + * This method creates the actions that are used to manipulate the + * JInternalFrame. + */ + protected void createActions() + { + closeAction = new CloseAction(); + closeAction.putValue(AbstractAction.ACTION_COMMAND_KEY, CLOSE_CMD); + + iconifyAction = new IconifyAction(); + iconifyAction.putValue(AbstractAction.ACTION_COMMAND_KEY, ICONIFY_CMD); + + maximizeAction = new MaximizeAction(); + maximizeAction.putValue(AbstractAction.ACTION_COMMAND_KEY, MAXIMIZE_CMD); + + sizeAction = new SizeAction(); + sizeAction.putValue(AbstractAction.ACTION_COMMAND_KEY, SIZE_CMD); + + restoreAction = new RestoreAction(); + restoreAction.putValue(AbstractAction.ACTION_COMMAND_KEY, RESTORE_CMD); + + moveAction = new MoveAction(); + moveAction.putValue(AbstractAction.ACTION_COMMAND_KEY, MOVE_CMD); + } + + /** + * This method is used to install the listeners. + */ + protected void installListeners() + { + propertyChangeListener = new PropertyChangeHandler(); + frame.addPropertyChangeListener(propertyChangeListener); + } + + /** + * This method is used to uninstall the listeners. + */ + protected void uninstallListeners() + { + frame.removePropertyChangeListener(propertyChangeListener); + propertyChangeListener = null; + } + + /** + * This method installs the defaults determined by the look and feel. + */ + protected void installDefaults() + { + // FIXME: move icons to defaults. + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + setFont(defaults.getFont("InternalFrame.titleFont")); + activeFGColor = defaults.getColor("InternalFrame.activeTitleForeground"); + activeBGColor = defaults.getColor("InternalFrame.activeTitleBackground"); + inactiveFGColor = defaults.getColor("InternalFrame.inactiveTitleForeground"); + inactiveBGColor = defaults.getColor("InternalFrame.inactiveTitleBackground"); + } + + /** + * This method uninstalls the defaults. + */ + protected void uninstallDefaults() + { + setFont(null); + activeFGColor = null; + activeBGColor = null; + inactiveFGColor = null; + inactiveBGColor = null; + } + + /** + * This method creates the buttons used in the TitlePane. + */ + protected void createButtons() + { + closeButton = new PaneButton(closeAction); + if (!frame.isClosable()) + closeButton.setVisible(false); + iconButton = new PaneButton(iconifyAction); + if (!frame.isIconifiable()) + iconButton.setVisible(false); + maxButton = new PaneButton(maximizeAction); + if (!frame.isMaximizable()) + maxButton.setVisible(false); + } + + /** + * This method sets the icons in the buttons. This is a no-op method here, it + * can be overridden by subclasses to set icons for the minimize-, maximize- + * and close-buttons. + */ + protected void setButtonIcons() + { + } + + /** + * This method creates the MenuBar used in the TitlePane. + */ + protected void assembleSystemMenu() + { + menuBar = createSystemMenuBar(); + windowMenu = createSystemMenu(); + + menuBar.add(windowMenu); + + addSystemMenuItems(windowMenu); + enableActions(); + } + + /** + * This method adds the MenuItems to the given JMenu. + * + * @param systemMenu The JMenu to add MenuItems to. + */ + protected void addSystemMenuItems(JMenu systemMenu) + { + JMenuItem tmp; + + tmp = new JMenuItem(RESTORE_CMD); + tmp.addActionListener(restoreAction); + tmp.setMnemonic(KeyEvent.VK_R); + systemMenu.add(tmp); + + tmp = new JMenuItem(MOVE_CMD); + tmp.addActionListener(moveAction); + tmp.setMnemonic(KeyEvent.VK_M); + systemMenu.add(tmp); + + tmp = new JMenuItem(SIZE_CMD); + tmp.addActionListener(sizeAction); + tmp.setMnemonic(KeyEvent.VK_S); + systemMenu.add(tmp); + + tmp = new JMenuItem(ICONIFY_CMD); + tmp.addActionListener(iconifyAction); + tmp.setMnemonic(KeyEvent.VK_N); + systemMenu.add(tmp); + + tmp = new JMenuItem(MAXIMIZE_CMD); + tmp.addActionListener(maximizeAction); + tmp.setMnemonic(KeyEvent.VK_X); + systemMenu.add(tmp); + + systemMenu.addSeparator(); + + tmp = new JMenuItem(CLOSE_CMD); + tmp.addActionListener(closeAction); + tmp.setMnemonic(KeyEvent.VK_C); + systemMenu.add(tmp); + } + + /** + * This method creates a new JMenubar. + * + * @return A new JMenuBar. + */ + protected JMenuBar createSystemMenuBar() + { + if (menuBar == null) + menuBar = new SystemMenuBar(); + menuBar.removeAll(); + return menuBar; + } + + /** + * This method creates a new JMenu. + * + * @return A new JMenu. + */ + protected JMenu createSystemMenu() + { + if (windowMenu == null) + windowMenu = new JMenu(); + windowMenu.removeAll(); + return windowMenu; + } + + /** + * This method programmatically shows the JMenu. + */ + protected void showSystemMenu() + { + // FIXME: Untested as KeyEvents are not hooked up. + menuBar.getMenu(1).getPopupMenu().show(); + } + + /** + * This method paints the TitlePane. + * + * @param g The Graphics object to paint with. + */ + public void paintComponent(Graphics g) + { + paintTitleBackground(g); + Font f = g.getFont(); + FontMetrics fm = g.getFontMetrics(f); + if (frame.getTitle() != null && title != null) + { + Color saved = g.getColor(); + if (frame.isSelected()) + g.setColor(activeFGColor); + else + g.setColor(inactiveFGColor); + title.setText(getTitle(frame.getTitle(), fm, title.getBounds().width)); + SwingUtilities.paintComponent(g, title, null, title.getBounds()); + g.setColor(saved); + } + } + + /** + * This method paints the TitlePane's background. + * + * @param g The Graphics object to paint with. + */ + protected void paintTitleBackground(Graphics g) + { + Color saved = g.getColor(); + Dimension dims = getSize(); + + Color bg = getBackground(); + if (frame.isSelected()) + bg = activeBGColor; + else + bg = inactiveBGColor; + g.setColor(bg); + g.fillRect(0, 0, dims.width, dims.height); + g.setColor(saved); + } + + /** + * This method returns the title string based on the available width and the + * font metrics. + * + * @param text The desired title. + * @param fm The FontMetrics of the font used. + * @param availableWidth The available width. + * + * @return The allowable string. + */ + protected String getTitle(String text, FontMetrics fm, int availableWidth) + { + Rectangle vr = new Rectangle(0, 0, availableWidth, fm.getHeight()); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + String value = SwingUtilities.layoutCompoundLabel(this, fm, text, null, + SwingConstants.CENTER, + SwingConstants.LEFT, + SwingConstants.CENTER, + SwingConstants.LEFT, vr, + ir, tr, 0); + return value; + } + + /** + * This method fires something similar to a WINDOW_CLOSING event. + * + * @param frame The JInternalFrame that is being closed. + */ + protected void postClosingEvent(JInternalFrame frame) + { + // FIXME: Implement postClosingEvent when I figure out what + // it's supposed to do. + // It says that this fires an WINDOW_CLOSING like event. + // So the closest thing is some kind of InternalFrameEvent. + // But none is fired. + // Can't see it called or anything. + } + + /** + * This method enables the actions for the TitlePane given the frame's + * properties. + */ + protected void enableActions() + { + closeAction.setEnabled(frame.isClosable()); + + iconifyAction.setEnabled(frame.isIconifiable()); + // The maximize action is responsible for restoring it + // as well, if clicked from the button + maximizeAction.setEnabled(frame.isMaximizable()); + + // The restoring action is only active when selected + // from the menu. + restoreAction.setEnabled(frame.isMaximum()); + + sizeAction.setEnabled(frame.isResizable()); + + // FIXME: Tie MoveAction enabled status to a variable. + moveAction.setEnabled(false); + } + + /** + * This method creates a new PropertyChangeListener. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * This method creates a new LayoutManager for the TitlePane. + * + * @return A new LayoutManager. + */ + protected LayoutManager createLayout() + { + return new TitlePaneLayout(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java new file mode 100644 index 00000000000..16379668278 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -0,0 +1,1719 @@ +/* BasicInternalFrameUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.AWTEvent; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; +import java.beans.VetoableChangeListener; + +import javax.swing.BorderFactory; +import javax.swing.DefaultDesktopManager; +import javax.swing.DesktopManager; +import javax.swing.JComponent; +import javax.swing.JDesktopPane; +import javax.swing.JInternalFrame; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; +import javax.swing.event.InternalFrameEvent; +import javax.swing.event.InternalFrameListener; +import javax.swing.event.MouseInputAdapter; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.InternalFrameUI; +import javax.swing.plaf.UIResource; + +/** + * This is the UI delegate for the Basic look and feel for JInternalFrames. + */ +public class BasicInternalFrameUI extends InternalFrameUI +{ + /** + * This is a helper class that listens to the JInternalFrame for + * InternalFrameEvents. + */ + protected class BasicInternalFrameListener implements InternalFrameListener + { + /** + * This method is called when the JInternalFrame is activated. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameActivated(InternalFrameEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the JInternalFrame is closed. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameClosed(InternalFrameEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the JInternalFrame is closing. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameClosing(InternalFrameEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the JInternalFrame is deactivated. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameDeactivated(InternalFrameEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the JInternalFrame is deiconified. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameDeiconified(InternalFrameEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the JInternalFrame is iconified. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameIconified(InternalFrameEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the JInternalFrame is opened. + * + * @param e The InternalFrameEvent. + */ + public void internalFrameOpened(InternalFrameEvent e) + { + // FIXME: Implement. + } + } + + /** + * This helper class listens to the edges of the JInternalFrame and the + * TitlePane for mouse events. It is responsible for dragging and resizing + * the JInternalFrame in response to the MouseEvents. + */ + protected class BorderListener extends MouseInputAdapter + implements SwingConstants + { + /** FIXME: Use for something. */ + protected final int RESIZE_NONE = 0; + + /** The x offset from the top left corner of the JInternalFrame. */ + private transient int xOffset = 0; + + /** The y offset from the top left corner of the JInternalFrame. */ + private transient int yOffset = 0; + + /** The direction that the resize is occuring in. */ + private transient int direction = -1; + + /** Cache rectangle that can be reused. */ + private transient Rectangle cacheRect = new Rectangle(); + + /** + * This method is called when the mouse is clicked. + * + * @param e The MouseEvent. + */ + public void mouseClicked(MouseEvent e) + { + // There is nothing to do when the mouse is clicked + // on the border. + } + + /** + * This method is called when the mouse is dragged. This method is + * responsible for resizing or dragging the JInternalFrame. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + // If the frame is maximized, there is nothing that + // can be dragged around. + if (frame.isMaximum()) + return; + DesktopManager dm = getDesktopManager(); + Rectangle b = frame.getBounds(); + Dimension min = frame.getMinimumSize(); + if (min == null) + min = new Dimension(0, 0); + Insets insets = frame.getInsets(); + int x = e.getX(); + int y = e.getY(); + if (e.getSource() == frame && frame.isResizable()) + { + switch (direction) + { + case NORTH: + cacheRect.setBounds(b.x, + Math.min(b.y + y, b.y + b.height + - min.height), b.width, b.height + - y); + break; + case NORTH_EAST: + cacheRect.setBounds(b.x, + Math.min(b.y + y, b.y + b.height + - min.height), x, b.height - y); + break; + case EAST: + cacheRect.setBounds(b.x, b.y, x, b.height); + break; + case SOUTH_EAST: + cacheRect.setBounds(b.x, b.y, x, y); + break; + case SOUTH: + cacheRect.setBounds(b.x, b.y, b.width, y); + break; + case SOUTH_WEST: + cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), + b.y, b.width - x, y); + break; + case WEST: + cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), + b.y, b.width - x, b.height); + break; + case NORTH_WEST: + cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), + Math.min(b.y + y, b.y + b.height + - min.height), b.width - x, + b.height - y); + break; + } + dm.resizeFrame(frame, cacheRect.x, cacheRect.y, + Math.max(min.width, cacheRect.width), + Math.max(min.height, cacheRect.height)); + } + else if (e.getSource() == titlePane) + { + Rectangle fBounds = frame.getBounds(); + + dm.dragFrame(frame, e.getX() - xOffset + b.x, + e.getY() - yOffset + b.y); + } + } + + /** + * This method is called when the mouse exits the JInternalFrame. + * + * @param e The MouseEvent. + */ + public void mouseExited(MouseEvent e) + { + // There is nothing to do when the mouse exits + // the border area. + } + + /** + * This method is called when the mouse is moved inside the + * JInternalFrame. + * + * @param e The MouseEvent. + */ + public void mouseMoved(MouseEvent e) + { + // There is nothing to do when the mouse moves + // over the border area. + } + + /** + * This method is called when the mouse is pressed. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + activateFrame(frame); + DesktopManager dm = getDesktopManager(); + int x = e.getX(); + int y = e.getY(); + Insets insets = frame.getInsets(); + + if (e.getSource() == frame && frame.isResizable()) + { + direction = sectionOfClick(x, y); + dm.beginResizingFrame(frame, direction); + } + else if (e.getSource() == titlePane) + { + Rectangle tBounds = titlePane.getBounds(); + + xOffset = e.getX() - tBounds.x + insets.left; + yOffset = e.getY() - tBounds.y + insets.top; + + dm.beginDraggingFrame(frame); + } + } + + /** + * This method is called when the mouse is released. + * + * @param e The MouseEvent. + */ + public void mouseReleased(MouseEvent e) + { + DesktopManager dm = getDesktopManager(); + xOffset = 0; + yOffset = 0; + if (e.getSource() == frame && frame.isResizable()) + dm.endResizingFrame(frame); + else if (e.getSource() == titlePane) + dm.endDraggingFrame(frame); + } + + /** + * This method determines the direction of the resize based on the + * coordinates and the size of the JInternalFrame. + * + * @param x The x coordinate of the MouseEvent. + * @param y The y coordinate of the MouseEvent. + * + * @return The direction of the resize (a SwingConstant direction). + */ + private int sectionOfClick(int x, int y) + { + Insets insets = frame.getInsets(); + Rectangle b = frame.getBounds(); + if (x < insets.left && y < insets.top) + return NORTH_WEST; + else if (x > b.width - insets.right && y < insets.top) + return NORTH_EAST; + else if (x > b.width - insets.right && y > b.height - insets.bottom) + return SOUTH_EAST; + else if (x < insets.left && y > b.height - insets.bottom) + return SOUTH_WEST; + else if (y < insets.top) + return NORTH; + else if (x < insets.left) + return WEST; + else if (y > b.height - insets.bottom) + return SOUTH; + else if (x > b.width - insets.right) + return EAST; + + return -1; + } + } + + /** + * This helper class listens to the JDesktopPane that parents this + * JInternalFrame and listens for resize events and resizes the + * JInternalFrame appropriately. + */ + protected class ComponentHandler implements ComponentListener + { + /** + * This method is called when the JDesktopPane is hidden. + * + * @param e The ComponentEvent fired. + */ + public void componentHidden(ComponentEvent e) + { + // Do nothing. + } + + /** + * This method is called when the JDesktopPane is moved. + * + * @param e The ComponentEvent fired. + */ + public void componentMoved(ComponentEvent e) + { + // Do nothing. + } + + /** + * This method is called when the JDesktopPane is resized. + * + * @param e The ComponentEvent fired. + */ + public void componentResized(ComponentEvent e) + { + if (frame.isMaximum()) + { + JDesktopPane pane = (JDesktopPane) e.getSource(); + Insets insets = pane.getInsets(); + Rectangle bounds = pane.getBounds(); + + frame.setBounds(bounds.x + insets.left, bounds.y + insets.top, + bounds.width - insets.left - insets.right, + bounds.height - insets.top - insets.bottom); + frame.revalidate(); + frame.repaint(); + } + + // Sun also resizes the icons. but it doesn't seem to do anything. + } + + /** + * This method is called when the JDesktopPane is shown. + * + * @param e The ComponentEvent fired. + */ + public void componentShown(ComponentEvent e) + { + // Do nothing. + } + } + + /** + * This helper class acts as the LayoutManager for JInternalFrames. + */ + public class InternalFrameLayout implements LayoutManager + { + /** + * This method is called when the given Component is added to the + * JInternalFrame. + * + * @param name The name of the Component. + * @param c The Component added. + */ + public void addLayoutComponent(String name, Component c) + { + } + + /** + * This method is used to set the bounds of the children of the + * JInternalFrame. + * + * @param c The Container to lay out. + */ + public void layoutContainer(Container c) + { + Dimension dims = frame.getSize(); + Insets insets = frame.getInsets(); + + dims.width -= insets.left + insets.right; + dims.height -= insets.top + insets.bottom; + + frame.getRootPane().getGlassPane().setBounds(0, 0, dims.width, + dims.height); + int nh = 0; + int sh = 0; + int ew = 0; + int ww = 0; + + if (northPane != null) + { + Dimension nDims = northPane.getPreferredSize(); + nh = Math.min(nDims.height, dims.height); + + northPane.setBounds(insets.left, insets.top, dims.width, nh); + } + + if (southPane != null) + { + Dimension sDims = southPane.getPreferredSize(); + sh = Math.min(sDims.height, dims.height - nh); + + southPane.setBounds(insets.left, insets.top + dims.height - sh, + dims.width, sh); + } + + int remHeight = dims.height - sh - nh; + + if (westPane != null) + { + Dimension wDims = westPane.getPreferredSize(); + ww = Math.min(dims.width, wDims.width); + + westPane.setBounds(insets.left, insets.top + nh, ww, remHeight); + } + + if (eastPane != null) + { + Dimension eDims = eastPane.getPreferredSize(); + ew = Math.min(eDims.width, dims.width - ww); + + eastPane.setBounds(insets.left + dims.width - ew, insets.top + nh, + ew, remHeight); + } + + int remWidth = dims.width - ww - ew; + + frame.getRootPane().setBounds(insets.left + ww, insets.top + nh, + remWidth, remHeight); + } + + /** + * This method returns the minimum layout size. + * + * @param c The Container to find a minimum layout size for. + * + * @return The minimum dimensions for the JInternalFrame. + */ + public Dimension minimumLayoutSize(Container c) + { + return getSize(c, true); + } + + /** + * This method returns the maximum layout size. + * + * @param c The Container to find a maximum layout size for. + * + * @return The maximum dimensions for the JInternalFrame. + */ + public Dimension maximumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * Th8is method returns the preferred layout size. + * + * @param c The Container to find a preferred layout size for. + * + * @return The preferred dimensions for the JInternalFrame. + */ + public Dimension preferredLayoutSize(Container c) + { + return getSize(c, false); + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + * @param min DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + private Dimension getSize(Container c, boolean min) + { + Insets insets = frame.getInsets(); + + Dimension contentDims = frame.getContentPane().getPreferredSize(); + if (min) + contentDims.width = contentDims.height = 0; + int nWidth = 0; + int nHeight = 0; + int sWidth = 0; + int sHeight = 0; + int eWidth = 0; + int eHeight = 0; + int wWidth = 0; + int wHeight = 0; + Dimension dims; + + if (northPane != null) + { + dims = northPane.getPreferredSize(); + if (dims != null) + { + nWidth = dims.width; + nHeight = dims.height; + } + } + + if (southPane != null) + { + dims = southPane.getPreferredSize(); + if (dims != null) + { + sWidth = dims.width; + sHeight = dims.height; + } + } + + if (eastPane != null) + { + dims = eastPane.getPreferredSize(); + if (dims != null) + { + sWidth = dims.width; + sHeight = dims.height; + } + } + + if (westPane != null) + { + dims = westPane.getPreferredSize(); + if (dims != null) + { + wWidth = dims.width; + wHeight = dims.height; + } + } + + int width = Math.max(sWidth, nWidth); + width = Math.max(width, contentDims.width + eWidth + wWidth); + + int height = Math.max(eHeight, wHeight); + height = Math.max(height, contentDims.height); + height += nHeight + sHeight; + + width += insets.left + insets.right; + height += insets.top + insets.bottom; + + return new Dimension(width, height); + } + + /** + * This method is called when a Component is removed from the + * JInternalFrame. + * + * @param c The Component that was removed. + */ + public void removeLayoutComponent(Component c) + { + } + } + + /** + * This helper class is used to listen to the JDesktopPane's glassPane for + * MouseEvents. The JInternalFrame can then be selected if a click is + * detected on its children. + */ + protected class GlassPaneDispatcher implements MouseInputListener + { + /** The MouseEvent target. */ + private transient Component mouseEventTarget; + + /** The component pressed. */ + private transient Component pressedComponent; + + /** The last component entered. */ + private transient Component lastComponentEntered; + + /** Used to store/reset lastComponentEntered. */ + private transient Component tempComponent; + + /** The number of presses. */ + private transient int pressCount; + + /** + * This method is called when the mouse enters the glass pane. + * + * @param e The MouseEvent. + */ + public void mouseEntered(MouseEvent e) + { + handleEvent(e); + } + + /** + * This method is called when the mouse is clicked on the glass pane. + * + * @param e The MouseEvent. + */ + public void mouseClicked(MouseEvent e) + { + handleEvent(e); + } + + /** + * This method is called when the mouse is dragged in the glass pane. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + handleEvent(e); + } + + /** + * This method is called when the mouse exits the glass pane. + * + * @param e The MouseEvent. + */ + public void mouseExited(MouseEvent e) + { + handleEvent(e); + } + + /** + * This method is called when the mouse is moved in the glass pane. + * + * @param e The MouseEvent. + */ + public void mouseMoved(MouseEvent e) + { + handleEvent(e); + } + + /** + * This method is called when the mouse is pressed in the glass pane. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + activateFrame(frame); + handleEvent(e); + } + + /** + * This method is called when the mouse is released in the glass pane. + * + * @param e The MouseEvent. + */ + public void mouseReleased(MouseEvent e) + { + handleEvent(e); + } + + /** + * This method acquires a candidate component to dispatch the MouseEvent + * to. + * + * @param me The MouseEvent to acquire a component for. + */ + private void acquireComponentForMouseEvent(MouseEvent me) + { + int x = me.getX(); + int y = me.getY(); + + // Find the candidate which should receive this event. + Component parent = frame.getContentPane(); + if (parent == null) + return; + Component candidate = null; + Point p = me.getPoint(); + while (candidate == null && parent != null) + { + candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); + if (candidate == null) + { + p = SwingUtilities.convertPoint(parent, p.x, p.y, + parent.getParent()); + parent = parent.getParent(); + } + } + + // If the only candidate we found was the native container itself, + // don't dispatch any event at all. We only care about the lightweight + // children here. + if (candidate == frame.getContentPane()) + candidate = null; + + // If our candidate is new, inform the old target we're leaving. + if (lastComponentEntered != null && lastComponentEntered.isShowing() + && lastComponentEntered != candidate) + { + Point tp = SwingUtilities.convertPoint(frame.getContentPane(), x, y, + lastComponentEntered); + MouseEvent exited = new MouseEvent(lastComponentEntered, + MouseEvent.MOUSE_EXITED, + me.getWhen(), me.getModifiersEx(), + tp.x, tp.y, me.getClickCount(), + me.isPopupTrigger(), + me.getButton()); + tempComponent = lastComponentEntered; + lastComponentEntered = null; + tempComponent.dispatchEvent(exited); + } + + // If we have a candidate, maybe enter it. + if (candidate != null) + { + mouseEventTarget = candidate; + if (candidate.isLightweight() && candidate.isShowing() + && candidate != frame.getContentPane() + && candidate != lastComponentEntered) + { + lastComponentEntered = mouseEventTarget; + Point cp = SwingUtilities.convertPoint(frame.getContentPane(), + x, y, lastComponentEntered); + MouseEvent entered = new MouseEvent(lastComponentEntered, + MouseEvent.MOUSE_ENTERED, + me.getWhen(), + me.getModifiersEx(), cp.x, + cp.y, me.getClickCount(), + me.isPopupTrigger(), + me.getButton()); + lastComponentEntered.dispatchEvent(entered); + } + } + + if (me.getID() == MouseEvent.MOUSE_RELEASED + || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0 + || me.getID() == MouseEvent.MOUSE_DRAGGED) + // If any of the following events occur while a button is held down, + // they should be dispatched to the same component to which the + // original MOUSE_PRESSED event was dispatched: + // - MOUSE_RELEASED + // - MOUSE_PRESSED: another button pressed while the first is held down + // - MOUSE_DRAGGED + mouseEventTarget = pressedComponent; + else if (me.getID() == MouseEvent.MOUSE_CLICKED) + { + // Don't dispatch CLICKED events whose target is not the same as the + // target for the original PRESSED event. + if (candidate != pressedComponent) + mouseEventTarget = null; + else if (pressCount == 0) + pressedComponent = null; + } + } + + /** + * This is a helper method that dispatches the GlassPane MouseEvents to + * the proper component. + * + * @param e The AWTEvent to be dispatched. Usually an instance of + * MouseEvent. + */ + private void handleEvent(AWTEvent e) + { + if (e instanceof MouseEvent) + { + MouseEvent me = SwingUtilities.convertMouseEvent(frame.getRootPane() + .getGlassPane(), + (MouseEvent) e, + frame.getRootPane() + .getGlassPane()); + + acquireComponentForMouseEvent(me); + + // Avoid dispatching ENTERED and EXITED events twice. + if (mouseEventTarget != null && mouseEventTarget.isShowing() + && e.getID() != MouseEvent.MOUSE_ENTERED + && e.getID() != MouseEvent.MOUSE_EXITED) + { + MouseEvent newEvt = SwingUtilities.convertMouseEvent(frame + .getContentPane(), + me, + mouseEventTarget); + mouseEventTarget.dispatchEvent(newEvt); + + switch (e.getID()) + { + case MouseEvent.MOUSE_PRESSED: + if (pressCount++ == 0) + pressedComponent = mouseEventTarget; + break; + case MouseEvent.MOUSE_RELEASED: + // Clear our memory of the original PRESSED event, only if + // we're not expecting a CLICKED event after this. If + // there is a CLICKED event after this, it will do clean up. + if (--pressCount == 0 + && mouseEventTarget != pressedComponent) + pressedComponent = null; + break; + } + } + } + } + } + + /** + * This helper class listens for PropertyChangeEvents from the + * JInternalFrame. + */ + public class InternalFramePropertyChangeListener + implements PropertyChangeListener, VetoableChangeListener + { + + /** + * This method is called when one of the JInternalFrame's properties + * change. This method is to allow JInternalFrame to veto an attempt + * to close the internal frame. This allows JInternalFrame to honour + * its defaultCloseOperation if that is DO_NOTHING_ON_CLOSE. + */ + public void vetoableChange(PropertyChangeEvent e) throws PropertyVetoException + { + if (e.getPropertyName().equals(JInternalFrame.IS_CLOSED_PROPERTY)) + { + if (frame.getDefaultCloseOperation() == JInternalFrame.HIDE_ON_CLOSE) + { + frame.setVisible(false); + frame.getDesktopPane().repaint(); + throw new PropertyVetoException ("close operation is HIDE_ON_CLOSE\n", e); + } + else if (frame.getDefaultCloseOperation() == JInternalFrame.DISPOSE_ON_CLOSE) + closeFrame(frame); + else + throw new PropertyVetoException ("close operation is DO_NOTHING_ON_CLOSE\n", e); + } + } + + /** + * This method is called when one of the JInternalFrame's properties + * change. + * + * @param evt The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent evt) + { + if (evt.getPropertyName().equals(JInternalFrame.IS_MAXIMUM_PROPERTY)) + { + if (frame.isMaximum()) + maximizeFrame(frame); + else + minimizeFrame(frame); + } + else if (evt.getPropertyName().equals(JInternalFrame.IS_ICON_PROPERTY)) + { + if (frame.isIcon()) + iconifyFrame(frame); + else + deiconifyFrame(frame); + } + else if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY)) + { + if (frame.isSelected()) + activateFrame(frame); + else + getDesktopManager().deactivateFrame(frame); + } + else if (evt.getPropertyName().equals(JInternalFrame.ROOT_PANE_PROPERTY) + || evt.getPropertyName().equals(JInternalFrame.GLASS_PANE_PROPERTY)) + { + Component old = (Component) evt.getOldValue(); + old.removeMouseListener(glassPaneDispatcher); + old.removeMouseMotionListener(glassPaneDispatcher); + + Component newPane = (Component) evt.getNewValue(); + newPane.addMouseListener(glassPaneDispatcher); + newPane.addMouseMotionListener(glassPaneDispatcher); + + frame.revalidate(); + } + /* FIXME: need to add ancestor properties to JComponents. + else if (evt.getPropertyName().equals(JComponent.ANCESTOR_PROPERTY)) + { + if (desktopPane != null) + desktopPane.removeComponentListener(componentListener); + desktopPane = frame.getDesktopPane(); + if (desktopPane != null) + desktopPane.addComponentListener(componentListener); + } + */ + } + } + + /** + * This helper class is the border for the JInternalFrame. + */ + private class InternalFrameBorder extends AbstractBorder + implements UIResource + { + /** The width of the border. */ + private static final int bSize = 5; + + /** The size of the corners. */ + private static final int offset = 10; + + /** + * This method returns whether the border is opaque. + * + * @return Whether the border is opaque. + */ + public boolean isBorderOpaque() + { + return true; + } + + /** + * This method returns the insets of the border. + * + * @param c The Component to find border insets for. + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(bSize, bSize, bSize, bSize); + } + + /** + * This method paints the border. + * + * @param c The Component that owns the border. + * @param g The Graphics object to paint with. + * @param x The x coordinate to paint at. + * @param y The y coordinate to paint at. + * @param width The width of the Component. + * @param height The height of the Component. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) + { + g.translate(x, y); + Color saved = g.getColor(); + Rectangle b = frame.getBounds(); + + Color d = c.getBackground(); + g.setColor(d); + g.fillRect(0, 0, bSize, b.height); + g.fillRect(0, 0, b.width, bSize); + g.fillRect(0, b.height - bSize, b.width, bSize); + g.fillRect(b.width - bSize, 0, bSize, b.height); + + int x1 = 0; + int x2 = bSize; + int x3 = b.width - bSize; + int x4 = b.width; + + int y1 = 0; + int y2 = bSize; + int y3 = b.height - bSize; + int y4 = b.height; + + g.setColor(Color.GRAY); + g.fillRect(0, 0, bSize, y4); + g.fillRect(0, 0, x4, bSize); + g.fillRect(0, y3, b.width, bSize); + g.fillRect(x3, 0, bSize, b.height); + + g.fill3DRect(0, offset, bSize, b.height - 2 * offset, false); + g.fill3DRect(offset, 0, b.width - 2 * offset, bSize, false); + g.fill3DRect(offset, b.height - bSize, b.width - 2 * offset, bSize, false); + g.fill3DRect(b.width - bSize, offset, bSize, b.height - 2 * offset, false); + + g.translate(-x, -y); + g.setColor(saved); + } + } + + /** + * The MouseListener that is responsible for dragging and resizing the + * JInternalFrame in response to MouseEvents. + */ + protected MouseInputAdapter borderListener; + + /** + * The ComponentListener that is responsible for resizing the JInternalFrame + * in response to ComponentEvents from the JDesktopPane. + */ + protected ComponentListener componentListener; + + /** + * The MouseListener that is responsible for activating the JInternalFrame + * when the mouse press activates one of its descendents. + */ + protected MouseInputListener glassPaneDispatcher; + + /** + * The PropertyChangeListener that is responsible for listening to + * PropertyChangeEvents from the JInternalFrame. + */ + protected PropertyChangeListener propertyChangeListener; + + /** + * The VetoableChangeListener. Listens to PropertyChangeEvents + * from the JInternalFrame and allows the JInternalFrame to + * veto attempts to close it. + */ + private VetoableChangeListener internalFrameVetoableChangeListener; + + /** The InternalFrameListener that listens to the JInternalFrame. */ + private transient BasicInternalFrameListener internalFrameListener; + + /** The JComponent placed at the east region of the JInternalFrame. */ + protected JComponent eastPane; + + /** The JComponent placed at the north region of the JInternalFrame. */ + protected JComponent northPane; + + /** The JComponent placed at the south region of the JInternalFrame. */ + protected JComponent southPane; + + /** The JComponent placed at the west region of the JInternalFrame. */ + protected JComponent westPane; + + /** + * The Keystroke bound to open the menu. + * @deprecated + */ + protected KeyStroke openMenuKey; + + /** The TitlePane displayed at the top of the JInternalFrame. */ + protected BasicInternalFrameTitlePane titlePane; + + /** The JInternalFrame this UI is responsible for. */ + protected JInternalFrame frame; + + /** The LayoutManager used in the JInternalFrame. */ + protected LayoutManager internalFrameLayout; + + /** The JDesktopPane that is the parent of the JInternalFrame. */ + private transient JDesktopPane desktopPane; + + /** + * Creates a new BasicInternalFrameUI object. + * + * @param b The JInternalFrame this UI will represent. + */ + public BasicInternalFrameUI(JInternalFrame b) + { + } + + /** + * This method will create a new BasicInternalFrameUI for the given + * JComponent. + * + * @param b The JComponent to create a BasicInternalFrameUI for. + * + * @return A new BasicInternalFrameUI. + */ + public static ComponentUI createUI(JComponent b) + { + return new BasicInternalFrameUI((JInternalFrame) b); + } + + /** + * This method installs a UI for the JInternalFrame. + * + * @param c The JComponent to install this UI on. + */ + public void installUI(JComponent c) + { + if (c instanceof JInternalFrame) + { + frame = (JInternalFrame) c; + + internalFrameLayout = createLayoutManager(); + frame.setLayout(internalFrameLayout); + + ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); + frame.getRootPane().getGlassPane().setVisible(true); + + installDefaults(); + installListeners(); + installComponents(); + installKeyboardActions(); + + frame.setOpaque(true); + titlePane.setOpaque(true); + frame.invalidate(); + } + } + + /** + * This method reverses the work done by installUI. + * + * @param c The JComponent to uninstall this UI for. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallComponents(); + uninstallListeners(); + uninstallDefaults(); + + frame.setLayout(null); + ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(true); + frame.getRootPane().getGlassPane().setVisible(false); + + frame = null; + } + + /** + * This method installs the defaults specified by the look and feel. + */ + protected void installDefaults() + { + // This is the border of InternalFrames in the BasicLookAndFeel. + // Note that there exist entries for various border colors in + // BasicLookAndFeel's defaults, but obviously they differ + // from the colors that are actually used by the JDK. + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + Color borderColor = defaults.getColor("InternalFrame.borderColor"); + Border inner = BorderFactory.createLineBorder(borderColor, 1); + Color borderDarkShadow = defaults.getColor + ("InternalFrame.borderDarkShadow"); + Color borderHighlight = defaults.getColor + ("InternalFrame.borderHighlight"); + Color borderShadow = defaults.getColor("InternalFrame.borderShadow"); + Color borderLight = defaults.getColor("InternalFrame.borderLight"); + Border outer = BorderFactory.createBevelBorder(BevelBorder.RAISED, + borderShadow, + borderHighlight, + borderDarkShadow, + borderShadow); + Border border = new BorderUIResource.CompoundBorderUIResource(outer, + inner); + frame.setBorder(border); + + // InternalFrames are invisible by default. + frame.setVisible(false); + } + + /** + * This method installs the keyboard actions for the JInternalFrame. + */ + protected void installKeyboardActions() + { + // FIXME: Implement. + } + + /** + * This method installs the Components for the JInternalFrame. + */ + protected void installComponents() + { + setNorthPane(createNorthPane(frame)); + setSouthPane(createSouthPane(frame)); + setEastPane(createEastPane(frame)); + setWestPane(createWestPane(frame)); + } + + /** + * This method installs the listeners for the JInternalFrame. + */ + protected void installListeners() + { + glassPaneDispatcher = createGlassPaneDispatcher(); + createInternalFrameListener(); + borderListener = createBorderListener(frame); + componentListener = createComponentListener(); + propertyChangeListener = createPropertyChangeListener(); + internalFrameVetoableChangeListener = new InternalFramePropertyChangeListener(); + + frame.addMouseListener(borderListener); + frame.addMouseMotionListener(borderListener); + frame.addInternalFrameListener(internalFrameListener); + frame.addPropertyChangeListener(propertyChangeListener); + frame.addVetoableChangeListener(internalFrameVetoableChangeListener); + frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher); + frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher); + } + + /** + * This method uninstalls the defaults for the JInternalFrame. + */ + protected void uninstallDefaults() + { + frame.setBorder(null); + } + + /** + * This method uninstalls the Components for the JInternalFrame. + */ + protected void uninstallComponents() + { + setNorthPane(null); + setSouthPane(null); + setEastPane(null); + setWestPane(null); + } + + /** + * This method uninstalls the listeners for the JInternalFrame. + */ + protected void uninstallListeners() + { + if (desktopPane != null) + desktopPane.removeComponentListener(componentListener); + + frame.getRootPane().getGlassPane().removeMouseMotionListener(glassPaneDispatcher); + frame.getRootPane().getGlassPane().removeMouseListener(glassPaneDispatcher); + + frame.removePropertyChangeListener(propertyChangeListener); + frame.removeInternalFrameListener(internalFrameListener); + frame.removeMouseMotionListener(borderListener); + frame.removeMouseListener(borderListener); + + propertyChangeListener = null; + componentListener = null; + borderListener = null; + internalFrameListener = null; + glassPaneDispatcher = null; + } + + /** + * This method uninstalls the keyboard actions for the JInternalFrame. + */ + protected void uninstallKeyboardActions() + { + // FIXME: Implement. + } + + /** + * This method creates a new LayoutManager for the JInternalFrame. + * + * @return A new LayoutManager for the JInternalFrame. + */ + protected LayoutManager createLayoutManager() + { + return new InternalFrameLayout(); + } + + /** + * This method creates a new PropertyChangeListener for the JInternalFrame. + * + * @return A new PropertyChangeListener for the JInternalFrame. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new InternalFramePropertyChangeListener(); + } + + /** + * This method returns the preferred size of the given JComponent. + * + * @param x The JComponent to find a preferred size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent x) + { + return internalFrameLayout.preferredLayoutSize(x); + } + + /** + * This method returns the minimum size of the given JComponent. + * + * @param x The JComponent to find a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent x) + { + return internalFrameLayout.minimumLayoutSize(x); + } + + /** + * This method returns the maximum size of the given JComponent. + * + * @param x The JComponent to find a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent x) + { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * This method replaces the currentPane with the newPane. When replacing it + * also removes the MouseHandlers for the old pane and installs them on + * the new pane. + * + * @param currentPane The old pane to remove. + * @param newPane The new pane to install. + */ + protected void replacePane(JComponent currentPane, JComponent newPane) + { + if (currentPane != null) + { + deinstallMouseHandlers(currentPane); + frame.remove(currentPane); + } + + if (newPane != null) + { + installMouseHandlers(newPane); + frame.add(newPane); + } + } + + /** + * This method removes the necessary MouseListeners from the given + * JComponent. + * + * @param c The JComponent to remove MouseListeners from. + */ + protected void deinstallMouseHandlers(JComponent c) + { + c.removeMouseListener(borderListener); + c.removeMouseMotionListener(borderListener); + } + + /** + * This method installs the necessary MouseListeners from the given + * JComponent. + * + * @param c The JComponent to install MouseListeners on. + */ + protected void installMouseHandlers(JComponent c) + { + c.addMouseListener(borderListener); + c.addMouseMotionListener(borderListener); + } + + /** + * This method creates the north pane used in the JInternalFrame. + * + * @param w The JInternalFrame to create a north pane for. + * + * @return The north pane. + */ + protected JComponent createNorthPane(JInternalFrame w) + { + titlePane = new BasicInternalFrameTitlePane(w); + return titlePane; + } + + /** + * This method creates the west pane used in the JInternalFrame. + * + * @param w The JInternalFrame to create a west pane for. + * + * @return The west pane. + */ + protected JComponent createWestPane(JInternalFrame w) + { + return null; + } + + /** + * This method creates the south pane used in the JInternalFrame. + * + * @param w The JInternalFrame to create a south pane for. + * + * @return The south pane. + */ + protected JComponent createSouthPane(JInternalFrame w) + { + return null; + } + + /** + * This method creates the east pane used in the JInternalFrame. + * + * @param w The JInternalFrame to create an east pane for. + * + * @return The east pane. + */ + protected JComponent createEastPane(JInternalFrame w) + { + return null; + } + + /** + * This method returns a new BorderListener for the given JInternalFrame. + * + * @param w The JIntenalFrame to create a BorderListener for. + * + * @return A new BorderListener. + */ + protected MouseInputAdapter createBorderListener(JInternalFrame w) + { + return new BorderListener(); + } + + /** + * This method creates a new InternalFrameListener for the JInternalFrame. + */ + protected void createInternalFrameListener() + { + internalFrameListener = new BasicInternalFrameListener(); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + protected final boolean isKeyBindingRegistered() + { + // FIXME: Implement. + return false; + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + protected final void setKeyBindingRegistered(boolean b) + { + // FIXME: Implement. + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public final boolean isKeyBindingActive() + { + // FIXME: Implement. + return false; + } + + /** + * DOCUMENT ME! + * + * @param b DOCUMENT ME! + */ + protected final void setKeyBindingActive(boolean b) + { + // FIXME: Implement. + } + + /** + * DOCUMENT ME! + */ + protected void setupMenuOpenKey() + { + // FIXME: Implement. + } + + /** + * DOCUMENT ME! + */ + protected void setupMenuCloseKey() + { + // FIXME: Implement. + } + + /** + * This method returns the north pane. + * + * @return The north pane. + */ + public JComponent getNorthPane() + { + return northPane; + } + + /** + * This method sets the north pane to be the given JComponent. + * + * @param c The new north pane. + */ + public void setNorthPane(JComponent c) + { + replacePane(northPane, c); + northPane = c; + } + + /** + * This method returns the south pane. + * + * @return The south pane. + */ + public JComponent getSouthPane() + { + return southPane; + } + + /** + * This method sets the south pane to be the given JComponent. + * + * @param c The new south pane. + */ + public void setSouthPane(JComponent c) + { + replacePane(southPane, c); + southPane = c; + } + + /** + * This method sets the east pane to be the given JComponent. + * + * @param c The new east pane. + */ + public void setEastPane(JComponent c) + { + replacePane(eastPane, c); + eastPane = c; + } + + /** + * This method returns the east pane. + * + * @return The east pane. + */ + public JComponent getEastPane() + { + return eastPane; + } + + /** + * This method sets the west pane to be the given JComponent. + * + * @param c The new west pane. + */ + public void setWestPane(JComponent c) + { + replacePane(westPane, c); + westPane = c; + } + + /** + * This method returns the west pane. + * + * @return The west pane. + */ + public JComponent getWestPane() + { + return westPane; + } + + /** + * This method returns the DesktopManager to use with the JInternalFrame. + * + * @return The DesktopManager to use with the JInternalFrame. + */ + protected DesktopManager getDesktopManager() + { + DesktopManager value = null; + JDesktopPane pane = frame.getDesktopPane(); + if (pane != null) + value = frame.getDesktopPane().getDesktopManager(); + if (value == null) + value = createDesktopManager(); + return value; + } + + /** + * This method returns a default DesktopManager that can be used with this + * JInternalFrame. + * + * @return A default DesktopManager that can be used with this + * JInternalFrame. + */ + protected DesktopManager createDesktopManager() + { + return new DefaultDesktopManager(); + } + + /** + * This is a convenience method that closes the JInternalFrame. + * + * @param f The JInternalFrame to close. + */ + protected void closeFrame(JInternalFrame f) + { + getDesktopManager().closeFrame(f); + } + + /** + * This is a convenience method that maximizes the JInternalFrame. + * + * @param f The JInternalFrame to maximize. + */ + protected void maximizeFrame(JInternalFrame f) + { + getDesktopManager().maximizeFrame(f); + } + + /** + * This is a convenience method that minimizes the JInternalFrame. + * + * @param f The JInternalFrame to minimize. + */ + protected void minimizeFrame(JInternalFrame f) + { + getDesktopManager().minimizeFrame(f); + } + + /** + * This is a convenience method that iconifies the JInternalFrame. + * + * @param f The JInternalFrame to iconify. + */ + protected void iconifyFrame(JInternalFrame f) + { + getDesktopManager().iconifyFrame(f); + } + + /** + * This is a convenience method that deiconifies the JInternalFrame. + * + * @param f The JInternalFrame to deiconify. + */ + protected void deiconifyFrame(JInternalFrame f) + { + getDesktopManager().deiconifyFrame(f); + } + + /** + * This is a convenience method that activates the JInternalFrame. + * + * @param f The JInternalFrame to activate. + */ + protected void activateFrame(JInternalFrame f) + { + getDesktopManager().activateFrame(f); + } + + /** + * This method returns a new ComponentListener for the JDesktopPane. + * + * @return A new ComponentListener. + */ + protected ComponentListener createComponentListener() + { + return new ComponentHandler(); + } + + /** + * This method returns a new GlassPaneDispatcher. + * + * @return A new GlassPaneDispatcher. + */ + protected MouseInputListener createGlassPaneDispatcher() + { + return new GlassPaneDispatcher(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java new file mode 100644 index 00000000000..e71e82f03d1 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java @@ -0,0 +1,425 @@ +/* BasicLabelUI.java + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.LabelUI; + + +/** + * This is the Basic Look and Feel class for the JLabel. One BasicLabelUI + * object is used to paint all JLabels that utilize the Basic Look and Feel. + */ +public class BasicLabelUI extends LabelUI implements PropertyChangeListener +{ + /** The labelUI that is shared by all labels. */ + protected static BasicLabelUI labelUI; + + /** + * Creates a new BasicLabelUI object. + */ + public BasicLabelUI() + { + super(); + } + + /** + * Creates and returns a UI for the label. Since one UI is shared by all + * labels, this means creating only if necessary and returning the shared + * UI. + * + * @param c The {@link JComponent} that a UI is being created for. + * + * @return A label UI for the Basic Look and Feel. + */ + public static ComponentUI createUI(JComponent c) + { + if (labelUI == null) + labelUI = new BasicLabelUI(); + return labelUI; + } + + /** + * Returns the preferred size of this component as calculated by the + * {@link #layoutCL(JLabel, FontMetrics, String, Icon, Rectangle, Rectangle, + * Rectangle)} method. + * + * @param c This {@link JComponent} to get a preferred size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + JLabel lab = (JLabel)c; + Rectangle vr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + Insets insets = lab.getInsets(); + FontMetrics fm = lab.getToolkit().getFontMetrics(lab.getFont()); + layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr); + Rectangle cr = tr.union(ir); + return new Dimension(insets.left + cr.width + insets.right, + insets.top + cr.height + insets.bottom); + + } + + /** + * This method returns the minimum size of the {@link JComponent} given. If + * this method returns null, then it is up to the Layout Manager to give + * this component a minimum size. + * + * @param c The {@link JComponent} to get a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum size of the {@link JComponent} given. If + * this method returns null, then it is up to the Layout Manager to give + * this component a maximum size. + * + * @param c The {@link JComponent} to get a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * The method that paints the label according to its current state. + * + * @param g The {@link Graphics} object to paint with. + * @param c The {@link JComponent} to paint. + */ + public void paint(Graphics g, JComponent c) + { + JLabel b = (JLabel) c; + + Font saved_font = g.getFont(); + + Rectangle tr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle vr = new Rectangle(); + + Font f = c.getFont(); + + g.setFont(f); + FontMetrics fm = g.getFontMetrics(f); + + vr = SwingUtilities.calculateInnerArea(c, vr); + + if (vr.width < 0) + vr.width = 0; + if (vr.height < 0) + vr.height = 0; + + Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon(); + + String text = layoutCL(b, fm, b.getText(), icon, vr, ir, tr); + + if (icon != null) + icon.paintIcon(b, g, ir.x, ir.y); + if (text != null && ! text.equals("")) + { + if (b.isEnabled()) + paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + else + paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + } + g.setFont(saved_font); + } + + /** + * This method is simply calls SwingUtilities's layoutCompoundLabel. + * + * @param label The label to lay out. + * @param fontMetrics The FontMetrics for the font used. + * @param text The text to paint. + * @param icon The icon to draw. + * @param viewR The entire viewable rectangle. + * @param iconR The icon bounds rectangle. + * @param textR The text bounds rectangle. + * + * @return A possibly clipped version of the text. + */ + protected String layoutCL(JLabel label, FontMetrics fontMetrics, + String text, Icon icon, Rectangle viewR, + Rectangle iconR, Rectangle textR) + { + return SwingUtilities.layoutCompoundLabel(label, fontMetrics, text, icon, + label.getVerticalAlignment(), + label.getHorizontalAlignment(), + label.getVerticalTextPosition(), + label.getHorizontalTextPosition(), + viewR, iconR, textR, + label.getIconTextGap()); + } + + /** + * Paints the text if the label is disabled. By default, this paints the + * clipped text returned by layoutCompoundLabel using the + * background.brighter() color. It also paints the same text using the + * background.darker() color one pixel to the right and one pixel down. + * + * @param l The {@link JLabel} being painted. + * @param g The {@link Graphics} object to paint with. + * @param s The String to paint. + * @param textX The x coordinate of the start of the baseline. + * @param textY The y coordinate of the start of the baseline. + */ + protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, + int textY) + { + Color saved_color = g.getColor(); + + g.setColor(l.getBackground().brighter()); + + int mnemIndex = l.getDisplayedMnemonicIndex(); + + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, + textY); + else + g.drawString(s, textX, textY); + + g.setColor(l.getBackground().darker()); + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX + 1, + textY + 1); + else + g.drawString(s, textX + 1, textY + 1); + + g.setColor(saved_color); + } + + /** + * Paints the text if the label is enabled. The text is painted using the + * foreground color. + * + * @param l The {@link JLabel} being painted. + * @param g The {@link Graphics} object to paint with. + * @param s The String to paint. + * @param textX The x coordinate of the start of the baseline. + * @param textY The y coordinate of the start of the baseline. + */ + protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, + int textY) + { + Color saved_color = g.getColor(); + g.setColor(l.getForeground()); + + int mnemIndex = l.getDisplayedMnemonicIndex(); + + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, + textY); + else + g.drawString(s, textX, textY); + + g.setColor(saved_color); + } + + /** + * This method installs the UI for the given {@link JComponent}. This + * method will install the component, defaults, listeners, and keyboard + * actions. + * + * @param c The {@link JComponent} that this UI is being installed on. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JLabel) + { + JLabel l = (JLabel) c; + + installComponents(l); + installDefaults(l); + installListeners(l); + installKeyboardActions(l); + } + } + + /** + * This method uninstalls the UI for the given {@link JComponent}. This + * method will uninstall the component, defaults, listeners, and keyboard + * actions. + * + * @param c The {@link JComponent} that this UI is being installed on. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + if (c instanceof JLabel) + { + JLabel l = (JLabel) c; + + uninstallKeyboardActions(l); + uninstallListeners(l); + uninstallDefaults(l); + uninstallComponents(l); + } + } + + /** + * This method installs the components for this {@link JLabel}. + * + * @param c The {@link JLabel} to install components for. + */ + protected void installComponents(JLabel c) + { + //FIXME: fix javadoc + implement. + } + + /** + * This method uninstalls the components for this {@link JLabel}. + * + * @param c The {@link JLabel} to uninstall components for. + */ + protected void uninstallComponents(JLabel c) + { + //FIXME: fix javadoc + implement. + } + + /** + * This method installs the defaults that are defined in the Basic look and + * feel for this {@link JLabel}. + * + * @param c The {@link JLabel} to install defaults for. + */ + protected void installDefaults(JLabel c) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + c.setForeground(defaults.getColor("Label.foreground")); + c.setBackground(defaults.getColor("Label.background")); + c.setFont(defaults.getFont("Label.font")); + //XXX: There are properties we don't use called disabledForeground + //and disabledShadow. + } + + /** + * This method uninstalls the defaults that are defined in the Basic look + * and feel for this {@link JLabel}. + * + * @param c The {@link JLabel} to uninstall defaults for. + */ + protected void uninstallDefaults(JLabel c) + { + c.setForeground(null); + c.setBackground(null); + c.setFont(null); + } + + /** + * This method installs the keyboard actions for the given {@link JLabel}. + * + * @param l The {@link JLabel} to install keyboard actions for. + */ + protected void installKeyboardActions(JLabel l) + { + //FIXME: implement. + } + + /** + * This method uninstalls the keyboard actions for the given {@link JLabel}. + * + * @param l The {@link JLabel} to uninstall keyboard actions for. + */ + protected void uninstallKeyboardActions(JLabel l) + { + //FIXME: implement. + } + + /** + * This method installs the listeners for the given {@link JLabel}. The UI + * delegate only listens to the label. + * + * @param c The {@link JLabel} to install listeners for. + */ + protected void installListeners(JLabel c) + { + c.addPropertyChangeListener(this); + } + + /** + * This method uninstalls the listeners for the given {@link JLabel}. The UI + * delegate only listens to the label. + * + * @param c The {@link JLabel} to uninstall listeners for. + */ + protected void uninstallListeners(JLabel c) + { + c.removePropertyChangeListener(this); + } + + /** + * This method is called whenever any JLabel's that use this UI has one of + * their properties change. + * + * @param e The {@link PropertyChangeEvent} that describes the change. + */ + public void propertyChange(PropertyChangeEvent e) + { + JLabel c = (JLabel) e.getSource(); + c.revalidate(); + c.repaint(); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java new file mode 100644 index 00000000000..24c6cd20b61 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java @@ -0,0 +1,1004 @@ +/* BasicListUI.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.CellRendererPane; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JViewport; +import javax.swing.ListCellRenderer; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ListUI; + +/** + * The Basic Look and Feel UI delegate for the + * JList. + */ +public class BasicListUI extends ListUI +{ + + /** + * A helper class which listens for {@link ComponentEvent}s from + * the JList. + */ + private class ComponentHandler extends ComponentAdapter { + + /** + * Called when the component is hidden. Invalidates the internal + * layout. + */ + public void componentResized(ComponentEvent ev) { + BasicListUI.this.damageLayout(); + } + } + + /** + * A helper class which listens for {@link FocusEvent}s + * from the JList. + */ + public class FocusHandler implements FocusListener + { + /** + * Called when the JList acquires focus. + * + * @param e The FocusEvent representing focus acquisition + */ + public void focusGained(FocusEvent e) + { + repaintCellFocus(); + } + + /** + * Called when the JList loses focus. + * + * @param e The FocusEvent representing focus loss + */ + public void focusLost(FocusEvent e) + { + repaintCellFocus(); + } + + /** + * Helper method to repaint the focused cell's + * lost or acquired focus state. + */ + void repaintCellFocus() + { + } + } + + /** + * A helper class which listens for {@link ListDataEvent}s generated by + * the {@link JList}'s {@link ListModel}. + * + * @see javax.swing.JList#getModel() + */ + public class ListDataHandler implements ListDataListener + { + /** + * Called when a general change has happened in the model which cannot + * be represented in terms of a simple addition or deletion. + * + * @param e The event representing the change + */ + public void contentsChanged(ListDataEvent e) + { + BasicListUI.this.damageLayout(); + } + + /** + * Called when an interval of objects has been added to the model. + * + * @param e The event representing the addition + */ + public void intervalAdded(ListDataEvent e) + { + BasicListUI.this.damageLayout(); + } + + /** + * Called when an inteval of objects has been removed from the model. + * + * @param e The event representing the removal + */ + public void intervalRemoved(ListDataEvent e) + { + BasicListUI.this.damageLayout(); + } + } + + /** + * A helper class which listens for {@link ListSelectionEvent}s + * from the {@link JList}'s {@link ListSelectionModel}. + */ + public class ListSelectionHandler implements ListSelectionListener + { + /** + * Called when the list selection changes. + * + * @param e The event representing the change + */ + public void valueChanged(ListSelectionEvent e) + { + } + } + + /** + * A helper class which listens for {@link KeyEvents}s + * from the {@link JList}. + */ + private class KeyHandler extends KeyAdapter + { + public KeyHandler() + { + } + + public void keyPressed( KeyEvent evt ) + { + int lead = BasicListUI.this.list.getLeadSelectionIndex(); + int max = BasicListUI.this.list.getModel().getSize() - 1; + // Do nothing if list is empty + if (max == -1) + return; + + // Process the key event. Bindings can be found in + // javax.swing.plaf.basic.BasicLookAndFeel.java + if ((evt.getKeyCode() == KeyEvent.VK_DOWN) + || (evt.getKeyCode() == KeyEvent.VK_KP_DOWN)) + { + if (!evt.isShiftDown()) + { + BasicListUI.this.list.clearSelection(); + BasicListUI.this.list.setSelectedIndex(Math.min(lead+1,max)); + } + else + { + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(Math.min(lead+1,max)); + } + } + else if ((evt.getKeyCode() == KeyEvent.VK_UP) + || (evt.getKeyCode() == KeyEvent.VK_KP_UP)) + { + if (!evt.isShiftDown()) + { + BasicListUI.this.list.clearSelection(); + BasicListUI.this.list.setSelectedIndex(Math.max(lead-1,0)); + } + else + { + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(Math.max(lead-1,0)); + } + } + else if (evt.getKeyCode() == KeyEvent.VK_PAGE_UP) + { + // FIXME: implement, need JList.ensureIndexIsVisible to work + } + else if (evt.getKeyCode() == KeyEvent.VK_PAGE_DOWN) + { + // FIXME: implement, need JList.ensureIndexIsVisible to work + } + else if (evt.getKeyCode() == KeyEvent.VK_BACK_SLASH + && evt.isControlDown()) + { + BasicListUI.this.list.clearSelection(); + } + else if ((evt.getKeyCode() == KeyEvent.VK_HOME) + || evt.getKeyCode() == KeyEvent.VK_END) + { + // index is either 0 for HOME, or last cell for END + int index = (evt.getKeyCode() == KeyEvent.VK_HOME) ? 0 : max; + + if (!evt.isShiftDown() ||(BasicListUI.this.list.getSelectionMode() + == ListSelectionModel.SINGLE_SELECTION)) + BasicListUI.this.list.setSelectedIndex(index); + else if (BasicListUI.this.list.getSelectionMode() == + ListSelectionModel.SINGLE_INTERVAL_SELECTION) + BasicListUI.this.list.setSelectionInterval + (BasicListUI.this.list.getAnchorSelectionIndex(), index); + else + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(index); + } + else if ((evt.getKeyCode() == KeyEvent.VK_A || evt.getKeyCode() + == KeyEvent.VK_SLASH) && evt.isControlDown()) + { + BasicListUI.this.list.setSelectionInterval(0, max); + } + else if (evt.getKeyCode() == KeyEvent.VK_SPACE && evt.isControlDown()) + { + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(Math.min(lead+1,max)); + } + + } + } + + /** + * A helper class which listens for {@link MouseEvent}s + * from the {@link JList}. + */ + public class MouseInputHandler implements MouseInputListener + { + /** + * Called when a mouse button press/release cycle completes + * on the {@link JList} + * + * @param event The event representing the mouse click + */ + public void mouseClicked(MouseEvent event) + { + Point click = event.getPoint(); + int index = BasicListUI.this.locationToIndex(list, click); + if (index == -1) + return; + if (event.isControlDown()) + { + if (BasicListUI.this.list.getSelectionMode() == + ListSelectionModel.SINGLE_SELECTION) + BasicListUI.this.list.setSelectedIndex(index); + else if (BasicListUI.this.list.isSelectedIndex(index)) + BasicListUI.this.list.removeSelectionInterval(index,index); + else + BasicListUI.this.list.addSelectionInterval(index,index); + } + else if (event.isShiftDown()) + { + if (BasicListUI.this.list.getSelectionMode() == + ListSelectionModel.SINGLE_SELECTION) + BasicListUI.this.list.setSelectedIndex(index); + else if (BasicListUI.this.list.getSelectionMode() == + ListSelectionModel.SINGLE_INTERVAL_SELECTION) + // COMPAT: the IBM VM is compatible with the following line of code. + // However, compliance with Sun's VM would correspond to replacing + // getAnchorSelectionIndex() with getLeadSelectionIndex().This is + // both unnatural and contradictory to the way they handle other + // similar UI interactions. + BasicListUI.this.list.setSelectionInterval + (BasicListUI.this.list.getAnchorSelectionIndex(), index); + else + // COMPAT: both Sun and IBM are compatible instead with: + // BasicListUI.this.list.setSelectionInterval + // (BasicListUI.this.list.getLeadSelectionIndex(),index); + // Note that for IBM this is contradictory to what they did in + // the above situation for SINGLE_INTERVAL_SELECTION. + // The most natural thing to do is the following: + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(index); + } + else + BasicListUI.this.list.setSelectedIndex(index); + } + + /** + * Called when a mouse button is pressed down on the + * {@link JList}. + * + * @param event The event representing the mouse press + */ + public void mousePressed(MouseEvent event) + { + } + + /** + * Called when a mouse button is released on + * the {@link JList} + * + * @param event The event representing the mouse press + */ + public void mouseReleased(MouseEvent event) + { + } + + /** + * Called when the mouse pointer enters the area bounded + * by the {@link JList} + * + * @param event The event representing the mouse entry + */ + public void mouseEntered(MouseEvent event) + { + } + + /** + * Called when the mouse pointer leaves the area bounded + * by the {@link JList} + * + * @param event The event representing the mouse exit + */ + public void mouseExited(MouseEvent event) + { + } + + /** + * Called when the mouse pointer moves over the area bounded + * by the {@link JList} while a button is held down. + * + * @param event The event representing the mouse drag + */ + public void mouseDragged(MouseEvent event) + { + } + + /** + * Called when the mouse pointer moves over the area bounded + * by the {@link JList}. + * + * @param event The event representing the mouse move + */ + public void mouseMoved(MouseEvent event) + { + } + } + + /** + * Helper class which listens to {@link PropertyChangeEvent}s + * from the {@link JList}. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called when the {@link JList} changes one of its bound properties. + * + * @param e The event representing the property change + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getSource() == BasicListUI.this.list) + { + if (e.getOldValue() != null && e.getOldValue() instanceof ListModel) + ((ListModel) e.getOldValue()).removeListDataListener(BasicListUI.this.listDataListener); + + if (e.getNewValue() != null && e.getNewValue() instanceof ListModel) + ((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener); + } + BasicListUI.this.damageLayout(); + } + } + + /** + * Creates a new BasicListUI for the component. + * + * @param c The component to create a UI for + * + * @return A new UI + */ + public static ComponentUI createUI(final JComponent c) + { + return new BasicListUI(); + } + + /** The current focus listener. */ + protected FocusListener focusListener; + + /** The data listener listening to the model. */ + protected ListDataListener listDataListener; + + /** The selection listener listening to the selection model. */ + protected ListSelectionListener listSelectionListener; + + /** The mouse listener listening to the list. */ + protected MouseInputListener mouseInputListener; + + /** The key listener listening to the list */ + private KeyHandler keyListener; + + /** The property change listener listening to the list. */ + protected PropertyChangeListener propertyChangeListener; + + + /** The component listener that receives notification for resizing the + * JList component.*/ + private ComponentListener componentListener; + + /** Saved reference to the list this UI was created for. */ + protected JList list; + + /** The height of a single cell in the list. */ + protected int cellHeight; + + /** The width of a single cell in the list. */ + protected int cellWidth; + + /** + * An array of varying heights of cells in the list, in cases where each + * cell might have a different height. + */ + protected int[] cellHeights; + + /** + * A simple counter. When nonzero, indicates that the UI class is out of + * date with respect to the underlying list, and must recalculate the + * list layout before painting or performing size calculations. + */ + protected int updateLayoutStateNeeded; + + /** + * The {@link CellRendererPane} that is used for painting. + */ + protected CellRendererPane rendererPane; + + /** + * Calculate the height of a particular row. If there is a fixed {@link + * #cellHeight}, return it; otherwise return the specific row height + * requested from the {@link #cellHeights} array. If the requested row + * is invalid, return <code>-1</code>. + * + * @param row The row to get the height of + * + * @return The height, in pixels, of the specified row + */ + protected int getRowHeight(int row) + { + if (row < 0 || row >= cellHeights.length) + return -1; + else if (cellHeight != -1) + return cellHeight; + else + return cellHeights[row]; + } + + /** + * Calculate the bounds of a particular cell, considering the upper left + * corner of the list as the origin position <code>(0,0)</code>. + * + * @param l Ignored; calculates over <code>this.list</code> + * @param index1 The first row to include in the bounds + * @param index2 The last row to incude in the bounds + * + * @return A rectangle encompassing the range of rows between + * <code>index1</code> and <code>index2</code> inclusive + */ + public Rectangle getCellBounds(JList l, int index1, int index2) + { + maybeUpdateLayoutState(); + + if (l != list || cellWidth == -1) + return null; + + int minIndex = Math.min(index1, index2); + int maxIndex = Math.max(index1, index2); + Point loc = indexToLocation(list, minIndex); + Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth, + getRowHeight(minIndex)); + + for (int i = minIndex + 1; i <= maxIndex; i++) + { + Point hiLoc = indexToLocation(list, i); + Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth, + getRowHeight(i)); + bounds = bounds.union(hibounds); + } + + return bounds; + } + + /** + * Calculate the Y coordinate of the upper edge of a particular row, + * considering the Y coordinate <code>0</code> to occur at the top of the + * list. + * + * @param row The row to calculate the Y coordinate of + * + * @return The Y coordinate of the specified row, or <code>-1</code> if + * the specified row number is invalid + */ + protected int convertRowToY(int row) + { + int y = 0; + for (int i = 0; i < row; ++i) + { + int h = getRowHeight(i); + if (h == -1) + return -1; + y += h; + } + return y; + } + + /** + * Calculate the row number containing a particular Y coordinate, + * considering the Y coodrinate <code>0</code> to occur at the top of the + * list. + * + * @param y0 The Y coordinate to calculate the row number for + * + * @return The row number containing the specified Y value, or <code>-1</code> + * if the specified Y coordinate is invalid + */ + protected int convertYToRow(int y0) + { + for (int row = 0; row < cellHeights.length; ++row) + { + int h = getRowHeight(row); + + if (y0 < h) + return row; + y0 -= h; + } + return -1; + } + + /** + * Recomputes the {@link #cellHeights}, {@link #cellHeight}, and {@link + * #cellWidth} properties by examining the variouis properties of the + * {@link JList}. + */ + protected void updateLayoutState() + { + int nrows = list.getModel().getSize(); + cellHeight = -1; + cellWidth = -1; + if (cellHeights == null || cellHeights.length != nrows) + cellHeights = new int[nrows]; + if (list.getFixedCellHeight() == -1 || list.getFixedCellWidth() == -1) + { + ListCellRenderer rend = list.getCellRenderer(); + for (int i = 0; i < nrows; ++i) + { + Component flyweight = rend.getListCellRendererComponent(list, + list.getModel() + .getElementAt(i), + 0, false, + false); + Dimension dim = flyweight.getPreferredSize(); + cellHeights[i] = dim.height; + // compute average cell height (little hack here) + cellHeight = (cellHeight * i + cellHeights[i]) / (i + 1); + cellWidth = Math.max(cellWidth, dim.width); + if (list.getLayoutOrientation() == JList.VERTICAL) + cellWidth = Math.max(cellWidth, list.getSize().width); + } + } + else + { + cellHeight = list.getFixedCellHeight(); + cellWidth = list.getFixedCellWidth(); + } + } + + /** + * Marks the current layout as damaged and requests revalidation from the + * JList. + * This is package-private to avoid an accessor method. + * + * @see #updateLayoutStateNeeded + */ + void damageLayout() + { + updateLayoutStateNeeded = 1; + } + + /** + * Calls {@link #updateLayoutState} if {@link #updateLayoutStateNeeded} + * is nonzero, then resets {@link #updateLayoutStateNeeded} to zero. + */ + protected void maybeUpdateLayoutState() + { + if (updateLayoutStateNeeded != 0) + { + updateLayoutState(); + updateLayoutStateNeeded = 0; + } + } + + /** + * Creates a new BasicListUI object. + */ + public BasicListUI() + { + focusListener = new FocusHandler(); + listDataListener = new ListDataHandler(); + listSelectionListener = new ListSelectionHandler(); + mouseInputListener = new MouseInputHandler(); + keyListener = new KeyHandler(); + propertyChangeListener = new PropertyChangeHandler(); + componentListener = new ComponentHandler(); + updateLayoutStateNeeded = 1; + rendererPane = new CellRendererPane(); + } + + /** + * Installs various default settings (mostly colors) from the {@link + * UIDefaults} into the {@link JList} + * + * @see #uninstallDefaults + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + list.setForeground(defaults.getColor("List.foreground")); + list.setBackground(defaults.getColor("List.background")); + list.setSelectionForeground(defaults.getColor("List.selectionForeground")); + list.setSelectionBackground(defaults.getColor("List.selectionBackground")); + list.setOpaque(true); + } + + /** + * Resets to <code>null</code> those defaults which were installed in + * {@link #installDefaults} + */ + protected void uninstallDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + list.setForeground(null); + list.setBackground(null); + list.setSelectionForeground(null); + list.setSelectionBackground(null); + } + + /** + * Attaches all the listeners we have in the UI class to the {@link + * JList}, its model and its selection model. + * + * @see #uninstallListeners + */ + protected void installListeners() + { + list.addFocusListener(focusListener); + list.getModel().addListDataListener(listDataListener); + list.addListSelectionListener(listSelectionListener); + list.addMouseListener(mouseInputListener); + list.addKeyListener(keyListener); + list.addMouseMotionListener(mouseInputListener); + list.addPropertyChangeListener(propertyChangeListener); + list.addComponentListener(componentListener); + } + + /** + * Detaches all the listeners we attached in {@link #installListeners}. + */ + protected void uninstallListeners() + { + list.removeFocusListener(focusListener); + list.getModel().removeListDataListener(listDataListener); + list.removeListSelectionListener(listSelectionListener); + list.removeMouseListener(mouseInputListener); + list.removeKeyListener(keyListener); + list.removeMouseMotionListener(mouseInputListener); + list.removePropertyChangeListener(propertyChangeListener); + } + + /** + * Installs keyboard actions for this UI in the {@link JList}. + */ + protected void installKeyboardActions() + { + } + + /** + * Uninstalls keyboard actions for this UI in the {@link JList}. + */ + protected void uninstallKeyboardActions() + { + } + + /** + * Installs the various aspects of the UI in the {@link JList}. In + * particular, calls {@link #installDefaults}, {@link #installListeners} + * and {@link #installKeyboardActions}. Also saves a reference to the + * provided component, cast to a {@link JList}. + * + * @param c The {@link JList} to install the UI into + */ + public void installUI(final JComponent c) + { + super.installUI(c); + list = (JList) c; + installDefaults(); + installListeners(); + installKeyboardActions(); + maybeUpdateLayoutState(); + } + + /** + * Uninstalls all the aspects of the UI which were installed in {@link + * #installUI}. When finished uninstalling, drops the saved reference to + * the {@link JList}. + * + * @param c Ignored; the UI is uninstalled from the {@link JList} + * reference saved during the call to {@link #installUI} + */ + public void uninstallUI(final JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallDefaults(); + list = null; + } + + /** + * Gets the size this list would prefer to assume. This is calculated by + * calling {@link #getCellBounds} over the entire list. + * + * @param c Ignored; uses the saved {@link JList} reference + * + * @return DOCUMENT ME! + */ + public Dimension getPreferredSize(JComponent c) + { + int size = list.getModel().getSize(); + if (size == 0) + return new Dimension(0, 0); + int visibleRows = list.getVisibleRowCount(); + int layoutOrientation = list.getLayoutOrientation(); + Rectangle bounds = getCellBounds(list, 0, list.getModel().getSize() - 1); + Dimension retVal = bounds.getSize(); + Component parent = list.getParent(); + if ((visibleRows == -1) && (parent instanceof JViewport)) + { + JViewport viewport = (JViewport) parent; + + if (layoutOrientation == JList.HORIZONTAL_WRAP) + { + int h = viewport.getSize().height; + int cellsPerCol = h / cellHeight; + int w = size / cellsPerCol * cellWidth; + retVal = new Dimension(w, h); + } + else if (layoutOrientation == JList.VERTICAL_WRAP) + { + int w = viewport.getSize().width; + int cellsPerRow = Math.max(w / cellWidth, 1); + int h = size / cellsPerRow * cellHeight; + retVal = new Dimension(w, h); + } + } + return retVal; + } + + /** + * Paints the packground of the list using the background color + * of the specified component. + * + * @param g The graphics context to paint in + * @param c The component to paint the background of + */ + private void paintBackground(Graphics g, JComponent c) + { + Dimension size = getPreferredSize(c); + Color save = g.getColor(); + g.setColor(c.getBackground()); + g.fillRect(0, 0, size.width, size.height); + g.setColor(save); + } + + /** + * Paints a single cell in the list. + * + * @param g The graphics context to paint in + * @param row The row number to paint + * @param bounds The bounds of the cell to paint, assuming a coordinate + * system beginning at <code>(0,0)</code> in the upper left corner of the + * list + * @param rend A cell renderer to paint with + * @param data The data to provide to the cell renderer + * @param sel A selection model to provide to the cell renderer + * @param lead The lead selection index of the list + */ + protected void paintCell(Graphics g, int row, Rectangle bounds, + ListCellRenderer rend, ListModel data, + ListSelectionModel sel, int lead) + { + boolean is_sel = list.isSelectedIndex(row); + boolean has_focus = false; + Component comp = rend.getListCellRendererComponent(list, + data.getElementAt(row), + 0, is_sel, has_focus); + //comp.setBounds(new Rectangle(0, 0, bounds.width, bounds.height)); + //comp.paint(g); + rendererPane.paintComponent(g, comp, list, bounds); + } + + /** + * Paints the list by calling {@link #paintBackground} and then repeatedly + * calling {@link #paintCell} for each visible cell in the list. + * + * @param g The graphics context to paint with + * @param c Ignored; uses the saved {@link JList} reference + */ + public void paint(Graphics g, JComponent c) + { + int nrows = list.getModel().getSize(); + if (nrows == 0) + return; + + maybeUpdateLayoutState(); + ListCellRenderer render = list.getCellRenderer(); + ListModel model = list.getModel(); + ListSelectionModel sel = list.getSelectionModel(); + int lead = sel.getLeadSelectionIndex(); + Rectangle clip = g.getClipBounds(); + paintBackground(g, list); + + for (int row = 0; row < nrows; ++row) + { + Rectangle bounds = getCellBounds(list, row, row); + if (bounds.intersects(clip)) + paintCell(g, row, bounds, render, model, sel, lead); + } + } + + /** + * Computes the index of a list cell given a point within the list. + * + * @param list the list which on which the computation is based on + * @param location the coordinates + * + * @return the index of the list item that is located at the given + * coordinates or <code>null</code> if the location is invalid + */ + public int locationToIndex(JList list, Point location) + { + int layoutOrientation = list.getLayoutOrientation(); + int index = -1; + switch (layoutOrientation) + { + case JList.VERTICAL: + index = convertYToRow(location.y); + break; + case JList.HORIZONTAL_WRAP: + // determine visible rows and cells per row + int visibleRows = list.getVisibleRowCount(); + int cellsPerRow = -1; + int numberOfItems = list.getModel().getSize(); + Dimension listDim = list.getSize(); + if (visibleRows <= 0) + { + try + { + cellsPerRow = listDim.width / cellWidth; + } + catch (ArithmeticException ex) + { + cellsPerRow = 1; + } + } + else + { + cellsPerRow = numberOfItems / visibleRows + 1; + } + + // determine index for the given location + int cellsPerColumn = numberOfItems / cellsPerRow + 1; + int gridX = Math.min(location.x / cellWidth, cellsPerRow - 1); + int gridY = Math.min(location.y / cellHeight, cellsPerColumn); + index = gridX + gridY * cellsPerRow; + break; + case JList.VERTICAL_WRAP: + // determine visible rows and cells per column + int visibleRows2 = list.getVisibleRowCount(); + if (visibleRows2 <= 0) + { + Dimension listDim2 = list.getSize(); + visibleRows2 = listDim2.height / cellHeight; + } + int numberOfItems2 = list.getModel().getSize(); + int cellsPerRow2 = numberOfItems2 / visibleRows2 + 1; + + Dimension listDim2 = list.getSize(); + int gridX2 = Math.min(location.x / cellWidth, cellsPerRow2 - 1); + int gridY2 = Math.min(location.y / cellHeight, visibleRows2); + index = gridY2 + gridX2 * visibleRows2; + break; + } + return index; + } + + public Point indexToLocation(JList list, int index) + { + int layoutOrientation = list.getLayoutOrientation(); + Point loc = null; + switch (layoutOrientation) + { + case JList.VERTICAL: + loc = new Point(0, convertRowToY(index)); + break; + case JList.HORIZONTAL_WRAP: + // determine visible rows and cells per row + int visibleRows = list.getVisibleRowCount(); + int numberOfCellsPerRow = -1; + if (visibleRows <= 0) + { + Dimension listDim = list.getSize(); + numberOfCellsPerRow = Math.max(listDim.width / cellWidth, 1); + } + else + { + int numberOfItems = list.getModel().getSize(); + numberOfCellsPerRow = numberOfItems / visibleRows + 1; + } + // compute coordinates inside the grid + int gridX = index % numberOfCellsPerRow; + int gridY = index / numberOfCellsPerRow; + int locX = gridX * cellWidth; + int locY = gridY * cellHeight; + loc = new Point(locX, locY); + break; + case JList.VERTICAL_WRAP: + // determine visible rows and cells per column + int visibleRows2 = list.getVisibleRowCount(); + if (visibleRows2 <= 0) + { + Dimension listDim2 = list.getSize(); + visibleRows2 = listDim2.height / cellHeight; + } + // compute coordinates inside the grid + if (visibleRows2 > 0) + { + int gridY2 = index % visibleRows2; + int gridX2 = index / visibleRows2; + int locX2 = gridX2 * cellWidth; + int locY2 = gridY2 * cellHeight; + loc = new Point(locX2, locY2); + } + else + loc = new Point(0, convertRowToY(index)); + break; + } + return loc; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java new file mode 100644 index 00000000000..14fe28f7110 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -0,0 +1,1058 @@ +/* BasicLookAndFeel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.ResourceBundle; + +import javax.swing.BorderFactory; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.UIDefaults; +import javax.swing.border.BevelBorder; +import javax.swing.border.Border; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.DimensionUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.text.JTextComponent; + +/** + * BasicLookAndFeel + * @author Andrew Selkirk + */ +public abstract class BasicLookAndFeel extends LookAndFeel + implements Serializable +{ + static final long serialVersionUID = -6096995660290287879L; + + /** + * Creates a new instance of the Basic look and feel. + */ + public BasicLookAndFeel() + { + // TODO + } + + /** + * Creates and returns a new instance of the default resources for this look + * and feel. + * + * @return The UI defaults. + */ + public UIDefaults getDefaults() + { + // Variables + UIDefaults def = new UIDefaults(); + // Initialize Class Defaults + initClassDefaults(def); + // Initialize System Colour Defaults + initSystemColorDefaults(def); + // Initialize Component Defaults + initComponentDefaults(def); + // Return UI Defaults + return def; + } + + /** + * Populates the <code>defaults</code> table with mappings between class IDs + * and fully qualified class names for the UI delegates. + * + * @param defaults the defaults table (<code>null</code> not permitted). + */ + protected void initClassDefaults(UIDefaults defaults) + { + // Variables + Object[] uiDefaults; + // Initialize Class Defaults + uiDefaults = new Object[] { + "ButtonUI", "javax.swing.plaf.basic.BasicButtonUI", + "CheckBoxMenuItemUI", "javax.swing.plaf.basic.BasicCheckBoxMenuItemUI", + "CheckBoxUI", "javax.swing.plaf.basic.BasicCheckBoxUI", + "ColorChooserUI", "javax.swing.plaf.basic.BasicColorChooserUI", + "ComboBoxUI", "javax.swing.plaf.basic.BasicComboBoxUI", + "DesktopIconUI", "javax.swing.plaf.basic.BasicDesktopIconUI", + "DesktopPaneUI", "javax.swing.plaf.basic.BasicDesktopPaneUI", + "EditorPaneUI", "javax.swing.plaf.basic.BasicEditorPaneUI", + "FileChooserUI", "javax.swing.plaf.basic.BasicFileChooserUI", + "FormattedTextFieldUI", "javax.swing.plaf.basic.BasicFormattedTextFieldUI", + "InternalFrameUI", "javax.swing.plaf.basic.BasicInternalFrameUI", + "LabelUI", "javax.swing.plaf.basic.BasicLabelUI", + "ListUI", "javax.swing.plaf.basic.BasicListUI", + "MenuBarUI", "javax.swing.plaf.basic.BasicMenuBarUI", + "MenuItemUI", "javax.swing.plaf.basic.BasicMenuItemUI", + "MenuUI", "javax.swing.plaf.basic.BasicMenuUI", + "OptionPaneUI", "javax.swing.plaf.basic.BasicOptionPaneUI", + "PanelUI", "javax.swing.plaf.basic.BasicPanelUI", + "PasswordFieldUI", "javax.swing.plaf.basic.BasicPasswordFieldUI", + "PopupMenuSeparatorUI", "javax.swing.plaf.basic.BasicPopupMenuSeparatorUI", + "PopupMenuUI", "javax.swing.plaf.basic.BasicPopupMenuUI", + "ProgressBarUI", "javax.swing.plaf.basic.BasicProgressBarUI", + "RadioButtonMenuItemUI", "javax.swing.plaf.basic.BasicRadioButtonMenuItemUI", + "RadioButtonUI", "javax.swing.plaf.basic.BasicRadioButtonUI", + "RootPaneUI", "javax.swing.plaf.basic.BasicRootPaneUI", + "ScrollBarUI", "javax.swing.plaf.basic.BasicScrollBarUI", + "ScrollPaneUI", "javax.swing.plaf.basic.BasicScrollPaneUI", + "SeparatorUI", "javax.swing.plaf.basic.BasicSeparatorUI", + "SliderUI", "javax.swing.plaf.basic.BasicSliderUI", + "SplitPaneUI", "javax.swing.plaf.basic.BasicSplitPaneUI", + "SpinnerUI", "javax.swing.plaf.basic.BasicSpinnerUI", + "StandardDialogUI", "javax.swing.plaf.basic.BasicStandardDialogUI", + "TabbedPaneUI", "javax.swing.plaf.basic.BasicTabbedPaneUI", + "TableHeaderUI", "javax.swing.plaf.basic.BasicTableHeaderUI", + "TableUI", "javax.swing.plaf.basic.BasicTableUI", + "TextPaneUI", "javax.swing.plaf.basic.BasicTextPaneUI", + "TextAreaUI", "javax.swing.plaf.basic.BasicTextAreaUI", + "TextFieldUI", "javax.swing.plaf.basic.BasicTextFieldUI", + "TextPaneUI", "javax.swing.plaf.basic.BasicTextPaneUI", + "ToggleButtonUI", "javax.swing.plaf.basic.BasicToggleButtonUI", + "ToolBarSeparatorUI", "javax.swing.plaf.basic.BasicToolBarSeparatorUI", + "ToolBarUI", "javax.swing.plaf.basic.BasicToolBarUI", + "ToolTipUI", "javax.swing.plaf.basic.BasicToolTipUI", + "TreeUI", "javax.swing.plaf.basic.BasicTreeUI", + "ViewportUI", "javax.swing.plaf.basic.BasicViewportUI" + }; + // Add Class Defaults to UI Defaults table + defaults.putDefaults(uiDefaults); + } + + /** + * Populates the <code>defaults</code> table with system color defaults. + * + * @param defaults the defaults table (<code>null</code> not permitted). + */ + protected void initSystemColorDefaults(UIDefaults defaults) + { + Color highLight = new Color(249, 247, 246); + Color light = new Color(239, 235, 231); + Color shadow = new Color(139, 136, 134); + Color darkShadow = new Color(16, 16, 16); + + Object[] uiDefaults; + uiDefaults = new Object[] { + "activeCaption", new ColorUIResource(0, 0, 128), + "activeCaptionBorder", new ColorUIResource(Color.lightGray), + "activeCaptionText", new ColorUIResource(Color.white), + "control", new ColorUIResource(light), + "controlDkShadow", new ColorUIResource(shadow), + "controlHighlight", new ColorUIResource(highLight), + "controlLtHighlight", new ColorUIResource(highLight), + "controlShadow", new ColorUIResource(shadow), + "controlText", new ColorUIResource(darkShadow), + "desktop", new ColorUIResource(0, 92, 92), + "inactiveCaption", new ColorUIResource(Color.gray), + "inactiveCaptionBorder", new ColorUIResource(Color.lightGray), + "inactiveCaptionText", new ColorUIResource(Color.lightGray), + "info", new ColorUIResource(light), + "infoText", new ColorUIResource(darkShadow), + "menu", new ColorUIResource(light), + "menuText", new ColorUIResource(darkShadow), + "scrollbar", new ColorUIResource(light), + "text", new ColorUIResource(Color.white), + "textHighlight", new ColorUIResource(Color.black), + "textHighlightText", new ColorUIResource(Color.white), + "textInactiveText", new ColorUIResource(Color.gray), + "textText", new ColorUIResource(Color.black), + "window", new ColorUIResource(light), + "windowBorder", new ColorUIResource(Color.black), + "windowText", new ColorUIResource(darkShadow) + }; + defaults.putDefaults(uiDefaults); + } + + /** + * Loads the system colors. This method is not implemented yet. + * + * @param defaults the defaults table (<code>null</code> not permitted). + * @param systemColors TODO + * @param useNative TODO + */ + protected void loadSystemColors(UIDefaults defaults, String[] systemColors, + boolean useNative) + { + // TODO + } + + /** + * loadResourceBundle + * @param defaults TODO + */ + private void loadResourceBundle(UIDefaults defaults) + { + ResourceBundle bundle; + Enumeration e; + String key; + String value; + bundle = ResourceBundle.getBundle("resources/basic"); + // Process Resources + e = bundle.getKeys(); + while (e.hasMoreElements()) + { + key = (String) e.nextElement(); + value = bundle.getString(key); + defaults.put(key, value); + } + } + + /** + * initComponentDefaults + * @param defaults the defaults table (<code>null</code> not permitted). + */ + protected void initComponentDefaults(UIDefaults defaults) + { + Object[] uiDefaults; + + Color highLight = new Color(249, 247, 246); + Color light = new Color(239, 235, 231); + Color shadow = new Color(139, 136, 134); + Color darkShadow = new Color(16, 16, 16); + + uiDefaults = new Object[] { + + "AbstractUndoableEdit.undoText", "Undo", + "AbstractUndoableEdit.redoText", "Redo", + "Button.background", new ColorUIResource(Color.LIGHT_GRAY), + "Button.border", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults table) + { + return BasicBorders.getButtonBorder(); + } + }, + "Button.darkShadow", new ColorUIResource(Color.BLACK), + "Button.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "SPACE", "pressed", + "released SPACE", "released" + }), + "Button.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Button.foreground", new ColorUIResource(Color.BLACK), + "Button.highlight", new ColorUIResource(Color.WHITE), + "Button.light", new ColorUIResource(Color.LIGHT_GRAY), + "Button.margin", new InsetsUIResource(2, 2, 2, 2), + "Button.shadow", new ColorUIResource(Color.GRAY), + "Button.textIconGap", new Integer(4), + "Button.textShiftOffset", new Integer(0), + "CheckBox.background", new ColorUIResource(light), + "CheckBox.border", new BorderUIResource.CompoundBorderUIResource(null, + null), + "CheckBox.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "SPACE", "pressed", + "released SPACE", "released" + }), + "CheckBox.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "CheckBox.foreground", new ColorUIResource(darkShadow), + "CheckBox.icon", BasicIconFactory.getCheckBoxIcon(), + "CheckBox.margin",new InsetsUIResource(2, 2, 2, 2), + "CheckBox.textIconGap", new Integer(4), + "CheckBox.textShiftOffset", new Integer(0), + "CheckBoxMenuItem.acceleratorFont", new FontUIResource("Dialog", + Font.PLAIN, 12), + "CheckBoxMenuItem.acceleratorForeground", + new ColorUIResource(darkShadow), + "CheckBoxMenuItem.acceleratorSelectionForeground", + new ColorUIResource(Color.white), + "CheckBoxMenuItem.arrowIcon", BasicIconFactory.getMenuItemArrowIcon(), + "CheckBoxMenuItem.background", new ColorUIResource(light), + "CheckBoxMenuItem.border", new BasicBorders.MarginBorder(), + "CheckBoxMenuItem.borderPainted", Boolean.FALSE, + "CheckBoxMenuItem.checkIcon", BasicIconFactory.getCheckBoxMenuItemIcon(), + "CheckBoxMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "CheckBoxMenuItem.foreground", new ColorUIResource(darkShadow), + "CheckBoxMenuItem.margin", new InsetsUIResource(2, 2, 2, 2), + "CheckBoxMenuItem.selectionBackground", new ColorUIResource(Color.black), + "CheckBoxMenuItem.selectionForeground", new ColorUIResource(Color.white), + "ColorChooser.background", new ColorUIResource(light), + "ColorChooser.cancelText", "Cancel", + "ColorChooser.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "ColorChooser.foreground", new ColorUIResource(darkShadow), + "ColorChooser.hsbBlueText", "B", + "ColorChooser.hsbBrightnessText", "B", + "ColorChooser.hsbGreenText", "G", + "ColorChooser.hsbHueText", "H", + "ColorChooser.hsbNameText", "HSB", + "ColorChooser.hsbRedText", "R", + "ColorChooser.hsbSaturationText", "S", + "ColorChooser.okText", "OK", + "ColorChooser.previewText", "Preview", + "ColorChooser.resetText", "Reset", + "ColorChooser.rgbBlueMnemonic", new Integer(66), + "ColorChooser.rgbBlueText", "Blue", + "ColorChooser.rgbGreenMnemonic", new Integer(71), + "ColorChooser.rgbGreenText", "Green", + "ColorChooser.rgbNameText", "RGB", + "ColorChooser.rgbRedMnemonic", new Integer(82), + "ColorChooser.rgbRedText", "Red", + "ColorChooser.sampleText", "Sample Text Sample Text", + "ColorChooser.swatchesDefaultRecentColor", new ColorUIResource(light), + "ColorChooser.swatchesNameText", "Swatches", + "ColorChooser.swatchesRecentSwatchSize", new Dimension(10, 10), + "ColorChooser.swatchesRecentText", "Recent:", + "ColorChooser.swatchesSwatchSize", new Dimension(10, 10), + "ComboBox.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "ESCAPE", "hidePopup", + "PAGE_UP", "pageUpPassThrough", + "PAGE_DOWN", "pageDownPassThrough", + "HOME", "homePassThrough", + "END", "endPassThrough" + }), + "ComboBox.background", new ColorUIResource(light), + "ComboBox.buttonBackground", new ColorUIResource(light), + "ComboBox.buttonDarkShadow", new ColorUIResource(shadow), + "ComboBox.buttonHighlight", new ColorUIResource(highLight), + "ComboBox.buttonShadow", new ColorUIResource(shadow), + "ComboBox.disabledBackground", new ColorUIResource(light), + "ComboBox.disabledForeground", new ColorUIResource(Color.gray), + "ComboBox.font", new FontUIResource("SansSerif", Font.PLAIN, 12), + "ComboBox.foreground", new ColorUIResource(Color.black), + "ComboBox.selectionBackground", new ColorUIResource(Color.black), + "ComboBox.selectionForeground", new ColorUIResource(Color.white), + "Desktop.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "KP_LEFT", "left", + "KP_RIGHT", "right", + "ctrl F5", "restore", + "LEFT", "left", + "ctrl alt F6", "selectNextFrame", + "UP", "up", + "ctrl F6", "selectNextFrame", + "RIGHT", "right", + "DOWN", "down", + "ctrl F7", "move", + "ctrl F8", "resize", + "ESCAPE", "escape", + "ctrl TAB", "selectNextFrame", + "ctrl F9", "minimize", + "KP_UP", "up", + "ctrl F4", "close", + "KP_DOWN", "down", + "ctrl F10", "maximize", + "ctrl alt shift F6","selectPreviousFrame" + }), + "Desktop.background", new ColorUIResource(0, 92, 92), + "DesktopIcon.border", new BorderUIResource.CompoundBorderUIResource(null, + null), + "EditorPane.background", new ColorUIResource(Color.white), + "EditorPane.border", new BasicBorders.MarginBorder(), + "EditorPane.caretBlinkRate", new Integer(500), + "EditorPane.caretForeground", new ColorUIResource(Color.black), + "EditorPane.font", new FontUIResource("Serif", Font.PLAIN, 12), + "EditorPane.foreground", new ColorUIResource(Color.black), + "EditorPane.inactiveForeground", new ColorUIResource(Color.gray), + "EditorPane.keyBindings", new JTextComponent.KeyBinding[] { + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, + 0), "caret-up"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, + 0), "caret-down"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, + 0), "page-up"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, + 0), "page-down"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, + 0), "insert-break"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, + 0), "insert-tab") + }, + "EditorPane.margin", new InsetsUIResource(3, 3, 3, 3), + "EditorPane.selectionBackground", new ColorUIResource(Color.black), + "EditorPane.selectionForeground", new ColorUIResource(Color.white), + "FileChooser.acceptAllFileFilterText", "All Files (*.*)", + "FileChooser.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "ESCAPE", "cancelSelection" + }), + "FileChooser.cancelButtonMnemonic", new Integer(67), + "FileChooser.cancelButtonText", "Cancel", + "FileChooser.cancelButtonToolTipText", "Abort file chooser dialog", + // XXX Don't use gif +// "FileChooser.detailsViewIcon", new IconUIResource(new ImageIcon("icons/DetailsView.gif")), + "FileChooser.directoryDescriptionText", "Directory", + "FileChooser.fileDescriptionText", "Generic File", + "FileChooser.helpButtonMnemonic", new Integer(72), + "FileChooser.helpButtonText", "Help", + "FileChooser.helpButtonToolTipText", "FileChooser help", + // XXX Don't use gif +// "FileChooser.homeFolderIcon", new IconUIResource(new ImageIcon("icons/HomeFolder.gif")), + // XXX Don't use gif +// "FileChooser.listViewIcon", new IconUIResource(new ImageIcon("icons/ListView.gif")), + "FileChooser.newFolderErrorSeparator", ":", + "FileChooser.newFolderErrorText", "Error creating new folder", + // XXX Don't use gif +// "FileChooser.newFolderIcon", new IconUIResource(new ImageIcon("icons/NewFolder.gif")), + "FileChooser.openButtonMnemonic", new Integer(79), + "FileChooser.openButtonText", "Open", + "FileChooser.openButtonToolTipText", "Open selected file", + "FileChooser.saveButtonMnemonic", new Integer(83), + "FileChooser.saveButtonText", "Save", + "FileChooser.saveButtonToolTipText", "Save selected file", + // XXX Don't use gif +// "FileChooser.upFolderIcon", new IconUIResource(new ImageIcon("icons/UpFolder.gif")), + "FileChooser.updateButtonMnemonic", new Integer(85), + "FileChooser.updateButtonText", "Update", + "FileChooser.updateButtonToolTipText", "Update directory listing", + // XXX Don't use gif +// "FileView.computerIcon", new IconUIResource(new ImageIcon("icons/Computer.gif")), + // XXX Don't use gif +// "FileView.directoryIcon", new IconUIResource(new ImageIcon("icons/Directory.gif")), + // XXX Don't use gif +// "FileView.fileIcon", new IconUIResource(new ImageIcon("icons/File.gif")), + // XXX Don't use gif +// "FileView.floppyDriveIcon", new IconUIResource(new ImageIcon("icons/Floppy.gif")), + // XXX Don't use gif +// "FileView.hardDriveIcon", new IconUIResource(new ImageIcon("icons/HardDrive.gif")), + "FocusManagerClassName", "TODO", + "FormattedTextField.background", new ColorUIResource(light), + "FormattedTextField.caretForeground", new ColorUIResource(Color.black), + "FormattedTextField.foreground", new ColorUIResource(Color.black), + "FormattedTextField.inactiveBackground", new ColorUIResource(light), + "FormattedTextField.inactiveForeground", new ColorUIResource(Color.gray), + "FormattedTextField.selectionBackground", + new ColorUIResource(Color.black), + "FormattedTextField.selectionForeground", + new ColorUIResource(Color.white), + "FormView.resetButtonText", "Reset", + "FormView.submitButtonText", "Submit Query", + "InternalFrame.activeTitleBackground", new ColorUIResource(0, 0, 128), + "InternalFrame.activeTitleForeground", new ColorUIResource(Color.white), + "InternalFrame.border", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults table) + { + Color lineColor = new Color(238, 238, 238); + Border inner = BorderFactory.createLineBorder(lineColor, 1); + Color shadowInner = new Color(184, 207, 229); + Color shadowOuter = new Color(122, 138, 153); + Border outer = BorderFactory.createBevelBorder(BevelBorder.RAISED, + Color.WHITE, + Color.WHITE, + shadowOuter, + shadowInner); + Border border = new BorderUIResource.CompoundBorderUIResource(outer, + inner); + return border; + } + }, + "InternalFrame.borderColor", new ColorUIResource(light), + "InternalFrame.borderDarkShadow", new ColorUIResource(Color.BLACK), + "InternalFrame.borderHighlight", new ColorUIResource(Color.WHITE), + "InternalFrame.borderLight", new ColorUIResource(Color.LIGHT_GRAY), + "InternalFrame.borderShadow", new ColorUIResource(Color.GRAY), + "InternalFrame.closeIcon", BasicIconFactory.createEmptyFrameIcon(), + // XXX Don't use gif +// "InternalFrame.icon", new IconUIResource(new ImageIcon("icons/JavaCup.gif")), + "InternalFrame.iconifyIcon", BasicIconFactory.createEmptyFrameIcon(), + "InternalFrame.inactiveTitleBackground", new ColorUIResource(Color.gray), + "InternalFrame.inactiveTitleForeground", + new ColorUIResource(Color.lightGray), + "InternalFrame.maximizeIcon", BasicIconFactory.createEmptyFrameIcon(), + "InternalFrame.minimizeIcon", BasicIconFactory.createEmptyFrameIcon(), + "InternalFrame.titleFont", new FontUIResource("Dialog", Font.PLAIN, 12), + "InternalFrame.windowBindings", new Object[] { + "shift ESCAPE", "showSystemMenu", + "ctrl SPACE", "showSystemMenu", + "ESCAPE", "showSystemMenu" + }, + "Label.background", new ColorUIResource(light), + "Label.disabledForeground", new ColorUIResource(Color.white), + "Label.disabledShadow", new ColorUIResource(shadow), + "Label.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Label.foreground", new ColorUIResource(darkShadow), + "List.background", new ColorUIResource(light), + "List.border", new BasicBorders.MarginBorder(), + "List.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "PAGE_UP", "scrollUp", + "ctrl \\", "clearSelection", + "PAGE_DOWN", "scrollDown", + "shift PAGE_DOWN","scrollDownExtendSelection", + "END", "selectLastRow", + "HOME", "selectFirstRow", + "shift END", "selectLastRowExtendSelection", + "shift HOME", "selectFirstRowExtendSelection", + "UP", "selectPreviousRow", + "ctrl /", "selectAll", + "ctrl A", "selectAll", + "DOWN", "selectNextRow", + "shift UP", "selectPreviousRowExtendSelection", + "ctrl SPACE", "selectNextRowExtendSelection", + "shift DOWN", "selectNextRowExtendSelection", + "KP_UP", "selectPreviousRow", + "shift PAGE_UP","scrollUpExtendSelection", + "KP_DOWN", "selectNextRow" + }), + "List.foreground", new ColorUIResource(darkShadow), + "List.selectionBackground", new ColorUIResource(Color.black), + "List.selectionForeground", new ColorUIResource(Color.white), + "Menu.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12), + "Menu.acceleratorForeground", new ColorUIResource(darkShadow), + "Menu.acceleratorSelectionForeground", new ColorUIResource(Color.white), + "Menu.arrowIcon", BasicIconFactory.getMenuArrowIcon(), + "Menu.background", new ColorUIResource(light), + "Menu.border", new BasicBorders.MarginBorder(), + "Menu.borderPainted", Boolean.FALSE, + "Menu.checkIcon", BasicIconFactory.getMenuItemCheckIcon(), + "Menu.consumesTabs", Boolean.TRUE, + "Menu.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Menu.foreground", new ColorUIResource(darkShadow), + "Menu.margin", new InsetsUIResource(2, 2, 2, 2), + "Menu.selectedWindowInputMapBindings", new Object[] { + "ESCAPE", "cancel", + "DOWN", "selectNext", + "KP_DOWN", "selectNext", + "UP", "selectPrevious", + "KP_UP", "selectPrevious", + "LEFT", "selectParent", + "KP_LEFT", "selectParent", + "RIGHT", "selectChild", + "KP_RIGHT", "selectChild", + "ENTER", "return", + "SPACE", "return" + }, + "Menu.selectionBackground", new ColorUIResource(Color.black), + "Menu.selectionForeground", new ColorUIResource(Color.white), + "MenuBar.background", new ColorUIResource(light), + "MenuBar.border", new BasicBorders.MenuBarBorder(null, null), + "MenuBar.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "MenuBar.foreground", new ColorUIResource(darkShadow), + "MenuBar.highlight", new ColorUIResource(highLight), + "MenuBar.shadow", new ColorUIResource(shadow), + "MenuBar.windowBindings", new Object[] { + "F10", "takeFocus" + }, + "MenuItem.acceleratorDelimiter", "-", + "MenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12), + "MenuItem.acceleratorForeground", new ColorUIResource(darkShadow), + "MenuItem.acceleratorSelectionForeground", + new ColorUIResource(Color.white), + "MenuItem.arrowIcon", BasicIconFactory.getMenuItemArrowIcon(), + "MenuItem.background", new ColorUIResource(light), + "MenuItem.border", new BasicBorders.MarginBorder(), + "MenuItem.borderPainted", Boolean.FALSE, + "MenuItem.checkIcon", BasicIconFactory.getMenuItemCheckIcon(), + "MenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "MenuItem.foreground", new ColorUIResource(darkShadow), + "MenuItem.margin", new InsetsUIResource(2, 2, 2, 2), + "MenuItem.selectionBackground", new ColorUIResource(Color.black), + "MenuItem.selectionForeground", new ColorUIResource(Color.white), + "OptionPane.background", new ColorUIResource(light), + "OptionPane.border", + new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0), + "OptionPane.buttonAreaBorder", + new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0), + "OptionPane.cancelButtonText", "Cancel", + // XXX Don't use gif +// "OptionPane.errorIcon", +// new IconUIResource(new ImageIcon("icons/Error.gif")), + "OptionPane.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "OptionPane.foreground", new ColorUIResource(darkShadow), + // XXX Don't use gif +// "OptionPane.informationIcon", +// new IconUIResource(new ImageIcon("icons/Inform.gif")), + "OptionPane.messageAreaBorder", + new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0), + "OptionPane.messageForeground", new ColorUIResource(darkShadow), + "OptionPane.minimumSize", new DimensionUIResource(262, 90), + "OptionPane.noButtonText", "No", + "OptionPane.okButtonText", "OK", + // XXX Don't use gif +// "OptionPane.questionIcon", +// new IconUIResource(new ImageIcon("icons/Question.gif")), + // XXX Don't use gif +// "OptionPane.warningIcon", +// new IconUIResource(new ImageIcon("icons/Warn.gif")), + "OptionPane.windowBindings", new Object[] { + "ESCAPE", "close" + }, + "OptionPane.yesButtonText", "Yes", + "Panel.background", new ColorUIResource(light), + "Panel.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Panel.foreground", new ColorUIResource(Color.black), + "PasswordField.background", new ColorUIResource(light), + "PasswordField.border", new BasicBorders.FieldBorder(null, null, + null, null), + "PasswordField.caretBlinkRate", new Integer(500), + "PasswordField.caretForeground", new ColorUIResource(Color.black), + "PasswordField.font", new FontUIResource("MonoSpaced", Font.PLAIN, 12), + "PasswordField.foreground", new ColorUIResource(Color.black), + "PasswordField.inactiveBackground", new ColorUIResource(light), + "PasswordField.inactiveForeground", new ColorUIResource(Color.gray), + "PasswordField.keyBindings", new JTextComponent.KeyBinding[] { + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, + 0), + "notify-field-accept")}, + "PasswordField.margin", new InsetsUIResource(0, 0, 0, 0), + "PasswordField.selectionBackground", new ColorUIResource(Color.black), + "PasswordField.selectionForeground", new ColorUIResource(Color.white), + "PopupMenu.background", new ColorUIResource(light), + "PopupMenu.border", new BorderUIResource.BevelBorderUIResource(0), + "PopupMenu.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "PopupMenu.foreground", new ColorUIResource(darkShadow), + "ProgressBar.background", new ColorUIResource(light), + "ProgressBar.border", new BorderUIResource.LineBorderUIResource(Color.darkGray), + "ProgressBar.cellLength", new Integer(1), + "ProgressBar.cellSpacing", new Integer(0), + "ProgressBar.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "ProgressBar.foreground", new ColorUIResource(Color.black), + "ProgressBar.selectionBackground", new ColorUIResource(Color.black), + "ProgressBar.selectionForeground", new ColorUIResource(light), + "ProgressBar.repaintInterval", new Integer(250), + "ProgressBar.cycleTime", new Integer(6000), + "RadioButton.background", new ColorUIResource(light), + "RadioButton.border", new BorderUIResource.CompoundBorderUIResource(null, + null), + "RadioButton.darkShadow", new ColorUIResource(shadow), + "RadioButton.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "SPACE", "pressed", + "released SPACE", "released" + }), + "RadioButton.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "RadioButton.foreground", new ColorUIResource(darkShadow), + "RadioButton.highlight", new ColorUIResource(highLight), + "RadioButton.icon", BasicIconFactory.getRadioButtonIcon(), + "RadioButton.light", new ColorUIResource(highLight), + "RadioButton.margin", new InsetsUIResource(2, 2, 2, 2), + "RadioButton.shadow", new ColorUIResource(shadow), + "RadioButton.textIconGap", new Integer(4), + "RadioButton.textShiftOffset", new Integer(0), + "RadioButtonMenuItem.acceleratorFont", + new FontUIResource("Dialog", Font.PLAIN, 12), + "RadioButtonMenuItem.acceleratorForeground", + new ColorUIResource(darkShadow), + "RadioButtonMenuItem.acceleratorSelectionForeground", + new ColorUIResource(Color.white), + "RadioButtonMenuItem.arrowIcon", BasicIconFactory.getMenuItemArrowIcon(), + "RadioButtonMenuItem.background", new ColorUIResource(light), + "RadioButtonMenuItem.border", new BasicBorders.MarginBorder(), + "RadioButtonMenuItem.borderPainted", Boolean.FALSE, + "RadioButtonMenuItem.checkIcon", BasicIconFactory.getRadioButtonMenuItemIcon(), + "RadioButtonMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "RadioButtonMenuItem.foreground", new ColorUIResource(darkShadow), + "RadioButtonMenuItem.margin", new InsetsUIResource(2, 2, 2, 2), + "RadioButtonMenuItem.selectionBackground", + new ColorUIResource(Color.black), + "RadioButtonMenuItem.selectionForeground", + new ColorUIResource(Color.white), + "RootPane.defaultButtonWindowKeyBindings", new Object[] { + "ENTER", "press", + "released ENTER", "release", + "ctrl ENTER", "press", + "ctrl released ENTER", "release" + }, + "ScrollBar.background", new ColorUIResource(224, 224, 224), + "ScrollBar.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "PAGE_UP", "negativeBlockIncrement", + "PAGE_DOWN", "positiveBlockIncrement", + "END", "maxScroll", + "HOME", "minScroll", + "LEFT", "positiveUnitIncrement", + "KP_UP", "negativeUnitIncrement", + "KP_DOWN", "positiveUnitIncrement", + "UP", "negativeUnitIncrement", + "RIGHT", "negativeUnitIncrement", + "KP_LEFT", "positiveUnitIncrement", + "DOWN", "positiveUnitIncrement", + "KP_RIGHT", "negativeUnitIncrement" + }), + "ScrollBar.foreground", new ColorUIResource(light), + "ScrollBar.maximumThumbSize", new DimensionUIResource(4096, 4096), + "ScrollBar.minimumThumbSize", new DimensionUIResource(8, 8), + "ScrollBar.thumb", new ColorUIResource(light), + "ScrollBar.thumbDarkShadow", new ColorUIResource(shadow), + "ScrollBar.thumbHighlight", new ColorUIResource(highLight), + "ScrollBar.thumbShadow", new ColorUIResource(shadow), + "ScrollBar.track", new ColorUIResource(light), + "ScrollBar.trackHighlight", new ColorUIResource(shadow), + "ScrollPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "PAGE_UP", "scrollUp", + "KP_LEFT", "unitScrollLeft", + "ctrl PAGE_DOWN","scrollRight", + "PAGE_DOWN", "scrollDown", + "KP_RIGHT", "unitScrollRight", + "LEFT", "unitScrollLeft", + "ctrl END", "scrollEnd", + "UP", "unitScrollUp", + "RIGHT", "unitScrollRight", + "DOWN", "unitScrollDown", + "ctrl HOME", "scrollHome", + "ctrl PAGE_UP", "scrollLeft", + "KP_UP", "unitScrollUp", + "KP_DOWN", "unitScrollDown" + }), + "ScrollPane.background", new ColorUIResource(light), + "ScrollPane.border", new BorderUIResource.EtchedBorderUIResource(), + "ScrollPane.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "ScrollPane.foreground", new ColorUIResource(darkShadow), + "Separator.background", new ColorUIResource(highLight), + "Separator.foreground", new ColorUIResource(shadow), + "Separator.highlight", new ColorUIResource(highLight), + "Separator.shadow", new ColorUIResource(shadow), + "Slider.background", new ColorUIResource(light), + "Slider.focus", new ColorUIResource(shadow), + "Slider.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "PAGE_UP", "positiveBlockIncrement", + "PAGE_DOWN", "negativeBlockIncrement", + "END", "maxScroll", + "HOME", "minScroll", + "LEFT", "negativeUnitIncrement", + "KP_UP", "positiveUnitIncrement", + "KP_DOWN", "negativeUnitIncrement", + "UP", "positiveUnitIncrement", + "RIGHT", "positiveUnitIncrement", + "KP_LEFT", "negativeUnitIncrement", + "DOWN", "negativeUnitIncrement", + "KP_RIGHT", "positiveUnitIncrement" + }), + "Slider.focusInsets", new InsetsUIResource(2, 2, 2, 2), + "Slider.foreground", new ColorUIResource(light), + "Slider.highlight", new ColorUIResource(highLight), + "Slider.shadow", new ColorUIResource(shadow), + "Slider.thumbHeight", new Integer(20), + "Slider.thumbWidth", new Integer(10), + "Slider.tickHeight", new Integer(12), + "Spinner.background", new ColorUIResource(light), + "Spinner.foreground", new ColorUIResource(light), + "SplitPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "F6", "toggleFocus", + "F8", "startResize", + "END", "selectMax", + "HOME", "selectMin", + "LEFT", "negativeIncremnent", + "KP_UP", "negativeIncrement", + "KP_DOWN", "positiveIncrement", + "UP", "negativeIncrement", + "RIGHT", "positiveIncrement", + "KP_LEFT", "negativeIncrement", + "DOWN", "positiveIncrement", + "KP_RIGHT", "positiveIncrement" + }), + "SplitPane.background", new ColorUIResource(light), + "SplitPane.border", new BasicBorders.SplitPaneBorder(null, null), + "SplitPane.darkShadow", new ColorUIResource(shadow), + "SplitPane.dividerSize", new Integer(10), + "SplitPane.highlight", new ColorUIResource(highLight), + "SplitPane.shadow", new ColorUIResource(shadow), + "TabbedPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "ctrl PAGE_DOWN","navigatePageDown", + "ctrl PAGE_UP", "navigatePageUp", + "ctrl UP", "requestFocus", + "ctrl KP_UP", "requestFocus" + }), + "TabbedPane.background", new ColorUIResource(light), + "TabbedPane.contentBorderInsets", new InsetsUIResource(2, 2, 3, 3), + "TabbedPane.darkShadow", new ColorUIResource(shadow), + "TabbedPane.focus", new ColorUIResource(darkShadow), + "TabbedPane.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "LEFT", "navigateLeft", + "KP_UP", "navigateUp", + "ctrl DOWN", "requestFocusForVisibleComponent", + "UP", "navigateUp", + "KP_DOWN", "navigateDown", + "RIGHT", "navigateRight", + "KP_LEFT", "navigateLeft", + "ctrl KP_DOWN", "requestFocusForVisibleComponent", + "KP_RIGHT", "navigateRight", + "DOWN", "navigateDown" + }), + "TabbedPane.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "TabbedPane.foreground", new ColorUIResource(darkShadow), + "TabbedPane.highlight", new ColorUIResource(highLight), + "TabbedPane.light", new ColorUIResource(highLight), + "TabbedPane.selectedTabPadInsets", new InsetsUIResource(2, 2, 2, 1), + "TabbedPane.shadow", new ColorUIResource(shadow), + "TabbedPane.tabbedPaneTabAreaInsets", new InsetsUIResource(3, 2, 1, 2), + "TabbedPane.tabbedPaneTabInsets", new InsetsUIResource(1, 4, 1, 4), + "TabbedPane.tabbedPaneContentBorderInsets", new InsetsUIResource(3, 2, 1, 2), + "TabbedPane.tabbedPaneTabPadInsets", new InsetsUIResource(1, 1, 1, 1), + "TabbedPane.tabRunOverlay", new Integer(2), + "TabbedPane.textIconGap", new Integer(4), + "Table.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "shift PAGE_DOWN","scrollDownExtendSelection", + "PAGE_DOWN", "scrollDownChangeSelection", + "END", "selectLastColumn", + "shift END", "selectLastColumnExtendSelection", + "HOME", "selectFirstColumn", + "ctrl END", "selectLastRow", + "ctrl shift END","selectLastRowExtendSelection", + "LEFT", "selectPreviousColumn", + "shift HOME", "selectFirstColumnExtendSelection", + "UP", "selectPreviousRow", + "RIGHT", "selectNextColumn", + "ctrl HOME", "selectFirstRow", + "shift LEFT", "selectPreviousColumnExtendSelection", + "DOWN", "selectNextRow", + "ctrl shift HOME","selectFirstRowExtendSelection", + "shift UP", "selectPreviousRowExtendSelection", + "F2", "startEditing", + "shift RIGHT", "selectNextColumnExtendSelection", + "TAB", "selectNextColumnCell", + "shift DOWN", "selectNextRowExtendSelection", + "ENTER", "selectNextRowCell", + "KP_UP", "selectPreviousRow", + "KP_DOWN", "selectNextRow", + "KP_LEFT", "selectPreviousColumn", + "KP_RIGHT", "selectNextColumn", + "shift TAB", "selectPreviousColumnCell", + "ctrl A", "selectAll", + "shift ENTER", "selectPreviousRowCell", + "shift KP_DOWN", "selectNextRowExtendSelection", + "shift KP_LEFT", "selectPreviousColumnExtendSelection", + "ESCAPE", "cancel", + "ctrl shift PAGE_UP", "scrollRightExtendSelection", + "shift KP_RIGHT", " selectNextColumnExtendSelection", + "ctrl PAGE_UP", "scrollLeftChangeSelection", + "shift PAGE_UP", "scrollUpExtendSelection", + "ctrl shift PAGE_DOWN", "scrollLeftExtendSelection", + "ctrl PAGE_DOWN", "scrollRightChangeSelection", + "PAGE_UP", "scrollUpChangeSelection" + }), + "Table.background", new ColorUIResource(light), + "Table.focusCellBackground", new ColorUIResource(light), + "Table.focusCellForeground", new ColorUIResource(darkShadow), + "Table.focusCellHighlightBorder", + new BorderUIResource.LineBorderUIResource( + new ColorUIResource(255, 255, 0)), + "Table.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Table.foreground", new ColorUIResource(darkShadow), + "Table.gridColor", new ColorUIResource(Color.gray), + "Table.scrollPaneBorder", new BorderUIResource.BevelBorderUIResource(0), + "Table.selectionBackground", new ColorUIResource(Color.black), + "Table.selectionForeground", new ColorUIResource(Color.white), + "TableHeader.background", new ColorUIResource(light), + "TableHeader.cellBorder", new BorderUIResource.BevelBorderUIResource(0), + "TableHeader.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "TableHeader.foreground", new ColorUIResource(darkShadow), + + "TextArea.background", new ColorUIResource(light), + "TextArea.border", new BasicBorders.MarginBorder(), + "TextArea.caretBlinkRate", new Integer(500), + "TextArea.caretForeground", new ColorUIResource(Color.black), + "TextArea.font", new FontUIResource("MonoSpaced", Font.PLAIN, 12), + "TextArea.foreground", new ColorUIResource(Color.black), + "TextArea.inactiveForeground", new ColorUIResource(Color.gray), + "TextArea.keyBindings", new JTextComponent.KeyBinding[] { + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, + 0), "caret-up"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, + 0), "caret-down"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, + 0), "page-up"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, + 0), "page-down"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, + 0), "insert-break"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, + 0), "insert-tab") + }, + "TextArea.margin", new InsetsUIResource(0, 0, 0, 0), + "TextArea.selectionBackground", new ColorUIResource(Color.black), + "TextArea.selectionForeground", new ColorUIResource(Color.white), + "TextField.background", new ColorUIResource(light), + "TextField.border", new BasicBorders.FieldBorder(null, null, null, null), + "TextField.caretBlinkRate", new Integer(500), + "TextField.caretForeground", new ColorUIResource(Color.black), + "TextField.darkShadow", new ColorUIResource(shadow), + "TextField.font", new FontUIResource("SansSerif", Font.PLAIN, 12), + "TextField.foreground", new ColorUIResource(Color.black), + "TextField.highlight", new ColorUIResource(highLight), + "TextField.inactiveBackground", new ColorUIResource(light), + "TextField.inactiveForeground", new ColorUIResource(Color.gray), + "TextField.light", new ColorUIResource(highLight), + "TextField.highlight", new ColorUIResource(light), + "TextField.keyBindings", new JTextComponent.KeyBinding[] { + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, + 0), + "notify-field-accept"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, + InputEvent.SHIFT_DOWN_MASK), + "selection-backward"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, + InputEvent.SHIFT_DOWN_MASK), + "selection-forward"), + }, + "TextField.margin", new InsetsUIResource(0, 0, 0, 0), + "TextField.selectionBackground", new ColorUIResource(Color.black), + "TextField.selectionForeground", new ColorUIResource(Color.white), + "TextPane.background", new ColorUIResource(Color.white), + "TextPane.border", new BasicBorders.MarginBorder(), + "TextPane.caretBlinkRate", new Integer(500), + "TextPane.caretForeground", new ColorUIResource(Color.black), + "TextPane.font", new FontUIResource("Serif", Font.PLAIN, 12), + "TextPane.foreground", new ColorUIResource(Color.black), + "TextPane.inactiveForeground", new ColorUIResource(Color.gray), + "TextPane.keyBindings", new JTextComponent.KeyBinding[] { + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_UP, + 0), "caret-up"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, + 0), "caret-down"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, + 0), "page-up"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, + 0), "page-down"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, + 0), "insert-break"), + new JTextComponent.KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, + 0), "insert-tab") + }, + "TextPane.margin", new InsetsUIResource(3, 3, 3, 3), + "TextPane.selectionBackground", new ColorUIResource(Color.black), + "TextPane.selectionForeground", new ColorUIResource(Color.white), + "TitledBorder.border", new BorderUIResource.EtchedBorderUIResource(), + "TitledBorder.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "TitledBorder.titleColor", new ColorUIResource(darkShadow), + "ToggleButton.background", new ColorUIResource(light), + "ToggleButton.border", + new BorderUIResource.CompoundBorderUIResource(null, null), + "ToggleButton.darkShadow", new ColorUIResource(shadow), + "ToggleButton.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "SPACE", "pressed", + "released SPACE", "released" + }), + "ToggleButton.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "ToggleButton.foreground", new ColorUIResource(darkShadow), + "ToggleButton.highlight", new ColorUIResource(highLight), + "ToggleButton.light", new ColorUIResource(light), + "ToggleButton.margin", new InsetsUIResource(2, 14, 2, 14), + "ToggleButton.shadow", new ColorUIResource(shadow), + "ToggleButton.textIconGap", new Integer(4), + "ToggleButton.textShiftOffset", new Integer(0), + "ToolBar.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "UP", "navigateUp", + "KP_UP", "navigateUp", + "DOWN", "navigateDown", + "KP_DOWN", "navigateDown", + "LEFT", "navigateLeft", + "KP_LEFT", "navigateLeft", + "RIGHT", "navigateRight", + "KP_RIGHT", "navigateRight" + }), + "ToolBar.background", new ColorUIResource(light), + "ToolBar.border", new BorderUIResource.EtchedBorderUIResource(), + "ToolBar.darkShadow", new ColorUIResource(shadow), + "ToolBar.dockingBackground", new ColorUIResource(light), + "ToolBar.dockingForeground", new ColorUIResource(Color.red), + "ToolBar.floatingBackground", new ColorUIResource(light), + "ToolBar.floatingForeground", new ColorUIResource(Color.darkGray), + "ToolBar.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "ToolBar.foreground", new ColorUIResource(darkShadow), + "ToolBar.highlight", new ColorUIResource(highLight), + "ToolBar.light", new ColorUIResource(highLight), + "ToolBar.separatorSize", new DimensionUIResource(20, 20), + "ToolBar.shadow", new ColorUIResource(shadow), + "ToolTip.background", new ColorUIResource(light), + "ToolTip.border", new BorderUIResource.LineBorderUIResource(Color.lightGray), + "ToolTip.font", new FontUIResource("SansSerif", Font.PLAIN, 12), + "ToolTip.foreground", new ColorUIResource(darkShadow), + "Tree.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { + "ESCAPE", "cancel" + }), + "Tree.background", new ColorUIResource(light), + "Tree.changeSelectionWithFocus", Boolean.TRUE, +// "Tree.closedIcon", new IconUIResource(new ImageIcon("icons/TreeClosed.png")), +// "Tree.collapsedIcon", new IconUIResource(new ImageIcon("icons/TreeCollapsed.png")), + "Tree.drawsFocusBorderAroundIcon", Boolean.FALSE, + "Tree.editorBorder", new BorderUIResource.LineBorderUIResource(Color.lightGray), + "Tree.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { + "shift PAGE_DOWN", "scrollDownExtendSelection", + "PAGE_DOWN", "scrollDownChangeSelection", + "END", "selectLast", + "ctrl KP_UP", "selectPreviousChangeLead", + "shift END", "selectLastExtendSelection", + "HOME", "selectFirst", + "ctrl END", "selectLastChangeLead", + "ctrl /", "selectAll", + "LEFT", "selectParent", + "shift HOME", "selectFirstExtendSelection", + "UP", "selectPrevious", + "ctrl KP_DOWN", "selectNextChangeLead", + "RIGHT", "selectChild", + "ctrl HOME", "selectFirstChangeLead", + "DOWN", "selectNext", + "ctrl KP_LEFT", "scrollLeft", + "shift UP", "selectPreviousExtendSelection", + "F2", "startEditing", + "ctrl LEFT", "scrollLeft", + "ctrl KP_RIGHT","scrollRight", + "ctrl UP", "selectPreviousChangeLead", + "shift DOWN", "selectNextExtendSelection", + "ENTER", "toggle", + "KP_UP", "selectPrevious", + "KP_DOWN", "selectNext", + "ctrl RIGHT", "scrollRight", + "KP_LEFT", "selectParent", + "KP_RIGHT", "selectChild", + "ctrl DOWN", "selectNextChangeLead", + "ctrl A", "selectAll", + "shift KP_UP", "selectPreviousExtendSelection", + "shift KP_DOWN","selectNextExtendSelection", + "ctrl SPACE", "toggleSelectionPreserveAnchor", + "ctrl shift PAGE_UP", "scrollUpExtendSelection", + "ctrl \\", "clearSelection", + "shift SPACE", "extendSelection", + "ctrl PAGE_UP", "scrollUpChangeLead", + "shift PAGE_UP","scrollUpExtendSelection", + "SPACE", "toggleSelectionPreserveAnchor", + "ctrl shift PAGE_DOWN", "scrollDownExtendSelection", + "PAGE_UP", "scrollUpChangeSelection", + "ctrl PAGE_DOWN", "scrollDownChangeLead" + }), + "Tree.font", new FontUIResource(new Font("Helvetica", Font.PLAIN, 12)), + "Tree.foreground", new ColorUIResource(Color.black), + "Tree.hash", new ColorUIResource(new Color(128, 128, 128)), + "Tree.leftChildIndent", new Integer(7), + "Tree.rightChildIndent", new Integer(13), + "Tree.rowHeight", new Integer(20), // FIXME + "Tree.scrollsOnExpand", Boolean.TRUE, + "Tree.selectionBackground", new ColorUIResource(Color.black), + "Tree.nonSelectionBackground", new ColorUIResource(new Color(239, 235, 231)), + "Tree.selectionBorderColor", new ColorUIResource(Color.black), + "Tree.selectionForeground", new ColorUIResource(new Color(255, 255, 255)), + "Tree.textBackground", new ColorUIResource(new Color(255, 255, 255)), + "Tree.textForeground", new ColorUIResource(Color.black), + "Viewport.background", new ColorUIResource(light), + "Viewport.foreground", new ColorUIResource(Color.black), + "Viewport.font", new FontUIResource("Dialog", Font.PLAIN, 12) + }; + defaults.putDefaults(uiDefaults); + } +} // class BasicLookAndFeel diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java new file mode 100644 index 00000000000..95f6b84fb7c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java @@ -0,0 +1,304 @@ +/* BasicMenuBarUI.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.BoxLayout; +import javax.swing.JComponent; +import javax.swing.JMenuBar; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.MenuBarUI; + +/** + * UI Delegate for JMenuBar. + */ +public class BasicMenuBarUI extends MenuBarUI +{ + protected ChangeListener changeListener; + + /*ContainerListener that listens to the ContainerEvents fired from menu bar*/ + protected ContainerListener containerListener; + + /*Property change listeners that listener to PropertyChangeEvent from menu bar*/ + protected PropertyChangeListener propertyChangeListener; + + /* menu bar for which this UI delegate is for*/ + protected JMenuBar menuBar; + + /** + * Creates a new BasicMenuBarUI object. + */ + public BasicMenuBarUI() + { + changeListener = createChangeListener(); + containerListener = createContainerListener(); + propertyChangeListener = new PropertyChangeHandler(); + } + + /** + * Creates ChangeListener + * + * @return The ChangeListener + */ + protected ChangeListener createChangeListener() + { + return new ChangeHandler(); + } + + /** + * Creates ContainerListener() to listen for ContainerEvents + * fired by JMenuBar. + * + * @return The ContainerListener + */ + protected ContainerListener createContainerListener() + { + return new ContainerHandler(); + } + + /** + * Factory method to create a BasicMenuBarUI for the given {@link + * JComponent}, which should be a {@link JMenuBar}. + * + * @param x The {@link JComponent} a UI is being created for. + * + * @return A BasicMenuBarUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicMenuBarUI(); + } + + /** + * Returns maximum size for the specified menu bar + * + * @param c component for which to get maximum size + * + * @return Maximum size for the specified menu bar + */ + public Dimension getMaximumSize(JComponent c) + { + // let layout manager calculate its size + return null; + } + + /** + * Returns maximum allowed size of JMenuBar. + * + * @param c menuBar for which to return maximum size + * + * @return Maximum size of the give menu bar. + */ + public Dimension getMinimumSize(JComponent c) + { + // let layout manager calculate its size + return null; + } + + /** + * Returns preferred size of JMenuBar. + * + * @param c menuBar for which to return preferred size + * + * @return Preferred size of the give menu bar. + */ + public Dimension getPreferredSize(JComponent c) + { + // let layout manager calculate its size + return null; + } + + /** + * Initializes any default properties that this UI has from the defaults for + * the Basic look and feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + menuBar.setBackground(defaults.getColor("MenuBar.background")); + menuBar.setBorder(defaults.getBorder("MenuBar.border")); + menuBar.setFont(defaults.getFont("MenuBar.font")); + menuBar.setForeground(defaults.getColor("MenuBar.foreground")); + menuBar.setOpaque(true); + } + + /** + * This method installs the keyboard actions for the JMenuBar. + */ + protected void installKeyboardActions() + { + // FIXME: implement + } + + /** + * This method installs the listeners needed for this UI to function. + */ + protected void installListeners() + { + menuBar.addContainerListener(containerListener); + menuBar.addPropertyChangeListener(propertyChangeListener); + } + + /** + * Installs and initializes all fields for this UI delegate. Any properties + * of the UI that need to be initialized and/or set to defaults will be + * done now. It will also install any listeners necessary. + * + * @param c The {@link JComponent} that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + menuBar = (JMenuBar) c; + menuBar.setLayout(new BoxLayout(menuBar, BoxLayout.X_AXIS)); + installDefaults(); + installListeners(); + installKeyboardActions(); + } + + /** + * This method uninstalls the defaults and nulls any objects created during + * install. + */ + protected void uninstallDefaults() + { + menuBar.setBackground(null); + menuBar.setBorder(null); + menuBar.setFont(null); + menuBar.setForeground(null); + } + + /** + * This method reverses the work done in installKeyboardActions. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * Unregisters all the listeners that this UI delegate was using. + */ + protected void uninstallListeners() + { + menuBar.removeContainerListener(containerListener); + menuBar.removePropertyChangeListener(propertyChangeListener); + } + + /** + * Performs the opposite of installUI. Any properties or resources that need + * to be cleaned up will be done now. It will also uninstall any listeners + * it has. In addition, any properties of this UI will be nulled. + * + * @param c The {@link JComponent} that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + uninstallDefaults(); + uninstallListeners(); + uninstallKeyboardActions(); + menuBar = null; + } + + protected class ChangeHandler implements ChangeListener + { + public void stateChanged(ChangeEvent event) + { + } + } + + /** + * This class handles ContainerEvents fired by JMenuBar. It revalidates + * and repaints menu bar whenever menu is added or removed from it. + */ + protected class ContainerHandler implements ContainerListener + { + /** + * This method is called whenever menu is added to the menu bar + * + * @param e The ContainerEvent. + */ + public void componentAdded(ContainerEvent e) + { + menuBar.revalidate(); + menuBar.repaint(); + } + + /** + * This method is called whenever menu is removed from the menu bar. + * + * @param e The ContainerEvent. + */ + public void componentRemoved(ContainerEvent e) + { + menuBar.revalidate(); + menuBar.repaint(); + } + } + + /** + * This class handles PropertyChangeEvents fired from the JMenuBar + */ + protected class PropertyChangeHandler implements PropertyChangeListener + { + /** + * This method is called whenever one of the properties of the MenuBar + * changes. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals("borderPainted")) + menuBar.repaint(); + if (e.getPropertyName().equals("margin")) + menuBar.repaint(); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java new file mode 100644 index 00000000000..a5bf0822ac5 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -0,0 +1,1006 @@ +/* BasicMenuItemUI.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.KeyStroke; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.MenuDragMouseEvent; +import javax.swing.event.MenuDragMouseListener; +import javax.swing.event.MenuKeyEvent; +import javax.swing.event.MenuKeyListener; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.MenuItemUI; + +/** + * UI Delegate for JMenuItem. + */ +public class BasicMenuItemUI extends MenuItemUI +{ + /** + * Font to be used when displaying menu item's accelerator. + */ + protected Font acceleratorFont; + + /** + * Color to be used when displaying menu item's accelerator. + */ + protected Color acceleratorForeground; + + /** + * Color to be used when displaying menu item's accelerator when menu item is + * selected. + */ + protected Color acceleratorSelectionForeground; + + /** + * Icon that is displayed after the text to indicated that this menu contains + * submenu. + */ + protected Icon arrowIcon; + + /** + * Icon that is displayed before the text. This icon is only used in + * JCheckBoxMenuItem or JRadioBoxMenuItem. + */ + protected Icon checkIcon; + + /** + * Number of spaces between icon and text. + */ + protected int defaultTextIconGap = 4; + + /** + * Color of the text when menu item is disabled + */ + protected Color disabledForeground; + + /** + * The menu Drag mouse listener listening to the menu item. + */ + protected MenuDragMouseListener menuDragMouseListener; + + /** + * The menu item itself + */ + protected JMenuItem menuItem; + + /** + * Menu Key listener listening to the menu item. + */ + protected MenuKeyListener menuKeyListener; + + /** + * mouse input listener listening to menu item. + */ + protected MouseInputListener mouseInputListener; + + /** + * Indicates if border should be painted + */ + protected boolean oldBorderPainted; + + /** + * Color of text that is used when menu item is selected + */ + protected Color selectionBackground; + + /** + * Color of the text that is used when menu item is selected. + */ + protected Color selectionForeground; + + /** + * String that separates description of the modifiers and the key + */ + private String acceleratorDelimiter; + + /** + * PropertyChangeListener to listen for property changes in the menu item + */ + private PropertyChangeListener propertyChangeListener; + + /** + * Number of spaces between accelerator and menu item's label. + */ + private int defaultAcceleratorLabelGap = 4; + + /** + * Creates a new BasicMenuItemUI object. + */ + public BasicMenuItemUI() + { + mouseInputListener = createMouseInputListener(menuItem); + menuDragMouseListener = createMenuDragMouseListener(menuItem); + menuKeyListener = createMenuKeyListener(menuItem); + propertyChangeListener = new PropertyChangeHandler(); + } + + /** + * Create MenuDragMouseListener to listen for mouse dragged events. + * + * @param c menu item to listen to + * + * @return The MenuDragMouseListener + */ + protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) + { + return new MenuDragMouseHandler(); + } + + /** + * Creates MenuKeyListener to listen to key events occuring when menu item + * is visible on the screen. + * + * @param c menu item to listen to + * + * @return The MenuKeyListener + */ + protected MenuKeyListener createMenuKeyListener(JComponent c) + { + return new MenuKeyHandler(); + } + + /** + * Handles mouse input events occuring for this menu item + * + * @param c menu item to listen to + * + * @return The MouseInputListener + */ + protected MouseInputListener createMouseInputListener(JComponent c) + { + return new MouseInputHandler(); + } + + /** + * Factory method to create a BasicMenuItemUI for the given {@link + * JComponent}, which should be a {@link JMenuItem}. + * + * @param c The {@link JComponent} a UI is being created for. + * + * @return A BasicMenuItemUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicMenuItemUI(); + } + + /** + * Programatically clicks menu item. + * + * @param msm MenuSelectionManager for the menu hierarchy + */ + protected void doClick(MenuSelectionManager msm) + { + menuItem.doClick(); + msm.clearSelectedPath(); + } + + /** + * Returns maximum size for the specified menu item + * + * @param c component for which to get maximum size + * + * @return Maximum size for the specified menu item. + */ + public Dimension getMaximumSize(JComponent c) + { + return null; + } + + /** + * Returns minimum size for the specified menu item + * + * @param c component for which to get minimum size + * + * @return Minimum size for the specified menu item. + */ + public Dimension getMinimumSize(JComponent c) + { + return null; + } + + /** + * Returns path to this menu item. + * + * @return $MenuElement[]$ Returns array of menu elements + * that constitute a path to this menu item. + */ + public MenuElement[] getPath() + { + ArrayList path = new ArrayList(); + + // Path to menu should also include its popup menu. + if (menuItem instanceof JMenu) + path.add(((JMenu) menuItem).getPopupMenu()); + + Component c = menuItem; + while (c instanceof MenuElement) + { + path.add(0, (MenuElement) c); + + if (c instanceof JPopupMenu) + c = ((JPopupMenu) c).getInvoker(); + else + c = c.getParent(); + } + + MenuElement[] pathArray = new MenuElement[path.size()]; + path.toArray(pathArray); + return pathArray; + } + + /** + * Returns preferred size for the given menu item. + * + * @param c menu item for which to get preferred size + * @param checkIcon chech icon displayed in the given menu item + * @param arrowIcon arrow icon displayed in the given menu item + * @param defaultTextIconGap space between icon and text in the given menuItem + * + * @return $Dimension$ preferred size for the given menu item + */ + protected Dimension getPreferredMenuItemSize(JComponent c, Icon checkIcon, + Icon arrowIcon, + int defaultTextIconGap) + { + JMenuItem m = (JMenuItem) c; + Dimension d = BasicGraphicsUtils.getPreferredButtonSize(m, + defaultTextIconGap); + + // if menu item has accelerator then take accelerator's size into account + // when calculating preferred size. + KeyStroke accelerator = m.getAccelerator(); + Rectangle rect; + + if (accelerator != null) + { + rect = getAcceleratorRect(accelerator, + m.getToolkit().getFontMetrics(acceleratorFont)); + + // add width of accelerator's text + d.width = d.width + rect.width + defaultAcceleratorLabelGap; + + // adjust the heigth of the preferred size if necessary + if (d.height < rect.height) + d.height = rect.height; + } + + if (checkIcon != null) + { + d.width = d.width + checkIcon.getIconWidth() + defaultTextIconGap; + + if (checkIcon.getIconHeight() > d.height) + d.height = checkIcon.getIconHeight(); + } + + if (arrowIcon != null && (c instanceof JMenu)) + { + d.width = d.width + arrowIcon.getIconWidth() + defaultTextIconGap; + + if (arrowIcon.getIconHeight() > d.height) + d.height = arrowIcon.getIconHeight(); + } + + return d; + } + + /** + * Returns preferred size of the given component + * + * @param c component for which to return preferred size + * + * @return $Dimension$ preferred size for the given component + */ + public Dimension getPreferredSize(JComponent c) + { + return getPreferredMenuItemSize(c, checkIcon, arrowIcon, defaultTextIconGap); + } + + protected String getPropertyPrefix() + { + return null; + } + + /** + * This method installs the components for this {@link JMenuItem}. + * + * @param menuItem The {@link JMenuItem} to install components for. + */ + protected void installComponents(JMenuItem menuItem) + { + // FIXME: Need to implement + } + + /** + * This method installs the defaults that are defined in the Basic look and + * feel for this {@link JMenuItem}. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + menuItem.setBackground(defaults.getColor("MenuItem.background")); + menuItem.setBorder(defaults.getBorder("MenuItem.border")); + menuItem.setFont(defaults.getFont("MenuItem.font")); + menuItem.setForeground(defaults.getColor("MenuItem.foreground")); + menuItem.setMargin(defaults.getInsets("MenuItem.margin")); + menuItem.setOpaque(true); + acceleratorFont = defaults.getFont("MenuItem.acceleratorFont"); + acceleratorForeground = defaults.getColor("MenuItem.acceleratorForeground"); + acceleratorSelectionForeground = defaults.getColor("MenuItem.acceleratorSelectionForeground"); + selectionBackground = defaults.getColor("MenuItem.selectionBackground"); + selectionForeground = defaults.getColor("MenuItem.selectionForeground"); + acceleratorDelimiter = defaults.getString("MenuItem.acceleratorDelimiter"); + + menuItem.setHorizontalTextPosition(SwingConstants.TRAILING); + menuItem.setHorizontalAlignment(SwingConstants.LEADING); + } + + /** + * This method installs the keyboard actions for this {@link JMenuItem}. + */ + protected void installKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * This method installs the listeners for the {@link JMenuItem}. + */ + protected void installListeners() + { + menuItem.addMouseListener(mouseInputListener); + menuItem.addMouseMotionListener(mouseInputListener); + menuItem.addMenuDragMouseListener(menuDragMouseListener); + menuItem.addMenuKeyListener(menuKeyListener); + menuItem.addPropertyChangeListener(propertyChangeListener); + } + + /** + * Installs and initializes all fields for this UI delegate. Any properties + * of the UI that need to be initialized and/or set to defaults will be + * done now. It will also install any listeners necessary. + * + * @param c The {@link JComponent} that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + menuItem = (JMenuItem) c; + installDefaults(); + installComponents(menuItem); + installListeners(); + } + + /** + * Paints given menu item using specified graphics context + * + * @param g The graphics context used to paint this menu item + * @param c Menu Item to paint + */ + public void paint(Graphics g, JComponent c) + { + paintMenuItem(g, c, checkIcon, arrowIcon, c.getBackground(), + c.getForeground(), defaultTextIconGap); + } + + /** + * Paints background of the menu item + * + * @param g The graphics context used to paint this menu item + * @param menuItem menu item to paint + * @param bgColor Background color to use when painting menu item + */ + protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) + { + Dimension size = getPreferredSize(menuItem); + Color foreground = g.getColor(); + g.setColor(bgColor); + g.drawRect(0, 0, size.width, size.height); + g.setColor(foreground); + } + + /** + * Paints specified menu item + * + * @param g The graphics context used to paint this menu item + * @param c menu item to paint + * @param checkIcon check icon to use when painting menu item + * @param arrowIcon arrow icon to use when painting menu item + * @param background Background color of the menu item + * @param foreground Foreground color of the menu item + * @param defaultTextIconGap space to use between icon and + * text when painting menu item + */ + protected void paintMenuItem(Graphics g, JComponent c, Icon checkIcon, + Icon arrowIcon, Color background, + Color foreground, int defaultTextIconGap) + { + JMenuItem m = (JMenuItem) c; + Rectangle tr = new Rectangle(); // text rectangle + Rectangle ir = new Rectangle(); // icon rectangle + Rectangle vr = new Rectangle(); // view rectangle + Rectangle br = new Rectangle(); // border rectangle + Rectangle ar = new Rectangle(); // accelerator rectangle + Rectangle cr = new Rectangle(); // checkIcon rectangle + + int vertAlign = m.getVerticalAlignment(); + int horAlign = m.getHorizontalAlignment(); + int vertTextPos = m.getVerticalTextPosition(); + int horTextPos = m.getHorizontalTextPosition(); + + Font f = m.getFont(); + g.setFont(f); + FontMetrics fm = g.getFontMetrics(f); + SwingUtilities.calculateInnerArea(m, br); + SwingUtilities.calculateInsetArea(br, m.getInsets(), vr); + paintBackground(g, m, m.getBackground()); + + /* MenuItems insets are equal to menuItems margin, space between text and + menuItems border. We need to paint insets region as well. */ + Insets insets = m.getInsets(); + br.x -= insets.left; + br.y -= insets.top; + br.width += insets.right + insets.left; + br.height += insets.top + insets.bottom; + + // Menu item is considered to be highlighted when it is selected. + if (m.isSelected() || m.getModel().isArmed() && + (m.getParent() instanceof MenuElement)) + { + if (m.isContentAreaFilled()) + { + g.setColor(selectionBackground); + g.fillRect(br.x, br.y, br.width, br.height); + } + } + else + { + if (m.isContentAreaFilled()) + { + g.setColor(m.getBackground()); + g.fillRect(br.x, br.y, br.width, br.height); + } + } + + // If this menu item is a JCheckBoxMenuItem then paint check icon + if (checkIcon != null) + { + SwingUtilities.layoutCompoundLabel(m, fm, null, checkIcon, vertAlign, + horAlign, vertTextPos, horTextPos, + vr, cr, tr, defaultTextIconGap); + checkIcon.paintIcon(m, g, cr.x, cr.y); + + // We need to calculate position of the menu text and position of + // user menu icon if there exists one relative to the check icon. + // So we need to adjust view rectangle s.t. its starting point is at + // checkIcon.width + defaultTextIconGap. + vr.x = cr.x + cr.width + defaultTextIconGap; + } + + // if this is a submenu, then paint arrow icon to indicate it. + if (arrowIcon != null && (c instanceof JMenu)) + { + if (! ((JMenu) c).isTopLevelMenu()) + { + int width = arrowIcon.getIconWidth(); + int height = arrowIcon.getIconHeight(); + + arrowIcon.paintIcon(m, g, vr.width - width + defaultTextIconGap, + vr.y + 2); + } + } + + // paint text and user menu icon if it exists + Icon i = m.getIcon(); + SwingUtilities.layoutCompoundLabel(c, fm, m.getText(), i, + vertAlign, horAlign, vertTextPos, + horTextPos, vr, ir, tr, + defaultTextIconGap); + if (i != null) + i.paintIcon(c, g, ir.x, ir.y); + + paintText(g, m, tr, m.getText()); + + // paint accelerator + String acceleratorText = ""; + + if (m.getAccelerator() != null) + { + acceleratorText = getAcceleratorText(m.getAccelerator()); + fm = g.getFontMetrics(acceleratorFont); + ar.width = fm.stringWidth(acceleratorText); + ar.x = br.width - ar.width; + vr.x = br.width - ar.width; + + SwingUtilities.layoutCompoundLabel(m, fm, acceleratorText, null, + vertAlign, horAlign, vertTextPos, + horTextPos, vr, ir, ar, + defaultTextIconGap); + + paintAccelerator(g, m, ar, acceleratorText); + } + } + + /** + * Paints label for the given menu item + * + * @param g The graphics context used to paint this menu item + * @param menuItem menu item for which to draw its label + * @param textRect rectangle specifiying position of the text relative to + * the given menu item + * @param text label of the menu item + */ + protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, + String text) + { + Font f = menuItem.getFont(); + g.setFont(f); + FontMetrics fm = g.getFontMetrics(f); + + if (text != null && ! text.equals("")) + { + if (menuItem.isEnabled()) + { + // Menu item is considered to be highlighted when it is selected. + if (menuItem.isSelected() || menuItem.getModel().isArmed() && + (menuItem.getParent() instanceof MenuElement)) + g.setColor(selectionForeground); + else + g.setColor(menuItem.getForeground()); + } + else + // FIXME: should fix this to use 'disabledForeground', but its + // default value in BasicLookAndFeel is null. + + // FIXME: should there be different foreground colours for selected + // or deselected, when disabled? + g.setColor(Color.gray); + + int mnemonicIndex = menuItem.getDisplayedMnemonicIndex(); + + if (mnemonicIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemonicIndex, + textRect.x, + textRect.y + + fm.getAscent()); + else + BasicGraphicsUtils.drawString(g, text, 0, textRect.x, + textRect.y + fm.getAscent()); + } + } + + /** + * This method uninstalls the components for this {@link JMenuItem}. + * + * @param menuItem The {@link JMenuItem} to uninstall components for. + */ + protected void uninstallComponents(JMenuItem menuItem) + { + // FIXME: need to implement + } + + /** + * This method uninstalls the defaults and sets any objects created during + * install to null + */ + protected void uninstallDefaults() + { + menuItem.setForeground(null); + menuItem.setBackground(null); + menuItem.setBorder(null); + menuItem.setMargin(null); + menuItem.setBackground(null); + menuItem.setBorder(null); + menuItem.setFont(null); + menuItem.setForeground(null); + menuItem.setMargin(null); + acceleratorFont = null; + acceleratorForeground = null; + acceleratorSelectionForeground = null; + arrowIcon = null; + selectionBackground = null; + selectionForeground = null; + acceleratorDelimiter = null; + } + + /** + * Uninstalls any keyboard actions. + */ + protected void uninstallKeyboardActions() + { + // FIXME: need to implement + } + + /** + * Unregisters all the listeners that this UI delegate was using. + */ + protected void uninstallListeners() + { + menuItem.removeMouseListener(mouseInputListener); + menuItem.removeMenuDragMouseListener(menuDragMouseListener); + menuItem.removeMenuKeyListener(menuKeyListener); + menuItem.removePropertyChangeListener(propertyChangeListener); + } + + /** + * Performs the opposite of installUI. Any properties or resources that need + * to be cleaned up will be done now. It will also uninstall any listeners + * it has. In addition, any properties of this UI will be nulled. + * + * @param c The {@link JComponent} that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + uninstallListeners(); + uninstallDefaults(); + uninstallComponents(menuItem); + menuItem = null; + } + + /** + * This method calls paint. + * + * @param g The graphics context used to paint this menu item + * @param c The menu item to paint + */ + public void update(Graphics g, JComponent c) + { + paint(g, c); + } + + /** + * Return text representation of the specified accelerator + * + * @param accelerator Accelerator for which to return string representation + * + * @return $String$ Text representation of the given accelerator + */ + private String getAcceleratorText(KeyStroke accelerator) + { + // convert keystroke into string format + String modifiersText = ""; + int modifiers = accelerator.getModifiers(); + char keyChar = accelerator.getKeyChar(); + int keyCode = accelerator.getKeyCode(); + + if (modifiers != 0) + modifiersText = KeyEvent.getKeyModifiersText(modifiers) + + acceleratorDelimiter; + + if (keyCode == KeyEvent.VK_UNDEFINED) + return modifiersText + keyChar; + else + return modifiersText + KeyEvent.getKeyText(keyCode); + } + + /** + * Calculates and return rectange in which accelerator should be displayed + * + * @param accelerator accelerator for which to return the display rectangle + * @param fm The font metrics used to measure the text + * + * @return $Rectangle$ reactangle which will be used to display accelerator + */ + private Rectangle getAcceleratorRect(KeyStroke accelerator, FontMetrics fm) + { + int width = fm.stringWidth(getAcceleratorText(accelerator)); + int height = fm.getHeight(); + return new Rectangle(0, 0, width, height); + } + + /** + * Paints accelerator inside menu item + * + * @param g The graphics context used to paint the border + * @param menuItem Menu item for which to draw accelerator + * @param acceleratorRect rectangle representing position + * of the accelerator relative to the menu item + * @param acceleratorText accelerator's text + */ + private void paintAccelerator(Graphics g, JMenuItem menuItem, + Rectangle acceleratorRect, + String acceleratorText) + { + g.setFont(acceleratorFont); + FontMetrics fm = g.getFontMetrics(acceleratorFont); + + if (menuItem.isEnabled()) + g.setColor(acceleratorForeground); + else + // FIXME: should fix this to use 'disabledForeground', but its + // default value in BasicLookAndFeel is null. + g.setColor(Color.gray); + + BasicGraphicsUtils.drawString(g, acceleratorText, 0, acceleratorRect.x, + acceleratorRect.y + fm.getAscent()); + } + + /** + * This class handles mouse events occuring inside the menu item. + * Most of the events are forwarded for processing to MenuSelectionManager + * of the current menu hierarchy. + * + */ + protected class MouseInputHandler implements MouseInputListener + { + /** + * Creates a new MouseInputHandler object. + */ + protected MouseInputHandler() + { + } + + /** + * This method is called when mouse is clicked on the menu item. + * It forwards this event to MenuSelectionManager. + * + * @param e A {@link MouseEvent}. + */ + public void mouseClicked(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + /** + * This method is called when mouse is dragged inside the menu item. + * It forwards this event to MenuSelectionManager. + * + * @param e A {@link MouseEvent}. + */ + public void mouseDragged(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + /** + * This method is called when mouse enters menu item. + * When this happens menu item is considered to be selected and selection path + * in MenuSelectionManager is set. This event is also forwarded to MenuSelection + * Manager for further processing. + * + * @param e A {@link MouseEvent}. + */ + public void mouseEntered(MouseEvent e) + { + Component source = (Component) e.getSource(); + if (source.getParent() instanceof MenuElement) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.setSelectedPath(getPath()); + manager.processMouseEvent(e); + } + } + + /** + * This method is called when mouse exits menu item. The event is + * forwarded to MenuSelectionManager for processing. + * + * @param e A {@link MouseEvent}. + */ + public void mouseExited(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + /** + * This method is called when mouse is inside the menu item. + * This event is forwarder to MenuSelectionManager for further processing. + * + * @param e A {@link MouseEvent}. + */ + public void mouseMoved(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + /** + * This method is called when mouse is pressed. This event is forwarded to + * MenuSelectionManager for further processing. + * + * @param e A {@link MouseEvent}. + */ + public void mousePressed(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + /** + * This method is called when mouse is released. If the mouse is released + * inside this menuItem, then this menu item is considered to be chosen and + * the menu hierarchy should be closed. + * + * @param e A {@link MouseEvent}. + */ + public void mouseReleased(MouseEvent e) + { + Rectangle size = menuItem.getBounds(); + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + if (e.getX() > 0 && e.getX() < size.width && e.getY() > 0 + && e.getY() < size.height) + { + manager.clearSelectedPath(); + menuItem.doClick(); + } + + else + manager.processMouseEvent(e); + } + } + + /** + * This class handles mouse dragged events. + */ + protected class MenuDragMouseHandler implements MenuDragMouseListener + { + /** + * Tbis method is invoked when mouse is dragged over the menu item. + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseDragged(MenuDragMouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.setSelectedPath(e.getPath()); + } + + /** + * Tbis method is invoked when mouse enters the menu item while it is + * being dragged. + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseEntered(MenuDragMouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.setSelectedPath(e.getPath()); + } + + /** + * Tbis method is invoked when mouse exits the menu item while + * it is being dragged + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseExited(MenuDragMouseEvent e) + { + } + + /** + * Tbis method is invoked when mouse was dragged and released + * inside the menu item. + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseReleased(MenuDragMouseEvent e) + { + MenuElement[] path = e.getPath(); + + if (path[path.length - 1] instanceof JMenuItem) + ((JMenuItem) path[path.length - 1]).doClick(); + + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.clearSelectedPath(); + } + } + + /** + * This class handles key events occuring when menu item is visible on the + * screen. + */ + protected class MenuKeyHandler implements MenuKeyListener + { + /** + * This method is invoked when key has been pressed + * + * @param e A {@link MenuKeyEvent}. + */ + public void menuKeyPressed(MenuKeyEvent e) + { + } + + /** + * This method is invoked when key has been pressed + * + * @param e A {@link MenuKeyEvent}. + */ + public void menuKeyReleased(MenuKeyEvent e) + { + } + + /** + * This method is invoked when key has been typed + * It handles the mnemonic key for the menu item. + * + * @param e A {@link MenuKeyEvent}. + */ + public void menuKeyTyped(MenuKeyEvent e) + { + } + } + + /** + * Helper class that listens for changes to the properties of the {@link + * JMenuItem}. + */ + protected class PropertyChangeHandler implements PropertyChangeListener + { + /** + * This method is called when one of the menu item's properties change. + * + * @param evt A {@link PropertyChangeEvent}. + */ + public void propertyChange(PropertyChangeEvent evt) + { + menuItem.revalidate(); + menuItem.repaint(); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java new file mode 100644 index 00000000000..6bd15ede2c5 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java @@ -0,0 +1,541 @@ +/* BasicMenuUI.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JPopupMenu; +import javax.swing.MenuSelectionManager; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MenuDragMouseEvent; +import javax.swing.event.MenuDragMouseListener; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuKeyEvent; +import javax.swing.event.MenuKeyListener; +import javax.swing.event.MenuListener; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; + +/** + * UI Delegate for JMenu + */ +public class BasicMenuUI extends BasicMenuItemUI +{ + protected ChangeListener changeListener; + + /* MenuListener listens to MenuEvents fired by JMenu */ + protected MenuListener menuListener; + + /* PropertyChangeListner that listens to propertyChangeEvents occuring in JMenu*/ + protected PropertyChangeListener propertyChangeListener; + + /** + * Creates a new BasicMenuUI object. + */ + public BasicMenuUI() + { + mouseInputListener = createMouseInputListener((JMenu) menuItem); + menuListener = createMenuListener((JMenu) menuItem); + propertyChangeListener = createPropertyChangeListener((JMenu) menuItem); + } + + /** + * This method creates a new ChangeListener. + * + * @return A new ChangeListener. + */ + protected ChangeListener createChangeListener(JComponent c) + { + return new ChangeHandler(); + } + + /** + * This method creates new MenuDragMouseListener to listen to mouse dragged events + * occuring in the Menu + * + * @param c the menu to listen to + * + * @return The MenuDrageMouseListener + */ + protected MenuDragMouseListener createMenuDragMouseListener(JComponent c) + { + return new MenuDragMouseHandler(); + } + + /** + * This method creates new MenuDragKeyListener to listen to key events + * + * @param c the menu to listen to + * + * @return The MenuKeyListener + */ + protected MenuKeyListener createMenuKeyListener(JComponent c) + { + return new MenuKeyHandler(); + } + + /** + * This method creates new MenuListener to listen to menu events + * occuring in the Menu + * + * @param c the menu to listen to + * + * @return The MenuListener + */ + protected MenuListener createMenuListener(JComponent c) + { + return new MenuHandler(); + } + + /** + * This method creates new MouseInputListener to listen to mouse input events + * occuring in the Menu + * + * @param c the menu to listen to + * + * @return The MouseInputListener + */ + protected MouseInputListener createMouseInputListener(JComponent c) + { + return new MouseInputHandler(); + } + + /** + * This method creates newPropertyChangeListener to listen to property changes + * occuring in the Menu + * + * @param c the menu to listen to + * + * @return The PropertyChangeListener + */ + protected PropertyChangeListener createPropertyChangeListener(JComponent c) + { + return new PropertyChangeHandler(); + } + + /** + * This method creates a new BasicMenuUI. + * + * @param c The JComponent to create a UI for. + * + * @return A new BasicMenuUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicMenuUI(); + } + + /** + * Get the component's maximum size. + * + * @param c The JComponent for which to get maximum size + * + * @return The maximum size of the component + */ + public Dimension getMaximumSize(JComponent c) + { + return c.getPreferredSize(); + } + + protected String getPropertyPrefix() + { + return null; + } + + /** + * Initializes any default properties that this UI has from the defaults for + * the Basic look and feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + menuItem.setBackground(defaults.getColor("Menu.background")); + menuItem.setBorder(defaults.getBorder("Menu.border")); + menuItem.setFont(defaults.getFont("Menu.font")); + menuItem.setForeground(defaults.getColor("Menu.foreground")); + menuItem.setMargin(defaults.getInsets("Menu.margin")); + acceleratorFont = defaults.getFont("Menu.acceleratorFont"); + acceleratorForeground = defaults.getColor("Menu.acceleratorForeground"); + acceleratorSelectionForeground = defaults.getColor("Menu.acceleratorSelectionForeground"); + selectionBackground = defaults.getColor("Menu.selectionBackground"); + selectionForeground = defaults.getColor("Menu.selectionForeground"); + arrowIcon = defaults.getIcon("Menu.arrowIcon"); + oldBorderPainted = defaults.getBoolean("Menu.borderPainted"); + menuItem.setOpaque(true); + } + + /** + * Installs any keyboard actions. The list of keys that need to be bound are + * listed in Basic look and feel's defaults. + * + */ + protected void installKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * Creates and registers all the listeners for this UI delegate. + */ + protected void installListeners() + { + ((JMenu) menuItem).addMouseListener(mouseInputListener); + ((JMenu) menuItem).addMouseMotionListener(mouseInputListener); + ((JMenu) menuItem).addMenuListener(menuListener); + ((JMenu) menuItem).addMenuDragMouseListener(menuDragMouseListener); + } + + protected void setupPostTimer(JMenu menu) + { + } + + /** + * This method uninstalls the defaults and sets any objects created during + * install to null + */ + protected void uninstallDefaults() + { + menuItem.setBackground(null); + menuItem.setBorder(null); + menuItem.setFont(null); + menuItem.setForeground(null); + menuItem.setMargin(null); + acceleratorFont = null; + acceleratorForeground = null; + acceleratorSelectionForeground = null; + selectionBackground = null; + selectionForeground = null; + arrowIcon = null; + } + + /** + * Uninstalls any keyboard actions. The list of keys used are listed in + * Basic look and feel's defaults. + */ + protected void uninstallKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * Unregisters all the listeners that this UI delegate was using. In + * addition, it will also null any listeners that it was using. + */ + protected void uninstallListeners() + { + ((JMenu) menuItem).removeMouseListener(mouseInputListener); + ((JMenu) menuItem).removeMenuListener(menuListener); + ((JMenu) menuItem).removePropertyChangeListener(propertyChangeListener); + } + + /** + * This class is used by menus to handle mouse events occuring in the + * menu. + */ + protected class MouseInputHandler implements MouseInputListener + { + public void mouseClicked(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + public void mouseDragged(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + private boolean popupVisible() + { + JMenuBar mb = (JMenuBar) ((JMenu)menuItem).getParent(); + // check if mb.isSelected because if no menus are selected + // we don't have to look through the list for popup menus + if (!mb.isSelected()) + return false; + for (int i=0;i<mb.getMenuCount();i++) + if (((JMenu)mb.getComponent(i)).isPopupMenuVisible()) + return true; + return false; + } + + public void mouseEntered(MouseEvent e) + { + /* When mouse enters menu item, it should be considered selected + + if (i) if this menu is a submenu in some other menu + (ii) or if this menu is in a menu bar and some other menu in a + menu bar was just selected and has its popup menu visible. + (If nothing was selected, menu should be pressed before + it will be selected) + */ + JMenu menu = (JMenu) menuItem; + + // NOTE: the following if used to require !menu.isArmed but I could find + // no reason for this and it was preventing some JDK-compatible behaviour. + // Specifically, if a menu is selected but its popup menu not visible, + // and then another menu is selected whose popup menu IS visible, when + // the mouse is moved over the first menu, its popup menu should become + // visible. + + if (! menu.isTopLevelMenu() || popupVisible()) + { + // set new selection and forward this event to MenuSelectionManager + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.setSelectedPath(getPath()); + manager.processMouseEvent(e); + } + } + + public void mouseExited(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + + public void mouseMoved(MouseEvent e) + { + } + + public void mousePressed(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + JMenu menu = (JMenu) menuItem; + manager.processMouseEvent(e); + + // Menu should be displayed when the menu is pressed only if + // it is top-level menu + if (menu.isTopLevelMenu()) + { + if (menu.getPopupMenu().isVisible()) + // If menu is visible and menu button was pressed.. + // then need to cancel the menu + manager.clearSelectedPath(); + else + { + // Display the menu + int x = 0; + int y = menu.getHeight(); + + manager.setSelectedPath(getPath()); + + JMenuBar mb = (JMenuBar) menu.getParent(); + + // set selectedIndex of the selectionModel of a menuBar + mb.getSelectionModel().setSelectedIndex(mb.getComponentIndex(menu)); + } + } + } + + public void mouseReleased(MouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.processMouseEvent(e); + } + } + + /** + * This class handles MenuEvents fired by the JMenu + */ + protected class MenuHandler implements MenuListener + { + /** + * This method is called when menu is cancelled. The menu is cancelled + * when its popup menu is closed without selection. It clears selected index + * in the selectionModel of the menu parent. + * + * @param e The MenuEvent. + */ + public void menuCanceled(MenuEvent e) + { + menuDeselected(e); + } + + /** + * This method is called when menu is deselected. It clears selected index + * in the selectionModel of the menu parent. + * + * @param e The MenuEvent. + */ + public void menuDeselected(MenuEvent e) + { + JMenu menu = (JMenu) menuItem; + if (menu.isTopLevelMenu()) + ((JMenuBar) menu.getParent()).getSelectionModel().clearSelection(); + else + ((JPopupMenu) menu.getParent()).getSelectionModel().clearSelection(); + } + + /** + * This method is called when menu is selected. It sets selected index + * in the selectionModel of the menu parent. + * + * @param e The MenuEvent. + */ + public void menuSelected(MenuEvent e) + { + JMenu menu = (JMenu) menuItem; + if (menu.isTopLevelMenu()) + ((JMenuBar) menu.getParent()).setSelected(menu); + else + ((JPopupMenu) menu.getParent()).setSelected(menu); + } + } + + /** + * This class handles PropertyChangeEvents fired from the JMenu + */ + protected class PropertyChangeHandler implements PropertyChangeListener + { + /** + * This method is called whenever one of the properties of the menu item + * changes. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + } + } + + /** + * @deprecated + */ + public class ChangeHandler implements ChangeListener + { + public void stateChanged(ChangeEvent e) + { + // FIXME: It seems that this class is not used anywhere + } + } + + /** + * This class handles mouse dragged events occuring in the menu. + */ + protected class MenuDragMouseHandler implements MenuDragMouseListener + { + /** + * This method is invoked when mouse is dragged over the menu item. + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseDragged(MenuDragMouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.setSelectedPath(e.getPath()); + } + + /** + * This method is invoked when mouse enters the menu item while it is + * being dragged. + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseEntered(MenuDragMouseEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.setSelectedPath(e.getPath()); + } + + /** + * This method is invoked when mouse exits the menu item while + * it is being dragged + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseExited(MenuDragMouseEvent e) + { + } + + /** + * This method is invoked when mouse was dragged and released + * inside the menu item. + * + * @param e The MenuDragMouseEvent + */ + public void menuDragMouseReleased(MenuDragMouseEvent e) + { + } + } + + /** + * This class handles key events occuring when menu item is visible on the + * screen. + */ + protected class MenuKeyHandler implements MenuKeyListener + { + /** + * This method is invoked when key has been pressed + * + * @param e A {@link MenuKeyEvent}. + */ + public void menuKeyPressed(MenuKeyEvent e) + { + } + + /** + * This method is invoked when key has been pressed + * + * @param e A {@link MenuKeyEvent}. + */ + public void menuKeyReleased(MenuKeyEvent e) + { + } + + /** + * This method is invoked when key has been typed + * It handles the mnemonic key for the menu item. + * + * @param e A {@link MenuKeyEvent}. + */ + public void menuKeyTyped(MenuKeyEvent e) + { + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java new file mode 100644 index 00000000000..ce29f24b42a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -0,0 +1,1329 @@ +/* BasicOptionPaneUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Polygon; +import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JInternalFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.OptionPaneUI; + +/** + * This class is the UI delegate for JOptionPane in the Basic Look and Feel. + */ +public class BasicOptionPaneUI extends OptionPaneUI +{ + /** + * This is a helper class that listens to the buttons located at the bottom + * of the JOptionPane. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class ButtonActionListener implements ActionListener + { + /** The index of the option this button represents. */ + protected int buttonIndex; + + /** + * Creates a new ButtonActionListener object with the given buttonIndex. + * + * @param buttonIndex The index of the option this button represents. + */ + public ButtonActionListener(int buttonIndex) + { + this.buttonIndex = buttonIndex; + } + + /** + * This method is called when one of the option buttons are pressed. + * + * @param e The ActionEvent. + */ + public void actionPerformed(ActionEvent e) + { + Object value = new Integer(JOptionPane.CLOSED_OPTION); + Object[] options = optionPane.getOptions(); + if (options != null) + value = new Integer(buttonIndex); + else + { + String text = ((JButton) e.getSource()).getText(); + if (text.equals(OK_STRING)) + value = new Integer(JOptionPane.OK_OPTION); + if (text.equals(CANCEL_STRING)) + value = new Integer(JOptionPane.CANCEL_OPTION); + if (text.equals(YES_STRING)) + value = new Integer(JOptionPane.YES_OPTION); + if (text.equals(NO_STRING)) + value = new Integer(JOptionPane.NO_OPTION); + } + optionPane.setValue(value); + resetInputValue(); + + Window owner = SwingUtilities.windowForComponent(optionPane); + + if (owner instanceof JDialog) + ((JDialog) owner).dispose(); + + //else we probably have some kind of internal frame. + JInternalFrame inf = (JInternalFrame) SwingUtilities.getAncestorOfClass(JInternalFrame.class, + optionPane); + if (inf != null) + { + try + { + inf.setClosed(true); + } + catch (PropertyVetoException pve) + { + } + } + } + } + + /** + * This helper layout manager is responsible for the layout of the button + * area. The button area is the panel that holds the buttons which + * represent the options. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public static class ButtonAreaLayout implements LayoutManager + { + /** Whether this layout will center the buttons. */ + protected boolean centersChildren = true; + + /** The space between the buttons. */ + protected int padding; + + /** Whether the buttons will share the same widths. */ + protected boolean syncAllWidths; + + /** The width of the widest button. */ + private transient int widthOfWidestButton; + + /** The height of the tallest button. */ + private transient int tallestButton; + + /** + * Creates a new ButtonAreaLayout object with the given sync widths + * property and padding. + * + * @param syncAllWidths Whether the buttons will share the same widths. + * @param padding The padding between the buttons. + */ + public ButtonAreaLayout(boolean syncAllWidths, int padding) + { + this.syncAllWidths = syncAllWidths; + this.padding = padding; + } + + /** + * This method is called when a component is added to the container. + * + * @param string The constraints string. + * @param comp The component added. + */ + public void addLayoutComponent(String string, Component comp) + { + // Do nothing. + } + + /** + * This method returns whether the children will be centered. + * + * @return Whether the children will be centered. + */ + public boolean getCentersChildren() + { + return centersChildren; + } + + /** + * This method returns the amount of space between components. + * + * @return The amount of space between components. + */ + public int getPadding() + { + return padding; + } + + /** + * This method returns whether all components will share widths (set to + * largest width). + * + * @return Whether all components will share widths. + */ + public boolean getSyncAllWidths() + { + return syncAllWidths; + } + + /** + * This method lays out the given container. + * + * @param container The container to lay out. + */ + public void layoutContainer(Container container) + { + Component[] buttonList = container.getComponents(); + int x = container.getInsets().left; + if (getCentersChildren()) + x += (int) ((double) (container.getSize().width) / 2 + - (double) (buttonRowLength(container)) / 2); + for (int i = 0; i < buttonList.length; i++) + { + Dimension dims = buttonList[i].getPreferredSize(); + if (syncAllWidths) + { + buttonList[i].setBounds(x, 0, widthOfWidestButton, dims.height); + x += widthOfWidestButton + getPadding(); + } + else + { + buttonList[i].setBounds(x, 0, dims.width, dims.height); + x += dims.width + getPadding(); + } + } + } + + /** + * This method returns the width of the given container taking into + * consideration the padding and syncAllWidths. + * + * @param c The container to calculate width for. + * + * @return The width of the given container. + */ + private int buttonRowLength(Container c) + { + Component[] buttonList = c.getComponents(); + + int buttonLength = 0; + int widest = 0; + int tallest = 0; + + for (int i = 0; i < buttonList.length; i++) + { + Dimension dims = buttonList[i].getPreferredSize(); + buttonLength += dims.width + getPadding(); + widest = Math.max(widest, dims.width); + tallest = Math.max(tallest, dims.height); + } + + widthOfWidestButton = widest; + tallestButton = tallest; + + int width; + if (getSyncAllWidths()) + width = widest * buttonList.length + + getPadding() * (buttonList.length - 1); + else + width = buttonLength; + + Insets insets = c.getInsets(); + width += insets.left + insets.right; + + return width; + } + + /** + * This method returns the minimum layout size for the given container. + * + * @param c The container to measure. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * This method returns the preferred size of the given container. + * + * @param c The container to measure. + * + * @return The preferred size. + */ + public Dimension preferredLayoutSize(Container c) + { + int w = buttonRowLength(c); + + return new Dimension(w, tallestButton); + } + + /** + * This method removes the given component from the layout manager's + * knowledge. + * + * @param c The component to remove. + */ + public void removeLayoutComponent(Component c) + { + // Do nothing. + } + + /** + * This method sets whether the children will be centered. + * + * @param newValue Whether the children will be centered. + */ + public void setCentersChildren(boolean newValue) + { + centersChildren = newValue; + } + + /** + * This method sets the amount of space between each component. + * + * @param newPadding The padding between components. + */ + public void setPadding(int newPadding) + { + padding = newPadding; + } + + /** + * This method sets whether the widths will be synced. + * + * @param newValue Whether the widths will be synced. + */ + public void setSyncAllWidths(boolean newValue) + { + syncAllWidths = newValue; + } + } + + /** + * This helper class handles property change events from the JOptionPane. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * This method is called when one of the properties of the JOptionPane + * changes. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JOptionPane.ICON_PROPERTY) + || e.getPropertyName().equals(JOptionPane.MESSAGE_TYPE_PROPERTY)) + addIcon(messageAreaContainer); + else if (e.getPropertyName().equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY)) + resetSelectedValue(); + else if (e.getPropertyName().equals(JOptionPane.INITIAL_VALUE_PROPERTY) + || e.getPropertyName().equals(JOptionPane.OPTIONS_PROPERTY) + || e.getPropertyName().equals(JOptionPane.OPTION_TYPE_PROPERTY)) + { + Container newButtons = createButtonArea(); + optionPane.remove(buttonContainer); + optionPane.add(newButtons); + buttonContainer = newButtons; + } + + else if (e.getPropertyName().equals(JOptionPane.MESSAGE_PROPERTY) + || e.getPropertyName().equals(JOptionPane.WANTS_INPUT_PROPERTY) + || e.getPropertyName().equals(JOptionPane.SELECTION_VALUES_PROPERTY)) + { + optionPane.removeAll(); + messageAreaContainer = createMessageArea(); + optionPane.add(messageAreaContainer); + optionPane.add(buttonContainer); + } + optionPane.invalidate(); + optionPane.repaint(); + } + } + + /** Whether the JOptionPane contains custom components. */ + protected boolean hasCustomComponents = false; + + // The initialFocusComponent seems to always be set to a button (even if + // I try to set initialSelectionValue). This is different from what the + // javadocs state (which should switch this reference to the input component + // if one is present since that is what's going to get focus). + + /** + * The button that will receive focus based on initialValue when no input + * component is present. If an input component is present, then the input + * component will receive focus instead. + */ + protected Component initialFocusComponent; + + /** The component that receives input when the JOptionPane needs it. */ + protected JComponent inputComponent; + + /** The minimum height of the JOptionPane. */ + public static int minimumHeight; + + /** The minimum width of the JOptionPane. */ + public static int minimumWidth; + + /** The minimum dimensions of the JOptionPane. */ + protected Dimension minimumSize; + + /** The propertyChangeListener for the JOptionPane. */ + protected PropertyChangeListener propertyChangeListener; + + /** The JOptionPane this UI delegate is used for. */ + protected JOptionPane optionPane; + + /** The size of the icons. */ + // FIXME: wrong name for a constant. + private static final int iconSize = 36; + + /** The foreground color for the message area. */ + private transient Color messageForeground; + + /** The border around the message area. */ + private transient Border messageBorder; + + /** The border around the button area. */ + private transient Border buttonBorder; + + /** The string used to describe OK buttons. */ + private static final String OK_STRING = "OK"; + + /** The string used to describe Yes buttons. */ + private static final String YES_STRING = "Yes"; + + /** The string used to describe No buttons. */ + private static final String NO_STRING = "No"; + + /** The string used to describe Cancel buttons. */ + private static final String CANCEL_STRING = "Cancel"; + + /** The container for the message area. + * This is package-private to avoid an accessor method. */ + transient Container messageAreaContainer; + + /** The container for the buttons. + * This is package-private to avoid an accessor method. */ + transient Container buttonContainer; + + /** + * A helper class that implements Icon. This is used temporarily until + * ImageIcons are fixed. + */ + private static class MessageIcon implements Icon + { + /** + * This method returns the width of the icon. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return iconSize; + } + + /** + * This method returns the height of the icon. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return iconSize; + } + + /** + * This method paints the icon as a part of the given component using the + * given graphics and the given x and y position. + * + * @param c The component that owns this icon. + * @param g The Graphics object to paint with. + * @param x The x coordinate. + * @param y The y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + } + } + + /** The icon displayed for ERROR_MESSAGE. */ + private static MessageIcon errorIcon = new MessageIcon() + { + public void paintIcon(Component c, Graphics g, int x, int y) + { + Polygon oct = new Polygon(new int[] { 0, 0, 9, 27, 36, 36, 27, 9 }, + new int[] { 9, 27, 36, 36, 27, 9, 0, 0 }, 8); + g.translate(x, y); + + Color saved = g.getColor(); + g.setColor(Color.RED); + + g.fillPolygon(oct); + + g.setColor(Color.BLACK); + g.drawRect(13, 16, 10, 4); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** The icon displayed for INFORMATION_MESSAGE. */ + private static MessageIcon infoIcon = new MessageIcon() + { + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.translate(x, y); + Color saved = g.getColor(); + + // Should be purple. + g.setColor(Color.RED); + + g.fillOval(0, 0, iconSize, iconSize); + + g.setColor(Color.BLACK); + g.drawOval(16, 6, 4, 4); + + Polygon bottomI = new Polygon(new int[] { 15, 15, 13, 13, 23, 23, 21, 21 }, + new int[] { 12, 28, 28, 30, 30, 28, 28, 12 }, + 8); + g.drawPolygon(bottomI); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** The icon displayed for WARNING_MESSAGE. */ + private static MessageIcon warningIcon = new MessageIcon() + { + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.translate(x, y); + Color saved = g.getColor(); + g.setColor(Color.YELLOW); + + Polygon triangle = new Polygon(new int[] { 0, 18, 36 }, + new int[] { 36, 0, 36 }, 3); + g.fillPolygon(triangle); + + g.setColor(Color.BLACK); + + Polygon excl = new Polygon(new int[] { 15, 16, 20, 21 }, + new int[] { 8, 26, 26, 8 }, 4); + g.drawPolygon(excl); + g.drawOval(16, 30, 4, 4); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + /** The icon displayed for MESSAGE_ICON. */ + private static MessageIcon questionIcon = new MessageIcon() + { + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.translate(x, y); + Color saved = g.getColor(); + g.setColor(Color.GREEN); + + g.fillRect(0, 0, iconSize, iconSize); + + g.setColor(Color.BLACK); + + g.drawOval(11, 2, 16, 16); + g.drawOval(14, 5, 10, 10); + + g.setColor(Color.GREEN); + g.fillRect(0, 10, iconSize, iconSize - 10); + + g.setColor(Color.BLACK); + + g.drawLine(11, 10, 14, 10); + + g.drawLine(24, 10, 17, 22); + g.drawLine(27, 10, 20, 22); + g.drawLine(17, 22, 20, 22); + + g.drawOval(17, 25, 3, 3); + + g.setColor(saved); + g.translate(-x, -y); + } + }; + + // FIXME: Uncomment when the ImageIcons are fixed. + + /* IconUIResource warningIcon, questionIcon, infoIcon, errorIcon;*/ + + /** + * Creates a new BasicOptionPaneUI object. + */ + public BasicOptionPaneUI() + { + } + + /** + * This method is messaged to add the buttons to the given container. + * + * @param container The container to add components to. + * @param buttons The buttons to add. (If it is an instance of component, + * the Object is added directly. If it is an instance of Icon, it is + * packed into a label and added. For all other cases, the string + * representation of the Object is retreived and packed into a + * label.) + * @param initialIndex The index of the component that is the initialValue. + */ + protected void addButtonComponents(Container container, Object[] buttons, + int initialIndex) + { + if (buttons == null) + return; + for (int i = 0; i < buttons.length; i++) + { + if (buttons[i] != null) + { + Component toAdd; + if (buttons[i] instanceof Component) + toAdd = (Component) buttons[i]; + else + { + if (buttons[i] instanceof Icon) + toAdd = new JButton((Icon) buttons[i]); + else + toAdd = new JButton(buttons[i].toString()); + hasCustomComponents = true; + } + if (toAdd instanceof JButton) + ((JButton) toAdd).addActionListener(createButtonActionListener(i)); + if (i == initialIndex) + initialFocusComponent = toAdd; + container.add(toAdd); + } + } + selectInitialValue(optionPane); + } + + /** + * This method adds the appropriate icon the given container. + * + * @param top The container to add an icon to. + */ + protected void addIcon(Container top) + { + JLabel iconLabel = null; + Icon icon = getIcon(); + if (icon != null) + { + iconLabel = new JLabel(icon); + top.add(iconLabel, BorderLayout.WEST); + } + } + + /** + * A helper method that returns an instance of GridBagConstraints to be used + * for creating the message area. + * + * @return An instance of GridBagConstraints. + */ + private static GridBagConstraints createConstraints() + { + GridBagConstraints constraints = new GridBagConstraints(); + constraints.gridx = GridBagConstraints.REMAINDER; + constraints.gridy = GridBagConstraints.REMAINDER; + constraints.gridwidth = 0; + constraints.anchor = GridBagConstraints.LINE_START; + constraints.fill = GridBagConstraints.NONE; + constraints.insets = new Insets(0, 0, 3, 0); + + return constraints; + } + + /** + * This method creates the proper object (if necessary) to represent msg. + * (If msg is an instance of Component, it will add it directly. If it is + * an icon, then it will pack it in a label and add it. Otherwise, it gets + * treated as a string. If the string is longer than maxll, a box is + * created and the burstStringInto is called with the box as the container. + * The box is then added to the given container. Otherwise, the string is + * packed in a label and placed in the given container.) This method is + * also used for adding the inputComponent to the container. + * + * @param container The container to add to. + * @param cons The constraints when adding. + * @param msg The message to add. + * @param maxll The max line length. + * @param internallyCreated Whether the msg is internally created. + */ + protected void addMessageComponents(Container container, + GridBagConstraints cons, Object msg, + int maxll, boolean internallyCreated) + { + if (msg == null) + return; + hasCustomComponents = internallyCreated; + if (msg instanceof Object[]) + { + Object[] arr = (Object[]) msg; + for (int i = 0; i < arr.length; i++) + addMessageComponents(container, cons, arr[i], maxll, + internallyCreated); + return; + } + else if (msg instanceof Component) + { + container.add((Component) msg, cons); + cons.gridy++; + } + else if (msg instanceof Icon) + { + container.add(new JLabel((Icon) msg), cons); + cons.gridy++; + } + else + { + // Undocumented behaviour. + // if msg.toString().length greater than maxll + // it will create a box and burst the string. + // otherwise, it will just create a label and re-call + // this method with the label o.O + if (msg.toString().length() > maxll) + { + Box tmp = new Box(BoxLayout.Y_AXIS); + burstStringInto(tmp, msg.toString(), maxll); + addMessageComponents(container, cons, tmp, maxll, true); + } + else + addMessageComponents(container, cons, new JLabel(msg.toString()), + maxll, true); + } + } + + /** + * This method creates instances of d (recursively if necessary based on + * maxll) and adds to c. + * + * @param c The container to add to. + * @param d The string to burst. + * @param maxll The max line length. + */ + protected void burstStringInto(Container c, String d, int maxll) + { + // FIXME: Verify that this is the correct behaviour. + // One interpretation of the spec is that this method + // should recursively call itself to create (and add) + // JLabels to the container if the length of the String d + // is greater than maxll. + // but in practice, even with a really long string, this is + // all that happens. + if (d == null || c == null) + return; + JLabel label = new JLabel(d); + c.add(label); + } + + /** + * This method returns true if the given JOptionPane contains custom + * components. + * + * @param op The JOptionPane to check. + * + * @return True if the JOptionPane contains custom components. + */ + public boolean containsCustomComponents(JOptionPane op) + { + return hasCustomComponents; + } + + /** + * This method creates a button action listener for the given button index. + * + * @param buttonIndex The index of the button in components. + * + * @return A new ButtonActionListener. + */ + protected ActionListener createButtonActionListener(int buttonIndex) + { + return new ButtonActionListener(buttonIndex); + } + + /** + * This method creates the button area. + * + * @return A new Button Area. + */ + protected Container createButtonArea() + { + JPanel buttonPanel = new JPanel(); + + buttonPanel.setLayout(createLayoutManager()); + addButtonComponents(buttonPanel, getButtons(), getInitialValueIndex()); + + return buttonPanel; + } + + /** + * This method creates a new LayoutManager for the button area. + * + * @return A new LayoutManager for the button area. + */ + protected LayoutManager createLayoutManager() + { + return new ButtonAreaLayout(getSizeButtonsToSameWidth(), 6); + } + + /** + * This method creates the message area. + * + * @return A new message area. + */ + protected Container createMessageArea() + { + JPanel messageArea = new JPanel(); + messageArea.setLayout(new BorderLayout()); + addIcon(messageArea); + + JPanel rightSide = new JPanel(); + rightSide.setBorder(BorderFactory.createEmptyBorder(0, 11, 17, 0)); + rightSide.setLayout(new GridBagLayout()); + GridBagConstraints con = createConstraints(); + + addMessageComponents(rightSide, con, getMessage(), + getMaxCharactersPerLineCount(), false); + + if (optionPane.getWantsInput()) + { + Object[] selection = optionPane.getSelectionValues(); + + if (selection == null) + inputComponent = new JTextField(15); + else if (selection.length < 20) + inputComponent = new JComboBox(selection); + else + inputComponent = new JList(selection); + if (inputComponent != null) + { + addMessageComponents(rightSide, con, inputComponent, + getMaxCharactersPerLineCount(), false); + resetSelectedValue(); + selectInitialValue(optionPane); + } + } + + messageArea.add(rightSide, BorderLayout.EAST); + + return messageArea; + } + + /** + * This method creates a new PropertyChangeListener for listening to the + * JOptionPane. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * This method creates a Container that will separate the message and button + * areas. + * + * @return A Container that will separate the message and button areas. + */ + protected Container createSeparator() + { + return (Container) Box.createVerticalStrut(17); + } + + /** + * This method creates a new BasicOptionPaneUI for the given component. + * + * @param x The component to create a UI for. + * + * @return A new BasicOptionPaneUI. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicOptionPaneUI(); + } + + /** + * This method returns the buttons for the JOptionPane. If no options are + * set, a set of options will be created based upon the optionType. + * + * @return The buttons that will be added. + */ + protected Object[] getButtons() + { + if (optionPane.getOptions() != null) + return optionPane.getOptions(); + switch (optionPane.getOptionType()) + { + case JOptionPane.YES_NO_OPTION: + return new Object[] { YES_STRING, NO_STRING }; + case JOptionPane.YES_NO_CANCEL_OPTION: + return new Object[] { YES_STRING, NO_STRING, CANCEL_STRING }; + case JOptionPane.OK_CANCEL_OPTION: + case JOptionPane.DEFAULT_OPTION: + return new Object[] { OK_STRING, CANCEL_STRING }; + } + return null; + } + + /** + * This method will return the icon the user has set or the icon that will + * be used based on message type. + * + * @return The icon to use in the JOptionPane. + */ + protected Icon getIcon() + { + if (optionPane.getIcon() != null) + return optionPane.getIcon(); + else + return getIconForType(optionPane.getMessageType()); + } + + /** + * This method returns the icon for the given messageType. + * + * @param messageType The type of message. + * + * @return The icon for the given messageType. + */ + protected Icon getIconForType(int messageType) + { + Icon tmp = null; + switch (messageType) + { + case JOptionPane.ERROR_MESSAGE: + tmp = errorIcon; + break; + case JOptionPane.INFORMATION_MESSAGE: + tmp = infoIcon; + break; + case JOptionPane.WARNING_MESSAGE: + tmp = warningIcon; + break; + case JOptionPane.QUESTION_MESSAGE: + tmp = questionIcon; + break; + } + return tmp; + // FIXME: Don't cast till the default icons are in. + // return new IconUIResource(tmp); + } + + /** + * This method returns the index of the initialValue in the options array. + * + * @return The index of the initalValue. + */ + protected int getInitialValueIndex() + { + Object[] buttons = getButtons(); + + if (buttons == null) + return -1; + + Object select = optionPane.getInitialValue(); + + for (int i = 0; i < buttons.length; i++) + { + if (select == buttons[i]) + return i; + } + return 0; + } + + /** + * This method returns the maximum number of characters that should be + * placed on a line. + * + * @return The maximum number of characteres that should be placed on a + * line. + */ + protected int getMaxCharactersPerLineCount() + { + return optionPane.getMaxCharactersPerLineCount(); + } + + /** + * This method returns the maximum size. + * + * @param c The JComponent to measure. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the message of the JOptionPane. + * + * @return The message. + */ + protected Object getMessage() + { + return optionPane.getMessage(); + } + + /** + * This method returns the minimum size of the JOptionPane. + * + * @return The minimum size. + */ + public Dimension getMinimumOptionPaneSize() + { + return minimumSize; + } + + /** + * This method returns the minimum size. + * + * @param c The JComponent to measure. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size of the JOptionPane. The preferred + * size is the maximum of the size desired by the layout and the minimum + * size. + * + * @param c The JComponent to measure. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + Dimension d = optionPane.getLayout().preferredLayoutSize(optionPane); + Dimension d2 = getMinimumOptionPaneSize(); + + int w = Math.max(d.width, d2.width); + int h = Math.max(d.height, d2.height); + return new Dimension(w, h); + } + + /** + * This method returns whether all buttons should have the same width. + * + * @return Whether all buttons should have the same width. + */ + protected boolean getSizeButtonsToSameWidth() + { + return true; + } + + /** + * This method installs components for the JOptionPane. + */ + protected void installComponents() + { + // reset it. + hasCustomComponents = false; + Container msg = createMessageArea(); + if (msg != null) + { + ((JComponent) msg).setBorder(messageBorder); + msg.setForeground(messageForeground); + messageAreaContainer = msg; + optionPane.add(msg); + } + + Container sep = createSeparator(); + if (sep != null) + optionPane.add(sep); + + Container button = createButtonArea(); + if (button != null) + { + ((JComponent) button).setBorder(buttonBorder); + buttonContainer = button; + optionPane.add(button); + } + + optionPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 11, 11)); + optionPane.invalidate(); + } + + /** + * This method installs defaults for the JOptionPane. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + optionPane.setFont(defaults.getFont("OptionPane.font")); + optionPane.setBackground(defaults.getColor("OptionPane.background")); + optionPane.setForeground(defaults.getColor("OptionPane.foreground")); + optionPane.setBorder(defaults.getBorder("OptionPane.border")); + optionPane.setOpaque(true); + + messageBorder = defaults.getBorder("OptionPane.messageAreaBorder"); + messageForeground = defaults.getColor("OptionPane.messageForeground"); + buttonBorder = defaults.getBorder("OptionPane.buttonAreaBorder"); + + minimumSize = defaults.getDimension("OptionPane.minimumSize"); + minimumWidth = minimumSize.width; + minimumHeight = minimumSize.height; + + // FIXME: Image icons don't seem to work properly right now. + // Once they do, replace the synthetic icons with these ones. + + /* + warningIcon = (IconUIResource) defaults.getIcon("OptionPane.warningIcon"); + infoIcon = (IconUIResource) defaults.getIcon("OptionPane.informationIcon"); + errorIcon = (IconUIResource) defaults.getIcon("OptionPane.errorIcon"); + questionIcon = (IconUIResource) defaults.getIcon("OptionPane.questionIcon"); + */ + } + + /** + * This method installs keyboard actions for the JOptionpane. + */ + protected void installKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method installs listeners for the JOptionPane. + */ + protected void installListeners() + { + propertyChangeListener = createPropertyChangeListener(); + + optionPane.addPropertyChangeListener(propertyChangeListener); + } + + /** + * This method installs the UI for the JOptionPane. + * + * @param c The JComponent to install the UI for. + */ + public void installUI(JComponent c) + { + if (c instanceof JOptionPane) + { + optionPane = (JOptionPane) c; + + installDefaults(); + installComponents(); + installListeners(); + installKeyboardActions(); + } + } + + /** + * Changes the inputValue property in the JOptionPane based on the current + * value of the inputComponent. + */ + protected void resetInputValue() + { + if (optionPane.getWantsInput() && inputComponent != null) + { + Object output = null; + if (inputComponent instanceof JTextField) + output = ((JTextField) inputComponent).getText(); + else if (inputComponent instanceof JComboBox) + output = ((JComboBox) inputComponent).getSelectedItem(); + else if (inputComponent instanceof JList) + output = ((JList) inputComponent).getSelectedValue(); + + if (output != null) + optionPane.setInputValue(output); + } + } + + /** + * This method requests focus to the inputComponent (if one is present) and + * the initialFocusComponent otherwise. + * + * @param op The JOptionPane. + */ + public void selectInitialValue(JOptionPane op) + { + if (inputComponent != null) + { + inputComponent.requestFocus(); + return; + } + if (initialFocusComponent != null) + initialFocusComponent.requestFocus(); + } + + /** + * This method resets the value in the inputComponent to the + * initialSelectionValue property. + * This is package-private to avoid an accessor method. + */ + void resetSelectedValue() + { + if (inputComponent != null) + { + Object init = optionPane.getInitialSelectionValue(); + if (init == null) + return; + if (inputComponent instanceof JTextField) + ((JTextField) inputComponent).setText((String) init); + else if (inputComponent instanceof JComboBox) + ((JComboBox) inputComponent).setSelectedItem(init); + else if (inputComponent instanceof JList) + { + // ((JList) inputComponent).setSelectedValue(init, true); + } + } + } + + /** + * This method uninstalls all the components in the JOptionPane. + */ + protected void uninstallComponents() + { + optionPane.removeAll(); + buttonContainer = null; + messageAreaContainer = null; + } + + /** + * This method uninstalls the defaults for the JOptionPane. + */ + protected void uninstallDefaults() + { + optionPane.setFont(null); + optionPane.setForeground(null); + optionPane.setBackground(null); + + minimumSize = null; + + messageBorder = null; + buttonBorder = null; + messageForeground = null; + + // FIXME: ImageIcons don't seem to work properly + + /* + warningIcon = null; + errorIcon = null; + questionIcon = null; + infoIcon = null; + */ + } + + /** + * This method uninstalls keyboard actions for the JOptionPane. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method uninstalls listeners for the JOptionPane. + */ + protected void uninstallListeners() + { + optionPane.removePropertyChangeListener(propertyChangeListener); + propertyChangeListener = null; + } + + /** + * This method uninstalls the UI for the given JComponent. + * + * @param c The JComponent to uninstall for. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallComponents(); + uninstallDefaults(); + + optionPane = null; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java new file mode 100644 index 00000000000..0896721ca99 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java @@ -0,0 +1,67 @@ +/* BasicPanelUI.java + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.PanelUI; + +public class BasicPanelUI extends PanelUI +{ + public static ComponentUI createUI(JComponent x) + { + return new BasicPanelUI(); + } + + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JPanel) + { + JPanel p = (JPanel) c; + installDefaults(p); + } + } + + public void installDefaults(JPanel p) + { + p.setOpaque(true); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPasswordFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPasswordFieldUI.java new file mode 100644 index 00000000000..044027b0b4a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPasswordFieldUI.java @@ -0,0 +1,67 @@ +/* BasicPasswordFieldUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.Element; +import javax.swing.text.PasswordView; +import javax.swing.text.View; + +public class BasicPasswordFieldUI extends BasicTextFieldUI +{ + public BasicPasswordFieldUI() + { + } + + public View create(Element elem) + { + return new PasswordView(elem); + } + + public static ComponentUI createUI(JComponent c) + { + return new BasicPasswordFieldUI(); + } + + protected String getPropertyPrefix() + { + return "PasswordField"; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuSeparatorUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuSeparatorUI.java new file mode 100644 index 00000000000..b6294772286 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuSeparatorUI.java @@ -0,0 +1,114 @@ +/* BasicPopupMenuSeparatorUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JPopupMenu; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ComponentUI; + +/** + * The Basic Look and Feel UI delegate for JPopupMenu.Separator. + */ +public class BasicPopupMenuSeparatorUI extends BasicSeparatorUI +{ + /** + * Creates a new BasicPopupMenuSeparatorUI object. + */ + public BasicPopupMenuSeparatorUI() + { + super(); + } + + /** + * Creates a new UI delegate for the given JComponent. + * + * @param c The JComponent to create a delegate for. + * + * @return A new BasicPopupMenuSeparatorUI + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicPopupMenuSeparatorUI(); + } + + /** + * The Popup Menu Separator has two lines. The top line will be + * painted using highlight color and the bottom using shadow color. + * + * @param g The Graphics object to paint with + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + if (! (c instanceof JPopupMenu.Separator)) + return; + + Rectangle r = new Rectangle(); + SwingUtilities.calculateInnerArea(c, r); + Color saved = g.getColor(); + + int midAB = r.width / 2 + r.x; + int midAD = r.height / 2 + r.y; + + g.setColor(highlight); + g.drawLine(r.x, midAD, r.x + r.width, midAD); + + g.setColor(shadow); + g.drawLine(r.x, midAD + 1, r.x + r.width, midAD + 1); + } + + /** + * This method returns the preferred size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + return super.getPreferredSize(c); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java new file mode 100644 index 00000000000..247117bc983 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -0,0 +1,674 @@ +/* BasicPopupMenuUI.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.MouseEvent; + +import javax.swing.BoxLayout; +import javax.swing.JComponent; +import javax.swing.JLayeredPane; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPopupMenu; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.RootPaneContainer; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.MouseInputListener; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.PopupMenuUI; + + +/** + * UI Delegate for JPopupMenu + */ +public class BasicPopupMenuUI extends PopupMenuUI +{ + /* popupMenu for which this UI delegate is for*/ + protected JPopupMenu popupMenu; + + /* MouseInputListener listens to mouse events. Package private for inner classes. */ + static transient MouseInputListener mouseInputListener; + + /* PopupMenuListener listens to popup menu events fired by JPopupMenu*/ + private transient PopupMenuListener popupMenuListener; + + /* ComponentListener listening to popupMenu's invoker. + * This is package-private to avoid an accessor method. */ + TopWindowListener topWindowListener; + + /** + * Creates a new BasicPopupMenuUI object. + */ + public BasicPopupMenuUI() + { + popupMenuListener = new PopupMenuHandler(); + topWindowListener = new TopWindowListener(); + } + + /** + * Factory method to create a BasicPopupMenuUI for the given {@link + * JComponent}, which should be a {@link JMenuItem}. + * + * @param x The {@link JComponent} a UI is being created for. + * + * @return A BasicPopupMenuUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicPopupMenuUI(); + } + + /** + * Installs and initializes all fields for this UI delegate. Any properties + * of the UI that need to be initialized and/or set to defaults will be + * done now. It will also install any listeners necessary. + * + * @param c The {@link JComponent} that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + popupMenu = (JPopupMenu) c; + popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS)); + popupMenu.setBorderPainted(true); + JPopupMenu.setDefaultLightWeightPopupEnabled(true); + + installDefaults(); + installListeners(); + } + + /** + * This method installs the defaults that are defined in the Basic look + * and feel for this {@link JPopupMenu}. + */ + public void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + popupMenu.setBackground(defaults.getColor("PopupMenu.background")); + popupMenu.setBorder(defaults.getBorder("PopupMenu.border")); + popupMenu.setFont(defaults.getFont("PopupMenu.font")); + popupMenu.setForeground(defaults.getColor("PopupMenu.foreground")); + popupMenu.setOpaque(true); + } + + /** + * This method installs the listeners for the {@link JMenuItem}. + */ + protected void installListeners() + { + popupMenu.addPopupMenuListener(popupMenuListener); + } + + /** + * This method installs the keyboard actions for this {@link JPopupMenu}. + */ + protected void installKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * Performs the opposite of installUI. Any properties or resources that need + * to be cleaned up will be done now. It will also uninstall any listeners + * it has. In addition, any properties of this UI will be nulled. + * + * @param c The {@link JComponent} that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + uninstallListeners(); + uninstallDefaults(); + popupMenu = null; + } + + /** + * This method uninstalls the defaults and sets any objects created during + * install to null + */ + protected void uninstallDefaults() + { + popupMenu.setBackground(null); + popupMenu.setBorder(null); + popupMenu.setFont(null); + popupMenu.setForeground(null); + } + + /** + * Unregisters all the listeners that this UI delegate was using. + */ + protected void uninstallListeners() + { + popupMenu.removePopupMenuListener(popupMenuListener); + } + + /** + * Uninstalls any keyboard actions. + */ + protected void uninstallKeyboardActions() + { + // FIXME: Need to implement + } + + /** + * This method returns the minimum size of the JPopupMenu. + * + * @param c The JComponent to find a size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return null; + } + + /** + * This method returns the preferred size of the JPopupMenu. + * + * @param c The JComponent to find a size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + return null; + } + + /** + * This method returns the minimum size of the JPopupMenu. + * + * @param c The JComponent to find a size for. + * + * @return The minimum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return null; + } + + /** + * Return true if given mouse event is a platform popup trigger, and false + * otherwise + * + * @param e MouseEvent that is to be checked for popup trigger event + * + * @return true if given mouse event is a platform popup trigger, and false + * otherwise + */ + public boolean isPopupTrigger(MouseEvent e) + { + return false; + } + + /** + * This listener handles PopupMenuEvents fired by JPopupMenu + */ + private class PopupMenuHandler implements PopupMenuListener + { + /** + * This method is invoked when JPopupMenu is cancelled. + * + * @param event the PopupMenuEvent + */ + public void popupMenuCanceled(PopupMenuEvent event) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.clearSelectedPath(); + } + + /** + * This method is invoked when JPopupMenu becomes invisible + * + * @param event the PopupMenuEvent + */ + public void popupMenuWillBecomeInvisible(PopupMenuEvent event) + { + // remove listener that listens to component events fired + // by the top - level window that this popup belongs to. + Component invoker = popupMenu.getInvoker(); + + RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities + .getRoot(invoker); + ((Container) rootContainer).removeComponentListener(topWindowListener); + + // If this popup menu is the last popup menu visible on the screen, then + // stop interrupting mouse events in the glass pane before hiding this + // last popup menu. + boolean topLevelMenu = (popupMenu.getInvoker() instanceof JMenu) + && ((JMenu) popupMenu.getInvoker()) + .isTopLevelMenu(); + + if (topLevelMenu || ! (popupMenu.getInvoker() instanceof MenuElement)) + { + // set glass pane not to interrupt mouse events and remove + // mouseInputListener + Container glassPane = (Container) rootContainer.getGlassPane(); + glassPane.setVisible(false); + glassPane.removeMouseListener(mouseInputListener); + mouseInputListener = null; + } + } + + /** + * This method is invoked when JPopupMenu becomes visible + * + * @param event the PopupMenuEvent + */ + public void popupMenuWillBecomeVisible(PopupMenuEvent event) + { + // Adds topWindowListener to top-level window to listener to + // ComponentEvents fired by it. We need to cancel this popup menu + // if topWindow to which this popup belongs was resized or moved. + Component invoker = popupMenu.getInvoker(); + RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities + .getRoot(invoker); + ((Container) rootContainer).addComponentListener(topWindowListener); + + // Set the glass pane to interrupt all mouse events originating in root + // container + if (mouseInputListener == null) + { + Container glassPane = (Container) rootContainer.getGlassPane(); + glassPane.setVisible(true); + mouseInputListener = new MouseInputHandler(rootContainer); + glassPane.addMouseListener(mouseInputListener); + glassPane.addMouseMotionListener(mouseInputListener); + } + + // if this popup menu is a free floating popup menu, + // then by default its first element should be always selected when + // this popup menu becomes visible. + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + + if (manager.getSelectedPath().length == 0) + { + // Set selected path to point to the first item in the popup menu + MenuElement[] path = new MenuElement[2]; + path[0] = popupMenu; + Component[] comps = popupMenu.getComponents(); + if (comps.length != 0 && comps[0] instanceof MenuElement) + { + path[1] = (MenuElement) comps[0]; + manager.setSelectedPath(path); + } + } + } + } + + /** + * ComponentListener that listens to Component Events fired by the top - + * level window to which popup menu belongs. If top-level window was + * resized, moved or hidded then popup menu will be hidded and selected + * path of current menu hierarchy will be set to null. + */ + private class TopWindowListener implements ComponentListener + { + /** + * This method is invoked when top-level window is resized. This method + * closes current menu hierarchy. + * + * @param e The ComponentEvent + */ + public void componentResized(ComponentEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.clearSelectedPath(); + } + + /** + * This method is invoked when top-level window is moved. This method + * closes current menu hierarchy. + * + * @param e The ComponentEvent + */ + public void componentMoved(ComponentEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.clearSelectedPath(); + } + + /** + * This method is invoked when top-level window is shown This method + * does nothing by default. + * + * @param e The ComponentEvent + */ + public void componentShown(ComponentEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.clearSelectedPath(); + } + + /** + * This method is invoked when top-level window is hidden This method + * closes current menu hierarchy. + * + * @param e The ComponentEvent + */ + public void componentHidden(ComponentEvent e) + { + MenuSelectionManager manager = MenuSelectionManager.defaultManager(); + manager.clearSelectedPath(); + } + } + + /** + * MouseInputHandler listens to all mouse events originated in the root + * container. This class is responsible for closing menu hierarchy when the + * user presses mouse over any component that do not belong to the current + * menu hierarchy. This is acomplished by interrupting all mouse event in + * the glass pane and checking if other component was pressed while menu + * was open, before redestributing events further to intended components + */ + private class MouseInputHandler implements MouseInputListener + { + private JLayeredPane layeredPane; + private Container glassPane; + private Cursor nativeCursor; + private transient Component mouseEventTarget; + private transient Component pressedComponent; + private transient Component lastComponentEntered; + private transient Component tempComponent; + private transient int pressCount; + + /** + * Creates a new MouseInputHandler object. + * + * @param c the top most root container + */ + public MouseInputHandler(RootPaneContainer c) + { + layeredPane = c.getLayeredPane(); + glassPane = (Container) c.getGlassPane(); + } + + /** + * Handles mouse clicked event + * + * @param e Mouse event + */ + public void mouseClicked(MouseEvent e) + { + handleEvent(e); + } + + /** + * Handles mouseDragged event + * + * @param e MouseEvent + */ + public void mouseDragged(MouseEvent e) + { + handleEvent(e); + } + + /** + * Handles mouseEntered event + * + * @param e MouseEvent + */ + public void mouseEntered(MouseEvent e) + { + handleEvent(e); + } + + /** + * Handles mouseExited event + * + * @param e MouseEvent + */ + public void mouseExited(MouseEvent e) + { + handleEvent(e); + } + + /** + * Handles mouse moved event + * + * @param e MouseEvent + */ + public void mouseMoved(MouseEvent e) + { + handleEvent(e); + } + + /** + * Handles mouse pressed event + * + * @param e MouseEvent + */ + public void mousePressed(MouseEvent e) + { + handleEvent(e); + } + + /** + * Handles mouse released event + * + * @param e MouseEvent + */ + public void mouseReleased(MouseEvent e) + { + handleEvent(e); + } + + /* + * This method determines component that was intended to received mouse + * event, before it was interrupted within the glass pane. This method + * also redispatches mouse entered and mouse exited events to the + * appropriate components. This code is slightly modified code from + * Container.LightweightDispatcher class, which is private inside + * Container class and cannot be used here. + */ + public void acquireComponentForMouseEvent(MouseEvent me) + { + int x = me.getX(); + int y = me.getY(); + + // Find the candidate which should receive this event. + Component parent = layeredPane; + Component candidate = null; + Point p = me.getPoint(); + while ((candidate == null) && (parent != null)) + { + p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent); + candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y); + + if (candidate == null) + { + p = SwingUtilities.convertPoint(parent, p.x, p.y, + parent.getParent()); + parent = parent.getParent(); + } + } + + // If the only candidate we found was the native container itself, + // don't dispatch any event at all. We only care about the lightweight + // children here. + if (candidate == layeredPane) + candidate = null; + + // If our candidate is new, inform the old target we're leaving. + if ((lastComponentEntered != null) && lastComponentEntered.isShowing() + && (lastComponentEntered != candidate)) + { + // Old candidate could have been removed from + // the layeredPane so we check first. + if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane)) + { + Point tp = SwingUtilities.convertPoint(layeredPane, x, y, + lastComponentEntered); + MouseEvent exited = new MouseEvent(lastComponentEntered, + MouseEvent.MOUSE_EXITED, + me.getWhen(), + me.getModifiersEx(), tp.x, + tp.y, me.getClickCount(), + me.isPopupTrigger(), + me.getButton()); + + tempComponent = lastComponentEntered; + lastComponentEntered = null; + tempComponent.dispatchEvent(exited); + } + + lastComponentEntered = null; + } + + // If we have a candidate, maybe enter it. + if (candidate != null) + { + mouseEventTarget = candidate; + + if (candidate.isLightweight() && candidate.isShowing() + && (candidate != layeredPane) + && (candidate != lastComponentEntered)) + { + lastComponentEntered = mouseEventTarget; + + Point cp = SwingUtilities.convertPoint(layeredPane, x, y, + lastComponentEntered); + MouseEvent entered = new MouseEvent(lastComponentEntered, + MouseEvent.MOUSE_ENTERED, + me.getWhen(), + me.getModifiersEx(), cp.x, + cp.y, me.getClickCount(), + me.isPopupTrigger(), + me.getButton()); + lastComponentEntered.dispatchEvent(entered); + } + } + + if ((me.getID() == MouseEvent.MOUSE_RELEASED) + || ((me.getID() == MouseEvent.MOUSE_PRESSED) && (pressCount > 0)) + || (me.getID() == MouseEvent.MOUSE_DRAGGED)) + { + // If any of the following events occur while a button is held down, + // they should be dispatched to the same component to which the + // original MOUSE_PRESSED event was dispatched: + // - MOUSE_RELEASED + // - MOUSE_PRESSED: another button pressed while the first is held down + // - MOUSE_DRAGGED + if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane)) + mouseEventTarget = pressedComponent; + else if (me.getID() == MouseEvent.MOUSE_CLICKED) + { + // Don't dispatch CLICKED events whose target is not the same as the + // target for the original PRESSED event. + if (candidate != pressedComponent) + mouseEventTarget = null; + else if (pressCount == 0) + pressedComponent = null; + } + } + } + + /* + * This method handles mouse events interrupted by glassPane. It + * redispatches the mouse events appropriately to the intended components. + * The code in this method is also taken from + * Container.LightweightDispatcher class. The code is slightly modified + * to handle the case when mouse is released over non-menu component. In + * this case this method closes current menu hierarchy before + * redispatching the event further. + */ + public void handleEvent(AWTEvent e) + { + if (e instanceof MouseEvent) + { + MouseEvent me = (MouseEvent) e; + + acquireComponentForMouseEvent(me); + + // Avoid dispatching ENTERED and EXITED events twice. + if (mouseEventTarget != null && mouseEventTarget.isShowing() + && (e.getID() != MouseEvent.MOUSE_ENTERED) + && (e.getID() != MouseEvent.MOUSE_EXITED)) + { + MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane, + me, + mouseEventTarget); + + mouseEventTarget.dispatchEvent(newEvt); + + // If mouse was clicked over the component that is not part + // of menu hierarchy,then must close the menu hierarchy */ + if (e.getID() == MouseEvent.MOUSE_RELEASED) + { + boolean partOfMenuHierarchy = false; + MenuSelectionManager manager = MenuSelectionManager + .defaultManager(); + + partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget); + + if (! partOfMenuHierarchy) + manager.clearSelectedPath(); + } + + switch (e.getID()) + { + case MouseEvent.MOUSE_PRESSED: + if (pressCount++ == 0) + pressedComponent = mouseEventTarget; + break; + case MouseEvent.MOUSE_RELEASED: + // Clear our memory of the original PRESSED event, only if + // we're not expecting a CLICKED event after this. If + // there is a CLICKED event after this, it will do clean up. + if ((--pressCount == 0) + && (mouseEventTarget != pressedComponent)) + pressedComponent = null; + break; + } + } + } + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java new file mode 100644 index 00000000000..d00628f53d4 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicProgressBarUI.java @@ -0,0 +1,827 @@ +/* BasicProgressBarUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.font.FontRenderContext; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JProgressBar; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ProgressBarUI; + +/** + * The Basic Look and Feel UI delegate for the + * JProgressBar. + */ +public class BasicProgressBarUI extends ProgressBarUI +{ + /** + * A helper class that listens for ChangeEvents + * from the progressBar's model. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class ChangeHandler implements ChangeListener + { + /** + * Called every time the state of the model changes. + * + * @param e The ChangeEvent given by the model. + */ + public void stateChanged(ChangeEvent e) + { + // Nothing to do but repaint. + progressBar.repaint(); + } + } + + /** + * This helper class is used to listen for + * PropertyChangeEvents from the progressBar. + */ + private class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called every time the properties of the + * progressBar change. + * + * @param e The PropertyChangeEvent given by the progressBar. + */ + public void propertyChange(PropertyChangeEvent e) + { + // Only need to listen for indeterminate changes. + // All other things are done on a repaint. + if (e.getPropertyName().equals("inderterminate")) + if (((Boolean) e.getNewValue()).booleanValue()) + startAnimationTimer(); + else + stopAnimationTimer(); + else + progressBar.repaint(); + } + } + + /** + * This helper class is used to listen for + * the animationTimer's intervals. On every interval, + * the bouncing box should move. + */ + private class Animator implements ActionListener + { + /** + * Called every time the animationTimer reaches + * its interval. + * + * @param e The ActionEvent given by the timer. + */ + public void actionPerformed(ActionEvent e) + { + // Incrementing the animation index will cause + // a repaint. + incrementAnimationIndex(); + } + } + + /** The timer used to move the bouncing box. */ + private transient Timer animationTimer; + + // The total number of frames must be an even number. + // The total number of frames is calculated from + // the cycleTime and repaintInterval given by + // the basic Look and Feel defaults. + // + // +-----------------------------------------------+ + // | frame0 | frame1 | frame2 | frame 3 | frame 4 | + // | | frame7 | frame6 | frame 5 | | + // +-----------------------------------------------+ + + /** The current animation index. */ + private transient int animationIndex; + + /** The total number of frames.*/ + private transient int numFrames; + + /** The helper that moves the bouncing box. */ + private transient Animator animation; + + /** The helper that listens for property change events. */ + private transient PropertyChangeHandler propertyListener; + + /** The Listener for the model. */ + protected ChangeListener changeListener; + + /** The progressBar for this UI. */ + protected JProgressBar progressBar; + + /** The length of the cell. The cell is the painted part. */ + private transient int cellLength; + + /** The gap between cells. */ + private transient int cellSpacing; + + /** The color of the text when the bar is not over it.*/ + private transient Color selectionBackground; + + /** The color of the text when the bar is over it. */ + private transient Color selectionForeground; + + /** + * Creates a new BasicProgressBarUI object. + */ + public BasicProgressBarUI() + { + super(); + } + + /** + * Creates a new BasicProgressBarUI for the component. + * + * @param x The JComponent to create the UI for. + * + * @return A new BasicProgressBarUI. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicProgressBarUI(); + } + + /** + * This method returns the length of the bar (from the minimum) + * in pixels (or units that the Graphics object draws in) based + * on the progressBar's getPercentComplete() value. + * + * @param b The insets of the progressBar. + * @param width The width of the progressBar. + * @param height The height of the progressBar. + * + * @return The length of the bar that should be painted in pixels. + */ + protected int getAmountFull(Insets b, int width, int height) + { + double percentDone = progressBar.getPercentComplete(); + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + return (int) (percentDone * (width - b.left - b.right)); + else + return (int) (percentDone * (height - b.top - b.bottom)); + } + + /** + * The current animation index. + * + * @return The current animation index. + */ + protected int getAnimationIndex() + { + return animationIndex; + } + + /** + * This method returns the size and position of the bouncing box + * for the current animation index. It stores the values in the + * given rectangle and returns it. It returns null if no box should + * be drawn. + * + * @param r The bouncing box rectangle. + * + * @return The bouncing box rectangle. + */ + protected Rectangle getBox(Rectangle r) + { + if (!progressBar.isIndeterminate()) + return null; + //numFrames has to be an even number as defined by spec. + int iterations = numFrames / 2 + 1; + + double boxDependent; + double boxIndependent; + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + Dimension dims = getPreferredInnerHorizontal(); + boxDependent = (double) dims.width / iterations; + boxIndependent = dims.height; + } + else + { + Dimension dims = getPreferredInnerVertical(); + boxDependent = (double) dims.height / iterations; + boxIndependent = dims.width; + } + + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(progressBar, vr); + + int index = getAnimationIndex(); + if (animationIndex > (numFrames + 1) / 2) + index = numFrames - getAnimationIndex(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + r.x = vr.x + (int) (index * boxDependent); + r.y = vr.y; + r.width = (int) boxDependent; + r.height = (int) boxIndependent; + } + else + { + index++; + r.x = vr.x; + r.y = vr.height - (int) (index * boxDependent) + vr.y; + r.width = (int) boxIndependent; + r.height = (int) boxDependent; + } + + return r; + } + + /** + * This method returns the length of the cells. + * + * @return The cell length. + */ + protected int getCellLength() + { + return cellLength; + } + + /** + * This method returns the spacing between cells. + * + * @return The cell gap. + */ + protected int getCellSpacing() + { + return cellSpacing; + } + + /** + * This method returns the maximum size of the JComponent. + * If it returns null, it is up to the LayoutManager + * to give it a size. + * + * @param c The component to find a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum size of the JComponent. + * If it returns null, it is up to the LayoutManager to + * give it a size. + * + * @param c The component to find a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size of the inner + * rectangle (the bounds without the insets) if the + * progressBar is horizontal. + * + * @return The preferred size of the progressBar minus + * insets if it's horizontal. + */ + protected Dimension getPreferredInnerHorizontal() + { + Rectangle vr = new Rectangle(); + + SwingUtilities.calculateInnerArea(progressBar, vr); + + return new Dimension(vr.width, vr.height); + } + + /** + * This method returns the preferred size of the inner + * rectangle (the bounds without insets) if the + * progressBar is vertical. + * + * @return The preferred size of the progressBar minus + * insets if it's vertical. + */ + protected Dimension getPreferredInnerVertical() + { + Rectangle vr = new Rectangle(); + + SwingUtilities.calculateInnerArea(progressBar, vr); + + return new Dimension(vr.width, vr.height); + } + + /** + * This method returns the preferred size of the + * given JComponent. If it returns null, then it + * is up to the LayoutManager to give it a size. + * + * @param c The component to find the preferred size for. + * + * @return The preferred size of the component. + */ + public Dimension getPreferredSize(JComponent c) + { + // The only thing we need to worry about is + // the text size. + Insets insets = c.getInsets(); + + // make a fontrenderer context so that we can make assumptions about + // the string bounds + FontRenderContext ctx = new FontRenderContext(new AffineTransform(), + false, false); + Rectangle2D bounds = c.getFont().getStringBounds(progressBar.getString(), + ctx); + int textW = (int) bounds.getWidth(); + int textH = (int) bounds.getHeight(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + if (textH < 20) + textH = 20; + if (textW < 200) + textW = 200; + } + else + { + if (textH < 200) + textH = 200; + if (textW < 20) + textW = 20; + } + textW += insets.left + insets.right; + textH += insets.top + insets.bottom; + return new Dimension(textW, textH); + } + + /** + * This method returns the Color that the text is shown in when the bar is + * not over the text. + * + * @return The color of the text when the bar is not over it. + */ + protected Color getSelectionBackground() + { + return selectionBackground; + } + + /** + * This method returns the Color that the text is shown in when the bar is + * over the text. + * + * @return The color of the text when the bar is over it. + */ + protected Color getSelectionForeground() + { + return selectionForeground; + } + + /** + * This method returns the point (the top left of the bounding box) + * where the text should be painted. + * + * @param g The Graphics object to measure FontMetrics with. + * @param progressString The string to paint. + * @param x The x coordinate of the overall bounds box. + * @param y The y coordinate of the overall bounds box. + * @param width The width of the overall bounds box. + * @param height The height of the overall bounds box. + * + * @return The top left of the bounding box where text should be painted. + */ + protected Point getStringPlacement(Graphics g, String progressString, int x, + int y, int width, int height) + { + Rectangle tr = new Rectangle(); + Rectangle vr = new Rectangle(x, y, width, height); + Rectangle ir = new Rectangle(); + + Font f = g.getFont(); + FontMetrics fm = g.getFontMetrics(f); + + SwingUtilities.layoutCompoundLabel(progressBar, fm, progressString, null, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, vr, ir, tr, 0); + return new Point(tr.x, tr.y); + } + + /** + * This method increments the animation index. + */ + protected void incrementAnimationIndex() + { + animationIndex++; + //numFrames is like string length, it should be named numFrames or something + if (animationIndex >= numFrames) + animationIndex = 0; + progressBar.repaint(); + } + + /** + * This method paints the progressBar. It delegates its responsibilities + * to paintDeterminate and paintIndeterminate. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + if (! progressBar.isIndeterminate()) + paintDeterminate(g, c); + else + paintIndeterminate(g, c); + } + + /** + * This method is called if the painting to be done is + * for a determinate progressBar. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + protected void paintDeterminate(Graphics g, JComponent c) + { + Color saved = g.getColor(); + int space = getCellSpacing(); + int len = getCellLength(); + int max = progressBar.getMaximum(); + int min = progressBar.getMinimum(); + int value = progressBar.getValue(); + + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(c, vr); + + Rectangle or = c.getBounds(); + + Insets insets = c.getInsets(); + + int amountFull = getAmountFull(insets, or.width, or.height); + + g.setColor(c.getBackground()); + g.fill3DRect(vr.x, vr.y, vr.width, vr.height, false); + + if (max != min && len != 0 && value > min) + { + int iterations = value / (space + len); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + double spaceInUnits = space * (double) vr.width / (max - min); + double lenInUnits = len * (double) vr.width / (max - min); + double currX = vr.x; + + g.setColor(c.getForeground()); + g.fill3DRect(vr.x, vr.y, amountFull, vr.height, true); + + g.setColor(c.getBackground()); + if (spaceInUnits != 0) + { + for (int i = 0; i < iterations; i++) + { + currX += lenInUnits; + g.fill3DRect((int) currX, vr.y, (int) spaceInUnits, + vr.height, true); + currX += spaceInUnits; + } + } + } + else + { + double currY = vr.y; + double spaceInUnits = space * (double) vr.height / (max - min); + double lenInUnits = len * (double) vr.height / (max - min); + + g.setColor(c.getForeground()); + g.fill3DRect(vr.x, vr.y + vr.height - amountFull, vr.width, + amountFull, true); + + g.setColor(c.getBackground()); + + if (spaceInUnits != 0) + { + for (int i = 0; i < iterations; i++) + { + currY -= lenInUnits + spaceInUnits; + g.fill3DRect(vr.x, (int) currY, vr.width, + (int) spaceInUnits, true); + } + } + } + } + + if (progressBar.isStringPainted() && !progressBar.getString().equals("")) + paintString(g, 0, 0, or.width, or.height, amountFull, insets); + g.setColor(saved); + } + + /** + * This method is called if the painting to be done is for + * an indeterminate progressBar. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + protected void paintIndeterminate(Graphics g, JComponent c) + { + //need to paint the box at it's current position. no text is painted since + //all we're doing is bouncing back and forth + Color saved = g.getColor(); + Insets insets = c.getInsets(); + + Rectangle or = c.getBounds(); + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(c, vr); + + g.setColor(c.getBackground()); + g.fill3DRect(vr.x, vr.y, vr.width, vr.height, false); + + Rectangle box = new Rectangle(); + getBox(box); + + g.setColor(c.getForeground()); + g.fill3DRect(box.x, box.y, box.width, box.height, true); + + if (progressBar.isStringPainted() && !progressBar.getString().equals("")) + paintString(g, 0, 0, or.width, or.height, + getAmountFull(insets, or.width, or.height), insets); + + g.setColor(saved); + } + + /** + * This method paints the string for the progressBar. + * + * @param g The Graphics object to paint with. + * @param x The x coordinate of the progressBar. + * @param y The y coordinate of the progressBar. + * @param width The width of the progressBar. + * @param height The height of the progressBar. + * @param amountFull The amount of the progressBar that has its bar filled. + * @param b The insets of the progressBar. + */ + protected void paintString(Graphics g, int x, int y, int width, int height, + int amountFull, Insets b) + { + // We want to place in the exact center of the bar. + Point placement = getStringPlacement(g, progressBar.getString(), + x + b.left, y + b.top, + width - b.left - b.right, + height - b.top - b.bottom); + Color saved = g.getColor(); + + // FIXME: The Color of the text should use selectionForeground and selectionBackground + // but that can't be done right now, so we'll use white in the mean time. + g.setColor(Color.WHITE); + + FontMetrics fm = g.getFontMetrics(progressBar.getFont()); + + g.drawString(progressBar.getString(), placement.x, + placement.y + fm.getAscent()); + + g.setColor(saved); + } + + /** + * This method sets the current animation index. If the index + * is greater than the number of frames, it resets to 0. + * + * @param newValue The new animation index. + */ + protected void setAnimationIndex(int newValue) + { + animationIndex = (newValue <= numFrames) ? newValue : 0; + progressBar.repaint(); + } + + /** + * This method sets the cell length. + * + * @param cellLen The cell length. + */ + protected void setCellLength(int cellLen) + { + cellLength = cellLen; + } + + /** + * This method sets the cell spacing. + * + * @param cellSpace The cell spacing. + */ + protected void setCellSpacing(int cellSpace) + { + cellSpacing = cellSpace; + } + + /** + * This method starts the animation timer. It is called + * when the propertyChangeListener detects that the progressBar + * has changed to indeterminate mode. + * + * @since 1.4 + */ + protected void startAnimationTimer() + { + if (animationTimer != null) + animationTimer.start(); + } + + /** + * This method stops the animation timer. It is called when + * the propertyChangeListener detects that the progressBar + * has changed to determinate mode. + * + * @since 1.4 + */ + protected void stopAnimationTimer() + { + if (animationTimer != null) + animationTimer.stop(); + setAnimationIndex(0); + } + + /** + * This method changes the settings for the progressBar to + * the defaults provided by the current Look and Feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + progressBar.setFont(defaults.getFont("ProgressBar.font")); + progressBar.setForeground(defaults.getColor("ProgressBar.foreground")); + progressBar.setBackground(defaults.getColor("ProgressBar.background")); + progressBar.setBorder(defaults.getBorder("ProgressBar.border")); + progressBar.setOpaque(true); + + selectionForeground = defaults.getColor("ProgressBar.selectionForeground"); + selectionBackground = defaults.getColor("ProgressBar.selectionBackground"); + cellLength = defaults.getInt("ProgressBar.cellLength"); + cellSpacing = defaults.getInt("ProgressBar.cellSpacing"); + + int repaintInterval = defaults.getInt("ProgressBar.repaintInterval"); + int cycleTime = defaults.getInt("ProgressBar.cycleTime"); + + if (cycleTime % repaintInterval != 0 + && (cycleTime / repaintInterval) % 2 != 0) + { + int div = (cycleTime / repaintInterval) + 2; + div /= 2; + div *= 2; + cycleTime = div * repaintInterval; + } + setAnimationIndex(0); + numFrames = cycleTime / repaintInterval; + animationTimer.setDelay(repaintInterval); + } + + /** + * The method uninstalls any defaults that were + * set by the current Look and Feel. + */ + protected void uninstallDefaults() + { + progressBar.setFont(null); + progressBar.setForeground(null); + progressBar.setBackground(null); + + selectionForeground = null; + selectionBackground = null; + } + + /** + * This method registers listeners to all the + * components that this UI delegate needs to listen to. + */ + protected void installListeners() + { + changeListener = new ChangeHandler(); + propertyListener = new PropertyChangeHandler(); + animation = new Animator(); + + progressBar.addChangeListener(changeListener); + progressBar.addPropertyChangeListener(propertyListener); + animationTimer.addActionListener(animation); + } + + /** + * This method unregisters listeners to all the + * components that were listened to. + */ + protected void uninstallListeners() + { + progressBar.removeChangeListener(changeListener); + progressBar.removePropertyChangeListener(propertyListener); + animationTimer.removeActionListener(animation); + + changeListener = null; + propertyListener = null; + animation = null; + } + + /** + * This method installs the UI for the given JComponent. + * This includes setting up defaults and listeners as + * well as initializing any values or objects that + * the UI may need. + * + * @param c The JComponent that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JProgressBar) + { + progressBar = (JProgressBar) c; + + animationTimer = new Timer(200, null); + animationTimer.setRepeats(true); + + installDefaults(); + installListeners(); + } + } + + /** + * This method removes the UI for the given JComponent. + * This includes removing any listeners or defaults + * that the installUI may have set up. + * + * @param c The JComponent that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + uninstallListeners(); + uninstallDefaults(); + + animationTimer = null; + progressBar = null; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java new file mode 100644 index 00000000000..d5cd7f4488e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java @@ -0,0 +1,102 @@ +/* BasicRadioButtonMenuItemUI.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.event.MouseEvent; + +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; + +/** + * UI Delegator for JRadioButtonMenuItem + */ +public class BasicRadioButtonMenuItemUI extends BasicMenuItemUI +{ + /** + * Creates a new BasicRadioButtonMenuItemUI object. + */ + public BasicRadioButtonMenuItemUI() + { + super(); + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + checkIcon = defaults.getIcon("RadioButtonMenuItem.checkIcon"); + } + + /** + * Factory method to create a BasicRadioButtonMenuItemUI for the given {@link + * JComponent}, which should be a JRadioButtonMenuItem. + * + * @param b The {@link JComponent} a UI is being created for. + * + * @return A BasicRadioButtonMenuItemUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent b) + { + return new BasicRadioButtonMenuItemUI(); + } + + /** + * DOCUMENT ME! + * + * @return $returnType$ DOCUMENT ME! + */ + protected String getPropertyPrefix() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @param item DOCUMENT ME! + * @param e DOCUMENT ME! + * @param path DOCUMENT ME! + * @param manager DOCUMENT ME! + */ + public void processMouseEvent(JMenuItem item, MouseEvent e, + MenuElement[] path, + MenuSelectionManager manager) + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java new file mode 100644 index 00000000000..38e117b18b2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -0,0 +1,87 @@ +/* BasicRadioButtonUI.java + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.AbstractButton; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; + +public class BasicRadioButtonUI extends BasicToggleButtonUI +{ + + protected Icon icon; + + public static ComponentUI createUI(final JComponent c) { + return new BasicRadioButtonUI(); + } + + public BasicRadioButtonUI() + { + icon = getDefaultIcon(); + } + + public void installUI(final JComponent c) { + super.installUI(c); + if (c instanceof AbstractButton) + { + AbstractButton b = (AbstractButton) c; + b.setIcon(icon); + } + } + + public Icon getDefaultIcon() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + return defaults.getIcon("RadioButton.icon"); + } + +} + + + + + + + + + + diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java new file mode 100644 index 00000000000..d97f7baea67 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java @@ -0,0 +1,66 @@ +/* BasicPanelUI.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.RootPaneUI; + +public class BasicRootPaneUI extends RootPaneUI + implements PropertyChangeListener +{ + public static ComponentUI createUI(JComponent x) + { + return new BasicRootPaneUI(); + } + + public void installUI(JComponent c) + { + c.setBackground(UIManager.getColor("control")); + super.installUI(c); + } + + public void propertyChange(PropertyChangeEvent event) + { + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java new file mode 100644 index 00000000000..892db2b031b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -0,0 +1,1271 @@ +/* BasicScrollBarUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.BoundedRangeModel; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ScrollBarUI; + +/** + * The Basic Look and Feel UI delegate for JScrollBar. + */ +public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, + SwingConstants +{ + /** + * A helper class that listens to the two JButtons on each end of the + * JScrollBar. + */ + protected class ArrowButtonListener extends MouseAdapter + { + /** + * Move the thumb in the direction specified by the button's arrow. If + * this button is held down, then it should keep moving the thumb. + * + * @param e The MouseEvent fired by the JButton. + */ + public void mousePressed(MouseEvent e) + { + scrollTimer.stop(); + scrollListener.setScrollByBlock(false); + if (e.getSource() == incrButton) + scrollListener.setDirection(POSITIVE_SCROLL); + else + scrollListener.setDirection(NEGATIVE_SCROLL); + scrollTimer.start(); + } + + /** + * Stops the thumb when the JButton is released. + * + * @param e The MouseEvent fired by the JButton. + */ + public void mouseReleased(MouseEvent e) + { + scrollTimer.stop(); + } + } + + /** + * A helper class that listens to the ScrollBar's model for ChangeEvents. + */ + protected class ModelListener implements ChangeListener + { + /** + * Called when the model changes. + * + * @param e The ChangeEvent fired by the model. + */ + public void stateChanged(ChangeEvent e) + { + // System.err.println(this + ".stateChanged()"); + calculatePreferredSize(); + getThumbBounds(); + scrollbar.repaint(); + } + } + + /** + * A helper class that listens to the ScrollBar's properties. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called when one of the ScrollBar's properties change. + * + * @param e The PropertyChangeEvent fired by the ScrollBar. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals("model")) + { + ((BoundedRangeModel) e.getOldValue()).removeChangeListener(modelListener); + scrollbar.getModel().addChangeListener(modelListener); + getThumbBounds(); + } + else if (e.getPropertyName().equals("orientation")) + { + incrButton.removeMouseListener(buttonListener); + decrButton.removeMouseListener(buttonListener); + int orientation = scrollbar.getOrientation(); + switch (orientation) + { + case (JScrollBar.HORIZONTAL): + incrButton = createIncreaseButton(EAST); + decrButton = createDecreaseButton(WEST); + break; + default: + incrButton = createIncreaseButton(SOUTH); + decrButton = createDecreaseButton(NORTH); + break; + } + incrButton.addMouseListener(buttonListener); + decrButton.addMouseListener(buttonListener); + calculatePreferredSize(); + } + scrollbar.repaint(); + } + } + + /** + * A helper class that listens for events from the timer that is used to + * move the thumb. + */ + protected class ScrollListener implements ActionListener + { + /** The direction the thumb moves in. */ + private transient int direction; + + /** Whether movement will be in blocks. */ + private transient boolean block; + + /** + * Creates a new ScrollListener object. The default is scrolling + * positively with block movement. + */ + public ScrollListener() + { + direction = POSITIVE_SCROLL; + block = true; + } + + /** + * Creates a new ScrollListener object using the given direction and + * block. + * + * @param dir The direction to move in. + * @param block Whether movement will be in blocks. + */ + public ScrollListener(int dir, boolean block) + { + direction = dir; + this.block = block; + } + + /** + * Sets the direction to scroll in. + * + * @param direction The direction to scroll in. + */ + public void setDirection(int direction) + { + this.direction = direction; + } + + /** + * Sets whether scrolling will be done in blocks. + * + * @param block Whether scrolling will be in blocks. + */ + public void setScrollByBlock(boolean block) + { + this.block = block; + } + + /** + * Called every time the timer reaches its interval. + * + * @param e The ActionEvent fired by the timer. + */ + public void actionPerformed(ActionEvent e) + { + if (block) + { + // Only need to check it if it's block scrolling + // We only block scroll if the click occurs + // in the track. + if (! trackListener.shouldScroll(direction)) + { + trackHighlight = NO_HIGHLIGHT; + scrollbar.repaint(); + return; + } + scrollByBlock(direction); + } + else + scrollByUnit(direction); + } + } + + /** + * Helper class that listens for movement on the track. + */ + protected class TrackListener extends MouseAdapter + implements MouseMotionListener + { + /** The current X coordinate of the mouse. */ + protected int currentMouseX; + + /** The current Y coordinate of the mouse. */ + protected int currentMouseY; + + /** + * The offset between the current mouse cursor and the current value of + * the scrollbar. + */ + protected int offset; + + /** + * This method is called when the mouse is being dragged. + * + * @param e The MouseEvent given. + */ + public void mouseDragged(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (scrollbar.getValueIsAdjusting()) + { + int value; + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + scrollbar.setValue(value); + } + } + + /** + * This method is called when the mouse is moved. + * + * @param e The MouseEvent given. + */ + public void mouseMoved(MouseEvent e) + { + // Not interested in where the mouse + // is unless it is being dragged. + } + + /** + * This method is called when the mouse is pressed. When it is pressed, + * the thumb should move in blocks towards the cursor. + * + * @param e The MouseEvent given. + */ + public void mousePressed(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (value == scrollbar.getValue()) + return; + + if (! thumbRect.contains(e.getPoint())) + { + scrollTimer.stop(); + scrollListener.setScrollByBlock(true); + if (value > scrollbar.getValue()) + { + trackHighlight = INCREASE_HIGHLIGHT; + scrollListener.setDirection(POSITIVE_SCROLL); + } + else + { + trackHighlight = DECREASE_HIGHLIGHT; + scrollListener.setDirection(NEGATIVE_SCROLL); + } + scrollTimer.start(); + } + else + { + // We'd like to keep track of where the cursor + // is inside the thumb. + // This works because the scrollbar's value represents + // "lower" edge of the thumb. The value at which + // the cursor is at must be greater or equal + // to that value. + scrollbar.setValueIsAdjusting(true); + offset = value - scrollbar.getValue(); + } + scrollbar.repaint(); + } + + /** + * This method is called when the mouse is released. It should stop + * movement on the thumb + * + * @param e The MouseEvent given. + */ + public void mouseReleased(MouseEvent e) + { + trackHighlight = NO_HIGHLIGHT; + scrollTimer.stop(); + + if (scrollbar.getValueIsAdjusting()) + scrollbar.setValueIsAdjusting(false); + scrollbar.repaint(); + } + + /** + * A helper method that decides whether we should keep scrolling in the + * given direction. + * + * @param direction The direction to check for. + * + * @return Whether the thumb should keep scrolling. + */ + public boolean shouldScroll(int direction) + { + int value; + if (scrollbar.getOrientation() == HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (direction == POSITIVE_SCROLL) + return (value > scrollbar.getValue()); + else + return (value < scrollbar.getValue()); + } + } + + /** The listener that listens to the JButtons. */ + protected ArrowButtonListener buttonListener; + + /** The listener that listens to the model. */ + protected ModelListener modelListener; + + /** The listener that listens to the scrollbar for property changes. */ + protected PropertyChangeListener propertyChangeListener; + + /** The listener that listens to the timer. */ + protected ScrollListener scrollListener; + + /** The listener that listens for MouseEvents on the track. */ + protected TrackListener trackListener; + + /** The JButton that decrements the scrollbar's value. */ + protected JButton decrButton; + + /** The JButton that increments the scrollbar's value. */ + protected JButton incrButton; + + /** The dimensions of the maximum thumb size. */ + protected Dimension maximumThumbSize; + + /** The dimensions of the minimum thumb size. */ + protected Dimension minimumThumbSize; + + /** The color of the thumb. */ + protected Color thumbColor; + + /** The outer shadow of the thumb. */ + protected Color thumbDarkShadowColor; + + /** The top and left edge color for the thumb. */ + protected Color thumbHighlightColor; + + /** The outer light shadow for the thumb. */ + protected Color thumbLightShadowColor; + + /** The color that is used when the mouse press occurs in the track. */ + protected Color trackHighlightColor; + + /** The color of the track. */ + protected Color trackColor; + + /** The size and position of the track. */ + protected Rectangle trackRect; + + /** The size and position of the thumb. */ + protected Rectangle thumbRect; + + /** Indicates that the decrease highlight should be painted. */ + protected static final int DECREASE_HIGHLIGHT = 1; + + /** Indicates that the increase highlight should be painted. */ + protected static final int INCREASE_HIGHLIGHT = 2; + + /** Indicates that no highlight should be painted. */ + protected static final int NO_HIGHLIGHT = 0; + + /** Indicates that the scrolling direction is positive. */ + private static final int POSITIVE_SCROLL = 1; + + /** Indicates that the scrolling direction is negative. */ + private static final int NEGATIVE_SCROLL = -1; + + /** The cached preferred size for the scrollbar. */ + private transient Dimension preferredSize; + + /** The current highlight status. */ + protected int trackHighlight; + + /** FIXME: Use this for something (presumably mouseDragged) */ + protected boolean isDragging; + + /** The timer used to move the thumb when the mouse is held. */ + protected Timer scrollTimer; + + /** The scrollbar this UI is acting for. */ + protected JScrollBar scrollbar; + + /** + * This method adds a component to the layout. + * + * @param name The name to associate with the component that is added. + * @param child The Component to add. + */ + public void addLayoutComponent(String name, Component child) + { + // You should not be adding stuff to this component. + // The contents are fixed. + } + + /** + * This method configures the scrollbar's colors. This can be done by + * looking up the standard colors from the Look and Feel defaults. + */ + protected void configureScrollBarColors() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + trackColor = defaults.getColor("ScrollBar.track"); + trackHighlightColor = defaults.getColor("ScrollBar.trackHighlight"); + thumbColor = defaults.getColor("ScrollBar.thumb"); + thumbHighlightColor = defaults.getColor("ScrollBar.thumbHighlight"); + thumbDarkShadowColor = defaults.getColor("ScrollBar.thumbDarkShadow"); + thumbLightShadowColor = defaults.getColor("ScrollBar.thumbShadow"); + } + + /** + * This method creates an ArrowButtonListener. + * + * @return A new ArrowButtonListener. + */ + protected ArrowButtonListener createArrowButtonListener() + { + return new ArrowButtonListener(); + } + + /** + * This method creates a new JButton with the appropriate icon for the + * orientation. + * + * @param orientation The orientation this JButton uses. + * + * @return The increase JButton. + */ + protected JButton createIncreaseButton(int orientation) + { + if (incrButton == null) + incrButton = new BasicArrowButton(orientation); + else + ((BasicArrowButton) incrButton).setDirection(orientation); + return incrButton; + } + + /** + * This method creates a new JButton with the appropriate icon for the + * orientation. + * + * @param orientation The orientation this JButton uses. + * + * @return The decrease JButton. + */ + protected JButton createDecreaseButton(int orientation) + { + if (decrButton == null) + decrButton = new BasicArrowButton(orientation); + else + ((BasicArrowButton) decrButton).setDirection(orientation); + return decrButton; + } + + /** + * This method creates a new ModelListener. + * + * @return A new ModelListener. + */ + protected ModelListener createModelListener() + { + return new ModelListener(); + } + + /** + * This method creates a new PropertyChangeListener. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * This method creates a new ScrollListener. + * + * @return A new ScrollListener. + */ + protected ScrollListener createScrollListener() + { + return new ScrollListener(); + } + + /** + * This method creates a new TrackListener. + * + * @return A new TrackListener. + */ + protected TrackListener createTrackListener() + { + return new TrackListener(); + } + + /** + * This method returns a new BasicScrollBarUI. + * + * @param c The JComponent to create a UI for. + * + * @return A new BasicScrollBarUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicScrollBarUI(); + } + + /** + * This method returns the maximum size for this JComponent. + * + * @param c The JComponent to measure the maximum size for. + * + * @return The maximum size for the component. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum thumb size. + * + * @return The maximum thumb size. + */ + protected Dimension getMaximumThumbSize() + { + return maximumThumbSize; + } + + /** + * This method returns the minimum size for this JComponent. + * + * @param c The JComponent to measure the minimum size for. + * + * @return The minimum size for the component. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum thumb size. + * + * @return The minimum thumb size. + */ + protected Dimension getMinimumThumbSize() + { + return minimumThumbSize; + } + + /** + * This method calculates the preferred size since calling + * getPreferredSize() returns a cached value. + * This is package-private to avoid an accessor method. + */ + void calculatePreferredSize() + { + // System.err.println(this + ".calculatePreferredSize()"); + int height; + int width; + height = width = 0; + + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + { + width += incrButton.getPreferredSize().getWidth(); + width += decrButton.getPreferredSize().getWidth(); + + width += (scrollbar.getMaximum() - scrollbar.getMinimum()); + + height = Math.max(incrButton.getPreferredSize().height, + decrButton.getPreferredSize().height); + height = Math.max(getMinimumThumbSize().height, height); + height = Math.max(20, height); + height = Math.min(getMaximumThumbSize().height, height); + } + else + { + height += incrButton.getPreferredSize().getHeight(); + height += decrButton.getPreferredSize().getHeight(); + + height += (scrollbar.getMaximum() - scrollbar.getMinimum()); + + width = Math.max(incrButton.getPreferredSize().width, + decrButton.getPreferredSize().width); + width = Math.max(getMinimumThumbSize().width, width); + width = Math.max(20, width); + width = Math.min(getMaximumThumbSize().width, width); + } + + Insets insets = scrollbar.getInsets(); + + height += insets.top + insets.bottom; + width += insets.left + insets.right; + + preferredSize = new Dimension(width, height); + } + + /** + * This method returns a cached value of the preferredSize. The only + * restrictions are: If the scrollbar is horizontal, the height should be + * the maximum of the height of the JButtons and the minimum width of the + * thumb. For vertical scrollbars, the calculation is similar (swap width + * for height and vice versa). + * + * @param c The JComponent to measure. + * + * @return The preferredSize. + */ + public Dimension getPreferredSize(JComponent c) + { + calculatePreferredSize(); + return preferredSize; + } + + /** + * This method returns the thumb's bounds based on the current value of the + * scrollbar. This method updates the cached value and returns that. + * + * @return The thumb bounds. + */ + protected Rectangle getThumbBounds() + { + int max = scrollbar.getMaximum(); + int min = scrollbar.getMinimum(); + int value = scrollbar.getValue(); + int extent = scrollbar.getVisibleAmount(); + + // System.err.println(this + ".getThumbBounds()"); + if (max == min) + { + thumbRect.x = trackRect.x; + thumbRect.y = trackRect.y; + if (scrollbar.getOrientation() == HORIZONTAL) + { + thumbRect.width = getMinimumThumbSize().width; + thumbRect.height = trackRect.height; + } + else + { + thumbRect.width = trackRect.width; + thumbRect.height = getMinimumThumbSize().height; + } + return thumbRect; + } + + if (scrollbar.getOrientation() == HORIZONTAL) + { + thumbRect.x = trackRect.x; + thumbRect.x += (value - min) * trackRect.width / (max - min); + thumbRect.y = trackRect.y; + + thumbRect.width = Math.max(extent * trackRect.width / (max - min), + getMinimumThumbSize().width); + thumbRect.height = trackRect.height; + } + else + { + thumbRect.x = trackRect.x; + thumbRect.y = trackRect.y + value * trackRect.height / (max - min); + + thumbRect.width = trackRect.width; + thumbRect.height = Math.max(extent * trackRect.height / (max - min), + getMinimumThumbSize().height); + } + return thumbRect; + } + + /** + * This method calculates the bounds of the track. This method updates the + * cached value and returns it. + * + * @return The track's bounds. + */ + protected Rectangle getTrackBounds() + { + SwingUtilities.calculateInnerArea(scrollbar, trackRect); + + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + { + trackRect.width -= incrButton.getPreferredSize().getWidth(); + trackRect.width -= decrButton.getPreferredSize().getWidth(); + + trackRect.x += decrButton.getPreferredSize().getWidth(); + } + else + { + trackRect.height -= incrButton.getPreferredSize().getHeight(); + trackRect.height -= decrButton.getPreferredSize().getHeight(); + + trackRect.y += incrButton.getPreferredSize().getHeight(); + } + return trackRect; + } + + /** + * This method installs any addition Components that are a part of or + * related to this scrollbar. + */ + protected void installComponents() + { + int orientation = scrollbar.getOrientation(); + switch (orientation) + { + case (JScrollBar.HORIZONTAL): + incrButton = createIncreaseButton(EAST); + decrButton = createDecreaseButton(WEST); + break; + default: + incrButton = createIncreaseButton(SOUTH); + decrButton = createDecreaseButton(NORTH); + break; + } + scrollbar.add(incrButton); + scrollbar.add(decrButton); + } + + /** + * This method installs the defaults for the scrollbar specified by the + * Basic Look and Feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + scrollbar.setForeground(defaults.getColor("ScrollBar.foreground")); + scrollbar.setBackground(defaults.getColor("ScrollBar.background")); + scrollbar.setBorder(defaults.getBorder("ScrollBar.border")); + scrollbar.setOpaque(true); + scrollbar.setLayout(this); + + thumbColor = defaults.getColor("ScrollBar.thumb"); + thumbDarkShadowColor = defaults.getColor("ScrollBar.thumbDarkShadow"); + thumbHighlightColor = defaults.getColor("ScrollBar.thumbHighlight"); + thumbLightShadowColor = defaults.getColor("ScrollBar.thumbShadow"); + + maximumThumbSize = defaults.getDimension("ScrollBar.maximumThumbSize"); + minimumThumbSize = defaults.getDimension("ScrollBar.minimumThumbSize"); + } + + /** + * This method installs the keyboard actions for the scrollbar. + */ + protected void installKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method installs any listeners for the scrollbar. This method also + * installs listeners for things such as the JButtons and the timer. + */ + protected void installListeners() + { + scrollListener = createScrollListener(); + trackListener = createTrackListener(); + buttonListener = createArrowButtonListener(); + modelListener = createModelListener(); + propertyChangeListener = createPropertyChangeListener(); + + scrollbar.addMouseMotionListener(trackListener); + scrollbar.addMouseListener(trackListener); + + incrButton.addMouseListener(buttonListener); + decrButton.addMouseListener(buttonListener); + + scrollbar.addPropertyChangeListener(propertyChangeListener); + scrollbar.getModel().addChangeListener(modelListener); + + scrollTimer.addActionListener(scrollListener); + } + + /** + * This method installs the UI for the component. This can include setting + * up listeners, defaults, and components. This also includes initializing + * any data objects. + * + * @param c The JComponent to install. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JScrollBar) + { + scrollbar = (JScrollBar) c; + + trackRect = new Rectangle(); + thumbRect = new Rectangle(); + + scrollTimer = new Timer(200, null); + scrollTimer.setRepeats(true); + + installComponents(); + installDefaults(); + configureScrollBarColors(); + installListeners(); + + calculatePreferredSize(); + } + } + + /** + * This method lays out the scrollbar. + * + * @param scrollbarContainer The Container to layout. + */ + public void layoutContainer(Container scrollbarContainer) + { + if (scrollbarContainer instanceof JScrollBar) + { + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + layoutHScrollbar((JScrollBar) scrollbarContainer); + else + layoutVScrollbar((JScrollBar) scrollbarContainer); + } + } + + /** + * This method lays out the scrollbar horizontally. + * + * @param sb The JScrollBar to layout. + */ + protected void layoutHScrollbar(JScrollBar sb) + { + // All we have to do is layout the 2 buttons? + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(scrollbar, vr); + + // Update the rectangles. + getTrackBounds(); + getThumbBounds(); + + Dimension incrDims = incrButton.getPreferredSize(); + Dimension decrDims = decrButton.getPreferredSize(); + + decrButton.setBounds(vr.x, vr.y, decrDims.width, trackRect.height); + incrButton.setBounds(trackRect.x + trackRect.width, vr.y, incrDims.width, + trackRect.height); + } + + /** + * This method lays out the scrollbar vertically. + * + * @param sb The JScrollBar to layout. + */ + protected void layoutVScrollbar(JScrollBar sb) + { + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(scrollbar, vr); + + // Update rectangles + getTrackBounds(); + getThumbBounds(); + + Dimension incrDims = incrButton.getPreferredSize(); + Dimension decrDims = decrButton.getPreferredSize(); + + decrButton.setBounds(vr.x, vr.y, trackRect.width, decrDims.height); + incrButton.setBounds(vr.x, trackRect.y + trackRect.height, + trackRect.width, incrDims.height); + } + + /** + * This method returns the minimum size required for the layout. + * + * @param scrollbarContainer The Container that is laid out. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container scrollbarContainer) + { + return preferredLayoutSize(scrollbarContainer); + } + + /** + * This method is called when the component is painted. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + paintTrack(g, c, getTrackBounds()); + paintThumb(g, c, getThumbBounds()); + + if (trackHighlight == INCREASE_HIGHLIGHT) + paintIncreaseHighlight(g); + else if (trackHighlight == DECREASE_HIGHLIGHT) + paintDecreaseHighlight(g); + } + + /** + * This method is called when repainting and the mouse is pressed in the + * track. It paints the track below the thumb with the trackHighlight + * color. + * + * @param g The Graphics object to paint with. + */ + protected void paintDecreaseHighlight(Graphics g) + { + Color saved = g.getColor(); + + g.setColor(trackHighlightColor); + if (scrollbar.getOrientation() == HORIZONTAL) + g.fillRect(trackRect.x, trackRect.y, thumbRect.x - trackRect.x, + trackRect.height); + else + g.fillRect(trackRect.x, trackRect.y, trackRect.width, + thumbRect.y - trackRect.y); + g.setColor(saved); + } + + /** + * This method is called when repainting and the mouse is pressed in the + * track. It paints the track above the thumb with the trackHighlight + * color. + * + * @param g The Graphics objet to paint with. + */ + protected void paintIncreaseHighlight(Graphics g) + { + Color saved = g.getColor(); + + g.setColor(trackHighlightColor); + if (scrollbar.getOrientation() == HORIZONTAL) + g.fillRect(thumbRect.x + thumbRect.width, trackRect.y, + trackRect.x + trackRect.width - thumbRect.x - thumbRect.width, + trackRect.height); + else + g.fillRect(trackRect.x, thumbRect.y + thumbRect.height, trackRect.width, + trackRect.y + trackRect.height - thumbRect.y + - thumbRect.height); + g.setColor(saved); + } + + /** + * This method paints the thumb. + * + * @param g The Graphics object to paint with. + * @param c The Component that is being painted. + * @param thumbBounds The thumb bounds. + */ + protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) + { + g.setColor(thumbColor); + g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width, + thumbBounds.height); + + BasicGraphicsUtils.drawBezel(g, thumbBounds.x, thumbBounds.y, + thumbBounds.width, thumbBounds.height, + false, false, thumbDarkShadowColor, + thumbDarkShadowColor, thumbHighlightColor, + thumbHighlightColor); + } + + /** + * This method paints the track. + * + * @param g The Graphics object to paint with. + * @param c The JComponent being painted. + * @param trackBounds The track's bounds. + */ + protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) + { + Color saved = g.getColor(); + g.setColor(trackColor); + g.fill3DRect(trackBounds.x, trackBounds.y, trackBounds.width, + trackBounds.height, false); + g.setColor(saved); + } + + /** + * This method returns the preferred size for the layout. + * + * @param scrollbarContainer The Container to find a size for. + * + * @return The preferred size for the layout. + */ + public Dimension preferredLayoutSize(Container scrollbarContainer) + { + if (scrollbarContainer instanceof JComponent) + return getPreferredSize((JComponent) scrollbarContainer); + else + return null; + } + + /** + * This method removes a child component from the layout. + * + * @param child The child to remove. + */ + public void removeLayoutComponent(Component child) + { + // You should not be removing stuff from this component. + } + + /** + * The method scrolls the thumb by a block in the direction specified. + * + * @param direction The direction to scroll. + */ + protected void scrollByBlock(int direction) + { + scrollbar.setValue(scrollbar.getValue() + + scrollbar.getBlockIncrement(direction)); + } + + /** + * The method scrolls the thumb by a unit in the direction specified. + * + * @param direction The direction to scroll. + */ + protected void scrollByUnit(int direction) + { + scrollbar.setValue(scrollbar.getValue() + + scrollbar.getUnitIncrement(direction)); + } + + /** + * This method sets the thumb's bounds. + * + * @param x The X position of the thumb. + * @param y The Y position of the thumb. + * @param width The width of the thumb. + * @param height The height of the thumb. + */ + protected void setThumbBounds(int x, int y, int width, int height) + { + thumbRect.x = x; + thumbRect.y = y; + thumbRect.width = width; + thumbRect.height = height; + } + + /** + * This method uninstalls any components that are a part of or related to + * this scrollbar. + */ + protected void uninstallComponents() + { + scrollbar.remove(incrButton); + scrollbar.remove(decrButton); + incrButton = null; + decrButton = null; + } + + /** + * This method uninstalls any defaults that this scrollbar acquired from the + * Basic Look and Feel defaults. + */ + protected void uninstallDefaults() + { + scrollbar.setForeground(null); + scrollbar.setBackground(null); + scrollbar.setBorder(null); + } + + /** + * This method uninstalls any keyboard actions this scrollbar acquired + * during install. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method uninstalls any listeners that were registered during install. + */ + protected void uninstallListeners() + { + scrollTimer.removeActionListener(scrollListener); + + scrollbar.getModel().removeChangeListener(modelListener); + scrollbar.removePropertyChangeListener(propertyChangeListener); + + decrButton.removeMouseListener(buttonListener); + incrButton.removeMouseListener(buttonListener); + + scrollbar.removeMouseListener(trackListener); + scrollbar.removeMouseMotionListener(trackListener); + + propertyChangeListener = null; + modelListener = null; + buttonListener = null; + trackListener = null; + scrollListener = null; + } + + /** + * This method uninstalls the UI. This includes removing any defaults, + * listeners, and components that this UI may have initialized. It also + * nulls any instance data. + * + * @param c The Component to uninstall for. + */ + public void uninstallUI(JComponent c) + { + uninstallDefaults(); + uninstallListeners(); + uninstallComponents(); + + scrollTimer = null; + + thumbRect = null; + trackRect = null; + + trackColor = null; + trackHighlightColor = null; + thumbColor = null; + thumbHighlightColor = null; + thumbDarkShadowColor = null; + thumbLightShadowColor = null; + + scrollbar = null; + } + + /** + * This method returns the value in the scrollbar's range given the y + * coordinate. If the value is out of range, it will return the closest + * legal value. + * This is package-private to avoid an accessor method. + * + * @param yPos The y coordinate to calculate a value for. + * + * @return The value for the y coordinate. + */ + int valueForYPosition(int yPos) + { + int min = scrollbar.getMinimum(); + int max = scrollbar.getMaximum(); + int len = trackRect.height; + + int value; + + // If the length is 0, you shouldn't be able to even see where the thumb is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + value = ((yPos - trackRect.y) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method returns the value in the scrollbar's range given the x + * coordinate. If the value is out of range, it will return the closest + * legal value. + * This is package-private to avoid an accessor method. + * + * @param xPos The x coordinate to calculate a value for. + * + * @return The value for the x coordinate. + */ + int valueForXPosition(int xPos) + { + int min = scrollbar.getMinimum(); + int max = scrollbar.getMaximum(); + int len = trackRect.width; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + value = ((xPos - trackRect.x) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java new file mode 100644 index 00000000000..7bb7acffb8d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java @@ -0,0 +1,130 @@ +/* BasicScrollPaneUI.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; +import javax.swing.ScrollPaneLayout; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ScrollPaneUI; + +public class BasicScrollPaneUI extends ScrollPaneUI + implements ScrollPaneConstants +{ + + /** The Scrollpane for which the UI is provided by this class. */ + protected JScrollPane scrollpane; + + public static ComponentUI createUI(final JComponent c) + { + return new BasicScrollPaneUI(); + } + + protected void installDefaults(JScrollPane p) + { + scrollpane = p; + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + p.setForeground(defaults.getColor("ScrollPane.foreground")); + p.setBackground(defaults.getColor("ScrollPane.background")); + p.setFont(defaults.getFont("ScrollPane.font")); + p.setBorder(defaults.getBorder("ScrollPane.border")); + p.setOpaque(true); + } + + protected void uninstallDefaults(JScrollPane p) + { + p.setForeground(null); + p.setBackground(null); + p.setFont(null); + p.setBorder(null); + scrollpane = null; + } + + public void installUI(final JComponent c) + { + super.installUI(c); + this.installDefaults((JScrollPane)c); + } + + public void uninstallUI(final JComponent c) + { + super.uninstallUI(c); + this.uninstallDefaults((JScrollPane)c); + } + + + public Dimension getMinimumSize(JComponent c) + { + JScrollPane p = (JScrollPane ) c; + ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout(); + return sl.minimumLayoutSize(c); + } + + public Dimension getPreferredSize(JComponent c) + { + JScrollPane p = (JScrollPane ) c; + ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout(); + return sl.preferredLayoutSize(c); + } + + + public void paint(Graphics g, JComponent c) + { + // do nothing; the normal painting-of-children algorithm, along with + // ScrollPaneLayout, does all the relevant work. + } +} + + + + + + + + + + + + diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java new file mode 100644 index 00000000000..38c9c7a2820 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSeparatorUI.java @@ -0,0 +1,269 @@ +/* BasicSeparatorUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SeparatorUI; + +/** + * The Basic Look and Feel UI delegate for JSeparator. + */ +public class BasicSeparatorUI extends SeparatorUI +{ + /** The shadow color. */ + protected Color shadow; + + /** The highlight color. */ + protected Color highlight; + + /** + * Creates a new UI delegate for the given JComponent. + * + * @param c The JComponent to create a delegate for. + * + * @return A new BasicSeparatorUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicSeparatorUI(); + } + + /** + * This method installs the UI for the given JComponent. + * This can include installing defaults, listeners, and + * initializing any instance data. + * + * @param c The JComponent that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + installDefaults(s); + installListeners(s); + } + } + + /** + * Uninstalls the UI for the given JComponent. This + * method reverses what was done when installing + * the UI on the JComponent. + * + * @param c The JComponent that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + uninstallListeners(s); + uninstallDefaults(s); + } + } + + /** + * This method installs the defaults that are given by + * the Basic Look and Feel. + * + * @param s The JSeparator that is being installed. + */ + protected void installDefaults(JSeparator s) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + shadow = defaults.getColor("Separator.shadow"); + highlight = defaults.getColor("Separator.highlight"); + s.setOpaque(false); + } + + /** + * This method removes the defaults that were given + * by the Basic Look and Feel. + * + * @param s The JSeparator that is being uninstalled. + */ + protected void uninstallDefaults(JSeparator s) + { + shadow = null; + highlight = null; + } + + /** + * This method installs any listeners that need + * to be attached to the JSeparator or any of its + * components. + * + * @param s The JSeparator that is being installed. + */ + protected void installListeners(JSeparator s) + { + // Separators don't receive events. + } + + /** + * This method uninstalls any listeners that + * were installed during the install UI process. + * + * @param s The JSeparator that is being uninstalled. + */ + protected void uninstallListeners(JSeparator s) + { + // Separators don't receive events. + } + + /** + * The separator is made of two lines. The top line will be + * the highlight color (or left line if it's vertical). The bottom + * or right line will be the shadow color. The two lines will + * be centered inside the bounds box. If the separator is horizontal, + * then it will be vertically centered, or if it's vertical, it will + * be horizontally centered. + * + * @param g The Graphics object to paint with + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + Rectangle r = new Rectangle(); + SwingUtilities.calculateInnerArea(c, r); + Color saved = g.getColor(); + + int midAB = r.width / 2 + r.x; + int midAD = r.height / 2 + r.y; + + JSeparator s; + if (c instanceof JSeparator) + s = (JSeparator) c; + else + return; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + g.setColor(highlight); + g.drawLine(r.x, midAD, r.x + r.width, midAD); + + g.setColor(shadow); + g.drawLine(r.x, midAD + 1, r.x + r.width, midAD + 1); + } + else + { + g.setColor(highlight); + g.drawLine(midAB, r.y, midAB, r.y + r.height); + + g.setColor(shadow); + g.drawLine(midAB + 1, r.y, midAB + 1, r.y + r.height); + } + } + + /** + * This method returns the preferred size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + Dimension dims = new Dimension(0, 0); + Insets insets = c.getInsets(); + + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + dims.height = 2; + dims.width = 40; + } + else + { + dims.width = 2; + dims.height = 40; + } + } + dims.width += insets.left + insets.right; + dims.height += insets.top + insets.bottom; + + return dims; + } + + /** + * This method returns the minimum size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java new file mode 100644 index 00000000000..0a72a62ff9c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java @@ -0,0 +1,2239 @@ +/* BasicSliderUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Dictionary; +import java.util.Enumeration; + +import javax.swing.BoundedRangeModel; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JSlider; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MouseInputAdapter; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SliderUI; + +/** + * <p> + * BasicSliderUI.java This is the UI delegate in the Basic look and feel that + * paints JSliders. + * </p> + * + * <p> + * The UI delegate keeps track of 6 rectangles that place the various parts of + * the JSlider inside the component. + * </p> + * + * <p> + * The rectangles are organized as follows: + * </p> + * <pre> + * +-------------------------------------------------------+ <-- focusRect + * | | + * | +==+-------------------+==+--------------------+==+<------ contentRect + * | | | | |<---thumbRect | | | + * | | | TRACK | | |<--------- trackRect + * | | +-------------------+==+--------------------+ | | + * | | | | | | + * | | | TICKS GO HERE |<-------- tickRect + * | | | | | | + * | +==+-------------------------------------------+==+ | + * | | | | | | + * | | | | |<----- labelRect + * | | | LABELS GO HERE | | | + * | | | | | | + * | | | | | | + * | | | | | | + * | | | | | | + * | | | | | + * </pre> + * + * <p> + * The space between the contentRect and the focusRect are the FocusInsets. + * </p> + * + * <p> + * The space between the focusRect and the component bounds is the insetCache + * which are the component's insets. + * </p> + * + * <p> + * The top of the thumb is the top of the contentRect. The trackRect has to be + * as tall as the thumb. + * </p> + * + * <p> + * The trackRect and tickRect do not start from the left edge of the + * focusRect. They are trackBuffer away from each side of the focusRect. This + * is so that the thumb has room to move. + * </p> + * + * <p> + * The labelRect does start right against the contentRect's left and right + * edges and it gets all remaining space. + * </p> + */ +public class BasicSliderUI extends SliderUI +{ + /** + * Helper class that listens to the {@link JSlider}'s model for changes. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class ChangeHandler implements ChangeListener + { + /** + * Called when the slider's model has been altered. The UI delegate should + * recalculate any rectangles that are dependent on the model for their + * positions and repaint. + * + * @param e A static {@link ChangeEvent} passed from the model. + */ + public void stateChanged(ChangeEvent e) + { + // Maximum, minimum, and extent values will be taken + // care of automatically when the slider is repainted. + // Only thing that needs recalculation is the thumb. + calculateThumbLocation(); + slider.repaint(); + } + } + + /** + * Helper class that listens for resize events. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class ComponentHandler extends ComponentAdapter + { + /** + * Called when the size of the component changes. The UI delegate should + * recalculate any rectangles that are dependent on the model for their + * positions and repaint. + * + * @param e A {@link ComponentEvent}. + */ + public void componentResized(ComponentEvent e) + { + calculateGeometry(); + + slider.revalidate(); + slider.repaint(); + } + } + + /** + * Helper class that listens for focus events. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class FocusHandler implements FocusListener + { + /** + * Called when the {@link JSlider} has gained focus. It should repaint + * the slider with the focus drawn. + * + * @param e A {@link FocusEvent}. + */ + public void focusGained(FocusEvent e) + { + // FIXME: implement. + } + + /** + * Called when the {@link JSlider} has lost focus. It should repaint the + * slider without the focus drawn. + * + * @param e A {@link FocusEvent}. + */ + public void focusLost(FocusEvent e) + { + // FIXME: implement. + } + } + + /** + * Helper class that listens for changes to the properties of the {@link + * JSlider}. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called when one of the properties change. The UI should recalculate any + * rectangles if necessary and repaint. + * + * @param e A {@link PropertyChangeEvent}. + */ + public void propertyChange(PropertyChangeEvent e) + { + // Check for orientation changes. + if (e.getPropertyName().equals("orientation")) + recalculateIfOrientationChanged(); + else if (e.getPropertyName().equals("model")) + { + BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue(); + oldModel.removeChangeListener(changeListener); + slider.getModel().addChangeListener(changeListener); + calculateThumbLocation(); + } + + // elif the componentOrientation changes (this is a bound property, + // just undocumented) we change leftToRightCache. In Sun's + // implementation, the LTR cache changes on a repaint. This is strange + // since there is no need to do so. We could events here and + // update the cache. + // elif the border/insets change, we recalculateInsets. + slider.repaint(); + } + } + + /** + * Helper class that listens to our swing timer. This class is responsible + * for listening to the timer and moving the thumb in the proper direction + * every interval. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class ScrollListener implements ActionListener + { + /** Indicates which direction the thumb should scroll. */ + private transient int direction; + + /** Indicates whether we should scroll in blocks or in units. */ + private transient boolean block; + + /** + * Creates a new ScrollListener object. + */ + public ScrollListener() + { + direction = POSITIVE_SCROLL; + block = false; + } + + /** + * Creates a new ScrollListener object. + * + * @param dir The direction to scroll in. + * @param block If movement will be in blocks. + */ + public ScrollListener(int dir, boolean block) + { + direction = dir; + this.block = block; + } + + /** + * Called every time the swing timer reaches its interval. If the thumb + * needs to move, then this method will move the thumb one block or unit + * in the direction desired. Otherwise, the timer can be stopped. + * + * @param e An {@link ActionEvent}. + */ + public void actionPerformed(ActionEvent e) + { + if (! trackListener.shouldScroll(direction)) + { + scrollTimer.stop(); + return; + } + + if (block) + scrollByBlock(direction); + else + scrollByUnit(direction); + } + + /** + * Sets the direction to scroll in. + * + * @param direction The direction to scroll in. + */ + public void setDirection(int direction) + { + this.direction = direction; + } + + /** + * Sets whether movement will be in blocks. + * + * @param block If movement will be in blocks. + */ + public void setScrollByBlock(boolean block) + { + this.block = block; + } + } + + /** + * Helper class that listens for mouse events. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class TrackListener extends MouseInputAdapter + { + /** The current X position of the mouse. */ + protected int currentMouseX; + + /** The current Y position of the mouse. */ + protected int currentMouseY; + + /** + * The offset between the current slider value and the cursor's position. + */ + protected int offset; + + /** + * Called when the mouse has been dragged. This should find the mouse's + * current position and adjust the value of the {@link JSlider} + * accordingly. + * + * @param e A {@link MouseEvent} + */ + public void mouseDragged(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (slider.getValueIsAdjusting()) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + slider.setValue(value); + } + } + + /** + * Called when the mouse has moved over a component but no buttons have + * been pressed yet. + * + * @param e A {@link MouseEvent} + */ + public void mouseMoved(MouseEvent e) + { + // Don't care that we're moved unless we're dragging. + } + + /** + * Called when the mouse is pressed. When the press occurs on the thumb + * itself, the {@link JSlider} should have its value set to where the + * mouse was pressed. If the press occurs on the track, then the thumb + * should move one block towards the direction of the mouse. + * + * @param e A {@link MouseEvent} + */ + public void mousePressed(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (slider.getSnapToTicks()) + value = findClosestTick(value); + + // If the thumb is hit, then we don't need to set the timers to move it. + if (! thumbRect.contains(e.getPoint())) + { + // The mouse has hit some other part of the slider. + // The value moves no matter where in the slider you hit. + if (value > slider.getValue()) + scrollDueToClickInTrack(POSITIVE_SCROLL); + else + scrollDueToClickInTrack(NEGATIVE_SCROLL); + } + else + { + slider.setValueIsAdjusting(true); + offset = value - slider.getValue(); + } + } + + /** + * Called when the mouse is released. This should stop the timer that + * scrolls the thumb. + * + * @param e A {@link MouseEvent} + */ + public void mouseReleased(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + if (slider.getValueIsAdjusting()) + { + slider.setValueIsAdjusting(false); + if (slider.getSnapToTicks()) + slider.setValue(findClosestTick(slider.getValue())); + } + if (scrollTimer != null) + scrollTimer.stop(); + } + + /** + * Indicates whether the thumb should scroll in the given direction. + * + * @param direction The direction to check. + * + * @return True if the thumb should move in that direction. + */ + public boolean shouldScroll(int direction) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (direction == POSITIVE_SCROLL) + return (value > slider.getValue()); + else + return (value < slider.getValue()); + } + } + + /** The preferred height of the thumb. */ + private transient int thumbHeight; + + /** The preferred width of the thumb. */ + private transient int thumbWidth; + + /** The preferred height of the tick rectangle. */ + private transient int tickHeight; + + /** Listener for changes from the model. */ + protected ChangeListener changeListener; + + /** Listener for changes to the {@link JSlider}. */ + protected PropertyChangeListener propertyChangeListener; + + /** Listener for the scrollTimer. */ + protected ScrollListener scrollListener; + + /** Listener for component resizing. */ + protected ComponentListener componentListener; + + /** Listener for focus handling. */ + protected FocusListener focusListener; + + /** Listener for mouse events. */ + protected TrackListener trackListener; + + /** The insets between the FocusRectangle and the ContentRectangle. */ + protected Insets focusInsets; + + /** The {@link JSlider}'s insets. */ + protected Insets insetCache; + + /** Rectangle describing content bounds. See diagram above. */ + protected Rectangle contentRect; + + /** Rectangle describing focus bounds. See diagram above. */ + protected Rectangle focusRect; + + /** Rectangle describing the thumb's bounds. See diagram above. */ + protected Rectangle thumbRect; + + /** Rectangle describing the tick bounds. See diagram above. */ + protected Rectangle tickRect; + + /** Rectangle describing the label bounds. See diagram above. */ + protected Rectangle labelRect; + + /** Rectangle describing the track bounds. See diagram above. */ + protected Rectangle trackRect; + + /** FIXME: use this somewhere. */ + public static final int MAX_SCROLL = 2; + + /** FIXME: use this somewhere. */ + public static final int MIN_SCROLL = -2; + + /** A constant describing scrolling towards the minimum. */ + public static final int NEGATIVE_SCROLL = -1; + + /** A constant describing scrolling towards the maximum. */ + public static final int POSITIVE_SCROLL = 1; + + /** The gap between the edges of the contentRect and trackRect. */ + protected int trackBuffer; + + /** Whether this slider is actually drawn left to right. */ + protected boolean leftToRightCache; + + /** A timer that periodically moves the thumb. */ + protected Timer scrollTimer; + + /** A reference to the {@link JSlider} that this UI was created for. */ + protected JSlider slider; + + /** The shadow color. */ + private transient Color shadowColor; + + /** The highlight color. */ + private transient Color highlightColor; + + /** The focus color. */ + private transient Color focusColor; + + /** + * Creates a new Basic look and feel Slider UI. + * + * @param b The {@link JSlider} that this UI was created for. + */ + public BasicSliderUI(JSlider b) + { + super(); + } + + /** + * Gets the shadow color to be used for this slider. The shadow color is the + * color used for drawing the top and left edges of the track. + * + * @return The shadow color. + */ + protected Color getShadowColor() + { + return shadowColor; + } + + /** + * Gets the highlight color to be used for this slider. The highlight color + * is the color used for drawing the bottom and right edges of the track. + * + * @return The highlight color. + */ + protected Color getHighlightColor() + { + return highlightColor; + } + + /** + * Gets the focus color to be used for this slider. The focus color is the + * color used for drawing the focus rectangle when the component gains + * focus. + * + * @return The focus color. + */ + protected Color getFocusColor() + { + return focusColor; + } + + /** + * Factory method to create a BasicSliderUI for the given {@link + * JComponent}, which should be a {@link JSlider}. + * + * @param b The {@link JComponent} a UI is being created for. + * + * @return A BasicSliderUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent b) + { + return new BasicSliderUI((JSlider) b); + } + + /** + * Installs and initializes all fields for this UI delegate. Any properties + * of the UI that need to be initialized and/or set to defaults will be + * done now. It will also install any listeners necessary. + * + * @param c The {@link JComponent} that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JSlider) + { + slider = (JSlider) c; + + focusRect = new Rectangle(); + contentRect = new Rectangle(); + thumbRect = new Rectangle(); + trackRect = new Rectangle(); + tickRect = new Rectangle(); + labelRect = new Rectangle(); + + insetCache = slider.getInsets(); + leftToRightCache = ! slider.getInverted(); + + scrollTimer = new Timer(200, null); + scrollTimer.setRepeats(true); + + installDefaults(slider); + installListeners(slider); + installKeyboardActions(slider); + + calculateFocusRect(); + + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + } + + /** + * Performs the opposite of installUI. Any properties or resources that need + * to be cleaned up will be done now. It will also uninstall any listeners + * it has. In addition, any properties of this UI will be nulled. + * + * @param c The {@link JComponent} that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + + uninstallKeyboardActions(slider); + uninstallListeners(slider); + + scrollTimer = null; + + focusRect = null; + contentRect = null; + thumbRect = null; + trackRect = null; + tickRect = null; + labelRect = null; + + focusInsets = null; + } + + /** + * Initializes any default properties that this UI has from the defaults for + * the Basic look and feel. + * + * @param slider The {@link JSlider} that is having this UI installed. + */ + protected void installDefaults(JSlider slider) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + slider.setForeground(defaults.getColor("Slider.foreground")); + slider.setBackground(defaults.getColor("Slider.background")); + shadowColor = defaults.getColor("Slider.shadow"); + highlightColor = defaults.getColor("Slider.highlight"); + focusColor = defaults.getColor("Slider.focus"); + slider.setBorder(defaults.getBorder("Slider.border")); + slider.setOpaque(true); + + thumbHeight = defaults.getInt("Slider.thumbHeight"); + thumbWidth = defaults.getInt("Slider.thumbWidth"); + tickHeight = defaults.getInt("Slider.tickHeight"); + + focusInsets = defaults.getInsets("Slider.focusInsets"); + } + + /** + * Creates a new {@link TrackListener}. + * + * @param slider The {@link JSlider} that this {@link TrackListener} is + * created for. + * + * @return A new {@link TrackListener}. + */ + protected TrackListener createTrackListener(JSlider slider) + { + return new TrackListener(); + } + + /** + * Creates a new {@link ChangeListener}. + * + * @param slider The {@link JSlider} that this {@link ChangeListener} is + * created for. + * + * @return A new {@link ChangeListener}. + */ + protected ChangeListener createChangeListener(JSlider slider) + { + return new ChangeHandler(); + } + + /** + * Creates a new {@link ComponentListener}. + * + * @param slider The {@link JSlider} that this {@link ComponentListener} is + * created for. + * + * @return A new {@link ComponentListener}. + */ + protected ComponentListener createComponentListener(JSlider slider) + { + return new ComponentHandler(); + } + + /** + * Creates a new {@link FocusListener}. + * + * @param slider The {@link JSlider} that this {@link FocusListener} is + * created for. + * + * @return A new {@link FocusListener}. + */ + protected FocusListener createFocusListener(JSlider slider) + { + return new FocusHandler(); + } + + /** + * Creates a new {@link ScrollListener}. + * + * @param slider The {@link JSlider} that this {@link ScrollListener} is + * created for. + * + * @return A new {@link ScrollListener}. + */ + protected ScrollListener createScrollListener(JSlider slider) + { + return new ScrollListener(); + } + + /** + * Creates a new {@link PropertyChangeListener}. + * + * @param slider The {@link JSlider} that this {@link + * PropertyChangeListener} is created for. + * + * @return A new {@link PropertyChangeListener}. + */ + protected PropertyChangeListener createPropertyChangeListener(JSlider slider) + { + return new PropertyChangeHandler(); + } + + /** + * Creates and registers all the listeners for this UI delegate. This + * includes creating the ScrollListener and registering it to the timer. + * + * @param slider The {@link JSlider} is having listeners installed. + */ + protected void installListeners(JSlider slider) + { + propertyChangeListener = createPropertyChangeListener(slider); + componentListener = createComponentListener(slider); + trackListener = createTrackListener(slider); + focusListener = createFocusListener(slider); + changeListener = createChangeListener(slider); + scrollListener = createScrollListener(slider); + + slider.addPropertyChangeListener(propertyChangeListener); + slider.addComponentListener(componentListener); + slider.addMouseListener(trackListener); + slider.addMouseMotionListener(trackListener); + slider.addFocusListener(focusListener); + slider.getModel().addChangeListener(changeListener); + + scrollTimer.addActionListener(scrollListener); + } + + /** + * Unregisters all the listeners that this UI delegate was using. In + * addition, it will also null any listeners that it was using. + * + * @param slider The {@link JSlider} that is having listeners removed. + */ + protected void uninstallListeners(JSlider slider) + { + slider.removePropertyChangeListener(propertyChangeListener); + slider.removeComponentListener(componentListener); + slider.removeMouseListener(trackListener); + slider.removeMouseMotionListener(trackListener); + slider.removeFocusListener(focusListener); + slider.getModel().removeChangeListener(changeListener); + + scrollTimer.removeActionListener(scrollListener); + + propertyChangeListener = null; + componentListener = null; + trackListener = null; + focusListener = null; + changeListener = null; + scrollListener = null; + } + + /** + * Installs any keyboard actions. The list of keys that need to be bound are + * listed in Basic look and feel's defaults. + * + * @param slider The {@link JSlider} that is having keyboard actions + * installed. + */ + protected void installKeyboardActions(JSlider slider) + { + // FIXME: implement. + } + + /** + * Uninstalls any keyboard actions. The list of keys used are listed in + * Basic look and feel's defaults. + * + * @param slider The {@link JSlider} that is having keyboard actions + * uninstalled. + */ + protected void uninstallKeyboardActions(JSlider slider) + { + // FIXME: implement. + } + + /* XXX: This is all after experimentation with SUN's implementation. + + PreferredHorizontalSize seems to be 200x21. + PreferredVerticalSize seems to be 21x200. + + MinimumHorizontalSize seems to be 36x21. + MinimumVerticalSize seems to be 21x36. + + PreferredSize seems to be 200x63. Or Components.getBounds? + + MinimumSize seems to be 36x63. + + MaximumSize seems to be 32767x63. + */ + + /** + * This method returns the preferred size when the slider is horizontally + * oriented. + * + * @return The dimensions of the preferred horizontal size. + */ + public Dimension getPreferredHorizontalSize() + { + Insets insets = slider.getInsets(); + + // The width should cover all the labels (which are usually the + // deciding factor of the width) + int width = getWidthOfWidestLabel() * (slider.getLabelTable() == null ? 0 + : slider.getLabelTable() + .size()); + + // If there are not enough labels. + // This number is pretty much arbitrary, but it looks nice. + if (width < 200) + width = 200; + + // We can only draw inside of the focusRectangle, so we have to + // pad it with insets. + width += insets.left + insets.right + focusInsets.left + focusInsets.right; + + // Height is determined by the thumb, the ticks and the labels. + int height = thumbHeight; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 + || slider.getMinorTickSpacing() > 0) + height += tickHeight; + + if (slider.getPaintLabels()) + height += getHeightOfTallestLabel(); + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + return new Dimension(width, height); + } + + /** + * This method returns the preferred size when the slider is vertically + * oriented. + * + * @return The dimensions of the preferred vertical size. + */ + public Dimension getPreferredVerticalSize() + { + Insets insets = slider.getInsets(); + + int height = getHeightOfTallestLabel() * (slider.getLabelTable() == null + ? 0 : slider.getLabelTable() + .size()); + + if (height < 200) + height = 200; + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + int width = thumbHeight; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 + || slider.getMinorTickSpacing() > 0) + width += tickHeight; + + if (slider.getPaintLabels()) + width += getWidthOfWidestLabel(); + + width += insets.left + insets.right + focusInsets.left + focusInsets.right; + + return new Dimension(width, height); + } + + /** + * This method returns the minimum size when the slider is horizontally + * oriented. + * + * @return The dimensions of the minimum horizontal size. + */ + public Dimension getMinimumHorizontalSize() + { + return getPreferredHorizontalSize(); + } + + /** + * This method returns the minimum size of the slider when it is vertically + * oriented. + * + * @return The dimensions of the minimum vertical size. + */ + public Dimension getMinimumVerticalSize() + { + return getPreferredVerticalSize(); + } + + /** + * This method returns the preferred size of the component. If it returns + * null, then it is up to the Layout Manager to give the {@link JComponent} + * a size. + * + * @param c The {@link JComponent} to find the preferred size for. + * + * @return The dimensions of the preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method returns the minimum size for this {@link JSlider} for this + * look and feel. If it returns null, then it is up to the Layout Manager + * to give the {@link JComponent} a size. + * + * @param c The {@link JComponent} to find the minimum size for. + * + * @return The dimensions of the minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method returns the maximum size for this {@link JSlider} for this + * look and feel. If it returns null, then it is up to the Layout Manager + * to give the {@link JComponent} a size. + * + * @param c The {@link JComponent} to find a maximum size for. + * + * @return The dimensions of the maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method calculates all the sizes of the rectangles by delegating to + * the helper methods calculateXXXRect. + */ + protected void calculateGeometry() + { + calculateFocusRect(); + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateTickRect(); + calculateLabelRect(); + calculateThumbLocation(); + } + + /** + * This method calculates the size and position of the focusRect. This + * method does not need to be called if the orientation changes. + */ + protected void calculateFocusRect() + { + insetCache = slider.getInsets(); + focusRect = SwingUtilities.calculateInnerArea(slider, focusRect); + + if (focusRect.width < 0) + focusRect.width = 0; + if (focusRect.height < 0) + focusRect.height = 0; + } + + /** + * This method calculates the size but not the position of the thumbRect. It + * must take into account the orientation of the slider. + */ + protected void calculateThumbSize() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + if (thumbWidth > contentRect.width) + thumbRect.width = contentRect.width / 4; + else + thumbRect.width = thumbWidth; + if (thumbHeight > contentRect.height) + thumbRect.height = contentRect.height; + else + thumbRect.height = thumbHeight; + } + else + { + // The thumb gets flipped when inverted, so thumbWidth + // actually is the height and vice versa. + if (thumbWidth > contentRect.height) + thumbRect.height = contentRect.height / 4; + else + thumbRect.height = thumbWidth; + if (thumbHeight > contentRect.width) + thumbRect.width = contentRect.width; + else + thumbRect.width = thumbHeight; + } + } + + /** + * This method calculates the size and position of the contentRect. This + * method does not need to be called if the orientation changes. + */ + protected void calculateContentRect() + { + contentRect.x = focusRect.x + focusInsets.left; + contentRect.y = focusRect.y + focusInsets.top; + contentRect.width = focusRect.width - focusInsets.left - focusInsets.right; + contentRect.height = focusRect.height - focusInsets.top + - focusInsets.bottom; + + if (contentRect.width < 0) + contentRect.width = 0; + if (contentRect.height < 0) + contentRect.height = 0; + } + + /** + * Calculates the position of the thumbRect based on the current value of + * the slider. It must take into account the orientation of the slider. + */ + protected void calculateThumbLocation() + { + int value = slider.getValue(); + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + thumbRect.x = xPositionForValue(value) - thumbRect.width / 2; + thumbRect.y = contentRect.y; + } + else + { + thumbRect.x = contentRect.x; + thumbRect.y = yPositionForValue(value) - thumbRect.height / 2; + } + } + + /** + * Calculates the gap size between the left edge of the contentRect and the + * left edge of the trackRect. + */ + protected void calculateTrackBuffer() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + trackBuffer = thumbRect.width; + else + trackBuffer = thumbRect.height; + } + + /** + * This method returns the size of the thumbRect. + * + * @return The dimensions of the thumb. + */ + protected Dimension getThumbSize() + { + // This is really just the bounds box for the thumb. + // The thumb will actually be pointed (like a rectangle + triangle at bottom) + return thumbRect.getSize(); + } + + /** + * Calculates the size and position of the trackRect. It must take into + * account the orientation of the slider. + */ + protected void calculateTrackRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + trackRect.x = contentRect.x + trackBuffer; + trackRect.y = contentRect.y; + trackRect.width = contentRect.width - 2 * trackBuffer; + trackRect.height = thumbRect.height; + } + else + { + trackRect.x = contentRect.x; + trackRect.y = contentRect.y + trackBuffer; + trackRect.width = thumbRect.width; + trackRect.height = contentRect.height - 2 * trackBuffer; + } + } + + /** + * This method returns the height of the tick area box if the slider is + * horizontal and the width of the tick area box is the slider is vertical. + * It not necessarily how long the ticks will be. If a gap between the edge + * of tick box and the actual tick is desired, then that will need to be + * handled in the tick painting methods. + * + * @return The height (or width if the slider is vertical) of the tick + * rectangle. + */ + protected int getTickLength() + { + return tickHeight; + } + + /** + * This method calculates the size and position of the tickRect. It must + * take into account the orientation of the slider. + */ + protected void calculateTickRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + tickRect.x = trackRect.x; + tickRect.y = trackRect.y + trackRect.height; + tickRect.width = trackRect.width; + tickRect.height = getTickLength(); + + if (tickRect.y + tickRect.height > contentRect.y + contentRect.height) + tickRect.height = contentRect.y + contentRect.height - tickRect.y; + } + else + { + tickRect.x = trackRect.x + trackRect.width; + tickRect.y = trackRect.y; + tickRect.width = getTickLength(); + tickRect.height = trackRect.height; + + if (tickRect.x + tickRect.width > contentRect.x + contentRect.width) + tickRect.width = contentRect.x + contentRect.width - tickRect.x; + } + } + + /** + * This method calculates the size and position of the labelRect. It must + * take into account the orientation of the slider. + */ + protected void calculateLabelRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + labelRect.x = contentRect.x; + labelRect.y = tickRect.y + tickRect.height; + labelRect.width = contentRect.width; + labelRect.height = contentRect.height - labelRect.y; + } + else + { + labelRect.x = tickRect.x + tickRect.width; + labelRect.y = contentRect.y; + labelRect.width = contentRect.width - labelRect.x; + labelRect.height = contentRect.height; + } + } + + /** + * This method returns the width of the widest label in the slider's label + * table. + * + * @return The width of the widest label or 0 if no label table exists. + */ + protected int getWidthOfWidestLabel() + { + int widest = 0; + Component label; + + if (slider.getLabelTable() == null) + return 0; + + Dimension pref; + for (Enumeration list = slider.getLabelTable().elements(); + list.hasMoreElements();) + { + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + pref = label.getPreferredSize(); + if (pref != null && pref.width > widest) + widest = pref.width; + } + return widest; + } + + /** + * This method returns the height of the tallest label in the slider's label + * table. + * + * @return The height of the tallest label or 0 if no label table exists. + */ + protected int getHeightOfTallestLabel() + { + int tallest = 0; + Component label; + + if (slider.getLabelTable() == null) + return 0; + Dimension pref; + for (Enumeration list = slider.getLabelTable().elements(); + list.hasMoreElements();) + { + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + pref = label.getPreferredSize(); + if (pref != null && pref.height > tallest) + tallest = pref.height; + } + return tallest; + } + + /** + * This method returns the width of the label whose key has the highest + * value. + * + * @return The width of the high value label or 0 if no label table exists. + */ + protected int getWidthOfHighValueLabel() + { + Component highValueLabel = getHighestValueLabel(); + if (highValueLabel != null) + return highValueLabel.getWidth(); + else + return 0; + } + + /** + * This method returns the width of the label whose key has the lowest + * value. + * + * @return The width of the low value label or 0 if no label table exists. + */ + protected int getWidthOfLowValueLabel() + { + Component lowValueLabel = getLowestValueLabel(); + if (lowValueLabel != null) + return lowValueLabel.getWidth(); + else + return 0; + } + + /** + * This method returns the height of the label whose key has the highest + * value. + * + * @return The height of the high value label or 0 if no label table exists. + */ + protected int getHeightOfHighValueLabel() + { + Component highValueLabel = getHighestValueLabel(); + if (highValueLabel != null) + return highValueLabel.getHeight(); + else + return 0; + } + + /** + * This method returns the height of the label whose key has the lowest + * value. + * + * @return The height of the low value label or 0 if no label table exists. + */ + protected int getHeightOfLowValueLabel() + { + Component lowValueLabel = getLowestValueLabel(); + if (lowValueLabel != null) + return lowValueLabel.getHeight(); + else + return 0; + } + + /** + * This method returns whether the slider is to be drawn inverted. + * + * @return True is the slider is to be drawn inverted. + */ + protected boolean drawInverted() + { + return ! (slider.getInverted() ^ leftToRightCache); + } + + /** + * This method returns the label whose key has the lowest value. + * + * @return The low value label or null if no label table exists. + */ + protected Component getLowestValueLabel() + { + Integer key = new Integer(Integer.MAX_VALUE); + Integer tmpKey; + Dictionary labelTable = slider.getLabelTable(); + + if (labelTable == null) + return null; + + for (Enumeration list = labelTable.keys(); list.hasMoreElements();) + { + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() < key.intValue()) + key = tmpKey; + } + Object comp = labelTable.get(key); + if (! (comp instanceof Component)) + return null; + return (Component) comp; + } + + /** + * This method returns the label whose key has the highest value. + * + * @return The high value label or null if no label table exists. + */ + protected Component getHighestValueLabel() + { + Integer key = new Integer(Integer.MIN_VALUE); + Integer tmpKey; + Dictionary labelTable = slider.getLabelTable(); + + if (labelTable == null) + return null; + + for (Enumeration list = labelTable.keys(); list.hasMoreElements();) + { + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() > key.intValue()) + key = tmpKey; + } + Object comp = labelTable.get(key); + if (! (comp instanceof Component)) + return null; + return (Component) comp; + } + + /** + * This method is used to paint the {@link JSlider}. It delegates all its + * duties to the various paint methods like paintTicks(), paintTrack(), + * paintThumb(), etc. + * + * @param g The {@link Graphics} object to paint with. + * @param c The {@link JComponent} that is being painted. + */ + public void paint(Graphics g, JComponent c) + { + // FIXME: Move this to propertyChangeEvent handler, when we get those. + leftToRightCache = slider.getComponentOrientation() != ComponentOrientation.RIGHT_TO_LEFT; + // FIXME: This next line is only here because the above line is here. + calculateThumbLocation(); + + if (slider.getPaintTrack()) + paintTrack(g); + if (slider.getPaintTicks()) + paintTicks(g); + if (slider.getPaintLabels()) + paintLabels(g); + + //FIXME: Paint focus. + paintThumb(g); + } + + /** + * This method recalculates any rectangles that need to be recalculated + * after the insets of the component have changed. + */ + protected void recalculateIfInsetsChanged() + { + // Examining a test program shows that either Sun calls private + // methods that we don't know about, or these don't do anything. + calculateFocusRect(); + + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + + /** + * This method recalculates any rectangles that need to be recalculated + * after the orientation of the slider changes. + */ + protected void recalculateIfOrientationChanged() + { + // Examining a test program shows that either Sun calls private + // methods that we don't know about, or these don't do anything. + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + + /** + * This method is called during a repaint if the slider has focus. It draws + * an outline of the focusRect using the color returned by + * getFocusColor(). + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintFocus(Graphics g) + { + Color saved_color = g.getColor(); + + g.setColor(getFocusColor()); + + g.drawRect(focusRect.x, focusRect.y, focusRect.width, focusRect.height); + + g.setColor(saved_color); + } + + /** + * <p> + * This method is called during a repaint if the track is to be drawn. It + * draws a 3D rectangle to represent the track. The track is not the size + * of the trackRect. The top and left edges of the track should be outlined + * with the shadow color. The bottom and right edges should be outlined + * with the highlight color. + * </p> + * <pre> + * a---d + * | | + * | | a------------------------d + * | | | | + * | | b------------------------c + * | | + * | | + * b---c + * </pre> + * + * <p> + * The b-a-d path needs to be drawn with the shadow color and the b-c-d path + * needs to be drawn with the highlight color. + * </p> + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintTrack(Graphics g) + { + Color saved_color = g.getColor(); + int width; + int height; + + Point a = new Point(trackRect.x, trackRect.y); + Point b = new Point(a); + Point c = new Point(a); + Point d = new Point(a); + + Polygon high; + Polygon shadow; + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + width = trackRect.width; + height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4; + + a.translate(0, (trackRect.height / 2) - (height / 2)); + b.translate(0, (trackRect.height / 2) + (height / 2)); + c.translate(trackRect.width, (trackRect.height / 2) + (height / 2)); + d.translate(trackRect.width, (trackRect.height / 2) - (height / 2)); + } + else + { + width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4; + height = trackRect.height; + + a.translate((trackRect.width / 2) - (width / 2), 0); + b.translate((trackRect.width / 2) - (width / 2), trackRect.height); + c.translate((trackRect.width / 2) + (width / 2), trackRect.height); + d.translate((trackRect.width / 2) + (width / 2), 0); + } + g.setColor(Color.GRAY); + g.fillRect(a.x, a.y, width, height); + + g.setColor(getHighlightColor()); + g.drawLine(b.x, b.y, c.x, c.y); + g.drawLine(c.x, c.y, d.x, d.y); + + g.setColor(getShadowColor()); + g.drawLine(b.x, b.y, a.x, a.y); + g.drawLine(a.x, a.y, d.x, d.y); + + g.setColor(saved_color); + } + + /** + * This method is called during a repaint if the ticks are to be drawn. This + * method must still verify that the majorTickSpacing and minorTickSpacing + * are greater than zero before drawing the ticks. + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintTicks(Graphics g) + { + int max = slider.getMaximum(); + int min = slider.getMinimum(); + int majorSpace = slider.getMajorTickSpacing(); + int minorSpace = slider.getMinorTickSpacing(); + + if (majorSpace > 0) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + double loc = tickRect.x; + double increment = (max == min) ? 0 + : majorSpace * (double) tickRect.width / (max + - min); + if (drawInverted()) + { + loc += tickRect.width; + increment *= -1; + } + for (int i = min; i <= max; i += majorSpace) + { + paintMajorTickForHorizSlider(g, tickRect, (int) loc); + loc += increment; + } + } + else + { + double loc = tickRect.height + tickRect.y; + double increment = (max == min) ? 0 + : -majorSpace * (double) tickRect.height / (max + - min); + if (drawInverted()) + { + loc = tickRect.y; + increment *= -1; + } + for (int i = min; i <= max; i += majorSpace) + { + paintMajorTickForVertSlider(g, tickRect, (int) loc); + loc += increment; + } + } + } + if (minorSpace > 0) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + double loc = tickRect.x; + double increment = (max == min) ? 0 + : minorSpace * (double) tickRect.width / (max + - min); + if (drawInverted()) + { + loc += tickRect.width; + increment *= -1; + } + for (int i = min; i <= max; i += minorSpace) + { + paintMinorTickForHorizSlider(g, tickRect, (int) loc); + loc += increment; + } + } + else + { + double loc = tickRect.height + tickRect.y; + double increment = (max == min) ? 0 + : -minorSpace * (double) tickRect.height / (max + - min); + if (drawInverted()) + { + loc = tickRect.y; + increment *= -1; + } + for (int i = min; i <= max; i += minorSpace) + { + paintMinorTickForVertSlider(g, tickRect, (int) loc); + loc += increment; + } + } + } + } + + /* Minor ticks start at 1/4 of the height (or width) of the tickRect and extend + to 1/2 of the tickRect. + + Major ticks start at 1/4 of the height and extend to 3/4. + */ + + /** + * This method paints a minor tick for a horizontal slider at the given x + * value. x represents the x coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param x The x coordinate to draw the tick at. + */ + protected void paintMinorTickForHorizSlider(Graphics g, + Rectangle tickBounds, int x) + { + int y = tickRect.y + tickRect.height / 4; + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawLine(x, y, x, y + tickRect.height / 4); + g.setColor(saved); + } + + /** + * This method paints a major tick for a horizontal slider at the given x + * value. x represents the x coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param x The x coordinate to draw the tick at. + */ + protected void paintMajorTickForHorizSlider(Graphics g, + Rectangle tickBounds, int x) + { + int y = tickRect.y + tickRect.height / 4; + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawLine(x, y, x, y + tickRect.height / 2); + g.setColor(saved); + } + + /** + * This method paints a minor tick for a vertical slider at the given y + * value. y represents the y coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param y The y coordinate to draw the tick at. + */ + protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + int x = tickRect.x + tickRect.width / 4; + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawLine(x, y, x + tickRect.width / 4, y); + g.setColor(saved); + } + + /** + * This method paints a major tick for a vertical slider at the given y + * value. y represents the y coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param y The y coordinate to draw the tick at. + */ + protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + int x = tickRect.x + tickRect.width / 4; + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawLine(x, y, x + tickRect.width / 2, y); + g.setColor(saved); + } + + /** + * This method paints all the labels from the slider's label table. This + * method must make sure that the label table is not null before painting + * the labels. Each entry in the label table is a (integer, component) + * pair. Every label is painted at the value of the integer. + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintLabels(Graphics g) + { + if (slider.getLabelTable() != null) + { + Dictionary table = slider.getLabelTable(); + Integer tmpKey; + Object key; + Object element; + Component label; + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintHorizontalLabel(g, tmpKey.intValue(), label); + } + } + else + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintVerticalLabel(g, tmpKey.intValue(), label); + } + } + } + } + + /** + * This method paints the label on the horizontal slider at the value + * specified. The value is not a coordinate. It is a value within the range + * of the slider. If the value is not within the range of the slider, this + * method will do nothing. This method should not paint outside the + * boundaries of the labelRect. + * + * @param g The {@link Graphics} object to draw with. + * @param value The value to paint at. + * @param label The label to paint. + */ + protected void paintHorizontalLabel(Graphics g, int value, Component label) + { + // This relies on clipping working properly or we'll end up + // painting all over the place. If our preferred size is ignored, then + // the labels may not fit inside the slider's bounds. Rather than mucking + // with font sizes and possible icon sizes, we'll set the bounds for + // the label and let it get clipped. + Dimension dim = label.getPreferredSize(); + int w = (int) dim.getWidth(); + int h = (int) dim.getHeight(); + + int max = slider.getMaximum(); + int min = slider.getMinimum(); + + if (value > max || value < min) + return; + + // value + // | + // ------------ + // | | + // | | + // | | + // The label must move w/2 to the right to fit directly under the value. + int xpos = xPositionForValue(value) - w / 2; + int ypos = labelRect.y; + + // We want to center the label around the xPositionForValue + // So we use xpos - w / 2. However, if value is min and the label + // is large, we run the risk of going out of bounds. So we bring it back + // to 0 if it becomes negative. + if (xpos < 0) + xpos = 0; + + // If the label + starting x position is greater than + // the x space in the label rectangle, we reset it to the largest + // amount possible in the rectangle. This means ugliness. + if (xpos + w > labelRect.x + labelRect.width) + w = labelRect.x + labelRect.width - xpos; + + // If the label is too tall. We reset it to the height of the label + // rectangle. + if (h > labelRect.height) + h = labelRect.height; + + label.setBounds(xpos, ypos, w, h); + javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + } + + /** + * This method paints the label on the vertical slider at the value + * specified. The value is not a coordinate. It is a value within the range + * of the slider. If the value is not within the range of the slider, this + * method will do nothing. This method should not paint outside the + * boundaries of the labelRect. + * + * @param g The {@link Graphics} object to draw with. + * @param value The value to paint at. + * @param label The label to paint. + */ + protected void paintVerticalLabel(Graphics g, int value, Component label) + { + Dimension dim = label.getPreferredSize(); + int w = (int) dim.getWidth(); + int h = (int) dim.getHeight(); + + int max = slider.getMaximum(); + int min = slider.getMinimum(); + + if (value > max || value < min) + return; + + int xpos = labelRect.x; + int ypos = yPositionForValue(value) - h / 2; + + if (ypos < 0) + ypos = 0; + + if (ypos + h > labelRect.y + labelRect.height) + h = labelRect.y + labelRect.height - ypos; + + if (w > labelRect.width) + w = labelRect.width; + + label.setBounds(xpos, ypos, w, h); + javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + } + + /** + * <p> + * This method paints a thumb. There are two types of thumb: + * </p> + * <pre> + * Vertical Horizontal + * a---b a-----b + * | | | \ + * e c | c + * \ / | / + * d e-----d + * </pre> + * + * <p> + * In the case of vertical thumbs, we highlight the path b-a-e-d and shadow + * the path b-c-d. In the case of horizontal thumbs, we highlight the path + * c-b-a-e and shadow the path c-d-e. In both cases we fill the path + * a-b-c-d-e before shadows and highlights are drawn. + * </p> + * + * @param g The graphics object to paint with + */ + public void paintThumb(Graphics g) + { + Color saved_color = g.getColor(); + + Polygon thumb = new Polygon(); + + Point a = new Point(thumbRect.x, thumbRect.y); + Point b = new Point(a); + Point c = new Point(a); + Point d = new Point(a); + Point e = new Point(a); + + Polygon bright; + Polygon dark; + Polygon all; + + // This will be in X-dimension if the slider is inverted and y if it isn't. + int turnPoint; + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + turnPoint = thumbRect.height * 3 / 4; + + b.translate(thumbRect.width, 0); + c.translate(thumbRect.width, turnPoint); + d.translate(thumbRect.width / 2, thumbRect.height); + e.translate(0, turnPoint); + + bright = new Polygon(new int[] { b.x, a.x, e.x, d.x }, + new int[] { b.y, a.y, e.y, d.y }, 4); + + dark = new Polygon(new int[] { b.x, c.x, d.x }, + new int[] { b.y, c.y, d.y }, 3); + all = new Polygon(new int[] { a.x + 1, b.x, c.x, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y, d.y + 1, e.y }, 5); + } + else + { + turnPoint = thumbRect.width * 3 / 4; + + b.translate(turnPoint, 0); + c.translate(thumbRect.width, thumbRect.height / 2); + d.translate(turnPoint, thumbRect.height); + e.translate(0, thumbRect.height); + + bright = new Polygon(new int[] { c.x, b.x, a.x, e.x }, + new int[] { c.y, b.y, a.y, e.y }, 4); + + dark = new Polygon(new int[] { c.x, d.x, e.x + 1 }, + new int[] { c.y, d.y, e.y }, 3); + + all = new Polygon(new int[] { a.x + 1, b.x, c.x - 1, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y, d.y, e.y }, 5); + } + + g.setColor(Color.WHITE); + g.drawPolyline(bright.xpoints, bright.ypoints, bright.npoints); + + g.setColor(Color.BLACK); + g.drawPolyline(dark.xpoints, dark.ypoints, dark.npoints); + + g.setColor(Color.GRAY); + g.fillPolygon(all); + + g.setColor(saved_color); + } + + /** + * This method sets the position of the thumbRect. + * + * @param x The new x position. + * @param y The new y position. + */ + public void setThumbLocation(int x, int y) + { + thumbRect.x = x; + thumbRect.y = y; + } + + /** + * This method is used to move the thumb one block in the direction + * specified. If the slider snaps to ticks, this method is responsible for + * snapping it to a tick after the thumb has been moved. + * + * @param direction The direction to move in. + */ + public void scrollByBlock(int direction) + { + // The direction is -1 for backwards and 1 for forwards. + int unit = direction * (slider.getMaximum() - slider.getMinimum()) / 10; + + int moveTo = slider.getValue() + unit; + + if (slider.getSnapToTicks()) + moveTo = findClosestTick(moveTo); + + slider.setValue(moveTo); + } + + /** + * This method is used to move the thumb one unit in the direction + * specified. If the slider snaps to ticks, this method is responsible for + * snapping it to a tick after the thumb has been moved. + * + * @param direction The direction to move in. + */ + public void scrollByUnit(int direction) + { + // The direction is -1 for backwards and 1 for forwards. + int moveTo = slider.getValue() + direction; + + if (slider.getSnapToTicks()) + moveTo = findClosestTick(moveTo); + + slider.setValue(moveTo); + } + + /** + * This method is called when there has been a click in the track and the + * thumb needs to be scrolled on regular intervals. This method is only + * responsible for starting the timer and not for stopping it. + * + * @param dir The direction to move in. + */ + protected void scrollDueToClickInTrack(int dir) + { + scrollTimer.stop(); + + scrollListener.setDirection(dir); + scrollListener.setScrollByBlock(true); + + scrollTimer.start(); + } + + /** + * This method returns the X coordinate for the value passed in. + * + * @param value The value to calculate an x coordinate for. + * + * @return The x coordinate for the value. + */ + protected int xPositionForValue(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int extent = slider.getExtent(); + int len = trackRect.width; + + int xPos = (max == min) ? 0 : (value - min) * len / (max - min); + + if (! drawInverted()) + xPos += trackRect.x; + else + { + xPos = trackRect.width - xPos; + xPos += trackRect.x; + } + return xPos; + } + + /** + * This method returns the y coordinate for the value passed in. + * + * @param value The value to calculate a y coordinate for. + * + * @return The y coordinate for the value. + */ + protected int yPositionForValue(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int extent = slider.getExtent(); + int len = trackRect.height; + + int yPos = (max == min) ? 0 : (value - min) * len / (max - min); + + if (! drawInverted()) + { + yPos = trackRect.height - yPos; + yPos += trackRect.y; + } + else + yPos += trackRect.y; + return yPos; + } + + /** + * This method returns the value in the slider's range given the y + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param yPos The y coordinate to calculate a value for. + * + * @return The value for the y coordinate. + */ + public int valueForYPosition(int yPos) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int len = trackRect.height; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + if (! drawInverted()) + value = ((len - (yPos - trackRect.y)) * (max - min) / len + min); + else + value = ((yPos - trackRect.y) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method returns the value in the slider's range given the x + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param xPos The x coordinate to calculate a value for. + * + * @return The value for the x coordinate. + */ + public int valueForXPosition(int xPos) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int len = trackRect.width; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + if (! drawInverted()) + value = ((xPos - trackRect.x) * (max - min) / len + min); + else + value = ((len - (xPos - trackRect.x)) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method finds the closest value that has a tick associated with it. + * This is package-private to avoid an accessor method. + * + * @param value The value to search from. + * + * @return The closest value that has a tick associated with it. + */ + int findClosestTick(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int majorSpace = slider.getMajorTickSpacing(); + int minorSpace = slider.getMinorTickSpacing(); + + // The default value to return is value + minor or + // value + major. + // Initializing at min - value leaves us with a default + // return value of min, which always has tick marks + // (if ticks are painted). + int minor = min - value; + int major = min - value; + + // If there are no major tick marks or minor tick marks + // e.g. snap is set to true but no ticks are set, then + // we can just return the value. + if (majorSpace <= 0 && minorSpace <= 0) + return value; + + // First check the major ticks. + if (majorSpace > 0) + { + int lowerBound = (value - min) / majorSpace; + int majLower = majorSpace * lowerBound + min; + int majHigher = majorSpace * (lowerBound + 1) + min; + + if (majHigher <= max && majHigher - value <= value - majLower) + major = majHigher - value; + else + major = majLower - value; + } + + if (minorSpace > 0) + { + int lowerBound = value / minorSpace; + int minLower = minorSpace * lowerBound; + int minHigher = minorSpace * (lowerBound + 1); + + if (minHigher <= max && minHigher - value <= value - minLower) + minor = minHigher - value; + else + minor = minLower - value; + } + + // Give preference to minor ticks + if (Math.abs(minor) > Math.abs(major)) + return value + major; + else + return value + minor; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java new file mode 100644 index 00000000000..97ab97b8972 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -0,0 +1,574 @@ +/* SpinnerUI.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JSpinner; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SpinnerUI; + +/** + * DOCUMENT ME! + * + * @author Ka-Hing Cheung + * + * @see javax.swing.JSpinner + * @since 1.4 + */ +public class BasicSpinnerUI extends SpinnerUI +{ + /** + * Creates a new <code>ComponentUI</code> for the specified + * <code>JComponent</code> + * + * @param c DOCUMENT ME! + * + * @return a ComponentUI + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicSpinnerUI(); + } + + /** + * Creates an editor component. Really, it just returns + * <code>JSpinner.getEditor()</code> + * + * @return a JComponent as an editor + * + * @see javax.swing.JSpinner#getEditor + */ + protected JComponent createEditor() + { + return spinner.getEditor(); + } + + /** + * Creates a <code>LayoutManager</code> that layouts the sub components. The + * subcomponents are identifies by the constraint "Next", "Previous" and + * "Editor" + * + * @return a LayoutManager + * + * @see java.awt.LayoutManager + */ + protected LayoutManager createLayout() + { + return new DefaultLayoutManager(); + } + + /** + * Creates the "Next" button + * + * @return the next button component + */ + protected Component createNextButton() + { + JButton button = new BasicArrowButton(BasicArrowButton.NORTH); + return button; + } + + /** + * Creates the "Previous" button + * + * @return the previous button component + */ + protected Component createPreviousButton() + { + JButton button = new BasicArrowButton(BasicArrowButton.SOUTH); + return button; + } + + /** + * Creates the <code>PropertyChangeListener</code> that will be attached by + * <code>installListeners</code>. It should watch for the "editor" + * property, when it's changed, replace the old editor with the new one, + * probably by calling <code>replaceEditor</code> + * + * @return a PropertyChangeListener + * + * @see #replaceEditor + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeListener() + { + public void propertyChange(PropertyChangeEvent evt) + { + // FIXME: Add check for enabled property change. Need to + // disable the buttons. + if ("editor".equals(evt.getPropertyName())) + BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(), + (JComponent) evt.getNewValue()); + } + }; + } + + /** + * Called by <code>installUI</code>. This should set various defaults + * obtained from <code>UIManager.getLookAndFeelDefaults</code>, as well as + * set the layout obtained from <code>createLayout</code> + * + * @see javax.swing.UIManager#getLookAndFeelDefaults + * @see #createLayout + * @see #installUI + */ + protected void installDefaults() + { + /* most of it copied from BasicLabelUI, I don't know what keys are + available, so someone may want to update this. Hence: TODO + */ + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + /* + spinner.setForeground(defaults.getColor("Spinner.foreground")); + spinner.setBackground(defaults.getColor("Spinner.background")); + spinner.setFont(defaults.getFont("Spinner.font")); + spinner.setBorder(defaults.getBorder("Spinner.border")); + */ + spinner.setLayout(createLayout()); + spinner.setOpaque(true); + } + + /* + * Called by <code>installUI</code>, which basically adds the + * <code>PropertyChangeListener</code> created by + * <code>createPropertyChangeListener</code> + * + * @see #createPropertyChangeListener + * @see #installUI + */ + protected void installListeners() + { + spinner.addPropertyChangeListener(listener); + } + + /* + * Install listeners to the next button so that it increments the model + */ + protected void installNextButtonListeners(Component c) + { + c.addMouseListener(new MouseAdapter() + { + public void mousePressed(MouseEvent evt) + { + if (! spinner.isEnabled()) + return; + increment(); + timer.setInitialDelay(500); + timer.start(); + } + + public void mouseReleased(MouseEvent evt) + { + timer.stop(); + } + + void increment() + { + Object next = BasicSpinnerUI.this.spinner.getNextValue(); + if (next != null) + BasicSpinnerUI.this.spinner.getModel().setValue(next); + } + + volatile boolean mouseDown = false; + Timer timer = new Timer(50, + new ActionListener() + { + public void actionPerformed(ActionEvent event) + { + increment(); + } + }); + }); + } + + /* + * Install listeners to the previous button so that it decrements the model + */ + protected void installPreviousButtonListeners(Component c) + { + c.addMouseListener(new MouseAdapter() + { + public void mousePressed(MouseEvent evt) + { + if (! spinner.isEnabled()) + return; + decrement(); + timer.setInitialDelay(500); + timer.start(); + } + + public void mouseReleased(MouseEvent evt) + { + timer.stop(); + } + + void decrement() + { + Object prev = BasicSpinnerUI.this.spinner.getPreviousValue(); + if (prev != null) + BasicSpinnerUI.this.spinner.getModel().setValue(prev); + } + + volatile boolean mouseDown = false; + Timer timer = new Timer(50, + new ActionListener() + { + public void actionPerformed(ActionEvent event) + { + decrement(); + } + }); + }); + } + + /** + * Install this UI to the <code>JComponent</code>, which in reality, is a + * <code>JSpinner</code>. Calls <code>installDefaults</code>, + * <code>installListeners</code>, and also adds the buttons and editor. + * + * @param c DOCUMENT ME! + * + * @see #installDefaults + * @see #installListeners + * @see #createNextButton + * @see #createPreviousButton + * @see #createEditor + */ + public void installUI(JComponent c) + { + super.installUI(c); + + spinner = (JSpinner) c; + + installDefaults(); + installListeners(); + + Component next = createNextButton(); + Component previous = createPreviousButton(); + + installNextButtonListeners(next); + installPreviousButtonListeners(previous); + + c.add(createEditor(), "Editor"); + c.add(next, "Next"); + c.add(previous, "Previous"); + } + + /** + * Replace the old editor with the new one + * + * @param oldEditor the old editor + * @param newEditor the new one to replace with + */ + protected void replaceEditor(JComponent oldEditor, JComponent newEditor) + { + spinner.remove(oldEditor); + spinner.add(newEditor); + } + + /** + * The reverse of <code>installDefaults</code>. Called by + * <code>uninstallUI</code> + */ + protected void uninstallDefaults() + { + spinner.setLayout(null); + } + + /** + * The reverse of <code>installListeners</code>, called by + * <code>uninstallUI</code> + */ + protected void uninstallListeners() + { + spinner.removePropertyChangeListener(listener); + } + + /** + * Called when the current L&F is replaced with another one, should call + * <code>uninstallDefaults</code> and <code>uninstallListeners</code> as + * well as remove the next/previous buttons and the editor + * + * @param c DOCUMENT ME! + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + + uninstallDefaults(); + uninstallListeners(); + c.removeAll(); + } + + /** The spinner for this UI */ + protected JSpinner spinner; + + /** DOCUMENT ME! */ + private PropertyChangeListener listener = createPropertyChangeListener(); + + /** + * DOCUMENT ME! + */ + private class DefaultLayoutManager implements LayoutManager + { + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + */ + public void layoutContainer(Container parent) + { + synchronized (parent.getTreeLock()) + { + Insets i = parent.getInsets(); + boolean l2r = parent.getComponentOrientation().isLeftToRight(); + /* + -------------- -------------- + | | n | | n | | + | e | - | or | - | e | + | | p | | p | | + -------------- -------------- + */ + Dimension e = minSize(editor); + Dimension n = minSize(next); + Dimension p = minSize(previous); + Dimension s = spinner.getPreferredSize(); + + int x = l2r ? i.left : i.right; + int y = i.top; + int w = Math.max(p.width, n.width); + int h = Math.max(p.height, n.height); + h = Math.max(h, e.height / 2); + int e_width = s.width - w; + + if (l2r) + { + setBounds(editor, x, y + (s.height - e.height) / 2, e_width, + e.height); + x += e_width; + + setBounds(next, x, y, w, h); + y += h; + + setBounds(previous, x, y, w, h); + } + else + { + setBounds(next, x, y + (s.height - e.height) / 2, w, h); + y += h; + + setBounds(previous, x, y, w, h); + x += w; + y -= h; + + setBounds(editor, x, y, e_width, e.height); + } + } + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension minimumLayoutSize(Container parent) + { + Dimension d = new Dimension(); + + if (editor != null) + { + Dimension tmp = editor.getMinimumSize(); + d.width += tmp.width; + d.height = tmp.height; + } + + int nextWidth = 0; + int previousWidth = 0; + int otherHeight = 0; + + if (next != null) + { + Dimension tmp = next.getMinimumSize(); + nextWidth = tmp.width; + otherHeight += tmp.height; + } + if (previous != null) + { + Dimension tmp = previous.getMinimumSize(); + previousWidth = tmp.width; + otherHeight += tmp.height; + } + + d.height = Math.max(d.height, otherHeight); + d.width += Math.max(nextWidth, previousWidth); + + return d; + } + + /** + * DOCUMENT ME! + * + * @param parent DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Dimension preferredLayoutSize(Container parent) + { + Dimension d = new Dimension(); + + if (editor != null) + { + Dimension tmp = editor.getPreferredSize(); + d.width += Math.max(tmp.width, 40); + d.height = tmp.height; + } + + int nextWidth = 0; + int previousWidth = 0; + int otherHeight = 0; + + if (next != null) + { + Dimension tmp = next.getPreferredSize(); + nextWidth = tmp.width; + otherHeight += tmp.height; + } + if (previous != null) + { + Dimension tmp = previous.getPreferredSize(); + previousWidth = tmp.width; + otherHeight += tmp.height; + } + + d.height = Math.max(d.height, otherHeight); + d.width += Math.max(nextWidth, previousWidth); + + return d; + } + + /** + * DOCUMENT ME! + * + * @param child DOCUMENT ME! + */ + public void removeLayoutComponent(Component child) + { + if (child == editor) + editor = null; + else if (child == next) + next = null; + else if (previous == child) + previous = null; + } + + /** + * DOCUMENT ME! + * + * @param name DOCUMENT ME! + * @param child DOCUMENT ME! + */ + public void addLayoutComponent(String name, Component child) + { + if ("Editor".equals(name)) + editor = child; + else if ("Next".equals(name)) + next = child; + else if ("Previous".equals(name)) + previous = child; + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + private Dimension minSize(Component c) + { + if (c == null) + return new Dimension(); + else + return c.getMinimumSize(); + } + + /** + * DOCUMENT ME! + * + * @param c DOCUMENT ME! + * @param x DOCUMENT ME! + * @param y DOCUMENT ME! + * @param w DOCUMENT ME! + * @param h DOCUMENT ME! + */ + private void setBounds(Component c, int x, int y, int w, int h) + { + if (c != null) + c.setBounds(x, y, w, h); + } + + /** DOCUMENT ME! */ + private Component editor; + + /** DOCUMENT ME! */ + private Component next; + + /** DOCUMENT ME! */ + private Component previous; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java new file mode 100644 index 00000000000..b8674ed2f08 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -0,0 +1,912 @@ +/* BasicSplitPaneDivider.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JButton; +import javax.swing.JSplitPane; +import javax.swing.SwingConstants; +import javax.swing.border.Border; + +/** + * The divider that separates the two parts of a JSplitPane in the Basic look + * and feel. + * + * <p> + * Implementation status: We do not have a real implementation yet. Currently, + * it is mostly a stub to allow compiling other parts of the + * javax.swing.plaf.basic package, although some parts are already + * functional. + * </p> + * + * @author Sascha Brawer (brawer_AT_dandelis.ch) + */ +public class BasicSplitPaneDivider extends Container + implements PropertyChangeListener +{ + /** + * Determined using the <code>serialver</code> tool of Apple/Sun JDK 1.3.1 + * on MacOS X 10.1.5. + */ + static final long serialVersionUID = 1463404307042803342L; + + /** + * The width and height of the little buttons for showing and hiding parts + * of a JSplitPane in a single mouse click. + */ + protected static final int ONE_TOUCH_SIZE = 6; + + /** The distance the one touch buttons will sit from the divider's edges. */ + protected static final int ONE_TOUCH_OFFSET = 2; + + /** + * An object that performs the tasks associated with an ongoing drag + * operation, or <code>null</code> if the user is currently not dragging + * the divider. + */ + protected DragController dragger; + + /** + * The delegate object that is responsible for the UI of the + * <code>JSplitPane</code> that contains this divider. + */ + protected BasicSplitPaneUI splitPaneUI; + + /** The thickness of the divider in pixels. */ + protected int dividerSize; + + /** A divider that is used for layout purposes. */ + protected Component hiddenDivider; + + /** The JSplitPane containing this divider. */ + protected JSplitPane splitPane; + + /** + * The listener for handling mouse events from both the divider and the + * containing <code>JSplitPane</code>. + * + * <p> + * The reason for also handling MouseEvents from the containing + * <code>JSplitPane</code> is that users should be able to start a drag + * gesture from inside the JSplitPane, but slightly outisde the divider. + * </p> + */ + protected MouseHandler mouseHandler = new MouseHandler(); + + /** + * The current orientation of the containing <code>JSplitPane</code>, which + * is either {@link javax.swing.JSplitPane#HORIZONTAL_SPLIT} or {@link + * javax.swing.JSplitPane#VERTICAL_SPLIT}. + */ + protected int orientation; + + /** + * The button for showing and hiding the left (or top) component of the + * <code>JSplitPane</code>. + */ + protected JButton leftButton; + + /** + * The button for showing and hiding the right (or bottom) component of the + * <code>JSplitPane</code>. + */ + protected JButton rightButton; + + /** + * The border of this divider. Typically, this will be an instance of {@link + * javax.swing.plaf.basic.BasicBorders.SplitPaneDividerBorder}. + * + * @see #getBorder() + * @see #setBorder(javax.swing.border.Border) + */ + private Border border; + + // This is not a pixel count. + // This int should be able to take 3 values. + // left (top), middle, right(bottom) + // 0 1 2 + + /** + * Keeps track of where the divider should be placed when using one touch + * expand buttons. + * This is package-private to avoid an accessor method. + */ + transient int currentDividerLocation = 1; + + /** DOCUMENT ME! */ + private transient Border tmpBorder = new Border() + { + public Insets getBorderInsets(Component c) + { + return new Insets(2, 2, 2, 2); + } + + public boolean isBorderOpaque() + { + return false; + } + + public void paintBorder(Component c, Graphics g, int x, int y, + int width, int height) + { + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawRect(x + 2, y + 2, width - 4, height - 4); + + g.setColor(saved); + } + }; + + /** + * Constructs a new divider. + * + * @param ui the UI delegate of the enclosing <code>JSplitPane</code>. + */ + public BasicSplitPaneDivider(BasicSplitPaneUI ui) + { + setLayout(new DividerLayout()); + setBasicSplitPaneUI(ui); + setDividerSize(splitPane.getDividerSize()); + setBorder(tmpBorder); + } + + /** + * Sets the delegate object that is responsible for the UI of the {@link + * javax.swing.JSplitPane} containing this divider. + * + * @param newUI the UI delegate, or <code>null</code> to release the + * connection to the current delegate. + */ + public void setBasicSplitPaneUI(BasicSplitPaneUI newUI) + { + /* Remove the connection to the existing JSplitPane. */ + if (splitPane != null) + { + splitPane.removePropertyChangeListener(this); + splitPane.removeMouseListener(mouseHandler); + splitPane.removeMouseMotionListener(mouseHandler); + removeMouseListener(mouseHandler); + removeMouseMotionListener(mouseHandler); + splitPane = null; + hiddenDivider = null; + } + + /* Establish the connection to the new JSplitPane. */ + splitPaneUI = newUI; + if (splitPaneUI != null) + splitPane = newUI.getSplitPane(); + if (splitPane != null) + { + splitPane.addPropertyChangeListener(this); + splitPane.addMouseListener(mouseHandler); + splitPane.addMouseMotionListener(mouseHandler); + addMouseListener(mouseHandler); + addMouseMotionListener(mouseHandler); + hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider(); + orientation = splitPane.getOrientation(); + oneTouchExpandableChanged(); + } + } + + /** + * Returns the delegate object that is responsible for the UI of the {@link + * javax.swing.JSplitPane} containing this divider. + * + * @return The UI for the JSplitPane. + */ + public BasicSplitPaneUI getBasicSplitPaneUI() + { + return splitPaneUI; + } + + /** + * Sets the thickness of the divider. + * + * @param newSize the new width or height in pixels. + */ + public void setDividerSize(int newSize) + { + this.dividerSize = newSize; + } + + /** + * Retrieves the thickness of the divider. + * + * @return The thickness of the divider. + */ + public int getDividerSize() + { + return dividerSize; + } + + /** + * Sets the border of this divider. + * + * @param border the new border. Typically, this will be an instance of + * {@link + * javax.swing.plaf.basic.BasicBorders.SplitPaneBorder}. + * + * @since 1.3 + */ + public void setBorder(Border border) + { + if (border != this.border) + { + Border oldValue = this.border; + this.border = border; + firePropertyChange("border", oldValue, border); + } + } + + /** + * Retrieves the border of this divider. + * + * @return the current border, or <code>null</code> if no border has been + * set. + * + * @since 1.3 + */ + public Border getBorder() + { + return border; + } + + /** + * Retrieves the insets of the divider. If a border has been installed on + * the divider, the result of calling its <code>getBorderInsets</code> + * method is returned. Otherwise, the inherited implementation will be + * invoked. + * + * @see javax.swing.border.Border#getBorderInsets(java.awt.Component) + */ + public Insets getInsets() + { + if (border != null) + return border.getBorderInsets(this); + else + return super.getInsets(); + } + + /** + * Returns the preferred size of this divider, which is + * <code>dividerSize</code> by <code>dividerSize</code> pixels. + * + * @return The preferred size of the divider. + */ + public Dimension getPreferredSize() + { + return getLayout().preferredLayoutSize(this); + } + + /** + * Returns the minimal size of this divider, which is + * <code>dividerSize</code> by <code>dividerSize</code> pixels. + * + * @return The minimal size of the divider. + */ + public Dimension getMinimumSize() + { + return getPreferredSize(); + } + + /** + * Processes events from the <code>JSplitPane</code> that contains this + * divider. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JSplitPane.ONE_TOUCH_EXPANDABLE_PROPERTY)) + oneTouchExpandableChanged(); + else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) + { + orientation = splitPane.getOrientation(); + if (splitPane.isOneTouchExpandable()) + { + layout(); + repaint(); + } + } + else if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY)) + dividerSize = splitPane.getDividerSize(); + } + + /** + * Paints the divider by painting its border. + * + * @param g The Graphics Object to paint with. + */ + public void paint(Graphics g) + { + Dimension dividerSize; + + super.paint(g); + if (border != null) + { + dividerSize = getSize(); + border.paintBorder(this, g, 0, 0, dividerSize.width, dividerSize.height); + } + } + + /** + * Reacts to changes of the <code>oneToughExpandable</code> property of the + * containing <code>JSplitPane</code>. + */ + protected void oneTouchExpandableChanged() + { + if (splitPane.isOneTouchExpandable()) + { + leftButton = createLeftOneTouchButton(); + rightButton = createRightOneTouchButton(); + add(leftButton); + add(rightButton); + + leftButton.addMouseListener(mouseHandler); + rightButton.addMouseListener(mouseHandler); + + // Set it to 1. + currentDividerLocation = 1; + } + else + { + if (leftButton != null && rightButton != null) + { + leftButton.removeMouseListener(mouseHandler); + rightButton.removeMouseListener(mouseHandler); + + remove(leftButton); + remove(rightButton); + leftButton = null; + rightButton = null; + } + } + layout(); + repaint(); + } + + /** + * Creates a button for showing and hiding the left (or top) part of a + * <code>JSplitPane</code>. + * + * @return The left one touch button. + */ + protected JButton createLeftOneTouchButton() + { + int dir = SwingConstants.WEST; + if (orientation == JSplitPane.VERTICAL_SPLIT) + dir = SwingConstants.NORTH; + JButton button = new BasicArrowButton(dir); + button.setBorder(null); + + return button; + } + + /** + * Creates a button for showing and hiding the right (or bottom) part of a + * <code>JSplitPane</code>. + * + * @return The right one touch button. + */ + protected JButton createRightOneTouchButton() + { + int dir = SwingConstants.EAST; + if (orientation == JSplitPane.VERTICAL_SPLIT) + dir = SwingConstants.SOUTH; + JButton button = new BasicArrowButton(dir); + button.setBorder(null); + return button; + } + + /** + * Prepares the divider for dragging by calling the + * <code>startDragging</code> method of the UI delegate of the enclosing + * <code>JSplitPane</code>. + * + * @see BasicSplitPaneUI#startDragging() + */ + protected void prepareForDragging() + { + if (splitPaneUI != null) + splitPaneUI.startDragging(); + } + + /** + * Drags the divider to a given location by calling the + * <code>dragDividerTo</code> method of the UI delegate of the enclosing + * <code>JSplitPane</code>. + * + * @param location the new location of the divider. + * + * @see BasicSplitPaneUI#dragDividerTo(int location) + */ + protected void dragDividerTo(int location) + { + if (splitPaneUI != null) + splitPaneUI.dragDividerTo(location); + } + + /** + * Finishes a dragging gesture by calling the <code>finishDraggingTo</code> + * method of the UI delegate of the enclosing <code>JSplitPane</code>. + * + * @param location the new, final location of the divider. + * + * @see BasicSplitPaneUI#finishDraggingTo(int location) + */ + protected void finishDraggingTo(int location) + { + if (splitPaneUI != null) + splitPaneUI.finishDraggingTo(location); + } + + /** + * This helper method moves the divider to one of the three locations when + * using one touch expand buttons. Location 0 is the left (or top) most + * location. Location 1 is the middle. Location 2 is the right (or bottom) + * most location. + * This is package-private to avoid an accessor method. + * + * @param locationIndex The location to move to. + */ + void moveDividerTo(int locationIndex) + { + Insets insets = splitPane.getInsets(); + switch (locationIndex) + { + case 1: + splitPane.setDividerLocation(splitPane.getLastDividerLocation()); + break; + case 0: + int top = (orientation == JSplitPane.HORIZONTAL_SPLIT) ? insets.left + : insets.top; + splitPane.setDividerLocation(top); + break; + case 2: + int bottom; + if (orientation == JSplitPane.HORIZONTAL_SPLIT) + bottom = splitPane.getBounds().width - insets.right - dividerSize; + else + bottom = splitPane.getBounds().height - insets.bottom - dividerSize; + splitPane.setDividerLocation(bottom); + break; + } + } + + /** + * The listener for handling mouse events from both the divider and the + * containing <code>JSplitPane</code>. + * + * <p> + * The reason for also handling MouseEvents from the containing + * <code>JSplitPane</code> is that users should be able to start a drag + * gesture from inside the JSplitPane, but slightly outisde the divider. + * </p> + * + * @author Sascha Brawer (brawer_AT_dandelis.ch) + */ + protected class MouseHandler extends MouseAdapter + implements MouseMotionListener + { + /** Keeps track of whether a drag is occurring. */ + private transient boolean isDragging; + + /** + * This method is called when the mouse is pressed. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + if (splitPane.isOneTouchExpandable()) + { + if (e.getSource() == leftButton) + { + currentDividerLocation--; + if (currentDividerLocation < 0) + currentDividerLocation = 0; + moveDividerTo(currentDividerLocation); + return; + } + else if (e.getSource() == rightButton) + { + currentDividerLocation++; + if (currentDividerLocation > 2) + currentDividerLocation = 2; + moveDividerTo(currentDividerLocation); + return; + } + } + isDragging = true; + currentDividerLocation = 1; + if (orientation == JSplitPane.HORIZONTAL_SPLIT) + dragger = new DragController(e); + else + dragger = new VerticalDragController(e); + prepareForDragging(); + } + + /** + * This method is called when the mouse is released. + * + * @param e The MouseEvent. + */ + public void mouseReleased(MouseEvent e) + { + if (isDragging) + dragger.completeDrag(e); + isDragging = false; + } + + /** + * Repeatedly invoked when the user is dragging the mouse cursor while + * having pressed a mouse button. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + if (dragger != null) + dragger.continueDrag(e); + } + + /** + * Repeatedly invoked when the user is dragging the mouse cursor without + * having pressed a mouse button. + * + * @param e The MouseEvent. + */ + public void mouseMoved(MouseEvent e) + { + // Do nothing. + } + } + + /** + * Performs the tasks associated with an ongoing drag operation. + * + * @author Sascha Brawer (brawer_AT_dandelis.ch) + */ + protected class DragController + { + /** + * The difference between where the mouse is clicked and the initial + * divider location. + */ + transient int offset; + + /** + * Creates a new DragController object. + * + * @param e The MouseEvent to initialize with. + */ + protected DragController(MouseEvent e) + { + offset = e.getX(); + } + + /** + * This method returns true if the divider can move. + * + * @return True if dragging is allowed. + */ + protected boolean isValid() + { + // Views can always be resized? + return true; + } + + /** + * Returns a position for the divider given the MouseEvent. + * + * @param e MouseEvent. + * + * @return The position for the divider to move to. + */ + protected int positionForMouseEvent(MouseEvent e) + { + return e.getX() + getX() - offset; + } + + /** + * This method returns one of the two paramters for the orientation. In + * this case, it returns x. + * + * @param x The x coordinate. + * @param y The y coordinate. + * + * @return The x coordinate. + */ + protected int getNeededLocation(int x, int y) + { + return x; + } + + /** + * This method is called to pass on the drag information to the UI through + * dragDividerTo. + * + * @param newX The x coordinate of the MouseEvent. + * @param newY The y coordinate of the MouseEvent. + */ + protected void continueDrag(int newX, int newY) + { + if (isValid()) + dragDividerTo(adjust(newX, newY)); + } + + /** + * This method is called to pass on the drag information to the UI + * through dragDividerTo. + * + * @param e The MouseEvent. + */ + protected void continueDrag(MouseEvent e) + { + if (isValid()) + dragDividerTo(positionForMouseEvent(e)); + } + + /** + * This method is called to finish the drag session by calling + * finishDraggingTo. + * + * @param x The x coordinate of the MouseEvent. + * @param y The y coordinate of the MouseEvent. + */ + protected void completeDrag(int x, int y) + { + finishDraggingTo(adjust(x, y)); + } + + /** + * This method is called to finish the drag session by calling + * finishDraggingTo. + * + * @param e The MouseEvent. + */ + protected void completeDrag(MouseEvent e) + { + finishDraggingTo(positionForMouseEvent(e)); + } + + /** + * This is a helper method that includes the offset in the needed + * location. + * + * @param x The x coordinate of the MouseEvent. + * @param y The y coordinate of the MouseEvent. + * + * @return The needed location adjusted by the offsets. + */ + int adjust(int x, int y) + { + return getNeededLocation(x, y) + getX() - offset; + } + } + + /** + * This is a helper class that controls dragging when the orientation is + * VERTICAL_SPLIT. + */ + protected class VerticalDragController extends DragController + { + /** + * Creates a new VerticalDragController object. + * + * @param e The MouseEvent to initialize with. + */ + protected VerticalDragController(MouseEvent e) + { + super(e); + offset = e.getY(); + } + + /** + * This method returns one of the two parameters given the orientation. In + * this case, it returns y. + * + * @param x The x coordinate of the MouseEvent. + * @param y The y coordinate of the MouseEvent. + * + * @return The y coordinate. + */ + protected int getNeededLocation(int x, int y) + { + return y; + } + + /** + * This method returns the new location of the divider given a MouseEvent. + * + * @param e The MouseEvent. + * + * @return The new location of the divider. + */ + protected int positionForMouseEvent(MouseEvent e) + { + return e.getY() + getY() - offset; + } + + /** + * This is a helper method that includes the offset in the needed + * location. + * + * @param x The x coordinate of the MouseEvent. + * @param y The y coordinate of the MouseEvent. + * + * @return The needed location adjusted by the offsets. + */ + int adjust(int x, int y) + { + return getNeededLocation(x, y) + getY() - offset; + } + } + + /** + * This helper class acts as the Layout Manager for the divider. + */ + protected class DividerLayout implements LayoutManager + { + /** + * Creates a new DividerLayout object. + */ + protected DividerLayout() + { + } + + /** + * This method is called when a Component is added. + * + * @param string The constraints string. + * @param c The Component to add. + */ + public void addLayoutComponent(String string, Component c) + { + // Do nothing. + } + + /** + * This method is called to lay out the container. + * + * @param c The container to lay out. + */ + public void layoutContainer(Container c) + { + if (splitPane.isOneTouchExpandable()) + { + changeButtonOrientation(); + positionButtons(); + } + } + + /** + * This method returns the minimum layout size. + * + * @param c The container to calculate for. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container c) + { + return preferredLayoutSize(c); + } + + /** + * This method returns the preferred layout size. + * + * @param c The container to calculate for. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container c) + { + return new Dimension(dividerSize, dividerSize); + } + + /** + * This method is called when a component is removed. + * + * @param c The component to remove. + */ + public void removeLayoutComponent(Component c) + { + // Do nothing. + } + + /** + * This method changes the button orientation when the orientation of the + * SplitPane changes. + */ + private void changeButtonOrientation() + { + if (orientation == JSplitPane.HORIZONTAL_SPLIT) + { + ((BasicArrowButton) rightButton).setDirection(SwingConstants.EAST); + ((BasicArrowButton) leftButton).setDirection(SwingConstants.WEST); + } + else + { + ((BasicArrowButton) rightButton).setDirection(SwingConstants.SOUTH); + ((BasicArrowButton) leftButton).setDirection(SwingConstants.NORTH); + } + } + + /** + * This method sizes and positions the buttons. + */ + private void positionButtons() + { + int w = 0; + int h = 0; + if (orientation == JSplitPane.HORIZONTAL_SPLIT) + { + rightButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET); + leftButton.setLocation(ONE_TOUCH_OFFSET, + ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE); + w = dividerSize - 2 * ONE_TOUCH_OFFSET; + h = 2 * ONE_TOUCH_SIZE; + } + else + { + leftButton.setLocation(ONE_TOUCH_OFFSET, ONE_TOUCH_OFFSET); + rightButton.setLocation(ONE_TOUCH_OFFSET + 2 * ONE_TOUCH_SIZE, + ONE_TOUCH_OFFSET); + h = dividerSize - 2 * ONE_TOUCH_OFFSET; + w = 2 * ONE_TOUCH_SIZE; + } + Dimension dims = new Dimension(w, h); + leftButton.setSize(dims); + rightButton.setSize(dims); + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java new file mode 100644 index 00000000000..ff7e8acfbb6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -0,0 +1,1556 @@ +/* BasicSplitPaneUI.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager2; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.JComponent; +import javax.swing.JSplitPane; +import javax.swing.KeyStroke; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SplitPaneUI; + +/** + * This is the Basic Look and Feel implementation of the SplitPaneUI class. + */ +public class BasicSplitPaneUI extends SplitPaneUI +{ + /** + * This Layout Manager controls the position and size of the components when + * the JSplitPane's orientation is HORIZONTAL_SPLIT. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class BasicHorizontalLayoutManager implements LayoutManager2 + { + // 3 components at a time. + // LEFT/TOP = 0 + // RIGHT/BOTTOM = 1 + // DIVIDER = 2 + + /** + * This array contains the components in the JSplitPane. The left/top + * component is at index 0, the right/bottom is at 1, and the divider is + * at 2. + */ + protected Component[] components = new Component[3]; + + // These are the _current_ widths of the associated component. + + /** + * This array contains the current width (for HORIZONTAL_SPLIT) or height + * (for VERTICAL_SPLIT) of the components. The indices are the same as + * for components. + */ + protected int[] sizes = new int[3]; + + /** + * This method adds the component given to the JSplitPane. The position of + * the component is given by the constraints object. + * + * @param comp The Component to add. + * @param constraints The constraints that bind the object. + */ + public void addLayoutComponent(Component comp, Object constraints) + { + addLayoutComponent((String) constraints, comp); + } + + /** + * This method is called to add a Component to the JSplitPane. The + * placement string determines where the Component will be placed. The + * string should be one of LEFT, RIGHT, TOP, BOTTOM or null (signals that + * the component is the divider). + * + * @param place The placement of the Component. + * @param component The Component to add. + * + * @throws IllegalArgumentException DOCUMENT ME! + */ + public void addLayoutComponent(String place, Component component) + { + int i = 0; + if (place == null) + i = 2; + else if (place.equals(JSplitPane.TOP) || place.equals(JSplitPane.LEFT)) + i = 0; + else if (place.equals(JSplitPane.BOTTOM) + || place.equals(JSplitPane.RIGHT)) + i = 1; + else + throw new IllegalArgumentException("Illegal placement in JSplitPane"); + components[i] = component; + resetSizeAt(i); + splitPane.revalidate(); + splitPane.repaint(); + } + + /** + * This method returns the width of the JSplitPane minus the insets. + * + * @param containerSize The Dimensions of the JSplitPane. + * @param insets The Insets of the JSplitPane. + * + * @return The width of the JSplitPane minus the insets. + */ + protected int getAvailableSize(Dimension containerSize, Insets insets) + { + return containerSize.width - insets.left - insets.right; + } + + /** + * This method returns the given insets left value. If the given inset is + * null, then 0 is returned. + * + * @param insets The Insets to use with the JSplitPane. + * + * @return The inset's left value. + */ + protected int getInitialLocation(Insets insets) + { + if (insets != null) + return insets.left; + return 0; + } + + /** + * This specifies how a component is aligned with respect to other + * components in the x fdirection. + * + * @param target The container. + * + * @return The component's alignment. + */ + public float getLayoutAlignmentX(Container target) + { + return target.getAlignmentX(); + } + + /** + * This specifies how a component is aligned with respect to other + * components in the y direction. + * + * @param target The container. + * + * @return The component's alignment. + */ + public float getLayoutAlignmentY(Container target) + { + return target.getAlignmentY(); + } + + /** + * This method returns the preferred width of the component. + * + * @param c The component to measure. + * + * @return The preferred width of the component. + */ + protected int getPreferredSizeOfComponent(Component c) + { + Dimension dims = c.getPreferredSize(); + if (dims != null) + return dims.width; + return 0; + } + + /** + * This method returns the current width of the component. + * + * @param c The component to measure. + * + * @return The width of the component. + */ + protected int getSizeOfComponent(Component c) + { + return c.getWidth(); + } + + /** + * This method returns the sizes array. + * + * @return The sizes array. + */ + protected int[] getSizes() + { + return sizes; + } + + /** + * This method invalidates the layout. It does nothing. + * + * @param c The container to invalidate. + */ + public void invalidateLayout(Container c) + { + // DO NOTHING + } + + /** + * This method lays out the components in the container. + * + * @param container The container to lay out. + */ + public void layoutContainer(Container container) + { + if (container instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) container; + distributeExtraSpace(); + Insets insets = split.getInsets(); + int width = getInitialLocation(insets); + Dimension dims = split.getSize(); + for (int i = 0; i < components.length; i += 2) + { + if (components[i] == null) + continue; + setComponentToSize(components[i], sizes[i], width, insets, dims); + width += sizes[i]; + } + if (components[1] != null) + { + setComponentToSize(components[1], sizes[1], width, insets, dims); + width += sizes[1]; + } + } + } + + /** + * This method returns the maximum size for the container given the + * components. It returns a new Dimension object that has width and + * height equal to Integer.MAX_VALUE. + * + * @param target The container to measure. + * + * @return The maximum size. + */ + public Dimension maximumLayoutSize(Container target) + { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * This method returns the container's minimum size. The minimum width is + * the sum of all the component's minimum widths. The minimum height is + * the maximum of all the components' minimum heights. + * + * @param target The container to measure. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container target) + { + if (target instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) target; + Insets insets = target.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getMinimumSize(); + if (dims != null) + { + width += dims.width; + height = Math.max(height, dims.height); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method returns the container's preferred size. The preferred width + * is the sum of all the component's preferred widths. The preferred + * height is the maximum of all the components' preferred heights. + * + * @param target The container to measure. + * + * @return The preferred size. + */ + public Dimension preferredLayoutSize(Container target) + { + if (target instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) target; + Insets insets = target.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getPreferredSize(); + if (dims != null) + { + width += dims.width; + if (! (components[i] instanceof BasicSplitPaneDivider)) + height = Math.max(height, dims.height); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method removes the component from the layout. + * + * @param component The component to remove from the layout. + */ + public void removeLayoutComponent(Component component) + { + for (int i = 0; i < components.length; i++) + { + if (component == components[i]) + { + components[i] = null; + sizes[i] = 0; + } + } + } + + /** + * This method resets the size of Component to the preferred size. + * + * @param index The index of the component to reset. + */ + protected void resetSizeAt(int index) + { + if (components[index] != null) + sizes[index] = getPreferredSizeOfComponent(components[index]); + } + + /** + * This method resets the sizes of all the components. + */ + public void resetToPreferredSizes() + { + for (int i = 0; i < components.length; i++) + resetSizeAt(i); + } + + /** + * This methods sets the bounds of the given component. The width is the + * size. The height is the container size minus the top and bottom + * inset. The x coordinate is the location given. The y coordinate is + * the top inset. + * + * @param c The component to set. + * @param size The width of the component. + * @param location The x coordinate. + * @param insets The insets to use. + * @param containerSize The height of the container. + */ + protected void setComponentToSize(Component c, int size, int location, + Insets insets, Dimension containerSize) + { + int w = size; + int h = containerSize.height - insets.top - insets.bottom; + int x = location; + int y = insets.top; + c.setBounds(x, y, w, h); + } + + /** + * This method stores the given int array as the new sizes array. + * + * @param newSizes The array to use as sizes. + */ + protected void setSizes(int[] newSizes) + { + sizes = newSizes; + } + + /** + * This method determines the size of each component. It should be called + * when a new Layout Manager is created for an existing JSplitPane. + */ + protected void updateComponents() + { + Component left = splitPane.getLeftComponent(); + Component right = splitPane.getRightComponent(); + + if (left != null) + { + components[0] = left; + resetSizeAt(0); + } + if (right != null) + { + components[1] = right; + resetSizeAt(1); + } + components[2] = divider; + resetSizeAt(2); + } + + /** + * This method resizes the left and right components to fit inside the + * JSplitPane when there is extra space. + */ + void distributeExtraSpace() + { + int availSize = getAvailableSize(splitPane.getSize(), + splitPane.getInsets()); + int[] newSizes = new int[3]; + double weight = splitPane.getResizeWeight(); + + int oldLen = sizes[0] + sizes[1]; + + // dividers don't change size. + availSize -= sizes[2] + oldLen; + + int rightAlloc = (int) (availSize * (1 - weight)); + int leftAlloc = availSize - rightAlloc; + + sizes[0] += leftAlloc; + sizes[1] += rightAlloc; + } + + /** + * This method returns the minimum width of the component at the given + * index. + * + * @param index The index to check. + * + * @return The minimum width. + */ + int minimumSizeOfComponent(int index) + { + Dimension dims = components[index].getMinimumSize(); + if (dims != null) + return dims.width; + else + return 0; + } + } //end BasicHorizontalLayoutManager + + /** + * This class is the Layout Manager for the JSplitPane when the orientation + * is VERTICAL_SPLIT. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class BasicVerticalLayoutManager + extends BasicHorizontalLayoutManager + { + /** + * This method returns the height of the container minus the top and + * bottom inset. + * + * @param containerSize The size of the container. + * @param insets The insets of the container. + * + * @return The height minus top and bottom inset. + */ + protected int getAvailableSize(Dimension containerSize, Insets insets) + { + return containerSize.height - insets.top - insets.bottom; + } + + /** + * This method returns the top inset. + * + * @param insets The Insets to use. + * + * @return The top inset. + */ + protected int getInitialLocation(Insets insets) + { + return insets.top; + } + + /** + * This method returns the preferred height of the component. + * + * @param c The component to measure. + * + * @return The preferred height of the component. + */ + protected int getPreferredSizeOfComponent(Component c) + { + Dimension dims = c.getPreferredSize(); + if (dims != null) + return dims.height; + return 0; + } + + /** + * This method returns the current height of the component. + * + * @param c The component to measure. + * + * @return The current height of the component. + */ + protected int getSizeOfComponent(Component c) + { + return c.getHeight(); + } + + /** + * This method returns the minimum layout size. The minimum height is the + * sum of all the components' minimum heights. The minimum width is the + * maximum of all the components' minimum widths. + * + * @param container The container to measure. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container container) + { + if (container instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) container; + Insets insets = container.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getMinimumSize(); + if (dims != null) + { + height += dims.height; + width = Math.max(width, dims.width); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method returns the preferred layout size. The preferred height is + * the sum of all the components' preferred heights. The preferred width + * is the maximum of all the components' preferred widths. + * + * @param container The container to measure. + * + * @return The preferred size. + */ + public Dimension preferredLayoutSize(Container container) + { + if (container instanceof JSplitPane) + { + JSplitPane split = (JSplitPane) container; + Insets insets = container.getInsets(); + + int height = 0; + int width = 0; + for (int i = 0; i < components.length; i++) + { + if (components[i] == null) + continue; + Dimension dims = components[i].getPreferredSize(); + if (dims != null) + { + height += dims.height; + width = Math.max(width, dims.width); + } + } + return new Dimension(width, height); + } + return null; + } + + /** + * This method sets the bounds of the given component. The y coordinate is + * the location given. The x coordinate is the left inset. The height is + * the size given. The width is the container size minus the left and + * right inset. + * + * @param c The component to set bounds for. + * @param size The height. + * @param location The y coordinate. + * @param insets The insets to use. + * @param containerSize The container's size. + */ + protected void setComponentToSize(Component c, int size, int location, + Insets insets, Dimension containerSize) + { + int y = location; + int x = insets.left; + int h = size; + int w = containerSize.width - insets.left - insets.right; + + c.setBounds(x, y, w, h); + } + + /** + * This method returns the minimum height of the component at the given + * index. + * + * @param index The index of the component to check. + * + * @return The minimum height of the given component. + */ + int minimumSizeOfComponent(int index) + { + Dimension dims = components[index].getMinimumSize(); + if (dims != null) + return dims.height; + else + return 0; + } + } + + /** + * This class handles FocusEvents from the JComponent. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class FocusHandler extends FocusAdapter + { + /** + * This method is called when the JSplitPane gains focus. + * + * @param ev The FocusEvent. + */ + public void focusGained(FocusEvent ev) + { + // FIXME: implement. + } + + /** + * This method is called when the JSplitPane loses focus. + * + * @param ev The FocusEvent. + */ + public void focusLost(FocusEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling down + * and right key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardDownRightHandler implements ActionListener + { + /** + * This method is called when the down or right keys are pressed. + * + * @param ev The ActionEvent + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling end + * key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardEndHandler implements ActionListener + { + /** + * This method is called when the end key is pressed. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling home + * key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardHomeHandler implements ActionListener + { + /** + * This method is called when the home key is pressed. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handling resize + * toggles. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardResizeToggleHandler implements ActionListener + { + /** + * This method is called when a resize is toggled. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This is a deprecated class. It is supposed to be used for handler up and + * left key presses. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class KeyboardUpLeftHandler implements ActionListener + { + /** + * This method is called when the left or up keys are pressed. + * + * @param ev The ActionEvent. + */ + public void actionPerformed(ActionEvent ev) + { + // FIXME: implement. + } + } + + /** + * This helper class handles PropertyChangeEvents from the JSplitPane. When + * a property changes, this will update the UI accordingly. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class PropertyHandler implements PropertyChangeListener + { + /** + * This method is called whenever one of the JSplitPane's properties + * change. + * + * @param e DOCUMENT ME! + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JSplitPane.DIVIDER_SIZE_PROPERTY)) + { + int newSize = splitPane.getDividerSize(); + int[] tmpSizes = layoutManager.getSizes(); + dividerSize = tmpSizes[2]; + Component left = splitPane.getLeftComponent(); + Component right = splitPane.getRightComponent(); + int newSpace = newSize - tmpSizes[2]; + + tmpSizes[2] = newSize; + + tmpSizes[0] += newSpace / 2; + tmpSizes[1] += newSpace / 2; + + layoutManager.setSizes(tmpSizes); + } + else if (e.getPropertyName().equals(JSplitPane.ORIENTATION_PROPERTY)) + { + int max = layoutManager.getAvailableSize(splitPane.getSize(), + splitPane.getInsets()); + int dividerLoc = getDividerLocation(splitPane); + double prop = ((double) dividerLoc) / max; + + resetLayoutManager(); + if (prop <= 1 && prop >= 0) + splitPane.setDividerLocation(prop); + } + layoutManager.layoutContainer(splitPane); + splitPane.repaint(); + // Don't have to deal with continuous_layout - only + // necessary in dragging modes (and it's checked + // every time you drag there) + // Don't have to deal with resize_weight (as there + // will be no extra space associated with this + // event - the changes to the weighting will + // be taken into account the next time the + // sizes change.) + // Don't have to deal with divider_location + // The method in JSplitPane calls our setDividerLocation + // so we'll know about those anyway. + // Don't have to deal with last_divider_location + // Although I'm not sure why, it doesn't seem to + // have any effect on Sun's JSplitPane. + // one_touch_expandable changes are dealt with + // by our divider. + } + } + + /** The location of the divider when dragging began. */ + protected int beginDragDividerLocation; + + /** The size of the divider while dragging. */ + protected int dividerSize; + + /** The location where the last drag location ended. */ + transient int lastDragLocation = -1; + + /** The distance the divider is moved when moved by keyboard actions. */ + protected static int KEYBOARD_DIVIDER_MOVE_OFFSET; + + /** The divider that divides this JSplitPane. */ + protected BasicSplitPaneDivider divider; + + /** The listener that listens for PropertyChangeEvents from the JSplitPane. */ + protected PropertyChangeListener propertyChangeListener; + + /** The JSplitPane's focus handler. */ + protected FocusListener focusListener; + + /** @deprecated The handler for down and right key presses. */ + protected ActionListener keyboardDownRightListener; + + /** @deprecated The handler for end key presses. */ + protected ActionListener keyboardEndListener; + + /** @deprecated The handler for home key presses. */ + protected ActionListener keyboardHomeListener; + + /** @deprecated The handler for toggling resizes. */ + protected ActionListener keyboardResizeToggleListener; + + /** @deprecated The handler for up and left key presses. */ + protected ActionListener keyboardUpLeftListener; + + /** The JSplitPane's current layout manager. */ + protected BasicHorizontalLayoutManager layoutManager; + + /** @deprecated The divider resize toggle key. */ + protected KeyStroke dividerResizeToggleKey; + + /** @deprecated The down key. */ + protected KeyStroke downKey; + + /** @deprecated The end key. */ + protected KeyStroke endKey; + + /** @deprecated The home key. */ + protected KeyStroke homeKey; + + /** @deprecated The left key. */ + protected KeyStroke leftKey; + + /** @deprecated The right key. */ + protected KeyStroke rightKey; + + /** @deprecated The up key. */ + protected KeyStroke upKey; + + /** Set to true when dragging heavy weight components. */ + protected boolean draggingHW; + + /** + * The constraints object used when adding the non-continuous divider to the + * JSplitPane. + */ + protected static final String NON_CONTINUOUS_DIVIDER + = "nonContinuousDivider"; + + /** The dark divider used when dragging in non-continuous layout mode. */ + protected Component nonContinuousLayoutDivider; + + /** The JSplitPane that this UI draws. */ + protected JSplitPane splitPane; + + /** + * Creates a new BasicSplitPaneUI object. + */ + public BasicSplitPaneUI() + { + } + + /** + * This method creates a new BasicSplitPaneUI for the given JComponent. + * + * @param x The JComponent to create a UI for. + * + * @return A new BasicSplitPaneUI. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicSplitPaneUI(); + } + + /** + * This method installs the BasicSplitPaneUI for the given JComponent. + * + * @param c The JComponent to install the UI for. + */ + public void installUI(JComponent c) + { + if (c instanceof JSplitPane) + { + splitPane = (JSplitPane) c; + installDefaults(); + installListeners(); + installKeyboardActions(); + } + } + + /** + * This method uninstalls the BasicSplitPaneUI for the given JComponent. + * + * @param c The JComponent to uninstall the UI for. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallDefaults(); + + splitPane = null; + } + + /** + * This method installs the defaults given by the Look and Feel. + */ + protected void installDefaults() + { + divider = createDefaultDivider(); + resetLayoutManager(); + nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); + splitPane.add(divider, JSplitPane.DIVIDER); + + // There is no need to add the nonContinuousLayoutDivider + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + splitPane.setBackground(defaults.getColor("SplitPane.background")); + splitPane.setBorder(defaults.getBorder("SplitPane.border")); + splitPane.setDividerSize(defaults.getInt("SplitPane.dividerSize")); + splitPane.setOpaque(true); + } + + /** + * This method uninstalls the defaults and nulls any objects created during + * install. + */ + protected void uninstallDefaults() + { + layoutManager = null; + splitPane.remove(divider); + divider = null; + nonContinuousLayoutDivider = null; + + splitPane.setBackground(null); + splitPane.setBorder(null); + } + + /** + * This method installs the listeners needed for this UI to function. + */ + protected void installListeners() + { + propertyChangeListener = createPropertyChangeListener(); + focusListener = createFocusListener(); + + splitPane.addPropertyChangeListener(propertyChangeListener); + splitPane.addFocusListener(focusListener); + } + + /** + * This method uninstalls all listeners registered for the UI. + */ + protected void uninstallListeners() + { + splitPane.removePropertyChangeListener(propertyChangeListener); + splitPane.removeFocusListener(focusListener); + + focusListener = null; + propertyChangeListener = null; + } + + /** + * This method installs the keyboard actions for the JSplitPane. + */ + protected void installKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method reverses the work done in installKeyboardActions. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method creates a new PropertyChangeListener. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyHandler(); + } + + /** + * This method creates a new FocusListener. + * + * @return A new FocusListener. + */ + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + + /** + * This method creates a new ActionListener for up and left key presses. + * + * @return A new ActionListener for up and left keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardUpLeftListener() + { + return new KeyboardUpLeftHandler(); + } + + /** + * This method creates a new ActionListener for down and right key presses. + * + * @return A new ActionListener for down and right keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardDownRightListener() + { + return new KeyboardDownRightHandler(); + } + + /** + * This method creates a new ActionListener for home key presses. + * + * @return A new ActionListener for home keys. + * + * @deprecated + */ + protected ActionListener createKeyboardHomeListener() + { + return new KeyboardHomeHandler(); + } + + /** + * This method creates a new ActionListener for end key presses.i + * + * @return A new ActionListener for end keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardEndListener() + { + return new KeyboardEndHandler(); + } + + /** + * This method creates a new ActionListener for resize toggle key events. + * + * @return A new ActionListener for resize toggle keys. + * + * @deprecated 1.3 + */ + protected ActionListener createKeyboardResizeToggleListener() + { + return new KeyboardResizeToggleHandler(); + } + + /** + * This method returns the orientation of the JSplitPane. + * + * @return The orientation of the JSplitPane. + */ + public int getOrientation() + { + return splitPane.getOrientation(); + } + + /** + * This method sets the orientation of the JSplitPane. + * + * @param orientation The new orientation of the JSplitPane. + */ + public void setOrientation(int orientation) + { + splitPane.setOrientation(orientation); + } + + /** + * This method returns true if the JSplitPane is using continuous layout. + * + * @return True if the JSplitPane is using continuous layout. + */ + public boolean isContinuousLayout() + { + return splitPane.isContinuousLayout(); + } + + /** + * This method sets the continuous layout property of the JSplitPane. + * + * @param b True if the JsplitPane is to use continuous layout. + */ + public void setContinuousLayout(boolean b) + { + splitPane.setContinuousLayout(b); + } + + /** + * This method returns the last location the divider was dragged to. + * + * @return The last location the divider was dragged to. + */ + public int getLastDragLocation() + { + return lastDragLocation; + } + + /** + * This method sets the last location the divider was dragged to. + * + * @param l The last location the divider was dragged to. + */ + public void setLastDragLocation(int l) + { + lastDragLocation = l; + } + + /** + * This method returns the BasicSplitPaneDivider that divides this + * JSplitPane. + * + * @return The divider for the JSplitPane. + */ + public BasicSplitPaneDivider getDivider() + { + return divider; + } + + /** + * This method creates a nonContinuousLayoutDivider for use with the + * JSplitPane in nonContinousLayout mode. The default divider is a gray + * Canvas. + * + * @return The default nonContinousLayoutDivider. + */ + protected Component createDefaultNonContinuousLayoutDivider() + { + if (nonContinuousLayoutDivider == null) + { + nonContinuousLayoutDivider = new Canvas(); + nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY); + } + return nonContinuousLayoutDivider; + } + + /** + * This method sets the component to use as the nonContinuousLayoutDivider. + * + * @param newDivider The component to use as the nonContinuousLayoutDivider. + */ + protected void setNonContinuousLayoutDivider(Component newDivider) + { + setNonContinuousLayoutDivider(newDivider, true); + } + + /** + * This method sets the component to use as the nonContinuousLayoutDivider. + * + * @param newDivider The component to use as the nonContinuousLayoutDivider. + * @param rememberSizes FIXME: document. + */ + protected void setNonContinuousLayoutDivider(Component newDivider, + boolean rememberSizes) + { + // FIXME: use rememberSizes for something + nonContinuousLayoutDivider = newDivider; + } + + /** + * This method returns the nonContinuousLayoutDivider. + * + * @return The nonContinuousLayoutDivider. + */ + public Component getNonContinuousLayoutDivider() + { + return nonContinuousLayoutDivider; + } + + /** + * This method returns the JSplitPane that this BasicSplitPaneUI draws. + * + * @return The JSplitPane. + */ + public JSplitPane getSplitPane() + { + return splitPane; + } + + /** + * This method creates the divider used normally with the JSplitPane. + * + * @return The default divider. + */ + public BasicSplitPaneDivider createDefaultDivider() + { + if (divider == null) + divider = new BasicSplitPaneDivider(this); + return divider; + } + + /** + * This method is called when JSplitPane's resetToPreferredSizes is called. + * It resets the sizes of all components in the JSplitPane. + * + * @param jc The JSplitPane to reset. + */ + public void resetToPreferredSizes(JSplitPane jc) + { + layoutManager.resetToPreferredSizes(); + } + + /** + * This method sets the location of the divider. + * + * @param jc The JSplitPane to set the divider location in. + * @param location The new location of the divider. + */ + public void setDividerLocation(JSplitPane jc, int location) + { + setLastDragLocation(getDividerLocation(splitPane)); + splitPane.setLastDividerLocation(getDividerLocation(splitPane)); + int[] tmpSizes = layoutManager.getSizes(); + tmpSizes[0] = location + - layoutManager.getInitialLocation(splitPane.getInsets()); + tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(), + splitPane.getInsets()) + - tmpSizes[0] - tmpSizes[1]; + + layoutManager.setSizes(tmpSizes); + splitPane.revalidate(); + splitPane.repaint(); + } + + /** + * This method returns the location of the divider. + * + * @param jc The JSplitPane to retrieve the location for. + * + * @return The location of the divider. + */ + public int getDividerLocation(JSplitPane jc) + { + return layoutManager.sizes[0] + + layoutManager.getInitialLocation(splitPane.getInsets()); + } + + /** + * This method returns the smallest value possible for the location of the + * divider. + * + * @param jc The JSplitPane. + * + * @return The minimum divider location. + */ + public int getMinimumDividerLocation(JSplitPane jc) + { + int value = layoutManager.getInitialLocation(jc.getInsets()); + if (layoutManager.components[0] != null) + value += layoutManager.minimumSizeOfComponent(0); + return value; + } + + /** + * This method returns the largest value possible for the location of the + * divider. + * + * @param jc The JSplitPane. + * + * @return The maximum divider location. + */ + public int getMaximumDividerLocation(JSplitPane jc) + { + int value = layoutManager.getInitialLocation(jc.getInsets()) + + layoutManager.getAvailableSize(jc.getSize(), jc.getInsets()) + - splitPane.getDividerSize(); + if (layoutManager.components[1] != null) + value -= layoutManager.minimumSizeOfComponent(1); + return value; + } + + /** + * This method is called after the children of the JSplitPane are painted. + * + * @param jc The JSplitPane. + * @param g The Graphics object to paint with. + */ + public void finishedPaintingChildren(JSplitPane jc, Graphics g) + { + if (! splitPane.isContinuousLayout() && nonContinuousLayoutDivider != null + && nonContinuousLayoutDivider.isVisible()) + javax.swing.SwingUtilities.paintComponent(g, nonContinuousLayoutDivider, + null, + nonContinuousLayoutDivider + .getBounds()); + } + + /** + * This method is called to paint the JSplitPane. + * + * @param g The Graphics object to paint with. + * @param jc The JSplitPane to paint. + */ + public void paint(Graphics g, JComponent jc) + { + } + + /** + * This method returns the preferred size of the JSplitPane. + * + * @param jc The JSplitPane. + * + * @return The preferred size of the JSplitPane. + */ + public Dimension getPreferredSize(JComponent jc) + { + return layoutManager.preferredLayoutSize((Container) jc); + } + + /** + * This method returns the minimum size of the JSplitPane. + * + * @param jc The JSplitPane. + * + * @return The minimum size of the JSplitPane. + */ + public Dimension getMinimumSize(JComponent jc) + { + return layoutManager.minimumLayoutSize((Container) jc); + } + + /** + * This method returns the maximum size of the JSplitPane. + * + * @param jc The JSplitPane. + * + * @return The maximum size of the JSplitPane. + */ + public Dimension getMaximumSize(JComponent jc) + { + return layoutManager.maximumLayoutSize((Container) jc); + } + + /** + * This method returns the border insets of the current border. + * + * @param jc The JSplitPane. + * + * @return The current border insets. + */ + public Insets getInsets(JComponent jc) + { + return splitPane.getBorder().getBorderInsets(splitPane); + } + + /** + * This method resets the current layout manager. The type of layout manager + * is dependent on the current orientation. + */ + protected void resetLayoutManager() + { + if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) + layoutManager = new BasicHorizontalLayoutManager(); + else + layoutManager = new BasicVerticalLayoutManager(); + getSplitPane().setLayout(layoutManager); + layoutManager.updateComponents(); + + // invalidating by itself does not invalidate the layout. + getSplitPane().revalidate(); + } + + /** + * This method is called when dragging starts. It resets lastDragLocation + * and dividerSize. + */ + protected void startDragging() + { + dividerSize = divider.getDividerSize(); + setLastDragLocation(-1); + + if (! splitPane.getLeftComponent().isLightweight() + || ! splitPane.getRightComponent().isLightweight()) + draggingHW = true; + + if (splitPane.isContinuousLayout()) + nonContinuousLayoutDivider.setVisible(false); + else + { + nonContinuousLayoutDivider.setVisible(true); + nonContinuousLayoutDivider.setBounds(divider.getBounds()); + } + splitPane.revalidate(); + splitPane.repaint(); + } + + /** + * This method is called whenever the divider is dragged. If the JSplitPane + * is in continuousLayout mode, the divider needs to be moved and the + * JSplitPane needs to be laid out. + * + * @param location The new location of the divider. + */ + protected void dragDividerTo(int location) + { + location = validLocation(location); + if (beginDragDividerLocation == -1) + beginDragDividerLocation = location; + + if (splitPane.isContinuousLayout()) + splitPane.setDividerLocation(location); + else + { + Point p = nonContinuousLayoutDivider.getLocation(); + if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) + p.x = location; + else + p.y = location; + nonContinuousLayoutDivider.setLocation(p); + } + setLastDragLocation(location); + splitPane.repaint(); + } + + /** + * This method is called when the dragging is finished. + * + * @param location The location where the drag finished. + */ + protected void finishDraggingTo(int location) + { + if (nonContinuousLayoutDivider != null) + nonContinuousLayoutDivider.setVisible(false); + draggingHW = false; + location = validLocation(location); + dragDividerTo(location); + splitPane.setDividerLocation(location); + splitPane.setLastDividerLocation(beginDragDividerLocation); + beginDragDividerLocation = -1; + splitPane.repaint(); + } + + /** + * This method returns the width of one of the sides of the divider's border. + * + * @return The width of one side of the divider's border. + * + * @deprecated 1.3 + */ + protected int getDividerBorderSize() + { + if (getOrientation() == JSplitPane.HORIZONTAL_SPLIT) + return divider.getBorder().getBorderInsets(divider).left; + else + return divider.getBorder().getBorderInsets(divider).top; + } + + /** + * This is a helper method that returns a valid location for the divider + * when dragging. + * + * @param location The location to check. + * + * @return A valid location. + */ + private int validLocation(int location) + { + if (location < getMinimumDividerLocation(splitPane)) + return getMinimumDividerLocation(splitPane); + if (location > getMaximumDividerLocation(splitPane)) + return getMaximumDividerLocation(splitPane); + return location; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java new file mode 100644 index 00000000000..8a27f98a3c9 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -0,0 +1,3084 @@ +/* BasicTabbedPaneUI.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.JViewport; +import javax.swing.KeyStroke; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.PanelUI; +import javax.swing.plaf.TabbedPaneUI; +import javax.swing.plaf.UIResource; +import javax.swing.text.View; + +/** + * This is the Basic Look and Feel's UI delegate for JTabbedPane. + */ +public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants +{ + /** + * A helper class that handles focus. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class FocusHandler extends FocusAdapter + { + /** + * This method is called when the component gains focus. + * + * @param e The FocusEvent. + */ + public void focusGained(FocusEvent e) + { + // FIXME: Implement. + } + + /** + * This method is called when the component loses focus. + * + * @param e The FocusEvent. + */ + public void focusLost(FocusEvent e) + { + // FIXME: Implement. + } + } + + /** + * A helper class for determining if mouse presses occur inside tabs and + * sets the index appropriately. In SCROLL_TAB_MODE, this class also + * handles the mouse clicks on the scrolling buttons. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class MouseHandler extends MouseAdapter + { + /** + * This method is called when the mouse is pressed. The index cannot + * change to a tab that is not enabled. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + int x = e.getX(); + int y = e.getY(); + int tabCount = tabPane.getTabCount(); + + if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + { + if (e.getSource() == incrButton) + { + if (++currentScrollLocation >= tabCount) + currentScrollLocation = tabCount - 1; + + int width = 0; + for (int i = currentScrollLocation - 1; i < tabCount; i++) + width += rects[i].width; + if (width < viewport.getWidth()) + // FIXME: Still getting mouse events after the button is disabled. + // incrButton.setEnabled(false); + currentScrollLocation--; + else if (! decrButton.isEnabled()) + decrButton.setEnabled(true); + tabPane.revalidate(); + tabPane.repaint(); + return; + } + else if (e.getSource() == decrButton) + { + if (--currentScrollLocation < 0) + currentScrollLocation = 0; + if (currentScrollLocation == 0) + decrButton.setEnabled(false); + else if (! incrButton.isEnabled()) + incrButton.setEnabled(true); + tabPane.revalidate(); + tabPane.repaint(); + return; + } + } + + int index = tabForCoordinate(tabPane, x, y); + + // We need to check since there are areas where tabs cannot be + // e.g. in the inset area. + if (index != -1 && tabPane.isEnabledAt(index)) + tabPane.setSelectedIndex(index); + tabPane.revalidate(); + tabPane.repaint(); + } + } + + /** + * This class handles PropertyChangeEvents fired from the JTabbedPane. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * This method is called whenever one of the properties of the JTabbedPane + * changes. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals("tabLayoutPolicy")) + { + layoutManager = createLayoutManager(); + + tabPane.setLayout(layoutManager); + } + else if (e.getPropertyName().equals("tabPlacement") + && tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + { + incrButton = createIncreaseButton(); + decrButton = createDecreaseButton(); + } + tabPane.layout(); + tabPane.repaint(); + } + } + + /** + * A LayoutManager responsible for placing all the tabs and the visible + * component inside the JTabbedPane. This class is only used for + * WRAP_TAB_LAYOUT. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class TabbedPaneLayout implements LayoutManager + { + /** + * This method is called when a component is added to the JTabbedPane. + * + * @param name The name of the component. + * @param comp The component being added. + */ + public void addLayoutComponent(String name, Component comp) + { + // Do nothing. + } + + /** + * This method is called when the rectangles need to be calculated. It + * also fixes the size of the visible component. + */ + public void calculateLayoutInfo() + { + calculateTabRects(tabPane.getTabPlacement(), tabPane.getTabCount()); + + if (tabPane.getSelectedIndex() != -1) + { + Component visible = getVisibleComponent(); + Insets insets = getContentBorderInsets(tabPane.getTabPlacement()); + if (visible != null) + visible.setBounds(contentRect.x + insets.left, + contentRect.y + insets.top, + contentRect.width - insets.left - insets.right, + contentRect.height - insets.top - insets.bottom); + } + } + + /** + * This method calculates the size of the the JTabbedPane. + * + * @param minimum Whether the JTabbedPane will try to be as small as it + * can. + * + * @return The desired size of the JTabbedPane. + */ + protected Dimension calculateSize(boolean minimum) + { + int tabPlacement = tabPane.getTabPlacement(); + int width = 0; + int height = 0; + + int componentHeight = 0; + int componentWidth = 0; + Component c; + Dimension dims; + for (int i = 0; i < tabPane.getTabCount(); i++) + { + c = tabPane.getComponentAt(i); + if (c == null) + continue; + calcRect = c.getBounds(); + dims = c.getPreferredSize(); + if (dims != null) + { + componentHeight = Math.max(componentHeight, dims.height); + componentWidth = Math.max(componentWidth, dims.width); + } + } + Insets insets = tabPane.getInsets(); + + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + { + int min = calculateMaxTabWidth(tabPlacement); + width = Math.max(min, componentWidth); + + int tabAreaHeight = preferredTabAreaHeight(tabPlacement, width); + height = tabAreaHeight + componentHeight; + } + else + { + int min = calculateMaxTabHeight(tabPlacement); + height = Math.max(min, componentHeight); + + int tabAreaWidth = preferredTabAreaWidth(tabPlacement, height); + width = tabAreaWidth + componentWidth; + } + + return new Dimension(width, height); + } + + // if tab placement is LEFT OR RIGHT, they share width. + // if tab placement is TOP OR BOTTOM, they share height + // PRE STEP: finds the default sizes for the labels as well as their locations. + // AND where they will be placed within the run system. + // 1. calls normalizeTab Runs. + // 2. calls rotate tab runs. + // 3. pads the tab runs. + // 4. pads the selected tab. + + /** + * This method is called to calculate the tab rectangles. This method + * will calculate the size and position of all rectangles (taking into + * account which ones should be in which tab run). It will pad them and + * normalize them as necessary. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabCount The run the current selection is in. + */ + protected void calculateTabRects(int tabPlacement, int tabCount) + { + if (tabCount == 0) + return; + assureRectsCreated(tabCount); + + FontMetrics fm = getFontMetrics(); + SwingUtilities.calculateInnerArea(tabPane, calcRect); + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + Insets insets = tabPane.getInsets(); + int max = 0; + int runs = 0; + int start = getTabRunIndent(tabPlacement, 1); + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + { + int maxHeight = calculateMaxTabHeight(tabPlacement); + + calcRect.width -= tabAreaInsets.left + tabAreaInsets.right; + max = calcRect.width + tabAreaInsets.left + insets.left; + start += tabAreaInsets.left + insets.left; + int width = 0; + int runWidth = start; + + for (int i = 0; i < tabCount; i++) + { + width = calculateTabWidth(tabPlacement, i, fm); + + if (runWidth + width > max) + { + runWidth = tabAreaInsets.left + insets.left + + getTabRunIndent(tabPlacement, ++runs); + rects[i] = new Rectangle(runWidth, + insets.top + tabAreaInsets.top, + width, maxHeight); + runWidth += width; + if (runs > tabRuns.length - 1) + expandTabRunsArray(); + tabRuns[runs] = i; + } + else + { + rects[i] = new Rectangle(runWidth, + insets.top + tabAreaInsets.top, + width, maxHeight); + runWidth += width; + } + } + runs++; + tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right; + tabAreaRect.height = runs * maxTabHeight + - (runs - 1) * tabRunOverlay + + tabAreaInsets.top + tabAreaInsets.bottom; + contentRect.width = tabAreaRect.width; + contentRect.height = tabPane.getHeight() - insets.top + - insets.bottom - tabAreaRect.height; + contentRect.x = insets.left; + tabAreaRect.x = insets.left; + if (tabPlacement == SwingConstants.BOTTOM) + { + contentRect.y = insets.top; + tabAreaRect.y = contentRect.y + contentRect.height; + } + else + { + tabAreaRect.y = insets.top; + contentRect.y = tabAreaRect.y + tabAreaRect.height; + } + } + else + { + int maxWidth = calculateMaxTabWidth(tabPlacement); + calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom; + max = calcRect.height + tabAreaInsets.top + insets.top; + + int height = 0; + start += tabAreaInsets.top + insets.top; + int runHeight = start; + + int fontHeight = fm.getHeight(); + + for (int i = 0; i < tabCount; i++) + { + height = calculateTabHeight(tabPlacement, i, fontHeight); + if (runHeight + height > max) + { + runHeight = tabAreaInsets.top + insets.top + + getTabRunIndent(tabPlacement, ++runs); + rects[i] = new Rectangle(insets.left + tabAreaInsets.left, + runHeight, maxWidth, height); + runHeight += height; + if (runs > tabRuns.length - 1) + expandTabRunsArray(); + tabRuns[runs] = i; + } + else + { + rects[i] = new Rectangle(insets.left + tabAreaInsets.left, + runHeight, maxWidth, height); + runHeight += height; + } + } + runs++; + + tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay + + tabAreaInsets.left + tabAreaInsets.right; + tabAreaRect.height = tabPane.getHeight() - insets.top + - insets.bottom; + tabAreaRect.y = insets.top; + contentRect.width = tabPane.getWidth() - insets.left - insets.right + - tabAreaRect.width; + contentRect.height = tabAreaRect.height; + contentRect.y = insets.top; + if (tabPlacement == SwingConstants.LEFT) + { + tabAreaRect.x = insets.left; + contentRect.x = tabAreaRect.x + tabAreaRect.width; + } + else + { + contentRect.x = insets.left; + tabAreaRect.x = contentRect.x + contentRect.width; + } + } + runCount = runs; + + tabRuns[0] = 0; + normalizeTabRuns(tabPlacement, tabCount, start, max); + selectedRun = getRunForTab(tabCount, tabPane.getSelectedIndex()); + if (shouldRotateTabRuns(tabPlacement)) + rotateTabRuns(tabPlacement, selectedRun); + + // Need to pad the runs and move them to the correct location. + for (int i = 0; i < runCount; i++) + { + int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1; + if (first == tabCount) + first = 0; + int last = lastTabInRun(tabCount, i); + if (shouldPadTabRun(tabPlacement, i)) + padTabRun(tabPlacement, first, last, max); + + // Done padding, now need to move it. + if (tabPlacement == SwingConstants.TOP && i > 0) + { + for (int j = first; j <= last; j++) + rects[j].y += (runCount - i) * maxTabHeight + - (runCount - i) * tabRunOverlay; + } + + if (tabPlacement == SwingConstants.BOTTOM) + { + int height = tabPane.getBounds().height - insets.bottom + - tabAreaInsets.bottom; + int adjustment; + if (i == 0) + adjustment = height - maxTabHeight; + else + adjustment = height - (runCount - i + 1) * maxTabHeight + - (runCount - i) * tabRunOverlay; + + for (int j = first; j <= last; j++) + rects[j].y = adjustment; + } + + if (tabPlacement == SwingConstants.LEFT && i > 0) + { + for (int j = first; j <= last; j++) + rects[j].x += (runCount - i) * maxTabWidth + - (runCount - i) * tabRunOverlay; + } + + if (tabPlacement == SwingConstants.RIGHT) + { + int width = tabPane.getBounds().width - insets.right + - tabAreaInsets.right; + int adjustment; + if (i == 0) + adjustment = width - maxTabWidth; + else + adjustment = width - (runCount - i + 1) * maxTabWidth + + (runCount - i) * tabRunOverlay; + + for (int j = first; j <= last; j++) + rects[j].x = adjustment; + } + } + padSelectedTab(tabPlacement, tabPane.getSelectedIndex()); + } + + /** + * This method is called when the JTabbedPane is laid out in + * WRAP_TAB_LAYOUT. It calls calculateLayoutInfo to find the positions + * of all its components. + * + * @param parent The Container to lay out. + */ + public void layoutContainer(Container parent) + { + calculateLayoutInfo(); + } + + /** + * This method returns the minimum layout size for the given container. + * + * @param parent The container that is being sized. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container parent) + { + return calculateSize(false); + } + + // If there is more free space in an adjacent run AND the tab in the run can fit in the + // adjacent run, move it. This method is not perfect, it is merely an approximation. + // If you play around with Sun's JTabbedPane, you'll see that + // it does do some pretty strange things with regards to not moving tabs + // that should be moved. + // start = the x position where the tabs will begin + // max = the maximum position of where the tabs can go to (tabAreaInsets.left + the width of the tab area) + + /** + * This method tries to "even out" the number of tabs in each run based on + * their widths. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabCount The number of tabs. + * @param start The x position where the tabs will begin. + * @param max The maximum x position where the tab can run to. + */ + protected void normalizeTabRuns(int tabPlacement, int tabCount, int start, + int max) + { + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + if (tabPlacement == SwingUtilities.TOP + || tabPlacement == SwingUtilities.BOTTOM) + { + // We should only do this for runCount - 1, cause we can only shift that many times between + // runs. + for (int i = 1; i < runCount; i++) + { + Rectangle currRun = rects[lastTabInRun(tabCount, i)]; + Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))]; + int spaceInCurr = currRun.x + currRun.width; + int spaceInNext = nextRun.x + nextRun.width; + + int diffNow = spaceInCurr - spaceInNext; + int diffLater = (spaceInCurr - currRun.width) + - (spaceInNext + currRun.width); + while (Math.abs(diffLater) < Math.abs(diffNow) + && spaceInNext + currRun.width < max) + { + tabRuns[i]--; + spaceInNext += currRun.width; + spaceInCurr -= currRun.width; + currRun = rects[lastTabInRun(tabCount, i)]; + diffNow = spaceInCurr - spaceInNext; + diffLater = (spaceInCurr - currRun.width) + - (spaceInNext + currRun.width); + } + + // Fix the bounds. + int first = lastTabInRun(tabCount, i) + 1; + int last = lastTabInRun(tabCount, getNextTabRun(i)); + int currX = tabAreaInsets.left; + for (int j = first; j <= last; j++) + { + rects[j].x = currX; + currX += rects[j].width; + } + } + } + else + { + for (int i = 1; i < runCount; i++) + { + Rectangle currRun = rects[lastTabInRun(tabCount, i)]; + Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))]; + int spaceInCurr = currRun.y + currRun.height; + int spaceInNext = nextRun.y + nextRun.height; + + int diffNow = spaceInCurr - spaceInNext; + int diffLater = (spaceInCurr - currRun.height) + - (spaceInNext + currRun.height); + while (Math.abs(diffLater) < Math.abs(diffNow) + && spaceInNext + currRun.height < max) + { + tabRuns[i]--; + spaceInNext += currRun.height; + spaceInCurr -= currRun.height; + currRun = rects[lastTabInRun(tabCount, i)]; + diffNow = spaceInCurr - spaceInNext; + diffLater = (spaceInCurr - currRun.height) + - (spaceInNext + currRun.height); + } + + int first = lastTabInRun(tabCount, i) + 1; + int last = lastTabInRun(tabCount, getNextTabRun(i)); + int currY = tabAreaInsets.top; + for (int j = first; j <= last; j++) + { + rects[j].y = currY; + currY += rects[j].height; + } + } + } + } + + /** + * This method pads the tab at the selected index by the selected tab pad + * insets (so that it looks larger). + * + * @param tabPlacement The placement of the tabs. + * @param selectedIndex The selected index. + */ + protected void padSelectedTab(int tabPlacement, int selectedIndex) + { + Insets insets = getSelectedTabPadInsets(tabPlacement); + rects[selectedIndex].x -= insets.left; + rects[selectedIndex].y -= insets.top; + rects[selectedIndex].width += insets.left + insets.right; + rects[selectedIndex].height += insets.top + insets.bottom; + } + + // If the tabs on the run don't fill the width of the window, make it fit now. + // start = starting index of the run + // end = last index of the run + // max = tabAreaInsets.left + width (or equivalent) + // assert start <= end. + + /** + * This method makes each tab in the run larger so that the tabs expand + * to fill the runs width/height (depending on tabPlacement). + * + * @param tabPlacement The placement of the tabs. + * @param start The index of the first tab. + * @param end The last index of the tab + * @param max The amount of space in the run (width for TOP and BOTTOM + * tabPlacement). + */ + protected void padTabRun(int tabPlacement, int start, int end, int max) + { + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + { + int runWidth = rects[end].x + rects[end].width; + int spaceRemaining = max - runWidth; + int numTabs = end - start + 1; + + // now divvy up the space. + int spaceAllocated = spaceRemaining / numTabs; + int currX = rects[start].x; + for (int i = start; i <= end; i++) + { + rects[i].x = currX; + rects[i].width += spaceAllocated; + currX += rects[i].width; + // This is used because since the spaceAllocated + // variable is an int, it rounds down. Sometimes, + // we don't fill an entire row, so we make it do + // so now. + if (i == end && rects[i].x + rects[i].width != max) + rects[i].width = max - rects[i].x; + } + } + else + { + int runHeight = rects[end].y + rects[end].height; + int spaceRemaining = max - runHeight; + int numTabs = end - start + 1; + + int spaceAllocated = spaceRemaining / numTabs; + int currY = rects[start].y; + for (int i = start; i <= end; i++) + { + rects[i].y = currY; + rects[i].height += spaceAllocated; + currY += rects[i].height; + if (i == end && rects[i].y + rects[i].height != max) + rects[i].height = max - rects[i].y; + } + } + } + + /** + * This method returns the preferred layout size for the given container. + * + * @param parent The container to size. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container parent) + { + return calculateSize(false); + } + + /** + * This method returns the preferred tab height given a tabPlacement and + * width. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param width The expected width. + * + * @return The preferred tab area height. + */ + protected int preferredTabAreaHeight(int tabPlacement, int width) + { + if (tabPane.getTabCount() == 0) + return calculateTabAreaHeight(tabPlacement, 0, 0); + + int runs = 0; + int runWidth = 0; + int tabWidth = 0; + + FontMetrics fm = getFontMetrics(); + + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + Insets insets = tabPane.getInsets(); + + // Only interested in width, this is a messed up rectangle now. + width -= tabAreaInsets.left + tabAreaInsets.right + insets.left + + insets.right; + + // The reason why we can't use runCount: + // This method is only called to calculate the size request + // for the tabbedPane. However, this size request is dependent on + // our desired width. We need to find out what the height would + // be IF we got our desired width. + for (int i = 0; i < tabPane.getTabCount(); i++) + { + tabWidth = calculateTabWidth(tabPlacement, i, fm); + if (runWidth + tabWidth > width) + { + runWidth = tabWidth; + runs++; + } + else + runWidth += tabWidth; + } + runs++; + + int maxTabHeight = calculateMaxTabHeight(tabPlacement); + int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs, + maxTabHeight); + return tabAreaHeight; + } + + /** + * This method calculates the preferred tab area width given a tab + * placement and height. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param height The expected height. + * + * @return The preferred tab area width. + */ + protected int preferredTabAreaWidth(int tabPlacement, int height) + { + if (tabPane.getTabCount() == 0) + return calculateTabAreaHeight(tabPlacement, 0, 0); + + int runs = 0; + int runHeight = 0; + int tabHeight = 0; + + FontMetrics fm = getFontMetrics(); + + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + Insets insets = tabPane.getInsets(); + + height -= tabAreaInsets.top + tabAreaInsets.bottom + insets.top + + insets.bottom; + int fontHeight = fm.getHeight(); + + for (int i = 0; i < tabPane.getTabCount(); i++) + { + tabHeight = calculateTabHeight(tabPlacement, i, fontHeight); + if (runHeight + tabHeight > height) + { + runHeight = tabHeight; + runs++; + } + else + runHeight += tabHeight; + } + runs++; + + int maxTabWidth = calculateMaxTabWidth(tabPlacement); + int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth); + return tabAreaWidth; + } + + /** + * This method rotates the places each run in the correct place the + * tabRuns array. See the comment for tabRuns for how the runs are placed + * in the array. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedRun The run the current selection is in. + */ + protected void rotateTabRuns(int tabPlacement, int selectedRun) + { + if (runCount == 1 || selectedRun == 1 || selectedRun == -1) + return; + int[] newTabRuns = new int[tabRuns.length]; + int currentRun = selectedRun; + int i = 1; + do + { + newTabRuns[i] = tabRuns[currentRun]; + currentRun = getNextTabRun(currentRun); + i++; + } + while (i < runCount); + if (runCount > 1) + newTabRuns[0] = tabRuns[currentRun]; + + tabRuns = newTabRuns; + BasicTabbedPaneUI.this.selectedRun = 1; + } + + /** + * This method is called when a component is removed from the + * JTabbedPane. + * + * @param comp The component removed. + */ + public void removeLayoutComponent(Component comp) + { + // Do nothing. + } + } + + /** + * This class acts as the LayoutManager for the JTabbedPane in + * SCROLL_TAB_MODE. + */ + private class TabbedPaneScrollLayout extends TabbedPaneLayout + { + /** + * This method returns the preferred layout size for the given container. + * + * @param parent The container to calculate a size for. + * + * @return The preferred layout size. + */ + public Dimension preferredLayoutSize(Container parent) + { + return super.calculateSize(true); + } + + /** + * This method returns the minimum layout size for the given container. + * + * @param parent The container to calculate a size for. + * + * @return The minimum layout size. + */ + public Dimension minimumLayoutSize(Container parent) + { + return super.calculateSize(true); + } + + /** + * This method calculates the tab area height given a desired width. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param width The expected width. + * + * @return The tab area height given the width. + */ + protected int preferredTabAreaHeight(int tabPlacement, int width) + { + if (tabPane.getTabCount() == 0) + return calculateTabAreaHeight(tabPlacement, 0, 0); + + int runs = 1; + + int maxTabHeight = calculateMaxTabHeight(tabPlacement); + int tabAreaHeight = calculateTabAreaHeight(tabPlacement, runs, + maxTabHeight); + return tabAreaHeight; + } + + /** + * This method calculates the tab area width given a desired height. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param height The expected height. + * + * @return The tab area width given the height. + */ + protected int preferredTabAreaWidth(int tabPlacement, int height) + { + if (tabPane.getTabCount() == 0) + return calculateTabAreaHeight(tabPlacement, 0, 0); + + int runs = 1; + + int maxTabWidth = calculateMaxTabWidth(tabPlacement); + int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth); + return tabAreaWidth; + } + + /** + * This method is called to calculate the tab rectangles. This method + * will calculate the size and position of all rectangles (taking into + * account which ones should be in which tab run). It will pad them and + * normalize them as necessary. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabCount The number of tabs. + */ + protected void calculateTabRects(int tabPlacement, int tabCount) + { + if (tabCount == 0) + return; + assureRectsCreated(tabCount); + + FontMetrics fm = getFontMetrics(); + SwingUtilities.calculateInnerArea(tabPane, calcRect); + Insets tabAreaInsets = getTabAreaInsets(tabPlacement); + Insets insets = tabPane.getInsets(); + int max = 0; + int runs = 1; + int start = 0; + int top = 0; + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + { + int maxHeight = calculateMaxTabHeight(tabPlacement); + calcRect.width -= tabAreaInsets.left + tabAreaInsets.right; + max = calcRect.width + tabAreaInsets.left + insets.left; + start = tabAreaInsets.left + insets.left; + int width = 0; + int runWidth = start; + top = insets.top + tabAreaInsets.top; + for (int i = 0; i < tabCount; i++) + { + width = calculateTabWidth(tabPlacement, i, fm); + + rects[i] = new Rectangle(runWidth, top, width, maxHeight); + runWidth += width; + } + tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right; + tabAreaRect.height = runs * maxTabHeight + - (runs - 1) * tabRunOverlay + + tabAreaInsets.top + tabAreaInsets.bottom; + contentRect.width = tabAreaRect.width; + contentRect.height = tabPane.getHeight() - insets.top + - insets.bottom - tabAreaRect.height; + contentRect.x = insets.left; + tabAreaRect.x = insets.left; + if (tabPlacement == SwingConstants.BOTTOM) + { + contentRect.y = insets.top; + tabAreaRect.y = contentRect.y + contentRect.height; + } + else + { + tabAreaRect.y = insets.top; + contentRect.y = tabAreaRect.y + tabAreaRect.height; + } + } + else + { + int maxWidth = calculateMaxTabWidth(tabPlacement); + + calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom; + max = calcRect.height + tabAreaInsets.top; + int height = 0; + start = tabAreaInsets.top + insets.top; + int runHeight = start; + int fontHeight = fm.getHeight(); + top = insets.left + tabAreaInsets.left; + for (int i = 0; i < tabCount; i++) + { + height = calculateTabHeight(tabPlacement, i, fontHeight); + rects[i] = new Rectangle(top, runHeight, maxWidth, height); + runHeight += height; + } + tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay + + tabAreaInsets.left + tabAreaInsets.right; + tabAreaRect.height = tabPane.getHeight() - insets.top + - insets.bottom; + tabAreaRect.y = insets.top; + contentRect.width = tabPane.getWidth() - insets.left - insets.right + - tabAreaRect.width; + contentRect.height = tabAreaRect.height; + contentRect.y = insets.top; + if (tabPlacement == SwingConstants.LEFT) + { + tabAreaRect.x = insets.left; + contentRect.x = tabAreaRect.x + tabAreaRect.width; + } + else + { + contentRect.x = insets.left; + tabAreaRect.x = contentRect.x + contentRect.width; + } + } + runCount = runs; + + padSelectedTab(tabPlacement, tabPane.getSelectedIndex()); + } + + /** + * This method is called when the JTabbedPane is laid out in + * SCROLL_TAB_LAYOUT. It finds the position for all components in the + * JTabbedPane. + * + * @param pane The JTabbedPane to be laid out. + */ + public void layoutContainer(Container pane) + { + super.layoutContainer(pane); + int tabCount = tabPane.getTabCount(); + Point p = null; + if (tabCount == 0) + return; + int tabPlacement = tabPane.getTabPlacement(); + incrButton.hide(); + decrButton.hide(); + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + { + if (tabAreaRect.x + tabAreaRect.width < rects[tabCount - 1].x + + rects[tabCount - 1].width) + { + Dimension incrDims = incrButton.getPreferredSize(); + Dimension decrDims = decrButton.getPreferredSize(); + + decrButton.setBounds(tabAreaRect.x + tabAreaRect.width + - incrDims.width - decrDims.width, + tabAreaRect.y, decrDims.width, + tabAreaRect.height); + incrButton.setBounds(tabAreaRect.x + tabAreaRect.width + - incrDims.width, tabAreaRect.y, + decrDims.width, tabAreaRect.height); + + tabAreaRect.width -= decrDims.width + incrDims.width; + incrButton.show(); + decrButton.show(); + } + } + + if (tabPlacement == SwingConstants.LEFT + || tabPlacement == SwingConstants.RIGHT) + { + if (tabAreaRect.y + tabAreaRect.height < rects[tabCount - 1].y + + rects[tabCount - 1].height) + { + Dimension incrDims = incrButton.getPreferredSize(); + Dimension decrDims = decrButton.getPreferredSize(); + + decrButton.setBounds(tabAreaRect.x, + tabAreaRect.y + tabAreaRect.height + - incrDims.height - decrDims.height, + tabAreaRect.width, decrDims.height); + incrButton.setBounds(tabAreaRect.x, + tabAreaRect.y + tabAreaRect.height + - incrDims.height, tabAreaRect.width, + incrDims.height); + + tabAreaRect.height -= decrDims.height + incrDims.height; + incrButton.show(); + decrButton.show(); + } + } + viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width, + tabAreaRect.height); + int tabC = tabPane.getTabCount() - 1; + if (tabCount > 0) + { + int w = Math.max(rects[tabC].width + rects[tabC].x, tabAreaRect.width); + int h = Math.max(rects[tabC].height, tabAreaRect.height); + p = findPointForIndex(currentScrollLocation); + + // we want to cover that entire space so that borders that run under + // the tab area don't show up when we move the viewport around. + panel.setSize(w + p.x, h + p.y); + } + viewport.setViewPosition(p); + viewport.repaint(); + } + } + + /** + * This class handles ChangeEvents from the JTabbedPane. + * + * @specnote Apparently this class was intended to be protected, + * but was made public by a compiler bug and is now + * public for compatibility. + */ + public class TabSelectionHandler implements ChangeListener + { + /** + * This method is called whenever a ChangeEvent is fired from the + * JTabbedPane. + * + * @param e The ChangeEvent fired. + */ + public void stateChanged(ChangeEvent e) + { + selectedRun = getRunForTab(tabPane.getTabCount(), + tabPane.getSelectedIndex()); + tabPane.revalidate(); + tabPane.repaint(); + } + } + + /** + * This helper class is a JPanel that fits inside the ScrollViewport. This + * panel's sole job is to paint the tab rectangles inside the viewport so + * that it's clipped correctly. + */ + private class ScrollingPanel extends JPanel + { + /** + * This is a private UI class for our panel. + */ + private class ScrollingPanelUI extends BasicPanelUI + { + /** + * This method overrides the default paint method. It paints the tab + * rectangles for the JTabbedPane in the panel. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex()); + } + } + + /** + * This method overrides the updateUI method. It makes the default UI for + * this ScrollingPanel to be a ScrollingPanelUI. + */ + public void updateUI() + { + setUI((PanelUI) new ScrollingPanelUI()); + } + } + + /** + * This is a helper class that paints the panel that paints tabs. This + * custom JViewport is used so that the tabs painted in the panel will be + * clipped. This class implements UIResource so tabs are not added when + * this objects of this class are added to the JTabbedPane. + */ + private class ScrollingViewport extends JViewport implements UIResource + { + } + + /** + * This is a helper class that implements UIResource so it is not added as a + * tab when an object of this class is added to the JTabbedPane. + */ + private class ScrollingButton extends BasicArrowButton implements UIResource + { + /** + * Creates a ScrollingButton given the direction. + * + * @param dir The direction to point in. + */ + public ScrollingButton(int dir) + { + super(dir); + } + } + + /** The button that increments the current scroll location. + * This is package-private to avoid an accessor method. */ + transient ScrollingButton incrButton; + + /** The button that decrements the current scroll location. + * This is package-private to avoid an accessor method. */ + transient ScrollingButton decrButton; + + /** The viewport used to display the tabs. + * This is package-private to avoid an accessor method. */ + transient ScrollingViewport viewport; + + /** The panel inside the viewport that paints the tabs. + * This is package-private to avoid an accessor method. */ + transient ScrollingPanel panel; + + /** The starting visible tab in the run in SCROLL_TAB_MODE. + * This is package-private to avoid an accessor method. */ + transient int currentScrollLocation; + + /** A reusable rectangle. */ + protected Rectangle calcRect; + + /** An array of Rectangles keeping track of the tabs' area and position. */ + protected Rectangle[] rects; + + /** The insets around the content area. */ + protected Insets contentBorderInsets; + + /** The extra insets around the selected tab. */ + protected Insets selectedTabPadInsets; + + /** The insets around the tab area. */ + protected Insets tabAreaInsets; + + /** The insets around each and every tab. */ + protected Insets tabInsets; + + /** + * The outer bottom and right edge color for both the tab and content + * border. + */ + protected Color darkShadow; + + /** The color of the focus outline on the selected tab. */ + protected Color focus; + + /** FIXME: find a use for this. */ + protected Color highlight; + + /** The top and left edge color for both the tab and content border. */ + protected Color lightHighlight; + + /** The inner bottom and right edge color for the tab and content border. */ + protected Color shadow; + + /** The maximum tab height. */ + protected int maxTabHeight; + + /** The maximum tab width. */ + protected int maxTabWidth; + + /** The number of runs in the JTabbedPane. */ + protected int runCount; + + /** The index of the run that the selected index is in. */ + protected int selectedRun; + + /** The amount of space each run overlaps the previous by. */ + protected int tabRunOverlay; + + /** The gap between text and label */ + protected int textIconGap; + + // Keeps track of tab runs. + // The organization of this array is as follows (lots of experimentation to + // figure this out) + // index 0 = furthest away from the component area (aka outer run) + // index 1 = closest to component area (aka selected run) + // index > 1 = listed in order leading from selected run to outer run. + // each int in the array is the tab index + 1 (counting starts at 1) + // for the last tab in the run. (same as the rects array) + + /** This array keeps track of which tabs are in which run. See above. */ + protected int[] tabRuns; + + /** + * This is the keystroke for moving down. + * + * @deprecated 1.3 + */ + protected KeyStroke downKey; + + /** + * This is the keystroke for moving left. + * + * @deprecated 1.3 + */ + protected KeyStroke leftKey; + + /** + * This is the keystroke for moving right. + * + * @deprecated 1.3 + */ + protected KeyStroke rightKey; + + /** + * This is the keystroke for moving up. + * + * @deprecated 1.3 + */ + protected KeyStroke upKey; + + /** The listener that listens for focus events. */ + protected FocusListener focusListener; + + /** The listener that listens for mouse events. */ + protected MouseListener mouseListener; + + /** The listener that listens for property change events. */ + protected PropertyChangeListener propertyChangeListener; + + /** The listener that listens for change events. */ + protected ChangeListener tabChangeListener; + + /** The tab pane that this UI paints. */ + protected JTabbedPane tabPane; + + /** The current layout manager for the tabPane. + * This is package-private to avoid an accessor method. */ + transient LayoutManager layoutManager; + + /** The rectangle that describes the tab area's position and size. + * This is package-private to avoid an accessor method. */ + transient Rectangle tabAreaRect; + + /** The rectangle that describes the content area's position and + * size. This is package-private to avoid an accessor method. */ + transient Rectangle contentRect; + + /** + * Creates a new BasicTabbedPaneUI object. + */ + public BasicTabbedPaneUI() + { + super(); + } + + /** + * This method creates a ScrollingButton that points in the appropriate + * direction for an increasing button. + * This is package-private to avoid an accessor method. + * + * @return The increase ScrollingButton. + */ + ScrollingButton createIncreaseButton() + { + if (incrButton == null) + incrButton = new ScrollingButton(SwingConstants.NORTH); + if (tabPane.getTabPlacement() == SwingConstants.TOP + || tabPane.getTabPlacement() == SwingConstants.BOTTOM) + incrButton.setDirection(SwingConstants.EAST); + else + incrButton.setDirection(SwingConstants.SOUTH); + return incrButton; + } + + /** + * This method creates a ScrollingButton that points in the appropriate + * direction for a decreasing button. + * This is package-private to avoid an accessor method. + * + * @return The decrease ScrollingButton. + */ + ScrollingButton createDecreaseButton() + { + if (decrButton == null) + decrButton = new ScrollingButton(SwingConstants.SOUTH); + if (tabPane.getTabPlacement() == SwingConstants.TOP + || tabPane.getTabPlacement() == SwingConstants.BOTTOM) + decrButton.setDirection(SwingConstants.WEST); + else + decrButton.setDirection(SwingConstants.NORTH); + return decrButton; + } + + /** + * This method finds the point to set the view position at given the index + * of a tab. The tab will be the first visible tab in the run. + * This is package-private to avoid an accessor method. + * + * @param index The index of the first visible tab. + * + * @return The position of the first visible tab. + */ + Point findPointForIndex(int index) + { + int tabPlacement = tabPane.getTabPlacement(); + int selectedIndex = tabPane.getSelectedIndex(); + Insets insets = getSelectedTabPadInsets(tabPlacement); + int w = 0; + int h = 0; + + if (tabPlacement == TOP || tabPlacement == BOTTOM) + { + if (index > 0) + { + w += rects[index - 1].x + rects[index - 1].width; + if (index > selectedIndex) + w -= insets.left + insets.right; + } + } + + else + { + if (index > 0) + { + h += rects[index - 1].y + rects[index - 1].height; + if (index > selectedIndex) + h -= insets.top + insets.bottom; + } + } + + Point p = new Point(w, h); + return p; + } + + /** + * This method creates a new BasicTabbedPaneUI. + * + * @param c The JComponent to create a UI for. + * + * @return A new BasicTabbedPaneUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicTabbedPaneUI(); + } + + /** + * This method installs the UI for the given JComponent. + * + * @param c The JComponent to install the UI for. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JTabbedPane) + { + tabPane = (JTabbedPane) c; + + installComponents(); + installDefaults(); + installListeners(); + installKeyboardActions(); + + layoutManager = createLayoutManager(); + tabPane.setLayout(layoutManager); + tabPane.layout(); + } + } + + /** + * This method uninstalls the UI for the given JComponent. + * + * @param c The JComponent to uninstall the UI for. + */ + public void uninstallUI(JComponent c) + { + layoutManager = null; + + uninstallKeyboardActions(); + uninstallListeners(); + uninstallDefaults(); + uninstallComponents(); + + tabPane = null; + } + + /** + * This method creates the appropriate layout manager for the JTabbedPane's + * current tab layout policy. If the tab layout policy is + * SCROLL_TAB_LAYOUT, then all the associated components that need to be + * created will be done so now. + * + * @return A layout manager given the tab layout policy. + */ + protected LayoutManager createLayoutManager() + { + if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) + return new TabbedPaneLayout(); + else + { + incrButton = createIncreaseButton(); + decrButton = createDecreaseButton(); + viewport = new ScrollingViewport(); + viewport.setLayout(null); + panel = new ScrollingPanel(); + viewport.setView(panel); + tabPane.add(incrButton); + tabPane.add(decrButton); + tabPane.add(viewport); + currentScrollLocation = 0; + decrButton.setEnabled(false); + panel.addMouseListener(mouseListener); + incrButton.addMouseListener(mouseListener); + decrButton.addMouseListener(mouseListener); + viewport.setBackground(Color.LIGHT_GRAY); + + return new TabbedPaneScrollLayout(); + } + } + + /** + * This method installs components for this JTabbedPane. + */ + protected void installComponents() + { + // Nothing to be done. + } + + /** + * This method uninstalls components for this JTabbedPane. + */ + protected void uninstallComponents() + { + // Nothing to be done. + } + + /** + * This method installs defaults for the Look and Feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + tabPane.setFont(defaults.getFont("TabbedPane.font")); + tabPane.setForeground(defaults.getColor("TabbedPane.foreground")); + tabPane.setBackground(defaults.getColor("TabbedPane.background")); + tabPane.setOpaque(false); + + highlight = defaults.getColor("TabbedPane.highlight"); + lightHighlight = defaults.getColor("TabbedPane.lightHighlight"); + + shadow = defaults.getColor("TabbedPane.shadow"); + darkShadow = defaults.getColor("TabbedPane.darkShadow"); + + focus = defaults.getColor("TabbedPane.focus"); + + textIconGap = defaults.getInt("TabbedPane.textIconGap"); + tabRunOverlay = defaults.getInt("TabbedPane.tabRunOverlay"); + + tabInsets = defaults.getInsets("TabbedPane.tabbedPaneTabInsets"); + selectedTabPadInsets = defaults.getInsets("TabbedPane.tabbedPaneTabPadInsets"); + tabAreaInsets = defaults.getInsets("TabbedPane.tabbedPaneTabAreaInsets"); + contentBorderInsets = defaults.getInsets("TabbedPane.tabbedPaneContentBorderInsets"); + + calcRect = new Rectangle(); + tabRuns = new int[10]; + tabAreaRect = new Rectangle(); + contentRect = new Rectangle(); + } + + /** + * This method uninstalls defaults for the Look and Feel. + */ + protected void uninstallDefaults() + { + calcRect = null; + tabAreaRect = null; + contentRect = null; + tabRuns = null; + + contentBorderInsets = null; + tabAreaInsets = null; + selectedTabPadInsets = null; + tabInsets = null; + + focus = null; + darkShadow = null; + shadow = null; + lightHighlight = null; + highlight = null; + + tabPane.setBackground(null); + tabPane.setForeground(null); + tabPane.setFont(null); + } + + /** + * This method creates and installs the listeners for this UI. + */ + protected void installListeners() + { + mouseListener = createMouseListener(); + tabChangeListener = createChangeListener(); + propertyChangeListener = createPropertyChangeListener(); + focusListener = createFocusListener(); + + tabPane.addMouseListener(mouseListener); + tabPane.addChangeListener(tabChangeListener); + tabPane.addPropertyChangeListener(propertyChangeListener); + tabPane.addFocusListener(focusListener); + } + + /** + * This method removes and nulls the listeners for this UI. + */ + protected void uninstallListeners() + { + tabPane.removeFocusListener(focusListener); + tabPane.removePropertyChangeListener(propertyChangeListener); + tabPane.removeChangeListener(tabChangeListener); + tabPane.removeMouseListener(mouseListener); + + focusListener = null; + propertyChangeListener = null; + tabChangeListener = null; + mouseListener = null; + } + + /** + * This method creates a new MouseListener. + * + * @return A new MouseListener. + */ + protected MouseListener createMouseListener() + { + return new MouseHandler(); + } + + /** + * This method creates a new FocusListener. + * + * @return A new FocusListener. + */ + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + + /** + * This method creates a new ChangeListener. + * + * @return A new ChangeListener. + */ + protected ChangeListener createChangeListener() + { + return new TabSelectionHandler(); + } + + /** + * This method creates a new PropertyChangeListener. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * This method installs keyboard actions for the JTabbedPane. + */ + protected void installKeyboardActions() + { + // FIXME: Implement. + } + + /** + * This method uninstalls keyboard actions for the JTabbedPane. + */ + protected void uninstallKeyboardActions() + { + // FIXME: Implement. + } + + /** + * This method returns the preferred size of the JTabbedPane. + * + * @param c The JComponent to find a size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + return layoutManager.preferredLayoutSize(tabPane); + } + + /** + * This method returns the minimum size of the JTabbedPane. + * + * @param c The JComponent to find a size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return layoutManager.minimumLayoutSize(tabPane); + } + + /** + * This method returns the maximum size of the JTabbedPane. + * + * @param c The JComponent to find a size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); + } + + /** + * This method paints the JTabbedPane. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + if (tabPane.getTabCount() == 0) + return; + if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT) + paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex()); + paintContentBorder(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex()); + } + + /** + * This method paints the tab area. This includes painting the rectangles + * that make up the tabs. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedIndex The selected index. + */ + protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) + { + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + + boolean isScroll = tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT; + + // Please note: the ordering of the painting is important. + // we WANT to paint the outermost run first and then work our way in. + int tabCount = tabPane.getTabCount(); + int currRun = 1; + if (tabCount < 1) + return; + + if (runCount > 1) + currRun = 0; + for (int i = 0; i < runCount; i++) + { + int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1; + if (isScroll) + first = currentScrollLocation; + else if (first == tabCount) + first = 0; + int last = lastTabInRun(tabCount, currRun); + if (isScroll) + { + for (int k = first; k < tabCount; k++) + { + if (rects[k].x + rects[k].width - rects[first].x > viewport + .getWidth()) + { + last = k; + break; + } + } + } + + for (int j = first; j <= last; j++) + { + if (j != selectedIndex || isScroll) + paintTab(g, tabPlacement, rects, j, ir, tr); + } + currRun = getPreviousTabRun(currRun); + } + if (! isScroll) + paintTab(g, tabPlacement, rects, selectedIndex, ir, tr); + } + + /** + * This method paints an individual tab. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param rects The array of rectangles that keep the size and position of + * the tabs. + * @param tabIndex The tab index to paint. + * @param iconRect The rectangle to use for the icon. + * @param textRect The rectangle to use for the text. + */ + protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects, + int tabIndex, Rectangle iconRect, Rectangle textRect) + { + FontMetrics fm = getFontMetrics(); + Icon icon = getIconForTab(tabIndex); + String title = tabPane.getTitleAt(tabIndex); + boolean isSelected = tabIndex == tabPane.getSelectedIndex(); + calcRect = getTabBounds(tabPane, tabIndex); + + int x = calcRect.x; + int y = calcRect.y; + int w = calcRect.width; + int h = calcRect.height; + if (getRunForTab(tabPane.getTabCount(), tabIndex) == 1) + { + Insets insets = getTabAreaInsets(tabPlacement); + switch (tabPlacement) + { + case TOP: + h += insets.bottom; + break; + case LEFT: + w += insets.right; + break; + case BOTTOM: + y -= insets.top; + h += insets.top; + break; + case RIGHT: + x -= insets.left; + w += insets.left; + break; + } + } + + layoutLabel(tabPlacement, fm, tabIndex, title, icon, calcRect, iconRect, + textRect, isSelected); + paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected); + paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected); + + // FIXME: Paint little folding corner and jagged edge clipped tab. + if (icon != null) + paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected); + if (title != null && ! title.equals("")) + paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title, + textRect, isSelected); + } + + /** + * This method lays out the tab and finds the location to paint the icon + * and text. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param metrics The font metrics for the font to paint with. + * @param tabIndex The tab index to paint. + * @param title The string painted. + * @param icon The icon painted. + * @param tabRect The tab bounds. + * @param iconRect The calculated icon bounds. + * @param textRect The calculated text bounds. + * @param isSelected Whether this tab is selected. + */ + protected void layoutLabel(int tabPlacement, FontMetrics metrics, + int tabIndex, String title, Icon icon, + Rectangle tabRect, Rectangle iconRect, + Rectangle textRect, boolean isSelected) + { + SwingUtilities.layoutCompoundLabel(metrics, title, icon, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, tabRect, + iconRect, textRect, textIconGap); + + int shiftX = getTabLabelShiftX(tabPlacement, tabIndex, isSelected); + int shiftY = getTabLabelShiftY(tabPlacement, tabIndex, isSelected); + + iconRect.x += shiftX; + iconRect.y += shiftY; + + textRect.x += shiftX; + textRect.y += shiftY; + } + + /** + * This method paints the icon. + * + * @param g The Graphics object to paint. + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index to paint. + * @param icon The icon to paint. + * @param iconRect The bounds of the icon. + * @param isSelected Whether this tab is selected. + */ + protected void paintIcon(Graphics g, int tabPlacement, int tabIndex, + Icon icon, Rectangle iconRect, boolean isSelected) + { + icon.paintIcon(tabPane, g, iconRect.x, iconRect.y); + } + + /** + * This method paints the text for the given tab. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param font The font to paint with. + * @param metrics The fontmetrics of the given font. + * @param tabIndex The tab index. + * @param title The string to paint. + * @param textRect The bounds of the string. + * @param isSelected Whether this tab is selected. + */ + protected void paintText(Graphics g, int tabPlacement, Font font, + FontMetrics metrics, int tabIndex, String title, + Rectangle textRect, boolean isSelected) + { + View textView = getTextViewForTab(tabIndex); + if (textView != null) + { + textView.paint(g, textRect); + return; + } + + Color fg = tabPane.getForegroundAt(tabIndex); + if (fg == null) + fg = tabPane.getForeground(); + Color bg = tabPane.getBackgroundAt(tabIndex); + if (bg == null) + bg = tabPane.getBackground(); + + Color saved_color = g.getColor(); + Font f = g.getFont(); + g.setFont(font); + + if (tabPane.isEnabledAt(tabIndex)) + { + g.setColor(fg); + + int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); + + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, + textRect.x, + textRect.y + + metrics.getAscent()); + else + g.drawString(title, textRect.x, textRect.y + metrics.getAscent()); + } + else + { + g.setColor(bg.brighter()); + + int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex); + + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, + textRect.x, textRect.y); + else + g.drawString(title, textRect.x, textRect.y); + + g.setColor(bg.darker()); + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex, + textRect.x + 1, + textRect.y + 1); + else + g.drawString(title, textRect.x + 1, textRect.y + 1); + } + + g.setColor(saved_color); + g.setFont(f); + } + + /** + * This method returns how much the label for the tab should shift in the X + * direction. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index being painted. + * @param isSelected Whether this tab is selected. + * + * @return The amount the label should shift by in the X direction. + */ + protected int getTabLabelShiftX(int tabPlacement, int tabIndex, + boolean isSelected) + { + // No reason to shift. + return 0; + } + + /** + * This method returns how much the label for the tab should shift in the Y + * direction. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index being painted. + * @param isSelected Whether this tab is selected. + * + * @return The amount the label should shift by in the Y direction. + */ + protected int getTabLabelShiftY(int tabPlacement, int tabIndex, + boolean isSelected) + { + // No reason to shift. + return 0; + } + + /** + * This method paints the focus rectangle around the selected tab. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param rects The array of rectangles keeping track of size and position. + * @param tabIndex The tab index. + * @param iconRect The icon bounds. + * @param textRect The text bounds. + * @param isSelected Whether this tab is selected. + */ + protected void paintFocusIndicator(Graphics g, int tabPlacement, + Rectangle[] rects, int tabIndex, + Rectangle iconRect, Rectangle textRect, + boolean isSelected) + { + Color saved = g.getColor(); + calcRect = iconRect.union(textRect); + + g.setColor(focus); + + g.drawRect(calcRect.x, calcRect.y, calcRect.width, calcRect.height); + + g.setColor(saved); + } + + /** + * This method paints the border for an individual tab. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index. + * @param x The x position of the tab. + * @param y The y position of the tab. + * @param w The width of the tab. + * @param h The height of the tab. + * @param isSelected Whether the tab is selected. + */ + protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex, + int x, int y, int w, int h, boolean isSelected) + { + Color saved = g.getColor(); + + if (! isSelected || tabPlacement != SwingConstants.TOP) + { + g.setColor(shadow); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + g.setColor(darkShadow); + g.drawLine(x, y + h, x + w, y + h); + } + + if (! isSelected || tabPlacement != SwingConstants.LEFT) + { + g.setColor(darkShadow); + g.drawLine(x + w, y, x + w, y + h); + g.setColor(shadow); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + } + + if (! isSelected || tabPlacement != SwingConstants.RIGHT) + { + g.setColor(lightHighlight); + g.drawLine(x, y, x, y + h); + } + + if (! isSelected || tabPlacement != SwingConstants.BOTTOM) + { + g.setColor(lightHighlight); + g.drawLine(x, y, x + w, y); + } + + g.setColor(saved); + } + + /** + * This method paints the background for an individual tab. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index. + * @param x The x position of the tab. + * @param y The y position of the tab. + * @param w The width of the tab. + * @param h The height of the tab. + * @param isSelected Whether the tab is selected. + */ + protected void paintTabBackground(Graphics g, int tabPlacement, + int tabIndex, int x, int y, int w, int h, + boolean isSelected) + { + Color saved = g.getColor(); + if (isSelected) + g.setColor(Color.LIGHT_GRAY); + else + { + Color bg = tabPane.getBackgroundAt(tabIndex); + if (bg == null) + bg = Color.GRAY; + g.setColor(bg); + } + + g.fillRect(x, y, w, h); + + g.setColor(saved); + } + + /** + * This method paints the border around the content area. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedIndex The index of the selected tab. + */ + protected void paintContentBorder(Graphics g, int tabPlacement, + int selectedIndex) + { + Insets insets = getContentBorderInsets(tabPlacement); + int x = contentRect.x; + int y = contentRect.y; + int w = contentRect.width; + int h = contentRect.height; + paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h); + paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h); + paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h); + paintContentBorderRightEdge(g, tabPlacement, selectedIndex, x, y, w, h); + } + + /** + * This method paints the top edge of the content border. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedIndex The selected tab index. + * @param x The x coordinate for the content area. + * @param y The y coordinate for the content area. + * @param w The width of the content area. + * @param h The height of the content area. + */ + protected void paintContentBorderTopEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + Color saved = g.getColor(); + g.setColor(lightHighlight); + + int startgap = rects[selectedIndex].x; + int endgap = rects[selectedIndex].x + rects[selectedIndex].width; + + int diff = 0; + + if (tabPlacement == SwingConstants.TOP) + { + if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + { + Point p = findPointForIndex(currentScrollLocation); + diff = p.x; + } + + g.drawLine(x, y, startgap - diff, y); + g.drawLine(endgap - diff, y, x + w, y); + } + else + g.drawLine(x, y, x + w, y); + + g.setColor(saved); + } + + /** + * This method paints the left edge of the content border. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedIndex The selected tab index. + * @param x The x coordinate for the content area. + * @param y The y coordinate for the content area. + * @param w The width of the content area. + * @param h The height of the content area. + */ + protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + Color saved = g.getColor(); + g.setColor(lightHighlight); + + int startgap = rects[selectedIndex].y; + int endgap = rects[selectedIndex].y + rects[selectedIndex].height; + + int diff = 0; + + if (tabPlacement == SwingConstants.LEFT) + { + if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + { + Point p = findPointForIndex(currentScrollLocation); + diff = p.y; + } + + g.drawLine(x, y, x, startgap - diff); + g.drawLine(x, endgap - diff, x, y + h); + } + else + g.drawLine(x, y, x, y + h); + + g.setColor(saved); + } + + /** + * This method paints the bottom edge of the content border. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedIndex The selected tab index. + * @param x The x coordinate for the content area. + * @param y The y coordinate for the content area. + * @param w The width of the content area. + * @param h The height of the content area. + */ + protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + Color saved = g.getColor(); + + int startgap = rects[selectedIndex].x; + int endgap = rects[selectedIndex].x + rects[selectedIndex].width; + + int diff = 0; + + if (tabPlacement == SwingConstants.BOTTOM) + { + if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + { + Point p = findPointForIndex(currentScrollLocation); + diff = p.x; + } + + g.setColor(shadow); + g.drawLine(x + 1, y + h - 1, startgap - diff, y + h - 1); + g.drawLine(endgap - diff, y + h - 1, x + w - 1, y + h - 1); + + g.setColor(darkShadow); + g.drawLine(x, y + h, startgap - diff, y + h); + g.drawLine(endgap - diff, y + h, x + w, y + h); + } + else + { + g.setColor(shadow); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + g.setColor(darkShadow); + g.drawLine(x, y + h, x + w, y + h); + } + + g.setColor(saved); + } + + /** + * This method paints the right edge of the content border. + * + * @param g The Graphics object to paint with. + * @param tabPlacement The JTabbedPane's tab placement. + * @param selectedIndex The selected tab index. + * @param x The x coordinate for the content area. + * @param y The y coordinate for the content area. + * @param w The width of the content area. + * @param h The height of the content area. + */ + protected void paintContentBorderRightEdge(Graphics g, int tabPlacement, + int selectedIndex, int x, int y, + int w, int h) + { + Color saved = g.getColor(); + int startgap = rects[selectedIndex].y; + int endgap = rects[selectedIndex].y + rects[selectedIndex].height; + + int diff = 0; + + if (tabPlacement == SwingConstants.RIGHT) + { + if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT) + { + Point p = findPointForIndex(currentScrollLocation); + diff = p.y; + } + + g.setColor(shadow); + g.drawLine(x + w - 1, y + 1, x + w - 1, startgap - diff); + g.drawLine(x + w - 1, endgap - diff, x + w - 1, y + h - 1); + + g.setColor(darkShadow); + g.drawLine(x + w, y, x + w, startgap - diff); + g.drawLine(x + w, endgap - diff, x + w, y + h); + } + else + { + g.setColor(shadow); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + g.setColor(darkShadow); + g.drawLine(x + w, y, x + w, y + h); + } + + g.setColor(saved); + } + + /** + * This method returns the tab bounds for the given index. + * + * @param pane The JTabbedPane. + * @param i The index to look for. + * + * @return The bounds of the tab with the given index. + */ + public Rectangle getTabBounds(JTabbedPane pane, int i) + { + return rects[i]; + } + + /** + * This method returns the number of runs. + * + * @param pane The JTabbedPane. + * + * @return The number of runs. + */ + public int getTabRunCount(JTabbedPane pane) + { + return runCount; + } + + /** + * This method returns the tab index given a coordinate. + * + * @param pane The JTabbedPane. + * @param x The x coordinate. + * @param y The y coordinate. + * + * @return The tab index that the coordinate lands in. + */ + public int tabForCoordinate(JTabbedPane pane, int x, int y) + { + Point p = new Point(x, y); + int tabCount = tabPane.getTabCount(); + int currRun = 1; + for (int i = 0; i < runCount; i++) + { + int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1; + if (first == tabCount) + first = 0; + int last = lastTabInRun(tabCount, currRun); + for (int j = first; j <= last; j++) + { + if (getTabBounds(pane, j).contains(p)) + return j; + } + currRun = getNextTabRun(currRun); + } + return -1; + } + + /** + * This method returns the tab bounds in the given rectangle. + * + * @param tabIndex The index to get bounds for. + * @param dest The rectangle to store bounds in. + * + * @return The rectangle passed in. + */ + protected Rectangle getTabBounds(int tabIndex, Rectangle dest) + { + dest.setBounds(getTabBounds(tabPane, tabIndex)); + return dest; + } + + /** + * This method returns the component that is shown in the content area. + * + * @return The component that is shown in the content area. + */ + protected Component getVisibleComponent() + { + return tabPane.getComponentAt(tabPane.getSelectedIndex()); + } + + /** + * This method sets the visible component. + * + * @param component The component to be set visible. + */ + protected void setVisibleComponent(Component component) + { + component.setVisible(true); + tabPane.setSelectedComponent(component); + } + + /** + * This method assures that enough rectangles are created given the + * tabCount. The old array is copied to the new one. + * + * @param tabCount The number of tabs. + */ + protected void assureRectsCreated(int tabCount) + { + if (rects == null) + rects = new Rectangle[tabCount]; + if (tabCount == rects.length) + return; + else + { + int numToCopy = Math.min(tabCount, rects.length); + Rectangle[] tmp = new Rectangle[tabCount]; + System.arraycopy(rects, 0, tmp, 0, numToCopy); + rects = tmp; + } + } + + /** + * This method expands the tabRuns array to give it more room. The old array + * is copied to the new one. + */ + protected void expandTabRunsArray() + { + // This method adds another 10 index positions to the tabRuns array. + if (tabRuns == null) + tabRuns = new int[10]; + else + { + int[] newRuns = new int[tabRuns.length + 10]; + System.arraycopy(tabRuns, 0, newRuns, 0, tabRuns.length); + tabRuns = newRuns; + } + } + + /** + * This method returns which run a particular tab belongs to. + * + * @param tabCount The number of tabs. + * @param tabIndex The tab to find. + * + * @return The tabRuns index that it belongs to. + */ + protected int getRunForTab(int tabCount, int tabIndex) + { + if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0) + return 1; + for (int i = 0; i < runCount; i++) + { + int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1; + if (first == tabCount) + first = 0; + int last = lastTabInRun(tabCount, i); + if (last >= tabIndex && first <= tabIndex) + return i; + } + return -1; + } + + /** + * This method returns the index of the last tab in a run. + * + * @param tabCount The number of tabs. + * @param run The run to check. + * + * @return The last tab in the given run. + */ + protected int lastTabInRun(int tabCount, int run) + { + if (tabRuns[run] == 0) + return tabCount - 1; + else + return tabRuns[run] - 1; + } + + /** + * This method returns the tab run overlay. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return The tab run overlay. + */ + protected int getTabRunOverlay(int tabPlacement) + { + return tabRunOverlay; + } + + /** + * This method returns the tab run indent. It is used in WRAP_TAB_LAYOUT and + * makes each tab run start indented by a certain amount. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param run The run to get indent for. + * + * @return The amount a run should be indented. + */ + protected int getTabRunIndent(int tabPlacement, int run) + { + return 0; + } + + /** + * This method returns whether a tab run should be padded. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param run The run to check. + * + * @return Whether the given run should be padded. + */ + protected boolean shouldPadTabRun(int tabPlacement, int run) + { + return true; + } + + /** + * This method returns whether the tab runs should be rotated. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return Whether runs should be rotated. + */ + protected boolean shouldRotateTabRuns(int tabPlacement) + { + return true; + } + + /** + * This method returns an icon for the tab. If the tab is disabled, it + * should return the disabledIcon. If it is enabled, then it should return + * the default icon. + * + * @param tabIndex The tab index to get an icon for. + * + * @return The icon for the tab index. + */ + protected Icon getIconForTab(int tabIndex) + { + if (tabPane.isEnabledAt(tabIndex)) + return tabPane.getIconAt(tabIndex); + else + return tabPane.getDisabledIconAt(tabIndex); + } + + /** + * This method returns a view that can paint the text for the label. + * + * @param tabIndex The tab index to get a view for. + * + * @return The view for the tab index. + */ + protected View getTextViewForTab(int tabIndex) + { + return null; + } + + /** + * This method returns the tab height, including insets, for the given index + * and fontheight. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The index of the tab to calculate. + * @param fontHeight The font height. + * + * @return This tab's height. + */ + protected int calculateTabHeight(int tabPlacement, int tabIndex, + int fontHeight) + { + Icon icon = getIconForTab(tabIndex); + Insets insets = getTabInsets(tabPlacement, tabIndex); + + if (icon != null) + { + Rectangle vr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + layoutLabel(tabPlacement, getFontMetrics(), tabIndex, + tabPane.getTitleAt(tabIndex), icon, vr, ir, tr, + tabIndex == tabPane.getSelectedIndex()); + calcRect = tr.union(ir); + } + else + calcRect.height = fontHeight; + + calcRect.height += insets.top + insets.bottom; + return calcRect.height; + } + + /** + * This method returns the max tab height. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return The maximum tab height. + */ + protected int calculateMaxTabHeight(int tabPlacement) + { + maxTabHeight = 0; + + FontMetrics fm = getFontMetrics(); + int fontHeight = fm.getHeight(); + + for (int i = 0; i < tabPane.getTabCount(); i++) + maxTabHeight = Math.max(calculateTabHeight(tabPlacement, i, fontHeight), + maxTabHeight); + + return maxTabHeight; + } + + /** + * This method calculates the tab width, including insets, for the given tab + * index and font metrics. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index to calculate for. + * @param metrics The font's metrics. + * + * @return The tab width for the given index. + */ + protected int calculateTabWidth(int tabPlacement, int tabIndex, + FontMetrics metrics) + { + Icon icon = getIconForTab(tabIndex); + Insets insets = getTabInsets(tabPlacement, tabIndex); + + if (icon != null) + { + Rectangle vr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + layoutLabel(tabPlacement, getFontMetrics(), tabIndex, + tabPane.getTitleAt(tabIndex), icon, vr, ir, tr, + tabIndex == tabPane.getSelectedIndex()); + calcRect = tr.union(ir); + } + else + calcRect.width = metrics.stringWidth(tabPane.getTitleAt(tabIndex)); + + calcRect.width += insets.left + insets.right; + return calcRect.width; + } + + /** + * This method calculates the max tab width. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return The maximum tab width. + */ + protected int calculateMaxTabWidth(int tabPlacement) + { + maxTabWidth = 0; + + FontMetrics fm = getFontMetrics(); + + for (int i = 0; i < tabPane.getTabCount(); i++) + maxTabWidth = Math.max(calculateTabWidth(tabPlacement, i, fm), + maxTabWidth); + + return maxTabWidth; + } + + /** + * This method calculates the tab area height, including insets, for the + * given amount of runs and tab height. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param horizRunCount The number of runs. + * @param maxTabHeight The max tab height. + * + * @return The tab area height. + */ + protected int calculateTabAreaHeight(int tabPlacement, int horizRunCount, + int maxTabHeight) + { + Insets insets = getTabAreaInsets(tabPlacement); + int tabAreaHeight = horizRunCount * maxTabHeight + - (horizRunCount - 1) * tabRunOverlay; + + tabAreaHeight += insets.top + insets.bottom; + + return tabAreaHeight; + } + + /** + * This method calculates the tab area width, including insets, for the + * given amount of runs and tab width. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param vertRunCount The number of runs. + * @param maxTabWidth The max tab width. + * + * @return The tab area width. + */ + protected int calculateTabAreaWidth(int tabPlacement, int vertRunCount, + int maxTabWidth) + { + Insets insets = getTabAreaInsets(tabPlacement); + int tabAreaWidth = vertRunCount * maxTabWidth + - (vertRunCount - 1) * tabRunOverlay; + + tabAreaWidth += insets.left + insets.right; + + return tabAreaWidth; + } + + /** + * This method returns the tab insets appropriately rotated. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab index. + * + * @return The tab insets for the given index. + */ + protected Insets getTabInsets(int tabPlacement, int tabIndex) + { + Insets target = new Insets(0, 0, 0, 0); + rotateInsets(tabInsets, target, tabPlacement); + return target; + } + + /** + * This method returns the selected tab pad insets appropriately rotated. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return The selected tab pad insets. + */ + protected Insets getSelectedTabPadInsets(int tabPlacement) + { + Insets target = new Insets(0, 0, 0, 0); + rotateInsets(selectedTabPadInsets, target, tabPlacement); + return target; + } + + /** + * This method returns the tab area insets appropriately rotated. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return The tab area insets. + */ + protected Insets getTabAreaInsets(int tabPlacement) + { + Insets target = new Insets(0, 0, 0, 0); + rotateInsets(tabAreaInsets, target, tabPlacement); + return target; + } + + /** + * This method returns the content border insets appropriately rotated. + * + * @param tabPlacement The JTabbedPane's tab placement. + * + * @return The content border insets. + */ + protected Insets getContentBorderInsets(int tabPlacement) + { + Insets target = new Insets(0, 0, 0, 0); + rotateInsets(contentBorderInsets, target, tabPlacement); + return target; + } + + /** + * This method returns the fontmetrics for the font of the JTabbedPane. + * + * @return The font metrics for the JTabbedPane. + */ + protected FontMetrics getFontMetrics() + { + FontMetrics fm = tabPane.getToolkit().getFontMetrics(tabPane.getFont()); + return fm; + } + + /** + * This method navigates from the selected tab into the given direction. As + * a result, a new tab will be selected (if possible). + * + * @param direction The direction to navigate in. + */ + protected void navigateSelectedTab(int direction) + { + int tabPlacement = tabPane.getTabPlacement(); + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + { + if (direction == SwingConstants.WEST) + selectPreviousTabInRun(tabPane.getSelectedIndex()); + else if (direction == SwingConstants.EAST) + selectNextTabInRun(tabPane.getSelectedIndex()); + + else + { + int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(), + tabPane.getSelectedIndex(), + (tabPlacement == SwingConstants.RIGHT) + ? true : false); + selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(), + offset); + } + } + if (tabPlacement == SwingConstants.LEFT + || tabPlacement == SwingConstants.RIGHT) + { + if (direction == SwingConstants.NORTH) + selectPreviousTabInRun(tabPane.getSelectedIndex()); + else if (direction == SwingConstants.SOUTH) + selectNextTabInRun(tabPane.getSelectedIndex()); + else + { + int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(), + tabPane.getSelectedIndex(), + (tabPlacement == SwingConstants.RIGHT) + ? true : false); + selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(), + offset); + } + } + } + + /** + * This method selects the next tab in the run. + * + * @param current The current selected index. + */ + protected void selectNextTabInRun(int current) + { + tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(), + current)); + } + + /** + * This method selects the previous tab in the run. + * + * @param current The current selected index. + */ + protected void selectPreviousTabInRun(int current) + { + tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(), + current)); + } + + /** + * This method selects the next tab (regardless of runs). + * + * @param current The current selected index. + */ + protected void selectNextTab(int current) + { + tabPane.setSelectedIndex(getNextTabIndex(current)); + } + + /** + * This method selects the previous tab (regardless of runs). + * + * @param current The current selected index. + */ + protected void selectPreviousTab(int current) + { + tabPane.setSelectedIndex(getPreviousTabIndex(current)); + } + + /** + * This method selects the correct tab given an offset from the current tab + * index. If the tab placement is TOP or BOTTOM, the offset will be in the + * y direction, otherwise, it will be in the x direction. A new coordinate + * will be found by adding the offset to the current location of the tab. + * The tab that the new location will be selected. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabIndex The tab to start from. + * @param offset The coordinate offset. + */ + protected void selectAdjacentRunTab(int tabPlacement, int tabIndex, + int offset) + { + int x = rects[tabIndex].x + rects[tabIndex].width / 2; + int y = rects[tabIndex].y + rects[tabIndex].height / 2; + + switch (tabPlacement) + { + case SwingConstants.TOP: + case SwingConstants.BOTTOM: + y += offset; + break; + case SwingConstants.RIGHT: + case SwingConstants.LEFT: + x += offset; + break; + } + + int index = tabForCoordinate(tabPane, x, y); + if (index != -1) + tabPane.setSelectedIndex(index); + } + + // This method is called when you press up/down to cycle through tab runs. + // it returns the distance (between the two runs' x/y position. + // where one run is the current selected run and the other run is the run in the + // direction of the scroll (dictated by the forward flag) + // the offset is an absolute value of the difference + + /** + * This method calculates the offset distance for use in + * selectAdjacentRunTab. The offset returned will be a difference in the y + * coordinate between the run in the desired direction and the current run + * (for tabPlacement in TOP or BOTTOM). Use x coordinate for LEFT and + * RIGHT. + * + * @param tabPlacement The JTabbedPane's tab placement. + * @param tabCount The number of tabs. + * @param tabIndex The starting index. + * @param forward If forward, the run in the desired direction will be the + * next run. + * + * @return The offset between the two runs. + */ + protected int getTabRunOffset(int tabPlacement, int tabCount, int tabIndex, + boolean forward) + { + int currRun = getRunForTab(tabCount, tabIndex); + int offset; + int nextRun = (forward) ? getNextTabRun(currRun) : getPreviousTabRun(currRun); + if (tabPlacement == SwingConstants.TOP + || tabPlacement == SwingConstants.BOTTOM) + offset = rects[lastTabInRun(tabCount, nextRun)].y + - rects[lastTabInRun(tabCount, currRun)].y; + else + offset = rects[lastTabInRun(tabCount, nextRun)].x + - rects[lastTabInRun(tabCount, currRun)].x; + return offset; + } + + /** + * This method returns the previous tab index. + * + * @param base The index to start from. + * + * @return The previous tab index. + */ + protected int getPreviousTabIndex(int base) + { + base--; + if (base < 0) + return tabPane.getTabCount() - 1; + return base; + } + + /** + * This method returns the next tab index. + * + * @param base The index to start from. + * + * @return The next tab index. + */ + protected int getNextTabIndex(int base) + { + base++; + if (base == tabPane.getTabCount()) + return 0; + return base; + } + + /** + * This method returns the next tab index in the run. If the next index is + * out of this run, it will return the starting tab index for the run. + * + * @param tabCount The number of tabs. + * @param base The index to start from. + * + * @return The next tab index in the run. + */ + protected int getNextTabIndexInRun(int tabCount, int base) + { + int index = getNextTabIndex(base); + int run = getRunForTab(tabCount, base); + if (index == lastTabInRun(tabCount, run) + 1) + index = lastTabInRun(tabCount, getPreviousTabRun(run)) + 1; + return getNextTabIndex(base); + } + + /** + * This method returns the previous tab index in the run. If the previous + * index is out of this run, it will return the last index for the run. + * + * @param tabCount The number of tabs. + * @param base The index to start from. + * + * @return The previous tab index in the run. + */ + protected int getPreviousTabIndexInRun(int tabCount, int base) + { + int index = getPreviousTabIndex(base); + int run = getRunForTab(tabCount, base); + if (index == lastTabInRun(tabCount, getPreviousTabRun(run))) + index = lastTabInRun(tabCount, run); + return getPreviousTabIndex(base); + } + + /** + * This method returns the index of the previous run. + * + * @param baseRun The run to start from. + * + * @return The index of the previous run. + */ + protected int getPreviousTabRun(int baseRun) + { + if (getTabRunCount(tabPane) == 1) + return 1; + + int prevRun = --baseRun; + if (prevRun < 0) + prevRun = getTabRunCount(tabPane) - 1; + return prevRun; + } + + /** + * This method returns the index of the next run. + * + * @param baseRun The run to start from. + * + * @return The index of the next run. + */ + protected int getNextTabRun(int baseRun) + { + if (getTabRunCount(tabPane) == 1) + return 1; + + int nextRun = ++baseRun; + if (nextRun == getTabRunCount(tabPane)) + nextRun = 0; + return nextRun; + } + + /** + * This method rotates the insets given a direction to rotate them in. + * Target placement should be one of TOP, LEFT, BOTTOM, RIGHT. The rotated + * insets will be stored in targetInsets. Passing in TOP as the direction + * does nothing. Passing in LEFT switches top and left, right and bottom. + * Passing in BOTTOM switches top and bottom. Passing in RIGHT switches top + * for left, left for bottom, bottom for right, and right for top. + * + * @param topInsets The reference insets. + * @param targetInsets An Insets object to store the new insets. + * @param targetPlacement The rotation direction. + */ + protected static void rotateInsets(Insets topInsets, Insets targetInsets, + int targetPlacement) + { + // Sun's version will happily throw an NPE if params are null, + // so I won't check it either. + switch (targetPlacement) + { + case SwingConstants.TOP: + targetInsets.top = topInsets.top; + targetInsets.left = topInsets.left; + targetInsets.right = topInsets.right; + targetInsets.bottom = topInsets.bottom; + break; + case SwingConstants.LEFT: + targetInsets.left = topInsets.top; + targetInsets.top = topInsets.left; + targetInsets.right = topInsets.bottom; + targetInsets.bottom = topInsets.right; + break; + case SwingConstants.BOTTOM: + targetInsets.top = topInsets.bottom; + targetInsets.bottom = topInsets.top; + targetInsets.left = topInsets.left; + targetInsets.right = topInsets.right; + break; + case SwingConstants.RIGHT: + targetInsets.top = topInsets.left; + targetInsets.left = topInsets.bottom; + targetInsets.bottom = topInsets.right; + targetInsets.right = topInsets.top; + break; + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java new file mode 100644 index 00000000000..700b406d076 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -0,0 +1,224 @@ +/* BasicTableHeaderUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; + +import javax.swing.CellRendererPane; +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TableHeaderUI; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; + +public class BasicTableHeaderUI + extends TableHeaderUI +{ + + public static ComponentUI createUI(JComponent h) + { + return new BasicTableHeaderUI(); + } + + protected JTableHeader header; + protected MouseInputListener mouseInputListener; + protected CellRendererPane rendererPane; + protected Border cellBorder; + + class MouseInputHandler + implements MouseInputListener + { + public void mouseClicked(MouseEvent e) {} + public void mouseDragged(MouseEvent e) {} + public void mouseEntered(MouseEvent e) {} + public void mouseExited(MouseEvent e) {} + public void mouseMoved(MouseEvent e) {} + public void mousePressed(MouseEvent e) {} + public void mouseReleased(MouseEvent e) {} + } + + protected MouseInputListener createMouseInputListener() + { + return new MouseInputHandler(); + } + + public BasicTableHeaderUI() + { + mouseInputListener = createMouseInputListener(); + } + + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + header.setBackground(defaults.getColor("TableHeader.background")); + header.setForeground(defaults.getColor("TableHeader.foreground")); + header.setFont(defaults.getFont("TableHeader.font")); + cellBorder = defaults.getBorder("TableHeader.cellBorder"); + } + + protected void installKeyboardActions() + { + } + + protected void installListeners() + { + header.addMouseListener(mouseInputListener); + } + + public void installUI(JComponent c) + { + header = (JTableHeader) c; + installDefaults(); + installKeyboardActions(); + installListeners(); + } + + protected void uninstallDefaults() + { + header.setBackground(null); + header.setForeground(null); + header.setFont(null); + } + + protected void uninstallKeyboardActions() + { + } + + protected void uninstallListeners() + { + header.removeMouseListener(mouseInputListener); + } + + public void uninstallUI(JComponent c) + { + uninstallListeners(); + uninstallKeyboardActions(); + uninstallDefaults(); + } + + public void paint(Graphics gfx, JComponent c) + { + TableColumnModel cmod = header.getColumnModel(); + int ncols = cmod.getColumnCount(); + if (ncols == 0) + return; + + Rectangle clip = gfx.getClipBounds(); + TableCellRenderer defaultRend = header.getDefaultRenderer(); + + for (int i = 0; i < ncols; ++i) + { + Rectangle bounds = header.getHeaderRect(i); + if (bounds.intersects(clip)) + { + TableColumn col = cmod.getColumn(i); + TableCellRenderer rend = col.getHeaderRenderer(); + if (rend == null) + rend = defaultRend; + Object val = col.getHeaderValue(); + Component comp = rend.getTableCellRendererComponent(header.getTable(), + val, + false, // isSelected + false, // isFocused + -1, i); + comp.setFont(header.getFont()); + comp.setBackground(header.getBackground()); + comp.setForeground(header.getForeground()); + if (comp instanceof JComponent) + ((JComponent)comp).setBorder(cellBorder); + gfx.translate(bounds.x, bounds.y); + comp.setSize(bounds.width, bounds.height); + comp.setLocation(0,0); + comp.paint(gfx); + gfx.translate(-bounds.x, -bounds.y); + } + } + + } + + public Dimension getPreferredSize(JComponent c) + { + TableColumnModel cmod = header.getColumnModel(); + TableCellRenderer defaultRend = header.getDefaultRenderer(); + int ncols = cmod.getColumnCount(); + Dimension ret = new Dimension(0,0); + int spacing = 0; + + if (header.getTable() != null + && header.getTable().getIntercellSpacing() != null) + spacing = header.getTable().getIntercellSpacing().width; + + for (int i = 0; i < ncols; ++i) + { + TableColumn col = cmod.getColumn(i); + TableCellRenderer rend = col.getHeaderRenderer(); + if (rend == null) + rend = defaultRend; + Object val = col.getHeaderValue(); + Component comp = rend.getTableCellRendererComponent(header.getTable(), + val, + false, // isSelected + false, // isFocused + -1, i); + comp.setFont(header.getFont()); + comp.setBackground(header.getBackground()); + comp.setForeground(header.getForeground()); + if (comp instanceof JComponent) + ((JComponent)comp).setBorder(cellBorder); + + Dimension d = comp.getPreferredSize(); + ret.width += spacing; + ret.height = Math.max(d.height, ret.height); + } + ret.width = cmod.getTotalColumnWidth(); + return ret; + } + + +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java new file mode 100644 index 00000000000..778743619bc --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java @@ -0,0 +1,398 @@ +/* BasicTableUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.CellRendererPane; +import javax.swing.JComponent; +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TableUI; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumn; +import javax.swing.table.TableColumnModel; + +public class BasicTableUI + extends TableUI +{ + public static ComponentUI createUI(JComponent comp) + { + return new BasicTableUI(); + } + + protected FocusListener focusListener; + protected KeyListener keyListener; + protected MouseInputListener mouseInputListener; + protected CellRendererPane rendererPane; + protected JTable table; + + /** The normal cell border. */ + Border cellBorder; + + /** The cell border for selected/highlighted cells. */ + Border highlightCellBorder; + + class FocusHandler implements FocusListener + { + public void focusGained(FocusEvent e) + { + } + public void focusLost(FocusEvent e) + { + } + } + + class KeyHandler implements KeyListener + { + public void keyPressed(KeyEvent e) + { + } + public void keyReleased(KeyEvent e) + { + } + public void keyTyped(KeyEvent e) + { + } + } + + class MouseInputHandler implements MouseInputListener + { + Point begin, curr; + + private void updateSelection(boolean controlPressed) + { + if (table.getRowSelectionAllowed()) + { + int lo_row = table.rowAtPoint(begin); + int hi_row = table.rowAtPoint(curr); + ListSelectionModel rowModel = table.getSelectionModel(); + if (lo_row != -1 && hi_row != -1) + { + if (controlPressed && rowModel.getSelectionMode() + != ListSelectionModel.SINGLE_SELECTION) + rowModel.addSelectionInterval(lo_row, hi_row); + else + rowModel.setSelectionInterval(lo_row, hi_row); + } + } + + if (table.getColumnSelectionAllowed()) + { + int lo_col = table.columnAtPoint(begin); + int hi_col = table.columnAtPoint(curr); + ListSelectionModel colModel = table.getColumnModel(). + getSelectionModel(); + if (lo_col != -1 && hi_col != -1) + { + if (controlPressed && colModel.getSelectionMode() != + ListSelectionModel.SINGLE_SELECTION) + colModel.addSelectionInterval(lo_col, hi_col); + else + colModel.setSelectionInterval(lo_col, hi_col); + } + } + } + + public void mouseClicked(MouseEvent e) + { + } + public void mouseDragged(MouseEvent e) + { + curr = new Point(e.getX(), e.getY()); + updateSelection(e.isControlDown()); + } + public void mouseEntered(MouseEvent e) + { + } + public void mouseExited(MouseEvent e) + { + } + public void mouseMoved(MouseEvent e) + { + } + public void mousePressed(MouseEvent e) + { + begin = new Point(e.getX(), e.getY()); + curr = new Point(e.getX(), e.getY()); + //if control is pressed and the cell is already selected, deselect it + if (e.isControlDown() && table. + isCellSelected(table.rowAtPoint(begin),table.columnAtPoint(begin))) + { + table.getSelectionModel(). + removeSelectionInterval(table.rowAtPoint(begin), + table.rowAtPoint(begin)); + table.getColumnModel().getSelectionModel(). + removeSelectionInterval(table.columnAtPoint(begin), + table.columnAtPoint(begin)); + } + else + updateSelection(e.isControlDown()); + + } + public void mouseReleased(MouseEvent e) + { + begin = null; + curr = null; + } + } + + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + protected KeyListener createKeyListener() + { + return new KeyHandler(); + } + protected MouseInputListener createMouseInputListener() + { + return new MouseInputHandler(); + } + + public Dimension getMaximumSize(JComponent comp) + { + return getPreferredSize(comp); + } + + public Dimension getMinimumSize(JComponent comp) + { + return getPreferredSize(comp); + } + + public Dimension getPreferredSize(JComponent comp) + { + int width = table.getColumnModel().getTotalColumnWidth(); + int height = table.getRowCount() * table.getRowHeight(); + return new Dimension(width, height); + } + + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + table.setFont(defaults.getFont("Table.font")); + table.setGridColor(defaults.getColor("Table.gridColor")); + table.setForeground(defaults.getColor("Table.foreground")); + table.setBackground(defaults.getColor("Table.background")); + table.setSelectionForeground(defaults.getColor("Table.selectionForeground")); + table.setSelectionBackground(defaults.getColor("Table.selectionBackground")); + table.setOpaque(true); + + highlightCellBorder = defaults.getBorder("Table.focusCellHighlightBorder"); + cellBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1); + } + protected void installKeyboardActions() + { + } + + protected void installListeners() + { + table.addFocusListener(focusListener); + table.addKeyListener(keyListener); + table.addMouseListener(mouseInputListener); + table.addMouseMotionListener(mouseInputListener); + } + + protected void uninstallDefaults() + { + // TODO: this method used to do the following which is not + // quite right (at least it breaks apps that run fine with the + // JDK): + // + // table.setFont(null); + // table.setGridColor(null); + // table.setForeground(null); + // table.setBackground(null); + // table.setSelectionForeground(null); + // table.setSelectionBackground(null); + // + // This would leave the component in a corrupt state, which is + // not acceptable. A possible solution would be to have component + // level defaults installed, that get overridden by the UI defaults + // and get restored in this method. I am not quite sure about this + // though. / Roman Kennke + } + + protected void uninstallKeyboardActions() + { + } + + protected void uninstallListeners() + { + table.removeFocusListener(focusListener); + table.removeKeyListener(keyListener); + table.removeMouseListener(mouseInputListener); + table.removeMouseMotionListener(mouseInputListener); + } + + public void installUI(JComponent comp) + { + table = (JTable)comp; + focusListener = createFocusListener(); + keyListener = createKeyListener(); + mouseInputListener = createMouseInputListener(); + installDefaults(); + installKeyboardActions(); + installListeners(); + } + + public void uninstallUI(JComponent c) + { + uninstallListeners(); + uninstallKeyboardActions(); + uninstallDefaults(); + } + + public void paint(Graphics gfx, JComponent ignored) + { + int ncols = table.getColumnCount(); + int nrows = table.getRowCount(); + if (nrows == 0 || ncols == 0) + return; + + Rectangle clip = gfx.getClipBounds(); + TableColumnModel cols = table.getColumnModel(); + + int height = table.getRowHeight(); + int x0 = 0, y0 = 0; + int x = x0; + int y = y0; + + Dimension gap = table.getIntercellSpacing(); + int ymax = clip.y + clip.height; + int xmax = clip.x + clip.width; + + // paint the cell contents + for (int c = 0; c < ncols && x < xmax; ++c) + { + y = y0; + TableColumn col = cols.getColumn(c); + int width = col.getWidth(); + int modelCol = col.getModelIndex(); + + for (int r = 0; r < nrows && y < ymax; ++r) + { + Rectangle bounds = new Rectangle(x, y, width, height); + if (bounds.intersects(clip)) + { + TableCellRenderer rend = table.getCellRenderer(r, c); + Component comp = table.prepareRenderer(rend, r, c); + gfx.translate(x, y); + comp.setBounds(new Rectangle(0, 0, width, height)); + // Set correct border on cell renderer. + if (comp instanceof JComponent) + { + if (table.isCellSelected(r, c)) + ((JComponent) comp).setBorder(highlightCellBorder); + else + ((JComponent) comp).setBorder(cellBorder); + } + comp.paint(gfx); + gfx.translate(-x, -y); + } + y += height; + if (gap != null) + y += gap.height; + } + x += width; + if (gap != null) + x += gap.width; + } + + // tighten up the x and y max bounds + ymax = y; + xmax = x; + + Color grid = table.getGridColor(); + + // paint vertical grid lines + if (grid != null && table.getShowVerticalLines()) + { + x = x0; + Color save = gfx.getColor(); + gfx.setColor(grid); + boolean paintedLine = false; + for (int c = 0; c < ncols && x < xmax; ++c) + { + x += cols.getColumn(c).getWidth();; + if (gap != null) + x += gap.width; + gfx.drawLine(x, y0, x, ymax); + paintedLine = true; + } + gfx.setColor(save); + } + + // paint horizontal grid lines + if (grid != null && table.getShowHorizontalLines()) + { + y = y0; + Color save = gfx.getColor(); + gfx.setColor(grid); + boolean paintedLine = false; + for (int r = 0; r < nrows && y < ymax; ++r) + { + y += height; + if (gap != null) + y += gap.height; + gfx.drawLine(x0, y, xmax, y); + paintedLine = true; + } + gfx.setColor(save); + } + + } + +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java new file mode 100644 index 00000000000..97b0ccb6ee6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java @@ -0,0 +1,68 @@ +/* BasicTextAreaUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.Element; +import javax.swing.text.PlainView; +import javax.swing.text.View; + +public class BasicTextAreaUI extends BasicTextUI +{ + public static ComponentUI createUI(JComponent comp) + { + return new BasicTextAreaUI(); + } + + public BasicTextAreaUI() + { + } + + public View create(Element elem) + { + return new PlainView(elem); + } + + protected String getPropertyPrefix() + { + return "TextArea"; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java new file mode 100644 index 00000000000..a300446c262 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java @@ -0,0 +1,80 @@ +/* BasicTextFieldUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.beans.PropertyChangeEvent; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.Element; +import javax.swing.text.FieldView; +import javax.swing.text.View; + +public class BasicTextFieldUI extends BasicTextUI +{ + public BasicTextFieldUI() + { + super(); + } + + public View create(Element elem) + { + return new FieldView(elem); + } + + public static ComponentUI createUI(JComponent c) + { + return new BasicTextFieldUI(); + } + + protected String getPropertyPrefix() + { + return "TextField"; + } + + public void installUI(JComponent c) + { + super.installUI(c); + } + + protected void propertyChange(PropertyChangeEvent event) + { + // Does nothing by default. + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java new file mode 100644 index 00000000000..55d908e1b88 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextPaneUI.java @@ -0,0 +1,68 @@ +/* BasicTextPaneUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.text.Element; +import javax.swing.text.PlainView; +import javax.swing.text.View; + +public class BasicTextPaneUI extends BasicEditorPaneUI +{ + public BasicTextPaneUI() + { + // Do nothing here. + } + + public static ComponentUI createUI(JComponent comp) + { + return new BasicTextPaneUI(); + } + + public View create(Element elem) + { + return new PlainView(elem); + } + + protected String getPropertyPrefix() + { + return "TextPane"; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java new file mode 100644 index 00000000000..dd0828e466a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java @@ -0,0 +1,635 @@ +/* BasicTextUI.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.TextUI; +import javax.swing.plaf.UIResource; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.DefaultCaret; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; +import javax.swing.text.Element; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; +import javax.swing.text.Keymap; +import javax.swing.text.PlainView; +import javax.swing.text.Position; +import javax.swing.text.View; +import javax.swing.text.ViewFactory; + + +public abstract class BasicTextUI extends TextUI + implements ViewFactory +{ + public static class BasicCaret extends DefaultCaret + implements UIResource + { + public BasicCaret() + { + } + } + + public static class BasicHighlighter extends DefaultHighlighter + implements UIResource + { + public BasicHighlighter() + { + } + } + + private class RootView extends View + { + private View view; + + public RootView() + { + super(null); + } + + // View methods. + + public ViewFactory getViewFactory() + { + // FIXME: Handle EditorKit somehow. + return BasicTextUI.this; + } + + public void setView(View v) + { + if (view != null) + view.setParent(null); + + if (v != null) + v.setParent(null); + + view = v; + } + + public Container getContainer() + { + return textComponent; + } + + public float getPreferredSpan(int axis) + { + if (view != null) + return view.getPreferredSpan(axis); + + return Integer.MAX_VALUE; + } + + public void paint(Graphics g, Shape s) + { + if (view != null) + view.paint(g, s); + } + + public Shape modelToView(int position, Shape a, Position.Bias bias) + throws BadLocationException + { + if (view == null) + return null; + + return ((PlainView) view).modelToView(position, a, bias).getBounds(); + } + + /** + * Notification about text insertions. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.insertUpdate(ev, shape, vf); + } + + /** + * Notification about text removals. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.removeUpdate(ev, shape, vf); + } + + /** + * Notification about text changes. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.changedUpdate(ev, shape, vf); + } + } + + class UpdateHandler implements PropertyChangeListener + { + public void propertyChange(PropertyChangeEvent event) + { + if (event.getPropertyName().equals("document")) + { + // Document changed. + modelChanged(); + } + } + } + + /** + * Listens for changes on the underlying model and forwards notifications + * to the View. This also updates the caret position of the text component. + * + * TODO: Maybe this should somehow be handled through EditorKits + */ + class DocumentHandler implements DocumentListener + { + /** + * Notification about a document change event. + * + * @param ev the DocumentEvent describing the change + */ + public void changedUpdate(DocumentEvent ev) + { + Dimension size = textComponent.getSize(); + rootView.changedUpdate(ev, new Rectangle(0, 0, size.width, size.height), + BasicTextUI.this); + } + + /** + * Notification about a document insert event. + * + * @param ev the DocumentEvent describing the insertion + */ + public void insertUpdate(DocumentEvent ev) + { + Dimension size = textComponent.getSize(); + rootView.insertUpdate(ev, new Rectangle(0, 0, size.width, size.height), + BasicTextUI.this); + int caretPos = textComponent.getCaretPosition(); + if (caretPos >= ev.getOffset()) + textComponent.setCaretPosition(caretPos + ev.getLength()); + } + + /** + * Notification about a document removal event. + * + * @param ev the DocumentEvent describing the removal + */ + public void removeUpdate(DocumentEvent ev) + { + Dimension size = textComponent.getSize(); + rootView.removeUpdate(ev, new Rectangle(0, 0, size.width, size.height), + BasicTextUI.this); + int caretPos = textComponent.getCaretPosition(); + if (caretPos >= ev.getOffset()) + textComponent.setCaretPosition(ev.getOffset()); + } + } + + static EditorKit kit = new DefaultEditorKit(); + + RootView rootView = new RootView(); + JTextComponent textComponent; + UpdateHandler updateHandler = new UpdateHandler(); + + /** The DocumentEvent handler. */ + DocumentHandler documentHandler = new DocumentHandler(); + + public BasicTextUI() + { + } + + protected Caret createCaret() + { + return new BasicCaret(); + } + + protected Highlighter createHighlighter() + { + return new BasicHighlighter(); + } + + protected final JTextComponent getComponent() + { + return textComponent; + } + + public void installUI(final JComponent c) + { + super.installUI(c); + c.setOpaque(true); + + textComponent = (JTextComponent) c; + + Document doc = textComponent.getDocument(); + if (doc == null) + { + doc = getEditorKit(textComponent).createDefaultDocument(); + textComponent.setDocument(doc); + } + + textComponent.addPropertyChangeListener(updateHandler); + modelChanged(); + + installDefaults(); + installListeners(); + installKeyboardActions(); + } + + protected void installDefaults() + { + Caret caret = textComponent.getCaret(); + if (caret == null) + { + caret = createCaret(); + textComponent.setCaret(caret); + } + + Highlighter highlighter = textComponent.getHighlighter(); + if (highlighter == null) + textComponent.setHighlighter(createHighlighter()); + + String prefix = getPropertyPrefix(); + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + textComponent.setBackground(defaults.getColor(prefix + ".background")); + textComponent.setForeground(defaults.getColor(prefix + ".foreground")); + textComponent.setMargin(defaults.getInsets(prefix + ".margin")); + textComponent.setBorder(defaults.getBorder(prefix + ".border")); + textComponent.setFont(defaults.getFont(prefix + ".font")); + + caret.setBlinkRate(defaults.getInt(prefix + ".caretBlinkRate")); + } + + private FocusListener focuslistener = new FocusListener() { + public void focusGained(FocusEvent e) + { + textComponent.repaint(); + } + public void focusLost(FocusEvent e) + { + textComponent.repaint(); + } + }; + + protected void installListeners() + { + textComponent.addFocusListener(focuslistener); + installDocumentListeners(); + } + + /** + * Installs the document listeners on the textComponent's model. + */ + private void installDocumentListeners() + { + Document doc = textComponent.getDocument(); + if (doc != null) + doc.addDocumentListener(documentHandler); + } + + /** + * Returns the name of the keymap for this type of TextUI. + * + * This is implemented so that the classname of this TextUI + * without the package prefix is returned. This way subclasses + * don't have to override this method. + * + * @return the name of the keymap for this TextUI + */ + protected String getKeymapName() + { + String fullClassName = getClass().getName(); + int index = fullClassName.lastIndexOf('.'); + String className = fullClassName.substring(index + 1); + return className; + } + + protected Keymap createKeymap() + { + String prefix = getPropertyPrefix(); + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + JTextComponent.KeyBinding[] bindings = + (JTextComponent.KeyBinding[]) defaults.get(prefix + ".keyBindings"); + if (bindings == null) + { + bindings = new JTextComponent.KeyBinding[0]; + defaults.put(prefix + ".keyBindings", bindings); + } + + Keymap km = JTextComponent.addKeymap(getKeymapName(), + JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP)); + JTextComponent.loadKeymap(km, bindings, textComponent.getActions()); + return km; + } + + protected void installKeyboardActions() + { + // load any bindings for the older Keymap interface + Keymap km = JTextComponent.getKeymap(getKeymapName()); + if (km == null) + km = createKeymap(); + textComponent.setKeymap(km); + + // load any bindings for the newer InputMap / ActionMap interface + SwingUtilities.replaceUIInputMap(textComponent, + JComponent.WHEN_FOCUSED, + getInputMap(JComponent.WHEN_FOCUSED)); + SwingUtilities.replaceUIActionMap(textComponent, getActionMap()); + } + + InputMap getInputMap(int condition) + { + String prefix = getPropertyPrefix(); + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + switch (condition) + { + case JComponent.WHEN_IN_FOCUSED_WINDOW: + // FIXME: is this the right string? nobody seems to use it. + return (InputMap) defaults.get(prefix + ".windowInputMap"); + case JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT: + return (InputMap) defaults.get(prefix + ".ancestorInputMap"); + default: + case JComponent.WHEN_FOCUSED: + return (InputMap) defaults.get(prefix + ".focusInputMap"); + } + } + + ActionMap getActionMap() + { + String prefix = getPropertyPrefix(); + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + ActionMap am = (ActionMap) defaults.get(prefix + ".actionMap"); + if (am == null) + { + am = createActionMap(); + defaults.put(prefix + ".actionMap", am); + } + return am; + } + + ActionMap createActionMap() + { + Action[] actions = textComponent.getActions(); + ActionMap am = new ActionMapUIResource(); + for (int i = 0; i < actions.length; ++i) + { + String name = (String) actions[i].getValue(Action.NAME); + if (name != null) + am.put(name, actions[i]); + } + return am; + } + + public void uninstallUI(final JComponent component) + { + super.uninstallUI(component); + rootView.setView(null); + + textComponent.removePropertyChangeListener(updateHandler); + + uninstallDefaults(); + uninstallListeners(); + uninstallKeyboardActions(); + + textComponent = null; + } + + protected void uninstallDefaults() + { + // Do nothing here. + } + + protected void uninstallListeners() + { + textComponent.removeFocusListener(focuslistener); + } + + protected void uninstallKeyboardActions() + { + // Do nothing here. + } + + protected abstract String getPropertyPrefix(); + + public Dimension getPreferredSize(JComponent c) + { + View v = getRootView(textComponent); + + float w = v.getPreferredSpan(View.X_AXIS); + float h = v.getPreferredSpan(View.Y_AXIS); + + return new Dimension((int) w, (int) h); + } + + /** + * Returns the maximum size for text components that use this UI. + * + * This returns (Integer.MAX_VALUE, Integer.MAX_VALUE). + * + * @return the maximum size for text components that use this UI + */ + public Dimension getMaximumSize(JComponent c) + { + // Sun's implementation returns Integer.MAX_VALUE here, so do we. + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + public final void paint(Graphics g, JComponent c) + { + paintSafely(g); + } + + protected void paintSafely(Graphics g) + { + Caret caret = textComponent.getCaret(); + Highlighter highlighter = textComponent.getHighlighter(); + + if (textComponent.isOpaque()) + paintBackground(g); + + if (highlighter != null + && textComponent.getSelectionStart() != textComponent.getSelectionEnd()) + highlighter.paint(g); + + rootView.paint(g, getVisibleEditorRect()); + + if (caret != null && textComponent.hasFocus()) + caret.paint(g); + } + + protected void paintBackground(Graphics g) + { + g.setColor(textComponent.getBackground()); + g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight()); + } + + public void damageRange(JTextComponent t, int p0, int p1) + { + damageRange(t, p0, p1, null, null); + } + + public void damageRange(JTextComponent t, int p0, int p1, + Position.Bias firstBias, Position.Bias secondBias) + { + } + + public EditorKit getEditorKit(JTextComponent t) + { + return kit; + } + + public int getNextVisualPositionFrom(JTextComponent t, int pos, + Position.Bias b, int direction, + Position.Bias[] biasRet) + throws BadLocationException + { + return 0; + } + + public View getRootView(JTextComponent t) + { + return rootView; + } + + public Rectangle modelToView(JTextComponent t, int pos) + throws BadLocationException + { + return modelToView(t, pos, Position.Bias.Forward); + } + + public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias) + throws BadLocationException + { + return rootView.modelToView(pos, getVisibleEditorRect(), bias).getBounds(); + } + + public int viewToModel(JTextComponent t, Point pt) + { + return viewToModel(t, pt, null); + } + + public int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn) + { + return 0; + } + + public View create(Element elem) + { + // Subclasses have to implement this to get this functionality. + return null; + } + + public View create(Element elem, int p0, int p1) + { + // Subclasses have to implement this to get this functionality. + return null; + } + + protected Rectangle getVisibleEditorRect() + { + int width = textComponent.getWidth(); + int height = textComponent.getHeight(); + + if (width <= 0 || height <= 0) + return null; + + Insets insets = textComponent.getInsets(); + return new Rectangle(insets.left, insets.top, + width - insets.left + insets.right, + height - insets.top + insets.bottom); + } + + protected final void setView(View view) + { + rootView.setView(view); + view.setParent(rootView); + } + + protected void modelChanged() + { + if (textComponent == null || rootView == null) + return; + ViewFactory factory = rootView.getViewFactory(); + if (factory == null) + return; + Document doc = textComponent.getDocument(); + if (doc == null) + return; + installDocumentListeners(); + Element elem = doc.getDefaultRootElement(); + if (elem == null) + return; + setView(factory.create(elem)); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java new file mode 100644 index 00000000000..84509ad6efd --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -0,0 +1,62 @@ +/* BasicToggleButtonUI.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +public class BasicToggleButtonUI extends BasicButtonUI +{ + public static ComponentUI createUI(final JComponent component) + { + return new BasicToggleButtonUI(); + } + + /** + * Returns the prefix for the UI defaults property for this UI class. + * This is 'ToggleButton' for this class. + * + * @return the prefix for the UI defaults property + */ + protected String getPropertyPrefix() + { + return "ToggleButton"; + } +} + diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java new file mode 100644 index 00000000000..db29fdca583 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarSeparatorUI.java @@ -0,0 +1,127 @@ +/* BasicToolBarSeparatorUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; + +/** + * The Basic Look and Feel UI delegate for Separator. + */ +public class BasicToolBarSeparatorUI extends BasicSeparatorUI +{ + private transient Dimension size; + + /** + * Creates a new UI delegate for the given JComponent. + * + * @param c The JComponent to create a delegate for. + * + * @return A new BasicToolBarSeparatorUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicToolBarSeparatorUI(); + } + + /** + * This method installs the defaults that are given by the Basic L&F. + * + * @param s The Separator that is being installed. + */ + protected void installDefaults(JSeparator s) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + size = defaults.getDimension("ToolBar.separatorSize"); + } + + /** + * This method does nothing as a Separator is just blank space. + * + * @param g The Graphics object to paint with + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + // Do nothing. + } + + /** + * This method returns the preferred size of the JComponent. + * + * @param c The JComponent to measure. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + return size; + } + + /** + * This method returns the minimum size of the JComponent. + * + * @param c The JComponent to measure. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return size; + } + + /** + * This method returns the maximum size of the JComponent. + * + * @param c The JComponent to measure. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return size; + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java new file mode 100644 index 00000000000..bc655a2742d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java @@ -0,0 +1,1435 @@ +/* BasicToolBarUI.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ContainerEvent; +import java.awt.event.ContainerListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Hashtable; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JToolBar; +import javax.swing.RootPaneContainer; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.BorderUIResource.EtchedBorderUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ToolBarUI; +import javax.swing.plaf.UIResource; + +/** + * This is the Basic Look and Feel UI class for JToolBar. + */ +public class BasicToolBarUI extends ToolBarUI implements SwingConstants +{ + /** Static owner of all DragWindows. + * This is package-private to avoid an accessor method. */ + static JFrame owner = new JFrame(); + + /** The border used when the JToolBar is in nonrollover mode. */ + private static Border nonRolloverBorder; + + /** The border used when the JToolBar is in rollover mode. */ + private static Border rolloverBorder; + + /** The last known BorderLayout constraint before floating. */ + protected String constraintBeforeFloating; + + /** The last known orientation of the JToolBar before floating. + * This is package-private to avoid an accessor method. */ + int lastGoodOrientation; + + /** The color of the border when it is dockable. */ + protected Color dockingBorderColor; + + /** The background color of the JToolBar when it is dockable. */ + protected Color dockingColor; + + /** The docking listener responsible for mouse events on the JToolBar. */ + protected MouseInputListener dockingListener; + + /** The window used for dragging the JToolBar. */ + protected BasicToolBarUI.DragWindow dragWindow; + + /** The color of the border when it is not dockable. */ + protected Color floatingBorderColor; + + /** The background color of the JToolBar when it is not dockable. */ + protected Color floatingColor; + + /** The index of the focused component. */ + protected int focusedCompIndex; + + /** The PropertyChangeListener for the JToolBar. */ + protected PropertyChangeListener propertyListener; + + /** The JToolBar this UI delegate is responsible for. */ + protected JToolBar toolBar; + + /** The Container listener for the JToolBar. */ + protected ContainerListener toolBarContListener; + + /** The Focus listener for the JToolBar. */ + protected FocusListener toolBarFocusListener; + + /** + * The floating window that is responsible for holding the JToolBar when it + * is dragged outside of its original parent. + */ + private transient Window floatFrame; + + /** The original parent of the JToolBar. + * This is package-private to avoid an accessor method. */ + transient Container origParent; + + /** A hashtable of components and their original borders. + * This is package-private to avoid an accessor method. */ + transient Hashtable borders; + + /** A window listener for the floatable frame. */ + private transient WindowListener windowListener; + + /** A set of cached bounds of the JToolBar. + * This is package-private to avoid an accessor method. */ + transient Dimension cachedBounds; + + /** The cached orientation of the JToolBar. + * This is package-private to avoid an accessor method. */ + transient int cachedOrientation; + + /** + * This method creates a new <code>BasicToolBarUI</code> object for the given JToolBar. + */ + public BasicToolBarUI() + { + // Do nothing here. + } + + /** + * This method returns whether the JToolBar can dock at the given position. + * + * @param c The component to try to dock in. + * @param p The position of the mouse cursor relative to the given + * component. + * + * @return Whether the JToolBar can dock. + */ + public boolean canDock(Component c, Point p) + { + return areaOfClick(c, p) != -1; + } + + /** + * This helper method returns the position of the JToolBar if it can dock. + * + * @param c The component to try to dock in. + * @param p The position of the mouse cursor relative to the given + * component. + * + * @return One of the SwingConstants directions or -1 if the JToolBar can't + * dock. + */ + private int areaOfClick(Component c, Point p) + { + // Has to dock in immediate parent, not eventual root container. + Rectangle pBounds = c.getBounds(); + + // XXX: In Sun's implementation, the space the toolbar has to dock is dependent on the size it had last. + Dimension d = toolBar.getSize(); + int limit = Math.min(d.width, d.height); + + // The order of checking is 1. top 2. bottom 3. left 4. right + if (! pBounds.contains(p)) + return -1; + + if (p.y < limit) + return SwingConstants.NORTH; + + if (p.y > (pBounds.height - limit)) + return SwingConstants.SOUTH; + + if (p.x < limit) + return SwingConstants.WEST; + + if (p.x > (pBounds.width - limit)) + return SwingConstants.EAST; + + return -1; + } + + /** + * This method creates a new DockingListener for the JToolBar. + * + * @return A new DockingListener for the JToolBar. + */ + protected MouseInputListener createDockingListener() + { + return new DockingListener(toolBar); + } + + /** + * This method creates a new DragWindow for the given JToolBar. + * + * @param toolbar The JToolBar to create a DragWindow for. + * + * @return A new DragWindow. + */ + protected BasicToolBarUI.DragWindow createDragWindow(JToolBar toolbar) + { + return new DragWindow(); + } + + /** + * This method creates a new floating frame for the JToolBar. By default, + * this UI uses createFloatingWindow instead. This method of creating a + * floating frame is deprecated. + * + * @param toolbar The JToolBar to create a floating frame for. + * + * @return A new floating frame. + */ + protected JFrame createFloatingFrame(JToolBar toolbar) + { + // FIXME: Though deprecated, this should still work. + return null; + } + + /** + * This method creates a new floating window for the JToolBar. This is the + * method used by default to create a floating container for the JToolBar. + * + * @param toolbar The JToolBar to create a floating window for. + * + * @return A new floating window. + */ + protected RootPaneContainer createFloatingWindow(JToolBar toolbar) + { + // This one is used by default though. + return new ToolBarDialog(); + } + + /** + * This method creates a new WindowListener for the JToolBar. + * + * @return A new WindowListener. + */ + protected WindowListener createFrameListener() + { + return new FrameListener(); + } + + /** + * This method creates a new nonRolloverBorder for JButtons when the + * JToolBar's rollover property is set to false. + * + * @return A new NonRolloverBorder. + */ + protected Border createNonRolloverBorder() + { + return new EtchedBorderUIResource(); + } + + /** + * This method creates a new PropertyChangeListener for the JToolBar. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyListener() + { + return new PropertyListener(); + } + + /** + * This method creates a new rollover border for JButtons when the + * JToolBar's rollover property is set to true. + * + * @return A new rollover border. + */ + protected Border createRolloverBorder() + { + return new EtchedBorderUIResource() + { + public void paintBorder(Component c, Graphics g, int x, int y, + int width, int height) + { + if (c instanceof JButton) + { + if (((JButton) c).getModel().isRollover()) + super.paintBorder(c, g, x, y, width, height); + } + } + }; + } + + /** + * This method creates a new Container listener for the JToolBar. + * + * @return A new Container listener. + */ + protected ContainerListener createToolBarContListener() + { + return new ToolBarContListener(); + } + + /** + * This method creates a new FocusListener for the JToolBar. + * + * @return A new FocusListener for the JToolBar. + */ + protected FocusListener createToolBarFocusListener() + { + return new ToolBarFocusListener(); + } + + /** + * This method creates a new UI delegate for the given JComponent. + * + * @param c The JComponent to create a UI delegate for. + * + * @return A new UI delegate. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicToolBarUI(); + } + + /** + * This method is called to drag the DragWindow around when the JToolBar is + * being dragged around. + * + * @param position The mouse cursor coordinates relative to the JToolBar. + * @param origin The screen position of the JToolBar. + */ + protected void dragTo(Point position, Point origin) + { + int loc = areaOfClick(origParent, + SwingUtilities.convertPoint(toolBar, position, + origParent)); + + if (loc != -1) + { + dragWindow.setBorderColor(dockingBorderColor); + dragWindow.setBackground(dockingColor); + } + else + { + dragWindow.setBorderColor(floatingBorderColor); + dragWindow.setBackground(floatingColor); + } + + int w = 0; + int h = 0; + + boolean tmp = ((loc == SwingConstants.NORTH) + || (loc == SwingConstants.SOUTH) || (loc == -1)); + + if (((cachedOrientation == SwingConstants.HORIZONTAL) && tmp) + || ((cachedOrientation == VERTICAL) && ! tmp)) + { + w = cachedBounds.width; + h = cachedBounds.height; + } + else + { + w = cachedBounds.height; + h = cachedBounds.width; + } + + Point p = dragWindow.getOffset(); + Insets insets = toolBar.getInsets(); + + dragWindow.setBounds((origin.x + position.x) - p.x + - ((insets.left + insets.right) / 2), + (origin.y + position.y) - p.y + - ((insets.top + insets.bottom) / 2), w, h); + + if (! dragWindow.isVisible()) + dragWindow.show(); + } + + /** + * This method is used at the end of a drag session to place the frame in + * either its original parent as a docked JToolBar or in its floating + * frame. + * + * @param position The position of the mouse cursor relative to the + * JToolBar. + * @param origin The screen position of the JToolBar before the drag session + * started. + */ + protected void floatAt(Point position, Point origin) + { + Point p = new Point(position); + int aoc = areaOfClick(origParent, + SwingUtilities.convertPoint(toolBar, p, origParent)); + + Container oldParent = toolBar.getParent(); + + oldParent.remove(toolBar); + oldParent.doLayout(); + oldParent.repaint(); + + Container newParent; + + if (aoc == -1) + newParent = ((RootPaneContainer) floatFrame).getContentPane(); + else + { + floatFrame.hide(); + newParent = origParent; + } + + String constraint; + switch (aoc) + { + case SwingConstants.EAST: + constraint = BorderLayout.EAST; + break; + case SwingConstants.NORTH: + constraint = BorderLayout.NORTH; + break; + case SwingConstants.SOUTH: + constraint = BorderLayout.SOUTH; + break; + case SwingConstants.WEST: + constraint = BorderLayout.WEST; + break; + default: + constraint = BorderLayout.CENTER; + break; + } + + int newOrientation = SwingConstants.HORIZONTAL; + if ((aoc != -1) + && ((aoc == SwingConstants.EAST) || (aoc == SwingConstants.WEST))) + newOrientation = SwingConstants.VERTICAL; + + if (aoc != -1) + { + constraintBeforeFloating = constraint; + lastGoodOrientation = newOrientation; + } + + newParent.add(toolBar, constraint); + + setFloating(aoc == -1, null); + toolBar.setOrientation(newOrientation); + + Insets insets = floatFrame.getInsets(); + Dimension dims = toolBar.getPreferredSize(); + p = dragWindow.getOffset(); + setFloatingLocation((position.x + origin.x) - p.x + - ((insets.left + insets.right) / 2), + (position.y + origin.y) - p.y + - ((insets.top + insets.bottom) / 2)); + + if (aoc == -1) + { + floatFrame.pack(); + floatFrame.setSize(dims.width + insets.left + insets.right, + dims.height + insets.top + insets.bottom); + floatFrame.show(); + } + + newParent.invalidate(); + newParent.validate(); + newParent.repaint(); + } + + /** + * This method returns the docking color. + * + * @return The docking color. + */ + public Color getDockingColor() + { + return dockingColor; + } + + /** + * This method returns the Color which is displayed when over a floating + * area. + * + * @return The color which is displayed when over a floating area. + */ + public Color getFloatingColor() + { + return floatingColor; + } + + /** + * This method returns the maximum size of the given JComponent for this UI. + * + * @param c The JComponent to find the maximum size for. + * + * @return The maximum size for this UI. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum size of the given JComponent for this UI. + * + * @param c The JComponent to find a minimum size for. + * + * @return The minimum size for this UI. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size of the given JComponent for this + * UI. + * + * @param c The JComponent to find a preferred size for. + * + * @return The preferred size for this UI. + */ + public Dimension getPreferredSize(JComponent c) + { + return toolBar.getLayout().preferredLayoutSize(c); + } + + /** + * This method installs the needed components for the JToolBar. + */ + protected void installComponents() + { + floatFrame = (Window) createFloatingWindow(toolBar); + + dragWindow = createDragWindow(toolBar); + + cachedBounds = toolBar.getPreferredSize(); + cachedOrientation = toolBar.getOrientation(); + + nonRolloverBorder = createNonRolloverBorder(); + rolloverBorder = createRolloverBorder(); + + borders = new Hashtable(); + + fillHashtable(); + } + + /** + * This method installs the defaults as specified by the look and feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + toolBar.setBorder(new ToolBarBorder()); + toolBar.setBackground(defaults.getColor("ToolBar.background")); + toolBar.setForeground(defaults.getColor("ToolBar.foreground")); + toolBar.setFont(defaults.getFont("ToolBar.font")); + + dockingBorderColor = defaults.getColor("ToolBar.dockingForeground"); + dockingColor = defaults.getColor("ToolBar.dockingBackground"); + + floatingBorderColor = defaults.getColor("ToolBar.floatingForeground"); + floatingColor = defaults.getColor("ToolBar.floatingBackground"); + } + + /** + * This method installs the keyboard actions for the JToolBar as specified + * by the look and feel. + */ + protected void installKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method installs listeners for the JToolBar. + * + * @param toolbar The JToolBar to register listeners for. + */ + protected void installListeners(JToolBar toolbar) + { + dockingListener = createDockingListener(); + toolBar.addMouseListener(dockingListener); + toolBar.addMouseMotionListener(dockingListener); + + propertyListener = createPropertyListener(); + toolBar.addPropertyChangeListener(propertyListener); + + toolBarContListener = createToolBarContListener(); + toolBar.addContainerListener(toolBarContListener); + + windowListener = createFrameListener(); + floatFrame.addWindowListener(windowListener); + + toolBarFocusListener = createToolBarFocusListener(); + toolBar.addFocusListener(toolBarFocusListener); + } + + /** + * This method installs non rollover borders for each component inside the + * given JComponent. + * + * @param c The JComponent whose children need to have non rollover borders + * installed. + */ + protected void installNonRolloverBorders(JComponent c) + { + Component[] components = toolBar.getComponents(); + + for (int i = 0; i < components.length; i++) + setBorderToNonRollover(components[i]); + } + + /** + * This method installs normal (or their original) borders for each + * component inside the given JComponent. + * + * @param c The JComponent whose children need to have their original + * borders installed. + */ + protected void installNormalBorders(JComponent c) + { + Component[] components = toolBar.getComponents(); + + for (int i = 0; i < components.length; i++) + setBorderToNormal(components[i]); + } + + /** + * This method install rollover borders for each component inside the given + * JComponent. + * + * @param c The JComponent whose children need to have rollover borders + * installed. + */ + protected void installRolloverBorders(JComponent c) + { + Component[] components = toolBar.getComponents(); + + for (int i = 0; i < components.length; i++) + setBorderToRollover(components[i]); + } + + /** + * This method fills the borders hashtable with a list of components that + * are JButtons and their borders. + */ + private void fillHashtable() + { + Component[] c = toolBar.getComponents(); + + for (int i = 0; i < c.length; i++) + { + if (c[i] instanceof JButton) + { + // Don't really care about anything other than JButtons + JButton b = (JButton) c[i]; + + if (b.getBorder() != null) + borders.put(b, b.getBorder()); + } + } + } + + /** + * This method installs the UI for the given JComponent. + * + * @param c The JComponent to install a UI for. + */ + public void installUI(JComponent c) + { + super.installUI(c); + + if (c instanceof JToolBar) + { + toolBar = (JToolBar) c; + toolBar.setOpaque(true); + installDefaults(); + installComponents(); + installListeners(toolBar); + installKeyboardActions(); + } + } + + /** + * This method returns whether the JToolBar is floating. + * + * @return Whether the JToolBar is floating. + */ + public boolean isFloating() + { + return floatFrame.isVisible(); + } + + /** + * This method returns whether rollover borders have been set. + * + * @return Whether rollover borders have been set. + */ + public boolean isRolloverBorders() + { + return toolBar.isRollover(); + } + + /** + * This method navigates in the given direction giving focus to the next + * component in the given direction. + * + * @param direction The direction to give focus to. + */ + protected void navigateFocusedComp(int direction) + { + // FIXME: Implement. + } + + /** + * This method sets the border of the given component to a non rollover + * border. + * + * @param c The Component whose border needs to be set. + */ + protected void setBorderToNonRollover(Component c) + { + if (c instanceof JButton) + { + JButton b = (JButton) c; + b.setRolloverEnabled(false); + b.setBorder(nonRolloverBorder); + } + } + + /** + * This method sets the border of the given component to its original value. + * + * @param c The Component whose border needs to be set. + */ + protected void setBorderToNormal(Component c) + { + if (c instanceof JButton) + { + JButton b = (JButton) c; + Border border = (Border) borders.get(b); + b.setBorder(border); + } + } + + /** + * This method sets the border of the given component to a rollover border. + * + * @param c The Component whose border needs to be set. + */ + protected void setBorderToRollover(Component c) + { + if (c instanceof JButton) + { + JButton b = (JButton) c; + b.setRolloverEnabled(true); + b.setBorder(rolloverBorder); + } + } + + /** + * This method sets the docking color. + * + * @param c The docking color. + */ + public void setDockingColor(Color c) + { + dockingColor = c; + } + + /** + * This method sets the floating property for the JToolBar. + * + * @param b Whether the JToolBar is floating. + * @param p FIXME + */ + public void setFloating(boolean b, Point p) + { + // FIXME: use p for something. It's not location + // since we already have setFloatingLocation. + floatFrame.setVisible(b); + } + + /** + * This method sets the color displayed when the JToolBar is not in a + * dockable area. + * + * @param c The floating color. + */ + public void setFloatingColor(Color c) + { + floatingColor = c; + } + + /** + * This method sets the floating location of the JToolBar. + * + * @param x The x coordinate for the floating frame. + * @param y The y coordinate for the floating frame. + */ + public void setFloatingLocation(int x, int y) + { + // x,y are the coordinates of the new JFrame created to store the toolbar + // XXX: The floating location is bogus is not floating. + floatFrame.setLocation(x, y); + floatFrame.invalidate(); + floatFrame.validate(); + floatFrame.repaint(); + } + + /** + * This is a convenience method for changing the orientation of the + * JToolBar. + * + * @param orientation The new orientation. + */ + public void setOrientation(int orientation) + { + toolBar.setOrientation(orientation); + } + + /** + * This method changes the child components to have rollover borders if the + * given parameter is true. Otherwise, the components are set to have non + * rollover borders. + * + * @param rollover Whether the children will have rollover borders. + */ + public void setRolloverBorders(boolean rollover) + { + if (rollover) + installRolloverBorders(toolBar); + else + installNonRolloverBorders(toolBar); + } + + /** + * This method uninstall UI installed components from the JToolBar. + */ + protected void uninstallComponents() + { + installNormalBorders(toolBar); + borders = null; + rolloverBorder = null; + nonRolloverBorder = null; + cachedBounds = null; + + floatFrame = null; + dragWindow = null; + } + + /** + * This method removes the defaults installed by the Look and Feel. + */ + protected void uninstallDefaults() + { + toolBar.setBackground(null); + toolBar.setForeground(null); + toolBar.setFont(null); + + dockingBorderColor = null; + dockingColor = null; + floatingBorderColor = null; + floatingColor = null; + } + + /** + * This method uninstalls keyboard actions installed by the UI. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method uninstalls listeners installed by the UI. + */ + protected void uninstallListeners() + { + toolBar.removeFocusListener(toolBarFocusListener); + toolBarFocusListener = null; + + floatFrame.removeWindowListener(windowListener); + windowListener = null; + + toolBar.removeContainerListener(toolBarContListener); + toolBarContListener = null; + + toolBar.removeMouseMotionListener(dockingListener); + toolBar.removeMouseListener(dockingListener); + dockingListener = null; + } + + /** + * This method uninstalls the UI. + * + * @param c The JComponent that is having this UI removed. + */ + public void uninstallUI(JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallComponents(); + uninstallDefaults(); + toolBar = null; + } + + /** + * This is the MouseHandler class that allows the user to drag the JToolBar + * in and out of the parent and dock it if it can. + */ + public class DockingListener implements MouseInputListener + { + /** Whether the JToolBar is being dragged. */ + protected boolean isDragging; + + /** + * The origin point. This point is saved from the beginning press and is + * used until the end of the drag session. + */ + protected Point origin; + + /** The JToolBar being dragged. */ + protected JToolBar toolBar; + + /** + * Creates a new DockingListener object. + * + * @param t The JToolBar this DockingListener is being used for. + */ + public DockingListener(JToolBar t) + { + toolBar = t; + } + + /** + * This method is called when the mouse is clicked. + * + * @param e The MouseEvent. + */ + public void mouseClicked(MouseEvent e) + { + // Don't care. + } + + /** + * This method is called when the mouse is dragged. It delegates the drag + * painting to the dragTo method. + * + * @param e The MouseEvent. + */ + public void mouseDragged(MouseEvent e) + { + if (isDragging) + dragTo(e.getPoint(), origin); + } + + /** + * This method is called when the mouse enters the JToolBar. + * + * @param e The MouseEvent. + */ + public void mouseEntered(MouseEvent e) + { + // Don't care (yet). + } + + /** + * This method is called when the mouse exits the JToolBar. + * + * @param e The MouseEvent. + */ + public void mouseExited(MouseEvent e) + { + // Don't care (yet). + } + + /** + * This method is called when the mouse is moved in the JToolBar. + * + * @param e The MouseEvent. + */ + public void mouseMoved(MouseEvent e) + { + } + + /** + * This method is called when the mouse is pressed in the JToolBar. If the + * press doesn't occur in a place where it causes the JToolBar to be + * dragged, it returns. Otherwise, it starts a drag session. + * + * @param e The MouseEvent. + */ + public void mousePressed(MouseEvent e) + { + if (! toolBar.isFloatable()) + return; + + Point ssd = e.getPoint(); + Insets insets = toolBar.getInsets(); + + // Verify that this click occurs in the top inset. + if (toolBar.getOrientation() == SwingConstants.HORIZONTAL) + { + if (e.getX() > insets.left) + return; + } + else + { + if (e.getY() > insets.top) + return; + } + + origin = new Point(0, 0); + SwingUtilities.convertPointToScreen(ssd, toolBar); + + if (! (SwingUtilities.getAncestorOfClass(Window.class, toolBar) instanceof UIResource)) + // Need to know who keeps the toolBar if it gets dragged back into it. + origParent = toolBar.getParent(); + + SwingUtilities.convertPointToScreen(origin, toolBar); + + isDragging = true; + + if (dragWindow != null) + dragWindow.setOffset(new Point(e.getX(), e.getY())); + + dragTo(e.getPoint(), origin); + } + + /** + * This method is called when the mouse is released from the JToolBar. + * + * @param e The MouseEvent. + */ + public void mouseReleased(MouseEvent e) + { + if (! isDragging || ! toolBar.isFloatable()) + return; + + isDragging = false; + floatAt(e.getPoint(), origin); + dragWindow.hide(); + } + } + + /** + * This is the window that appears when the JToolBar is being dragged + * around. + */ + protected class DragWindow extends Window + { + /** + * The current border color. It changes depending on whether the JToolBar + * is over a place that allows it to dock. + */ + private Color borderColor; + + /** The between the mouse and the top left corner of the window. */ + private Point offset; + + /** + * Creates a new DragWindow object. + * This is package-private to avoid an accessor method. + */ + DragWindow() + { + super(owner); + } + + /** + * The color that the border should be. + * + * @return The border color. + */ + public Color getBorderColor() + { + if (borderColor == null) + return Color.BLACK; + + return borderColor; + } + + /** + * This method returns the insets for the DragWindow. + * + * @return The insets for the DragWindow. + */ + public Insets getInsets() + { + // This window has no decorations, so insets are empty. + return new Insets(0, 0, 0, 0); + } + + /** + * This method returns the mouse offset from the top left corner of the + * DragWindow. + * + * @return The mouse offset. + */ + public Point getOffset() + { + return offset; + } + + /** + * This method paints the DragWindow. + * + * @param g The Graphics object to paint with. + */ + public void paint(Graphics g) + { + // No visiting children necessary. + Color saved = g.getColor(); + Rectangle b = getBounds(); + + g.setColor(getBorderColor()); + g.drawRect(0, 0, b.width - 1, b.height - 1); + + g.setColor(saved); + } + + /** + * This method changes the border color. + * + * @param c The new border color. + */ + public void setBorderColor(Color c) + { + borderColor = c; + } + + /** + * This method changes the mouse offset. + * + * @param p The new mouse offset. + */ + public void setOffset(Point p) + { + offset = p; + } + + /** + * FIXME: Do something. + * + * @param o DOCUMENT ME! + */ + public void setOrientation(int o) + { + // FIXME: implement. + } + } + + /** + * This helper class listens for Window events from the floatable window and + * if it is closed, returns the JToolBar to the last known good location. + */ + protected class FrameListener extends WindowAdapter + { + /** + * This method is called when the floating window is closed. + * + * @param e The WindowEvent. + */ + public void windowClosing(WindowEvent e) + { + Container parent = toolBar.getParent(); + parent.remove(toolBar); + + if (origParent != null) + { + origParent.add(toolBar, + (constraintBeforeFloating != null) + ? constraintBeforeFloating : BorderLayout.NORTH); + toolBar.setOrientation(lastGoodOrientation); + } + + origParent.invalidate(); + origParent.validate(); + origParent.repaint(); + } + } + + /** + * This helper class listens for PropertyChangeEvents from the JToolBar. + */ + protected class PropertyListener implements PropertyChangeListener + { + /** + * This method is called when a property from the JToolBar is changed. + * + * @param e The PropertyChangeEvent. + */ + public void propertyChange(PropertyChangeEvent e) + { + // FIXME: need name properties so can change floatFrame title. + if (e.getPropertyName().equals("rollover")) + setRolloverBorders(toolBar.isRollover()); + } + } + + /** + * This helper class listens for components added to and removed from the + * JToolBar. + */ + protected class ToolBarContListener implements ContainerListener + { + /** + * This method is responsible for setting rollover or non rollover for new + * buttons added to the JToolBar. + * + * @param e The ContainerEvent. + */ + public void componentAdded(ContainerEvent e) + { + if (e.getChild() instanceof JButton) + { + JButton b = (JButton) e.getChild(); + + if (b.getBorder() != null) + borders.put(b, b.getBorder()); + } + + if (isRolloverBorders()) + setBorderToRollover(e.getChild()); + else + setBorderToNonRollover(e.getChild()); + + cachedBounds = toolBar.getPreferredSize(); + cachedOrientation = toolBar.getOrientation(); + } + + /** + * This method is responsible for giving the child components their + * original borders when they are removed. + * + * @param e The ContainerEvent. + */ + public void componentRemoved(ContainerEvent e) + { + setBorderToNormal(e.getChild()); + cachedBounds = toolBar.getPreferredSize(); + cachedOrientation = toolBar.getOrientation(); + } + } + + /** + * This is the floating window that is returned when getFloatingWindow is + * called. + */ + private class ToolBarDialog extends JDialog implements UIResource + { + /** + * Creates a new ToolBarDialog object with the name given by the JToolBar. + */ + public ToolBarDialog() + { + super(); + setName((toolBar.getName() != null) ? toolBar.getName() : ""); + } + } + + /** + * DOCUMENT ME! + */ + protected class ToolBarFocusListener implements FocusListener + { + /** + * Creates a new ToolBarFocusListener object. + */ + protected ToolBarFocusListener() + { + // FIXME: implement. + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void focusGained(FocusEvent e) + { + // FIXME: implement. + } + + /** + * DOCUMENT ME! + * + * @param e DOCUMENT ME! + */ + public void focusLost(FocusEvent e) + { + // FIXME: implement. + } + } + + /** + * This helper class acts as the border for the JToolBar. + */ + private static class ToolBarBorder implements Border + { + /** The size of the larger, draggable side of the border. */ + private static final int offset = 10; + + /** The other sides. */ + private static final int regular = 2; + + /** + * This method returns the border insets for the JToolBar. + * + * @param c The Component to find insets for. + * + * @return The border insets. + */ + public Insets getBorderInsets(Component c) + { + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + int orientation = tb.getOrientation(); + + if (! tb.isFloatable()) + return new Insets(regular, regular, regular, regular); + else if (orientation == SwingConstants.HORIZONTAL) + return new Insets(regular, offset, regular, regular); + else + return new Insets(offset, regular, regular, regular); + } + + return new Insets(0, 0, 0, 0); + } + + /** + * This method returns whether the border is opaque. + * + * @return Whether the border is opaque. + */ + public boolean isBorderOpaque() + { + return false; + } + + /** + * This method paints the ribbed area of the border. + * + * @param g The Graphics object to paint with. + * @param x The x coordinate of the area. + * @param y The y coordinate of the area. + * @param w The width of the area. + * @param h The height of the area. + * @param size The size of the bump. + * @param c The color of the bumps. + */ + private void paintBumps(Graphics g, int x, int y, int w, int h, int size, + Color c) + { + Color saved = g.getColor(); + g.setColor(c); + + int hgap = 2 * size; + int vgap = 4 * size; + int count = 0; + + for (int i = x; i < (w + x); i += hgap) + for (int j = ((count++ % 2) == 0) ? y : (y + (2 * size)); j < (h + y); + j += vgap) + g.fillRect(i, j, size, size); + + g.setColor(saved); + } + + /** + * This method paints the border around the given Component. + * + * @param c The Component whose border is being painted. + * @param g The Graphics object to paint with. + * @param x The x coordinate of the component. + * @param y The y coordinate of the component. + * @param width The width of the component. + * @param height The height of the component. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int width, + int height) + { + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + + int orientation = tb.getOrientation(); + + if (orientation == SwingConstants.HORIZONTAL) + { + paintBumps(g, x, y, offset, height, 1, Color.WHITE); + paintBumps(g, x + 1, y + 1, offset - 1, height - 1, 1, Color.GRAY); + } + else + { + paintBumps(g, x, y, width, offset, 1, Color.WHITE); + paintBumps(g, x + 1, y + 1, width - 1, offset - 1, 1, Color.GRAY); + } + } + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java new file mode 100644 index 00000000000..b7a08aa728e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolTipUI.java @@ -0,0 +1,288 @@ +/* BasicToolTipUI.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JToolTip; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ToolTipUI; + +/** + * This is the Basic Look and Feel UI class for JToolTip. + */ +public class BasicToolTipUI extends ToolTipUI +{ + /** The default Border around the JToolTip. */ + private static Border defaultBorder = new Border() + { + // FIXME: This needs to go into Basic Look and Feel + // defaults. + + /** + * This method returns the border insets. + * + * @param c The Component to find Border insets for. + * + * @return The Border insets. + */ + public Insets getBorderInsets(Component c) + { + return new Insets(4, 4, 4, 4); + } + + /** + * This method returns whether the border is opaque. + * + * @return Whether the border is opaque. + */ + public boolean isBorderOpaque() + { + return false; + } + + /** + * This method paints the border. + * + * @param c The Component to paint this border around. + * @param g The Graphics object to paint with. + * @param x The x coordinate to start painting at. + * @param y The y coordinate to start painting at. + * @param w The width of the Component. + * @param h The height of the Component. + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawRect(0, 0, w - 1, h - 1); + + g.setColor(saved); + } + }; + + /** The shared instance of BasicToolTipUI used for all ToolTips. */ + private static BasicToolTipUI shared; + + /** + * Creates a new BasicToolTipUI object. + */ + public BasicToolTipUI() + { + super(); + } + + /** + * This method creates a new BasicToolTip UI for the given + * JComponent. + * + * @param c The JComponent to create a UI for. + * + * @return A BasicToolTipUI that can be used by the given JComponent. + */ + public static ComponentUI createUI(JComponent c) + { + if (shared == null) + shared = new BasicToolTipUI(); + return shared; + } + + /** + * This method returns the msximum size of the given JComponent. + * + * @param c The JComponent to find a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum size of the given JComponent. + * + * @param c The JComponent to find a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size of the given JComponent. + * + * @param c The JComponent to find a preferred size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + JToolTip tip = (JToolTip) c; + Rectangle vr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + Insets insets = tip.getInsets(); + FontMetrics fm = tip.getToolkit().getFontMetrics(tip.getFont()); + SwingUtilities.layoutCompoundLabel(tip, fm, tip.getTipText(), null, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, vr, ir, tr, 0); + return new Dimension(insets.left + tr.width + insets.right, + insets.top + tr.height + insets.bottom); + } + + /** + * This method installs the defaults for the given JComponent. + * + * @param c The JComponent to install defaults for. + */ + protected void installDefaults(JComponent c) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + c.setBackground(defaults.getColor("ToolTip.background")); + c.setForeground(defaults.getColor("ToolTip.foreground")); + c.setFont(defaults.getFont("ToolTip.font")); + c.setBorder(defaultBorder); + } + + /** + * This method installs the listeners for the given JComponent. + * + * @param c The JComponent to install listeners for. + */ + protected void installListeners(JComponent c) + { + } + + /** + * This method installs the UI for the given JComponent. + * + * @param c The JComponent to install the UI for. + */ + public void installUI(JComponent c) + { + c.setOpaque(true); + installDefaults(c); + installListeners(c); + } + + /** + * This method paints the given JComponent with the given Graphics object. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + JToolTip tip = (JToolTip) c; + + String text = tip.getTipText(); + if (text == null) + return; + + Rectangle vr = new Rectangle(); + vr = SwingUtilities.calculateInnerArea(tip, vr); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + FontMetrics fm = tip.getToolkit().getFontMetrics(tip.getFont()); + SwingUtilities.layoutCompoundLabel(tip, fm, tip.getTipText(), null, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, vr, ir, tr, 0); + + Color saved = g.getColor(); + g.setColor(Color.BLACK); + + g.drawString(text, vr.x, vr.y + fm.getAscent()); + + g.setColor(saved); + } + + /** + * This method uninstalls the defaults for the given JComponent. + * + * @param c The JComponent to uninstall defaults for. + */ + protected void uninstallDefaults(JComponent c) + { + c.setForeground(null); + c.setBackground(null); + c.setFont(null); + c.setBorder(null); + } + + /** + * This method uninstalls listeners for the given JComponent. + * + * @param c The JComponent to uninstall listeners for. + */ + protected void uninstallListeners(JComponent c) + { + } + + /** + * This method uninstalls the UI for the given JComponent. + * + * @param c The JComponent to uninstall. + */ + public void uninstallUI(JComponent c) + { + uninstallDefaults(c); + uninstallListeners(c); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java new file mode 100644 index 00000000000..b9d3b629b66 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java @@ -0,0 +1,2813 @@ +/* BasicTreeUI.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.CellRendererPane; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.MouseInputListener; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TreeUI; +import javax.swing.tree.AbstractLayoutCache; +import javax.swing.tree.FixedHeightLayoutCache; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellEditor; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellEditor; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeSelectionModel; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import java.util.Enumeration; +import java.util.Hashtable; + +/** + * A delegate providing the user interface for <code>JTree</code> according to + * the Basic look and feel. + * + * @see javax.swing.JTree + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Lillian Angel (langel@redhat.com) + */ +public class BasicTreeUI + extends TreeUI +{ + + /** Collapse Icon for the tree. */ + protected transient Icon collapsedIcon; + + /** Expanded Icon for the tree. */ + protected transient Icon expandedIcon; + + /** Distance between left margin and where vertical dashes will be drawn. */ + protected int leftChildIndent; + + /** + * Distance between leftChildIndent and where cell contents will be drawn. + */ + protected int rightChildIndent; + + /** + * Total fistance that will be indented. The sum of leftChildIndent and + * rightChildIndent . + */ + protected int totalChildIndent; + + /** Minimum preferred size. */ + protected Dimension preferredMinsize; + + /** Index of the row that was last selected. */ + protected int lastSelectedRow; + + /** Component that we're going to be drawing onto. */ + protected JTree tree; + + /** Renderer that is being used to do the actual cell drawing. */ + protected transient TreeCellRenderer currentCellRenderer; + + /** + * Set to true if the renderer that is currently in the tree was created by + * this instance. + */ + protected boolean createdRenderer; + + /** Editor for the tree. */ + protected transient TreeCellEditor cellEditor; + + /** + * Set to true if editor that is currently in the tree was created by this + * instance. + */ + protected boolean createdCellEditor; + + /** + * Set to false when editing and shouldSelectCall() returns true meaning the + * node should be selected before editing, used in completeEditing. + */ + protected boolean stopEditingInCompleteEditing; + + /** Used to paint the TreeCellRenderer. */ + protected CellRendererPane rendererPane; + + /** Size needed to completely display all the nodes. */ + protected Dimension preferredSize; + + /** Is the preferredSize valid? */ + protected boolean validCachedPreferredSize; + + /** Object responsible for handling sizing and expanded issues. */ + protected AbstractLayoutCache treeState; + + /** Used for minimizing the drawing of vertical lines. */ + protected Hashtable drawingCache; + + /** + * True if doing optimizations for a largeModel. Subclasses that don't + * support this may wish to override createLayoutCache to not return a + * FixedHeightLayoutCache instance. + */ + protected boolean largeModel; + + /** Responsible for telling the TreeState the size needed for a node. */ + protected AbstractLayoutCache.NodeDimensions nodeDimensions; + + /** Used to determine what to display. */ + protected TreeModel treeModel; + + /** Model maintaining the selection. */ + protected TreeSelectionModel treeSelectionModel; + + /** + * How much the depth should be offset to properly calculate x locations. + * This is based on whether or not the root is visible, and if the root + * handles are visible. + */ + protected int depthOffset; + + /** + * When editing, this will be the Component that is doing the actual editing. + */ + protected Component editingComponent; + + /** Path that is being edited. */ + protected TreePath editingPath; + + /** + * Row that is being edited. Should only be referenced if editingComponent is + * null. + */ + protected int editingRow; + + /** Set to true if the editor has a different size than the renderer. */ + protected boolean editorHasDifferentSize; + + /** Listeners */ + private PropertyChangeListener propertyChangeListener; + + private FocusListener focusListener; + + private TreeSelectionListener treeSelectionListener; + + private MouseInputListener mouseInputListener; + + private KeyListener keyListener; + + private PropertyChangeListener selectionModelPropertyChangeListener; + + private ComponentListener componentListener; + + private CellEditorListener cellEditorListener; + + private TreeExpansionListener treeExpansionListener; + + private TreeModelListener treeModelListener; + + /** + * Creates a new BasicTreeUI object. + */ + public BasicTreeUI() + { + drawingCache = new Hashtable(); + cellEditor = createDefaultCellEditor(); + currentCellRenderer = createDefaultCellRenderer(); + nodeDimensions = createNodeDimensions(); + rendererPane = createCellRendererPane(); + configureLayoutCache(); + + propertyChangeListener = createPropertyChangeListener(); + focusListener = createFocusListener(); + treeSelectionListener = createTreeSelectionListener(); + mouseInputListener = new MouseInputHandler(null, null, null); + keyListener = createKeyListener(); + selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener(); + componentListener = createComponentListener(); + cellEditorListener = createCellEditorListener(); + treeExpansionListener = createTreeExpansionListener(); + treeModelListener = createTreeModelListener(); + + createdRenderer = true; + createdCellEditor = true; + editingRow = -1; + lastSelectedRow = -1; + } + + /** + * Returns an instance of the UI delegate for the specified component. + * + * @param c the <code>JComponent</code> for which we need a UI delegate + * for. + * @return the <code>ComponentUI</code> for c. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicTreeUI(); + } + + /** + * Returns the Hash color. + * + * @return the <code>Color</code> of the Hash. + */ + protected Color getHashColor() + { + return UIManager.getLookAndFeelDefaults().getColor("Tree.hash"); + } + + /** + * Sets the Hash color. + * + * @param the <code>Color</code> to set the Hash to. + */ + protected void setHashColor(Color color) + { + // FIXME: not implemented + + } + + /** + * Sets the left child's indent value. + * + * @param newAmount is the new indent value for the left child. + */ + public void setLeftChildIndent(int newAmount) + { + leftChildIndent = newAmount; + } + + /** + * Returns the indent value for the left child. + * + * @return the indent value for the left child. + */ + public int getLeftChildIndent(int newAmount) + { + return leftChildIndent; + } + + /** + * Sets the right child's indent value. + * + * @param newAmount is the new indent value for the right child. + */ + public void setRightChildIndent(int newAmount) + { + rightChildIndent = newAmount; + } + + /** + * Returns the indent value for the right child. + * + * @return the indent value for the right child. + */ + public int getRightChildIndent(int newAmount) + { + return rightChildIndent; + } + + /** + * Sets the expanded icon. + * + * @param newG is the new expanded icon. + */ + public void setExpandedIcon(Icon newG) + { + expandedIcon = newG; + } + + /** + * Returns the current expanded icon. + * + * @return the current expanded icon. + */ + public Icon getExpandedIcon() + { + return expandedIcon; + } + + /** + * Sets the collapsed icon. + * + * @param newG is the new collapsed icon. + */ + public void setCollapsedIcon(Icon newG) + { + collapsedIcon = newG; + } + + /** + * Returns the current collapsed icon. + * + * @return the current collapsed icon. + */ + public Icon getCollapsedIcon() + { + return collapsedIcon; + } + + /** + * Updates the componentListener, if necessary. + * + * @param largeModel sets this.largeModel to it. + */ + protected void setLargeModel(boolean largeModel) + { + if (largeModel != this.largeModel) + { + tree.removeComponentListener(componentListener); + this.largeModel = largeModel; + tree.addComponentListener(componentListener); + } + } + + /** + * Returns true if largeModel is set + * + * @return true if largeModel is set, otherwise false. + */ + protected boolean isLargeModel() + { + return largeModel; + } + + /** + * Sets the row height. + * + * @param rowHeight is the height to set this.rowHeight to. + */ + protected void setRowHeight(int rowHeight) + { + treeState.setRowHeight(rowHeight); + } + + /** + * Returns the current row height. + * + * @return current row height. + */ + protected int getRowHeight() + { + return treeState.getRowHeight(); + } + + /** + * Sets the TreeCellRenderer to <code>tcr</code>. This invokes + * <code>updateRenderer</code>. + * + * @param tcr is the new TreeCellRenderer. + */ + protected void setCellRenderer(TreeCellRenderer tcr) + { + currentCellRenderer = tcr; + updateRenderer(); + } + + /** + * Return currentCellRenderer, which will either be the trees renderer, or + * defaultCellRenderer, which ever was not null. + * + * @return the current Cell Renderer + */ + protected TreeCellRenderer getCellRenderer() + { + if (currentCellRenderer != null) + return currentCellRenderer; + + return createDefaultCellRenderer(); + } + + /** + * Sets the tree's model. + * + * @param model to set the treeModel to. + */ + protected void setModel(TreeModel model) + { + treeState.setModel(model); + treeModel = model; + } + + /** + * Returns the tree's model + * + * @return treeModel + */ + protected TreeModel getModel() + { + return treeModel; + } + + /** + * Sets the root to being visible. + * + * @param newValue sets the visibility of the root + */ + protected void setRootVisible(boolean newValue) + { + treeState.setRootVisible(newValue); + } + + /** + * Returns true if the root is visible. + * + * @return true if the root is visible. + */ + protected boolean isRootVisible() + { + return treeState.isRootVisible(); + } + + /** + * Determines whether the node handles are to be displayed. + * + * @param newValue sets whether or not node handles should be displayed. + */ + protected void setShowsRootHandles(boolean newValue) + { + tree.setShowsRootHandles(newValue); + } + + /** + * Returns true if the node handles are to be displayed. + * + * @return true if the node handles are to be displayed. + */ + protected boolean getShowsRootHandles() + { + return tree.getShowsRootHandles(); + } + + /** + * Sets the cell editor. + * + * @param editor to set the cellEditor to. + */ + protected void setCellEditor(TreeCellEditor editor) + { + cellEditor = editor; + } + + /** + * Returns the <code>TreeCellEditor</code> for this tree. + * + * @return the cellEditor for this tree. + */ + protected TreeCellEditor getCellEditor() + { + return cellEditor; + } + + /** + * Configures the receiver to allow, or not allow, editing. + * + * @param newValue sets the receiver to allow editing if true. + */ + protected void setEditable(boolean newValue) + { + tree.setEditable(newValue); + } + + /** + * Returns true if the receiver allows editing. + * + * @return true if the receiver allows editing. + */ + protected boolean isEditable() + { + return tree.isEditable(); + } + + /** + * Resets the selection model. The appropriate listeners are installed on the + * model. + * + * @param newLSM resets the selection model. + */ + protected void setSelectionModel(TreeSelectionModel newLSM) + { + if (newLSM != null) + { + treeSelectionModel = newLSM; + tree.setSelectionModel(treeSelectionModel); + } + } + + /** + * Returns the current selection model. + * + * @return the current selection model. + */ + protected TreeSelectionModel getSelectionModel() + { + return treeSelectionModel; + } + + /** + * Returns the Rectangle enclosing the label portion that the last item in + * path will be drawn to. Will return null if any component in path is + * currently valid. + * + * @param tree is the current tree the path will be drawn to. + * @param path is the current path the tree to draw to. + * @return the Rectangle enclosing the label portion that the last item in + * the path will be drawn to. + */ + public Rectangle getPathBounds(JTree tree, TreePath path) + { + Object cell = path.getLastPathComponent(); + TreeModel mod = tree.getModel(); + Point loc = getCellLocation(0, 0, tree, mod, cell, mod.getRoot()); + int x = (int) loc.getX(); + int y = (int) loc.getY(); + return getCellBounds(x, y, cell); + } + + /** + * Returns the path for passed in row. If row is not visible null is + * returned. + * + * @param tree is the current tree to return path for. + * @param row is the row number of the row to return. + * @return the path for passed in row. If row is not visible null is + * returned. + */ + public TreePath getPathForRow(JTree tree, int row) + { + DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel()) + .getRoot()); + + for (int i = 0; i < row; i++) + node = getNextVisibleNode(node); + + // in case nothing was found + if (node == null) + return null; + + // something was found + return new TreePath(node.getPath()); + } + + /** + * Get next visible node in the tree. + * Package private for use in inner classes. + * @param the current node + * @return the next visible node in the JTree. Return null if there are no + * more. + */ + DefaultMutableTreeNode getNextVisibleNode(DefaultMutableTreeNode node) + { + DefaultMutableTreeNode next = null; + TreePath current = null; + + if (node != null) + next = node.getNextNode(); + + if (next != null) + { + current = new TreePath(next.getPath()); + if (tree.isVisible(current)) + return next; + + while (next != null && !tree.isVisible(current)) + { + next = next.getNextNode(); + + if (next != null) + current = new TreePath(next.getPath()); + } + } + return next; + } + + /** + * Get previous visible node in the tree. + * Package private for use in inner classes. + * + * @param the current node + * @return the next visible node in the JTree. Return null if there are no + * more. + */ + DefaultMutableTreeNode getPreviousVisibleNode + (DefaultMutableTreeNode node) + { + DefaultMutableTreeNode prev = null; + TreePath current = null; + + if (node != null) + prev = node.getPreviousNode(); + + if (prev != null) + { + current = new TreePath(prev.getPath()); + if (tree.isVisible(current)) + return prev; + + while (prev != null && !tree.isVisible(current)) + { + prev = prev.getPreviousNode(); + + if (prev != null) + current = new TreePath(prev.getPath()); + } + } + return prev; + } + + /** + * Returns the row that the last item identified in path is visible at. Will + * return -1 if any of the elments in the path are not currently visible. + * + * @param tree is the current tree to return the row for. + * @param path is the path used to find the row. + * @return the row that the last item identified in path is visible at. Will + * return -1 if any of the elments in the path are not currently + * visible. + */ + public int getRowForPath(JTree tree, TreePath path) + { + // FIXME: check visibility + // right now, just returns last element because + // expand/collapse is not implemented + return path.getPathCount() - 1; + } + + /** + * Returns the number of rows that are being displayed. + * + * @param tree is the current tree to return the number of rows for. + * @return the number of rows being displayed. + */ + public int getRowCount(JTree tree) + { + DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel()) + .getRoot()); + int count = 0; + + while (node != null) + { + count++; + node = getNextVisibleNode(node); + } + + return count; + } + + /** + * Returns the path to the node that is closest to x,y. If there is nothing + * currently visible this will return null, otherwise it'll always return a + * valid path. If you need to test if the returned object is exactly at x,y + * you should get the bounds for the returned path and test x,y against that. + * + * @param tree the tree to search for the closest path + * @param x is the x coordinate of the location to search + * @param y is the y coordinate of the location to search + * @return the tree path closes to x,y. + */ + public TreePath getClosestPathForLocation(JTree tree, int x, int y) + { + return treeState.getPathClosestTo(x, y); + } + + /** + * Returns true if the tree is being edited. The item that is being edited + * can be returned by getEditingPath(). + * + * @param tree is the tree to check for editing. + * @return true if the tree is being edited. + */ + public boolean isEditing(JTree tree) + { + // FIXME: not implemented + return false; + } + + /** + * Stops the current editing session. This has no effect if the tree is not + * being edited. Returns true if the editor allows the editing session to + * stop. + * + * @param tree is the tree to stop the editing on + * @return true if the editor allows the editing session to stop. + */ + public boolean stopEditing(JTree tree) + { + // FIXME: not implemented + return false; + } + + /** + * Cancels the current editing session. + * + * @param tree is the tree to cancel the editing session on. + */ + public void cancelEditing(JTree tree) + { + // FIXME: not implemented + } + + /** + * Selects the last item in path and tries to edit it. Editing will fail if + * the CellEditor won't allow it for the selected item. + * + * @param tree is the tree to edit on. + * @param path is the path in tree to edit on. + */ + public void startEditingAtPath(JTree tree, TreePath path) + { + // FIXME: not implemented + } + + /** + * Returns the path to the element that is being editted. + * + * @param tree is the tree to get the editing path from. + * @return the path that is being edited. + */ + public TreePath getEditingPath(JTree tree) + { + // FIXME: not implemented + return null; + } + + /** + * Invoked after the tree instance variable has been set, but before any + * default/listeners have been installed. + */ + protected void prepareForUIInstall() + { + // FIXME: not implemented + } + + /** + * Invoked from installUI after all the defaults/listeners have been + * installed. + */ + protected void completeUIInstall() + { + // FIXME: not implemented + } + + /** + * Invoked from uninstallUI after all the defaults/listeners have been + * uninstalled. + */ + protected void completeUIUninstall() + { + // FIXME: not implemented + } + + /** + * Installs the subcomponents of the tree, which is the renderer pane. + */ + protected void installComponents() + { + // FIXME: not implemented + } + + /** + * Creates an instance of NodeDimensions that is able to determine the size + * of a given node in the tree. + * + * @return the NodeDimensions of a given node in the tree + */ + protected AbstractLayoutCache.NodeDimensions createNodeDimensions() + { + // FIXME: not implemented + return null; + } + + /** + * Creates a listener that is reponsible for the updates the UI based on how + * the tree changes. + * + * @return the PropertyChangeListener that is reposnsible for the updates + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * Creates the listener responsible for updating the selection based on mouse + * events. + * + * @return the MouseListener responsible for updating. + */ + protected MouseListener createMouseListener() + { + return new MouseHandler(); + } + + /** + * Creates the listener that is responsible for updating the display when + * focus is lost/grained. + * + * @return the FocusListener responsible for updating. + */ + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + + /** + * Creates the listener reponsible for getting key events from the tree. + * + * @return the KeyListener responsible for getting key events. + */ + protected KeyListener createKeyListener() + { + return new KeyHandler(); + } + + /** + * Creates the listener responsible for getting property change events from + * the selection model. + * + * @returns the PropertyChangeListener reponsible for getting property change + * events from the selection model. + */ + protected PropertyChangeListener createSelectionModelPropertyChangeListener() + { + return new SelectionModelPropertyChangeHandler(); + } + + /** + * Creates the listener that updates the display based on selection change + * methods. + * + * @return the TreeSelectionListener responsible for updating. + */ + protected TreeSelectionListener createTreeSelectionListener() + { + return new TreeSelectionHandler(); + } + + /** + * Creates a listener to handle events from the current editor + * + * @return the CellEditorListener that handles events from the current editor + */ + protected CellEditorListener createCellEditorListener() + { + return new CellEditorHandler(); + } + + /** + * Creates and returns a new ComponentHandler. This is used for the large + * model to mark the validCachedPreferredSize as invalid when the component + * moves. + * + * @return a new ComponentHandler. + */ + protected ComponentListener createComponentListener() + { + return new ComponentHandler(); + } + + /** + * Creates and returns the object responsible for updating the treestate when + * a nodes expanded state changes. + * + * @return the TreeExpansionListener responsible for updating the treestate + */ + protected TreeExpansionListener createTreeExpansionListener() + { + return new TreeExpansionHandler(); + } + + /** + * Creates the object responsible for managing what is expanded, as well as + * the size of nodes. + * + * @return the object responsible for managing what is expanded. + */ + protected AbstractLayoutCache createLayoutCache() + { + return new FixedHeightLayoutCache(); + } + + /** + * Returns the renderer pane that renderer components are placed in. + * + * @return the rendererpane that render components are placed in. + */ + protected CellRendererPane createCellRendererPane() + { + return new CellRendererPane(); + } + + /** + * Creates a default cell editor. + * + * @return the default cell editor. + */ + protected TreeCellEditor createDefaultCellEditor() + { + return new DefaultTreeCellEditor(tree, + (DefaultTreeCellRenderer) createDefaultCellRenderer(), cellEditor); + } + + /** + * Returns the default cell renderer that is used to do the stamping of each + * node. + * + * @return the default cell renderer that is used to do the stamping of each + * node. + */ + protected TreeCellRenderer createDefaultCellRenderer() + { + return new DefaultTreeCellRenderer(); + } + + /** + * Returns a listener that can update the tree when the model changes. + * + * @return a listener that can update the tree when the model changes. + */ + protected TreeModelListener createTreeModelListener() + { + return new TreeModelHandler(); + } + + /** + * Uninstall all registered listeners + */ + protected void uninstallListeners() + { + tree.removePropertyChangeListener(propertyChangeListener); + tree.removeFocusListener(focusListener); + tree.removeTreeSelectionListener(treeSelectionListener); + tree.removeMouseListener(mouseInputListener); + tree.removeKeyListener(keyListener); + tree.removePropertyChangeListener(selectionModelPropertyChangeListener); + tree.removeComponentListener(componentListener); + tree.getCellEditor().removeCellEditorListener(cellEditorListener); + tree.removeTreeExpansionListener(treeExpansionListener); + tree.getModel().removeTreeModelListener(treeModelListener); + } + + /** + * Uninstall all keyboard actions. + */ + protected void uninstallKeyboardActions() + { + } + + /** + * Uninstall the rendererPane. + */ + protected void uninstallComponents() + { + // FIXME: not implemented + } + + /** + * The vertical element of legs between nodes starts at the bottom of the + * parent node by default. This method makes the leg start below that. + * + * @return the vertical leg buffer + */ + protected int getVerticalLegBuffer() + { + // FIXME: not implemented + return 0; + } + + /** + * The horizontal element of legs between nodes starts at the right of the + * left-hand side of the child node by default. This method makes the leg end + * before that. + * + * @return the horizontal leg buffer + */ + protected int getHorizontalLegBuffer() + { + // FIXME: not implemented + return 0; + } + + /** + * Make all the nodes that are expanded in JTree expanded in LayoutCache. + * This invokes update ExpandedDescendants with the root path. + */ + protected void updateLayoutCacheExpandedNodes() + { + // FIXME: not implemented + } + + /** + * Updates the expanded state of all the descendants of the <code>path</code> + * by getting the expanded descendants from the tree and forwarding to the + * tree state. + * + * @param path the path used to update the expanded states + */ + protected void updateExpandedDescendants(TreePath path) + { + // FIXME: not implemented + } + + /** + * Returns a path to the last child of <code>parent</code> + * + * @param parent is the topmost path to specified + * @return a path to the last child of parent + */ + protected TreePath getLastChildPath(TreePath parent) + { + return ((TreePath) parent.getLastPathComponent()); + } + + /** + * Updates how much each depth should be offset by. + */ + protected void updateDepthOffset() + { + // FIXME: not implemented + } + + /** + * Updates the cellEditor based on editability of the JTree that we're + * contained in. Ig the tree is editable but doesn't have a cellEditor, a + * basic one will be used. + */ + protected void updateCellEditor() + { + // FIXME: not implemented + } + + /** + * Messaged from the tree we're in when the renderer has changed. + */ + protected void updateRenderer() + { + // FIXME: not implemented + } + + /** + * Resets the treeState instance based on the tree we're providing the look + * and feel for. + */ + protected void configureLayoutCache() + { + treeState = createLayoutCache(); + } + + /** + * Marks the cached size as being invalid, and messages the tree with + * <code>treeDidChange</code>. + */ + protected void updateSize() + { + // FIXME: not implemented + } + + /** + * Updates the <code>preferredSize</code> instance variable, which is + * returned from <code>getPreferredSize()</code>. For left to right + * orientations, the size is determined from the current AbstractLayoutCache. + * For RTL orientations, the preferred size becomes the width minus the + * minimum x position. + */ + protected void updateCachedPreferredSize() + { + // FIXME: not implemented + } + + /** + * Messaged from the VisibleTreeNode after it has been expanded. + * + * @param path is the path that has been expanded. + */ + protected void pathWasExpanded(TreePath path) + { + // FIXME: not implemented + } + + /** + * Messaged from the VisibleTreeNode after it has collapsed + */ + protected void pathWasCollapsed(TreePath path) + { + // FIXME: not implemented + } + + /** + * Install all defaults for the tree. + * + * @param tree is the JTree to install defaults for + */ + protected void installDefaults(JTree tree) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + tree.setFont(defaults.getFont("Tree.font")); + tree.setForeground(defaults.getColor("Tree.foreground")); + tree.setBackground(defaults.getColor("Tree.background")); + tree.setOpaque(true); + + rightChildIndent = defaults.getInt("Tree.rightChildIndent"); + leftChildIndent = defaults.getInt("Tree.leftChildIndent"); + setRowHeight(defaults.getInt("Tree.rowHeight")); + } + + /** + * Install all keyboard actions for this + */ + protected void installKeyboardActions() + { + } + + /** + * Install all listeners for this + */ + protected void installListeners() + { + tree.addPropertyChangeListener(propertyChangeListener); + tree.addFocusListener(focusListener); + tree.addTreeSelectionListener(treeSelectionListener); + tree.addMouseListener(mouseInputListener); + tree.addKeyListener(keyListener); + tree.addPropertyChangeListener(selectionModelPropertyChangeListener); + tree.addComponentListener(componentListener); + cellEditor.addCellEditorListener(cellEditorListener); + tree.addTreeExpansionListener(treeExpansionListener); + treeModel.addTreeModelListener(treeModelListener); + } + + /** + * Install the UI for the component + * + * @param c the component to install UI for + */ + public void installUI(JComponent c) + { + super.installUI(c); + installDefaults((JTree) c); + tree = (JTree) c; + setModel(tree.getModel()); + tree.setRootVisible(true); + tree.expandPath(new TreePath(((DefaultMutableTreeNode) + (tree.getModel()).getRoot()).getPath())); + treeSelectionModel = tree.getSelectionModel(); + installListeners(); + installKeyboardActions(); + completeUIInstall(); + } + + /** + * Uninstall the defaults for the tree + * + * @param tree to uninstall defaults for + */ + protected void uninstallDefaults(JTree tree) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + tree.setFont(null); + tree.setForeground(null); + tree.setBackground(null); + tree.setCellRenderer(null); + } + + /** + * Uninstall the UI for the component + * + * @param c the component to uninstall UI for + */ + public void uninstallUI(JComponent c) + { + uninstallDefaults((JTree) c); + uninstallKeyboardActions(); + uninstallListeners(); + tree = null; + completeUIUninstall(); + } + + /** + * Paints the specified component appropriate for the look and feel. This + * method is invoked from the ComponentUI.update method when the specified + * component is being painted. Subclasses should override this method and use + * the specified Graphics object to render the content of the component. + * + * @param g the Graphics context in which to paint + * @param c the component being painted; this argument is often ignored, but + * might be used if the UI object is stateless and shared by multiple + * components + */ + public void paint(Graphics g, JComponent c) + { + JTree tree = (JTree) c; + TreeModel mod = tree.getModel(); + g.translate(10, 10); + paintRecursive(g, 0, 0, 0, 0, tree, mod, mod.getRoot()); + paintControlIcons(g, 0, 0, 0, 0, tree, mod, mod.getRoot()); + g.translate(-10, -10); + } + + /** + * Ensures that the rows identified by beginRow through endRow are visible. + * + * @param beginRow is the first row + * @param endRow is the last row + */ + protected void ensureRowsAreVisible(int beginRow, int endRow) + { + // FIXME: not implemented + } + + /** + * Sets the preferred minimum size. + * + * @param newSize is the new preferred minimum size. + */ + public void setPreferredMinSize(Dimension newSize) + { + // FIXME: not implemented + } + + /** + * Gets the preferred minimum size. + * + * @returns the preferred minimum size. + */ + public Dimension getPreferredMinSize() + { + // FIXME: not implemented + return null; + } + + /** + * Returns the preferred size to properly display the tree, this is a cover + * method for getPreferredSize(c, false). + * + * @param c the component whose preferred size is being queried; this + * argument is often ignored but might be used if the UI object is + * stateless and shared by multiple components + * @return the preferred size + */ + public Dimension getPreferredSize(JComponent c) + { + return getPreferredSize(c, false); + } + + /** + * Returns the preferred size to represent the tree in c. If checkConsistancy + * is true, checkConsistancy is messaged first. + * + * @param c the component whose preferred size is being queried. + * @param checkConsistancy if true must check consistancy + * @return the preferred size + */ + public Dimension getPreferredSize(JComponent c, boolean checkConsistancy) + { + // FIXME: checkConsistancy not implemented, c not used + DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel()) + .getRoot()); + int maxWidth = 0; + int count = 0; + if (node != null) + { + maxWidth = (int) (getCellBounds(0, 0, node).getWidth()); + while (node != null) + { + count++; + DefaultMutableTreeNode nextNode = node.getNextNode(); + if (nextNode != null) + maxWidth = Math.max(maxWidth, (int) (getCellBounds(0, 0, nextNode) + .getWidth())); + node = nextNode; + } + } + + return new Dimension(maxWidth, (getRowHeight() * count)); + } + + /** + * Returns the minimum size for this component. Which will be the min + * preferred size or (0,0). + * + * @param c the component whose min size is being queried. + * @returns the preferred size or null + */ + public Dimension getMinimumSize(JComponent c) + { + // FIXME: not implemented + return getPreferredSize(c); + } + + /** + * Returns the maximum size for the component, which will be the preferred + * size if the instance is currently in JTree or (0,0). + * + * @param c the component whose preferred size is being queried + * @return the max size or null + */ + public Dimension getMaximumSize(JComponent c) + { + // FIXME: not implemented + return getPreferredSize(c); + } + + /** + * Messages to stop the editing session. If the UI the receiver is providing + * the look and feel for returns true from + * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked + * on the current editor. Then completeEditing will be messaged with false, + * true, false to cancel any lingering editing. + */ + protected void completeEditing() + { + // FIXME: not implemented + } + + /** + * Stops the editing session. If messageStop is true, the editor is messaged + * with stopEditing, if messageCancel is true the editor is messaged with + * cancelEditing. If messageTree is true, the treeModel is messaged with + * valueForPathChanged. + * + * @param messageStop message to stop editing + * @param messageCancel message to cancel editing + * @param messageTree message to treeModel + */ + protected void completeEditing(boolean messageStop, boolean messageCancel, + boolean messageTree) + { + // FIXME: not implemented + } + + /** + * Will start editing for node if there is a cellEditor and shouldSelectCall + * returns true. This assumes that path is valid and visible. + * + * @param path is the path to start editing + * @param event is the MouseEvent performed on the path + * @return true if successful + */ + protected boolean startEditing(TreePath path, MouseEvent event) + { + // FIXME: not implemented + return false; + } + + /** + * If the <code>mouseX</code> and <code>mouseY</code> are in the expand + * or collapse region of the row, this will toggle the row. + * + * @param path the path we are concerned with + * @param mouseX is the cursor's x position + * @param mouseY is the cursor's y position + */ + protected void checkForClickInExpandControl(TreePath path, int mouseX, + int mouseY) + { + // FIXME: not implemented + } + + /** + * Returns true if the <code>mouseX</code> and <code>mouseY</code> fall + * in the area of row that is used to expand/collpse the node and the node at + * row does not represent a leaf. + * + * @param path the path we are concerned with + * @param mouseX is the cursor's x position + * @param mouseY is the cursor's y position + * @return true if the <code>mouseX</code> and <code>mouseY</code> fall + * in the area of row that is used to expand/collpse the node and the + * node at row does not represent a leaf. + */ + protected boolean isLocationInExpandControl(TreePath path, int mouseX, + int mouseY) + { + // FIXME: not implemented + return false; + } + + /** + * Messaged when the user clicks the particular row, this invokes + * toggleExpandState. + * + * @param path the path we are concerned with + * @param mouseX is the cursor's x position + * @param mouseY is the cursor's y position + */ + protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY) + { + // FIXME: not implemented + } + + /** + * Expands path if it is not expanded, or collapses row if it is expanded. If + * expanding a path and JTree scroll on expand, ensureRowsAreVisible is + * invoked to scroll as many of the children to visible as possible (tries to + * scroll to last visible descendant of path). + * + * @param path the path we are concerned with + */ + protected void toggleExpandState(TreePath path) + { + // FIXME: not implemented + } + + /** + * Returning true signifies a mouse event on the node should toggle the + * selection of only the row under the mouse. + * + * @param event is the MouseEvent performed on the row. + * @return true signifies a mouse event on the node should toggle the + * selection of only the row under the mouse. + */ + protected boolean isToggleSelectionEvent(MouseEvent event) + { + // FIXME: not implemented + return false; + } + + /** + * Returning true signifies a mouse event on the node should select from the + * anchor point. + * + * @param event is the MouseEvent performed on the node. + * @return true signifies a mouse event on the node should select from the + * anchor point. + */ + protected boolean isMultiSelectEvent(MouseEvent event) + { + // FIXME: not implemented + return false; + } + + /** + * Returning true indicates the row under the mouse should be toggled based + * on the event. This is invoked after checkForClickInExpandControl, implying + * the location is not in the expand (toggle) control. + * + * @param event is the MouseEvent performed on the row. + * @return true indicates the row under the mouse should be toggled based on + * the event. + */ + protected boolean isToggleEvent(MouseEvent event) + { + // FIXME: not implemented + return false; + } + + /** + * Messaged to update the selection based on a MouseEvent over a particular + * row. If the even is a toggle selection event, the row is either selected, + * or deselected. If the event identifies a multi selection event, the + * selection is updated from the anchor point. Otherwise, the row is + * selected, and if the even specified a toggle event the row is + * expanded/collapsed. + * + * @param path is the path selected for an event + * @param event is the MouseEvent performed on the path. + */ + protected void selectPathForEvent(TreePath path, MouseEvent event) + { + // FIXME: not implemented + } + + /** + * Returns true if the node at <code>row</code> is a leaf. + * + * @param row is the row we are concerned with. + * @return true if the node at <code>row</code> is a leaf. + */ + protected boolean isLeaf(int row) + { + TreePath pathForRow = getPathForRow(tree, row); + if (pathForRow == null) + return true; + + Object node = pathForRow.getLastPathComponent(); + + if (node instanceof TreeNode) + return ((TreeNode) node).isLeaf(); + else + return true; + } + + /** + * Selects the specified path in the tree depending on modes. + * Package private for use in inner classes. + * + * @param tree is the tree we are selecting the path in + * @param path is the path we are selecting + */ + void selectPath(JTree tree, TreePath path) + { + if (path != null) + { + if (tree.isPathSelected(path)) + tree.removeSelectionPath(path); + else if (tree.getSelectionModel().getSelectionMode() + == TreeSelectionModel.SINGLE_TREE_SELECTION) + { + tree.getSelectionModel().clearSelection(); + tree.addSelectionPath(path); + tree.setLeadSelectionPath(path); + } + else if (tree.getSelectionModel().getSelectionMode() + == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) + { + // TODO + } + else + { + tree.getSelectionModel().setSelectionMode( + TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); + tree.addSelectionPath(path); + tree.setLeadSelectionPath(path); + } + } + } + + /* * INTERNAL CLASSES * */ + + /** + * Updates the preferred size when scrolling, if necessary. + */ + public class ComponentHandler + extends ComponentAdapter + implements ActionListener + { + /** + * Timer used when inside a scrollpane and the scrollbar is adjusting + */ + protected Timer timer; + + /** ScrollBar that is being adjusted */ + protected JScrollBar scrollBar; + + /** + * Constructor + */ + public ComponentHandler() + { + } + + /** + * Invoked when the component's position changes. + * + * @param e the event that occurs when moving the component + */ + public void componentMoved(ComponentEvent e) + { + } + + /** + * Creats, if necessary, and starts a Timer to check if needed to resize + * the bounds + */ + protected void startTimer() + { + } + + /** + * Returns the JScrollPane housing the JTree, or null if one isn't found. + * + * @return JScrollPane housing the JTree, or null if one isn't found. + */ + protected JScrollPane getScrollPane() + { + return null; + } + + /** + * Public as a result of Timer. If the scrollBar is null, or not + * adjusting, this stops the timer and updates the sizing. + * + * @param ae is the action performed + */ + public void actionPerformed(ActionEvent ae) + { + } + }// ComponentHandler + + /** + * Listener responsible for getting cell editing events and updating the tree + * accordingly. + */ + public class CellEditorHandler + implements CellEditorListener + { + /** + * Constructor + */ + public CellEditorHandler() + { + } + + /** + * Messaged when editing has stopped in the tree. Tells the listeners + * editing has stopped. + * + * @param e is the notification event + */ + public void editingStopped(ChangeEvent e) + { + } + + /** + * Messaged when editing has been canceled in the tree. This tells the + * listeners the editor has canceled editing. + * + * @param e is the notification event + */ + public void editingCanceled(ChangeEvent e) + { + } + }// CellEditorHandler + + /** + * Repaints the lead selection row when focus is lost/grained. + */ + public class FocusHandler + implements FocusListener + { + /** + * Constructor + */ + public FocusHandler() + { + } + + /** + * Invoked when focus is activated on the tree we're in, redraws the lead + * row. Invoked when a component gains the keyboard focus. + * + * @param e is the focus event that is activated + */ + public void focusGained(FocusEvent e) + { + } + + /** + * Invoked when focus is deactivated on the tree we're in, redraws the + * lead row. Invoked when a component loses the keyboard focus. + * + * @param e is the focus event that is deactivated + */ + public void focusLost(FocusEvent e) + { + } + }// FocusHandler + + /** + * This is used to get multiple key down events to appropriately genereate + * events. + */ + public class KeyHandler + extends KeyAdapter + { + /** Key code that is being generated for. */ + protected Action repeatKeyAction; + + /** Set to true while keyPressed is active */ + protected boolean isKeyDown; + + /** + * Constructor + */ + public KeyHandler() + { + } + + /** + * Invoked when a key has been typed. Moves the keyboard focus to the + * first element whose first letter matches the alphanumeric key pressed + * by the user. Subsequent same key presses move the keyboard focus to the + * next object that starts with the same letter. + * + * @param e the key typed + */ + public void keyTyped(KeyEvent e) + { + } + + /** + * Invoked when a key has been pressed. + * + * @param e the key pressed + */ + public void keyPressed(KeyEvent e) + { + TreePath start = BasicTreeUI.this.tree.getLeadSelectionPath(); + DefaultMutableTreeNode last = null; + + if (start != null) + last = (DefaultMutableTreeNode) start.getLastPathComponent(); + if (last != null) + { + if (e.getKeyCode() == KeyEvent.VK_DOWN) + { + DefaultMutableTreeNode next = (DefaultMutableTreeNode) + BasicTreeUI.this.getNextVisibleNode(last); + + if (next != null) + BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, + new TreePath(next.getPath())); + } + else if (e.getKeyCode() == KeyEvent.VK_UP) + { + DefaultMutableTreeNode prev = (DefaultMutableTreeNode) + BasicTreeUI.this.getPreviousVisibleNode(last); + + if (prev != null) + BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, + new TreePath(prev.getPath())); + } + else if (e.getKeyCode() == KeyEvent.VK_LEFT) + { + TreePath path = new TreePath(last.getPath()); + + if (!last.isLeaf() && BasicTreeUI.this.tree.isExpanded(path)) + { + BasicTreeUI.this.tree.collapsePath(path); + BasicTreeUI.this.tree.fireTreeCollapsed(path); + } + } + else if (e.getKeyCode() == KeyEvent.VK_RIGHT) + { + TreePath path = new TreePath(last.getPath()); + + if (!last.isLeaf() && BasicTreeUI.this.tree.isCollapsed(path)) + { + BasicTreeUI.this.tree.expandPath(path); + BasicTreeUI.this.tree.fireTreeExpanded(path); + } + } + } + } + + /** + * Invoked when a key has been released + * + * @param e the key released + */ + public void keyReleased(KeyEvent e) + { + } + }// KeyHandler + + /** + * MouseListener is responsible for updating the selevtion based on mouse + * events. + */ + public class MouseHandler + extends MouseAdapter + implements MouseMotionListener + { + /** + * Constructor + */ + public MouseHandler() + { + } + + /** + * Invoked when a mouse button has been pressed on a component. + * + * @param e is the mouse event that occured + */ + public void mousePressed(MouseEvent e) + { + } + + /** + * Invoked when a mouse button is pressed on a component and then dragged. + * MOUSE_DRAGGED events will continue to be delivered to the component + * where the drag originated until the mouse button is released + * (regardless of whether the mouse position is within the bounds of the + * component). + * + * @param e is the mouse event that occured + */ + public void mouseDragged(MouseEvent e) + { + } + + /** + * Invoked when the mouse button has been moved on a component (with no + * buttons no down). + * + * @param e the mouse event that occured + */ + public void mouseMoved(MouseEvent e) + { + } + + /** + * Invoked when a mouse button has been released on a component. + * + * @param e is the mouse event that occured + */ + public void mouseReleased(MouseEvent e) + { + } + }// MouseHandler + + /** + * MouseInputHandler handles passing all mouse events, including mouse motion + * events, until the mouse is released to the destination it is constructed + * with. + */ + public class MouseInputHandler + implements MouseInputListener + { + /** Source that events are coming from */ + protected Component source; + + /** Destination that receives all events. */ + protected Component destination; + + /** Number of mouse clicks on a non-leaf */ + private int clickCount = 0; + + /** + * Constructor + * + * @param source that events are coming from + * @param destination that receives all events + * @param event is the event received + */ + public MouseInputHandler(Component source, Component destination, + MouseEvent e) + { + } + + /** + * Invoked when the mouse button has been clicked (pressed and released) + * on a component. + * + * @param e mouse event that occured + */ + public void mouseClicked(MouseEvent e) + { + Point click = e.getPoint(); + int clickX = (int) click.getX(); + int clickY = (int) click.getY(); + int row = (clickY / getRowHeight()) - 1; + TreePath path = BasicTreeUI.this.tree.getPathForRow(row); + + boolean inBounds = false; + boolean cntlClick = false; + Rectangle bounds = BasicTreeUI.this.getPathBounds( + BasicTreeUI.this.tree, path); + int x = (int) bounds.getX(); + int y = (int) bounds.getY(); + + if (clickY > y && clickY < (y + bounds.height + 10)) + { + if (clickX > x && clickX < (x + bounds.width + 20)) + inBounds = true; + else if (clickX < (x - rightChildIndent + 5) && + clickX > (x - rightChildIndent - 5)) + cntlClick = true; + } + + if ((inBounds || cntlClick) && path != null && + BasicTreeUI.this.tree.isVisible(path)) + { + if (!cntlClick && !BasicTreeUI.this.isLeaf(row)) + clickCount++; + + if (clickCount == 2 || cntlClick == true) + { + clickCount = 0; + BasicTreeUI.this.tree.getSelectionModel().clearSelection(); + if (BasicTreeUI.this.tree.isExpanded(path)) + { + BasicTreeUI.this.tree.collapsePath(path); + BasicTreeUI.this.tree.fireTreeCollapsed(path); + } + else + { + BasicTreeUI.this.tree.expandPath(path); + BasicTreeUI.this.tree.fireTreeExpanded(path); + } + } + + BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, path); + } + } + + /** + * Invoked when a mouse button has been pressed on a component. + * + * @param e mouse event that occured + */ + public void mousePressed(MouseEvent e) + { + } + + /** + * Invoked when a mouse button has been released on a component. + * + * @param e mouse event that occured + */ + public void mouseReleased(MouseEvent e) + { + } + + /** + * Invoked when the mouse enters a component. + * + * @param e mouse event that occured + */ + public void mouseEntered(MouseEvent e) + { + } + + /** + * Invoked when the mouse exits a component. + * + * @param e mouse event that occured + */ + public void mouseExited(MouseEvent e) + { + } + + /** + * Invoked when a mouse button is pressed on a component and then dragged. + * MOUSE_DRAGGED events will continue to be delivered to the component + * where the drag originated until the mouse button is released + * (regardless of whether the mouse position is within the bounds of the + * component). + * + * @param e mouse event that occured + */ + public void mouseDragged(MouseEvent e) + { + } + + /** + * Invoked when the mouse cursor has been moved onto a component but no + * buttons have been pushed. + * + * @param e mouse event that occured + */ + public void mouseMoved(MouseEvent e) + { + } + + /** + * Removes event from the source + */ + protected void removeFromSource() + { + } + }// MouseInputHandler + + /** + * Class responsible for getting size of node, method is forwarded to + * BasicTreeUI method. X location does not include insets, that is handled in + * getPathBounds. + */ + public class NodeDimensionsHandler + extends AbstractLayoutCache.NodeDimensions + { + /** + * Constructor + */ + public NodeDimensionsHandler() + { + } + + /** + * Responsible for getting the size of a particular node. + * + * @param value the value to be represented + * @param row row being queried + * @param depth the depth of the row + * @param expanded true if row is expanded + * @param size a Rectangle containing the size needed to represent value + * @return containing the node dimensions, or null if node has no + * dimension + */ + public Rectangle getNodeDimensions(Object value, int row, int depth, + boolean expanded, Rectangle size) + { + return null; + } + + /** + * Returns the amount to indent the given row + * + * @return amount to indent the given row. + */ + protected int getRowX(int row, int depth) + { + return 0; + } + }// NodeDimensionsHandler + + /** + * PropertyChangeListener for the tree. Updates the appropriate varaible, or + * TreeState, based on what changes. + */ + public class PropertyChangeHandler + implements PropertyChangeListener + { + + /** + * Constructor + */ + public PropertyChangeHandler() + { + } + + /** + * This method gets called when a bound property is changed. + * + * @param event A PropertyChangeEvent object describing the event source + * and the property that has changed. + */ + public void propertyChange(PropertyChangeEvent event) + { + } + }// PropertyChangeHandler + + /** + * Listener on the TreeSelectionModel, resets the row selection if any of the + * properties of the model change. + */ + public class SelectionModelPropertyChangeHandler + implements PropertyChangeListener + { + + /** + * Constructor + */ + public SelectionModelPropertyChangeHandler() + { + } + + /** + * This method gets called when a bound property is changed. + * + * @param event A PropertyChangeEvent object describing the event source + * and the property that has changed. + */ + public void propertyChange(PropertyChangeEvent event) + { + } + }// SelectionModelPropertyChangeHandler + + /** + * ActionListener that invokes cancelEditing when action performed. + */ + public class TreeCancelEditingAction + extends AbstractAction + { + + /** + * Constructor + */ + public TreeCancelEditingAction() + { + } + + /** + * Invoked when an action occurs. + * + * @param e event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled, false otherwise + */ + public boolean isEnabled() + { + return false; + } + }// TreeCancelEditingAction + + /** + * Updates the TreeState in response to nodes expanding/collapsing. + */ + public class TreeExpansionHandler + implements TreeExpansionListener + { + + /** + * Constructor + */ + public TreeExpansionHandler() + { + } + + /** + * Called whenever an item in the tree has been expanded. + * + * @param event is the event that occured + */ + public void treeExpanded(TreeExpansionEvent event) + { + BasicTreeUI.this.tree.repaint(); + } + + /** + * Called whenever an item in the tree has been collapsed. + * + * @param event is the event that occured + */ + public void treeCollapsed(TreeExpansionEvent event) + { + BasicTreeUI.this.tree.repaint(); + } + }// TreeExpansionHandler + + /** + * TreeHomeAction is used to handle end/home actions. Scrolls either the + * first or last cell to be visible based on direction. + */ + public class TreeHomeAction + extends AbstractAction + { + + /** direction is either home or end */ + protected int direction; + + /** + * Constructor + * + * @param direction - it is home or end + * @param name is the name of the direction + */ + public TreeHomeAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e is the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled. + */ + public boolean isEnabled() + { + return false; + } + }// TreeHomeAction + + /** + * TreeIncrementAction is used to handle up/down actions. Selection is moved + * up or down based on direction. + */ + public class TreeIncrementAction + extends AbstractAction + { + + /** Specifies the direction to adjust the selection by. */ + protected int direction; + + /** + * Constructor + * + * @param direction up or down + * @param name is the name of the direction + */ + public TreeIncrementAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e is the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled. + */ + public boolean isEnabled() + { + return false; + } + }// TreeIncrementAction + + /** + * Forwards all TreeModel events to the TreeState. + */ + public class TreeModelHandler + implements TreeModelListener + { + /** + * Constructor + */ + public TreeModelHandler() + { + } + + /** + * Invoked after a node (or a set of siblings) has changed in some way. + * The node(s) have not changed locations in the tree or altered their + * children arrays, but other attributes have changed and may affect + * presentation. Example: the name of a file has changed, but it is in the + * same location in the file system. To indicate the root has changed, + * childIndices and children will be null. Use e.getPath() to get the + * parent of the changed node(s). e.getChildIndices() returns the + * index(es) of the changed node(s). + * + * @param e is the event that occured + */ + public void treeNodesChanged(TreeModelEvent e) + { + } + + /** + * Invoked after nodes have been inserted into the tree. Use e.getPath() + * to get the parent of the new node(s). e.getChildIndices() returns the + * index(es) of the new node(s) in ascending order. + * + * @param e is the event that occured + */ + public void treeNodesInserted(TreeModelEvent e) + { + } + + /** + * Invoked after nodes have been removed from the tree. Note that if a + * subtree is removed from the tree, this method may only be invoked once + * for the root of the removed subtree, not once for each individual set + * of siblings removed. Use e.getPath() to get the former parent of the + * deleted node(s). e.getChildIndices() returns, in ascending order, the + * index(es) the node(s) had before being deleted. + * + * @param e is the event that occured + */ + public void treeNodesRemoved(TreeModelEvent e) + { + } + + /** + * Invoked after the tree has drastically changed structure from a given + * node down. If the path returned by e.getPath() is of length one and the + * first element does not identify the current root node the first element + * should become the new root of the tree. Use e.getPath() to get the path + * to the node. e.getChildIndices() returns null. + * + * @param e is the event that occured + */ + public void treeStructureChanged(TreeModelEvent e) + { + } + }// TreeModelHandler + + /** + * TreePageAction handles page up and page down events. + */ + public class TreePageAction + extends AbstractAction + { + /** Specifies the direction to adjust the selection by. */ + protected int direction; + + /** + * Constructor + * + * @param direction up or down + * @param name is the name of the direction + */ + public TreePageAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e is the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled. + */ + public boolean isEnabled() + { + return false; + } + }// TreePageAction + + /** + * Listens for changes in the selection model and updates the display + * accordingly. + */ + public class TreeSelectionHandler + implements TreeSelectionListener + { + /** + * Constructor + */ + public TreeSelectionHandler() + { + } + + /** + * Messaged when the selection changes in the tree we're displaying for. + * Stops editing, messages super and displays the changed paths. + * + * @param event the event that characterizes the change. + */ + public void valueChanged(TreeSelectionEvent event) + { + } + }// TreeSelectionHandler + + /** + * For the first selected row expandedness will be toggled. + */ + public class TreeToggleAction + extends AbstractAction + { + /** + * Constructor + * + * @param name is the name of <code>Action</code> field + */ + public TreeToggleAction(String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled, false otherwise + */ + public boolean isEnabled() + { + return false; + } + } // TreeToggleAction + + /** + * TreeTraverseAction is the action used for left/right keys. Will toggle + * the expandedness of a node, as well as potentially incrementing the + * selection. + */ + public class TreeTraverseAction + extends AbstractAction + { + /** + * Determines direction to traverse, 1 means expand, -1 means collapse. + */ + protected int direction; + + /** + * Constructor + * + * @param direction to traverse + * @param name is the name of the direction + */ + public TreeTraverseAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled, false otherwise + */ + public boolean isEnabled() + { + return false; + } + } // TreeTraverseAction + + /** + * Returns the cell bounds for painting selected cells + * + * @param x is the x location of the cell + * @param y is the y location of the cell + * @param cell is the Object to get the bounds for + * + * @returns Rectangle that represents the cell bounds + */ + private Rectangle getCellBounds(int x, int y, Object cell) + { + if (cell != null) + { + String s = cell.toString(); + Font f = tree.getFont(); + FontMetrics fm = tree.getToolkit().getFontMetrics(tree.getFont()); + + return new Rectangle(x, y, SwingUtilities.computeStringWidth(fm, s), + fm.getHeight()); + } + return null; + } + + /** + * Retrieves the location of some node, recursively starting at from + * some node. + * + * @param x is the starting x position, offset + * @param y is the starting y position, offset + * @param tree is the tree to traverse + * @param mod is the TreeModel to use + * @param node is the node to get the location for + * @param startNode is the node to start searching from + * + * @return Point - the location of node + */ + private Point getCellLocation(int x, int y, JTree tree, TreeModel mod, + Object node, Object startNode) + { + int rowHeight = getRowHeight(); + if (startNode == null || startNode.equals(node)) + return new Point(x + ((((DefaultMutableTreeNode) node). + getLevel() + 1) * rightChildIndent), y); + + if (!mod.isLeaf(startNode) + && tree.isExpanded(new TreePath( + ((DefaultMutableTreeNode) startNode).getPath()))) + { + Object child = mod.getChild(startNode, 0); + if (child != null) + return getCellLocation(x, y + rowHeight, tree, mod, + node, child); + } + + return getCellLocation(x, y + rowHeight, tree, mod, node, + getNextVisibleNode((DefaultMutableTreeNode) startNode)); + } + + /** + * Paints a leaf in the tree + * + * @param g the Graphics context in which to paint + * @param x the x location of the leaf + * @param y the y location of the leaf + * @param tree the tree to draw on + * @param leaf the object to draw + */ + private void paintLeaf(Graphics g, int x, int y, JTree tree, Object leaf) + { + TreePath curr = new TreePath(((DefaultMutableTreeNode) leaf).getPath()); + boolean selected = tree.isPathSelected(curr); + + if (tree.isVisible(curr)) + { + DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) + tree.getCellRenderer(); + boolean hasIcons = false; + Icon li = dtcr.getLeafIcon(); + if (li != null) + hasIcons = true; + + if (selected) + { + Component c = dtcr.getTreeCellRendererComponent(tree, leaf, + true, false, true, 0, false); + + if (hasIcons) + { + li.paintIcon(c, g, x, y + 2); + x += li.getIconWidth() + 4; + } + rendererPane.paintComponent(g, c, tree, + getCellBounds(x, y, leaf)); + } + else + { + Component c = dtcr.getTreeCellRendererComponent( + tree, leaf, false, false, true, 0, false); + + g.translate(x, y); + + if (hasIcons) + { + Component icon = dtcr.getTreeCellRendererComponent(tree, + li, false, false, true, 0, false); + icon.paint(g); + } + + c.paint(g); + g.translate(-x, -y); + } + } + } + + /** + * Paints a non-leaf in the tree + * + * @param g the Graphics context in which to paint + * @param x the x location of the non-leaf + * @param y the y location of the non-leaf + * @param tree the tree to draw on + * @param nonLeaf the object to draw + */ + private void paintNonLeaf(Graphics g, int x, int y, JTree tree, + Object nonLeaf) + { + TreePath curr = new TreePath(((DefaultMutableTreeNode) nonLeaf).getPath()); + boolean selected = tree.isPathSelected(curr); + boolean expanded = tree.isExpanded(curr); + + if (tree.isVisible(curr)) + { + DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) + tree.getCellRenderer(); + boolean hasIcons = false; + boolean hasOtherIcons = false; + Icon oi = dtcr.getOpenIcon(); + Icon ci = dtcr.getClosedIcon(); + + if (oi != null || ci != null) + hasIcons = true; + + if (selected) + { + Component c = dtcr.getTreeCellRendererComponent(tree, nonLeaf, + true, expanded, false, 0, false); + + if (hasIcons) + { + if (expanded) + { + oi.paintIcon(c, g, x, y + 2); + x += (oi.getIconWidth() + 4); + } + else + { + ci.paintIcon(c, g, x, y + 2); + x += (ci.getIconWidth() + 4); + } + + } + rendererPane.paintComponent(g, c, tree, + getCellBounds(x, y, nonLeaf)); + } + else + { + Component c = dtcr.getTreeCellRendererComponent(tree, nonLeaf, + false, expanded, false, 0, false); + g.translate(x, y); + + if (hasIcons) + { + Component icon; + if (expanded) + icon = dtcr.getTreeCellRendererComponent(tree, + oi, false, false, false, 0, false); + else + icon = dtcr.getTreeCellRendererComponent(tree, + ci, false, false, false, 0, false); + + icon.paint(g); + } + c.paint(g); + g.translate(-x, -y); + } + } + } + + /** + * Recursively paints all elements of the tree + * + * @param g the Graphics context in which to paint + * @param indentation of the current object + * @param descent is the number of elements drawn + * @param childNumber is the index of the current child in the tree + * @param depth is the depth of the current object in the tree + * @param tree is the tree to draw to + * @param mod is the TreeModel we are using to draw + * @param curr is the current object to draw + * + * @return int - current descent of the tree + */ + private int paintRecursive(Graphics g, int indentation, int descent, + int childNumber, int depth, JTree tree, TreeModel mod, Object curr) + { + Rectangle clip = g.getClipBounds(); + if (indentation > clip.x + clip.width + rightChildIndent + || descent > clip.y + clip.height + getRowHeight()) + return descent; + + int halfHeight = getRowHeight() / 2; + int halfWidth = rightChildIndent / 2; + int y0 = descent + halfHeight; + int heightOfLine = descent + halfHeight; + + if (mod.isLeaf(curr)) + { + paintLeaf(g, indentation + 4, descent, tree, curr); + descent += getRowHeight(); + } + else + { + if (depth > 0 || tree.isRootVisible()) + { + paintNonLeaf(g, indentation + 4, descent, tree, curr); + descent += getRowHeight(); + y0 += halfHeight; + } + + int max = mod.getChildCount(curr); + if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) curr) + .getPath()))) + { + for (int i = 0; i < max; ++i) + { + g.setColor(getHashColor()); + heightOfLine = descent + halfHeight; + g.drawLine(indentation + halfWidth, heightOfLine, + indentation + rightChildIndent, heightOfLine); + + descent = paintRecursive(g, indentation + rightChildIndent, + descent, i, depth + 1, tree, mod, mod.getChild(curr, i)); + } + } + } + + if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) curr) + .getPath()))) + if (y0 != heightOfLine) + { + g.setColor(getHashColor()); + g.drawLine(indentation + halfWidth, y0, indentation + halfWidth, + heightOfLine); + } + + return descent; + } + + /** + * Recursively paints all the control icons on the tree. + * + * @param g the Graphics context in which to paint + * @param indentation of the current object + * @param descent is the number of elements drawn + * @param childNumber is the index of the current child in the tree + * @param depth is the depth of the current object in the tree + * @param tree is the tree to draw to + * @param mod is the TreeModel we are using to draw + * @param curr is the current object to draw + * + * @return int - current descent of the tree + */ + private int paintControlIcons(Graphics g, int indentation, int descent, + int childNumber, int depth, JTree tree, TreeModel mod, Object node) + { + int h = descent; + int rowHeight = getRowHeight(); + Icon ei = UIManager.getLookAndFeelDefaults(). + getIcon("Tree.expandedIcon"); + Icon ci = UIManager.getLookAndFeelDefaults(). + getIcon("Tree.collapsedIcon"); + Rectangle clip = g.getClipBounds(); + if (ci == null || ei == null || indentation > clip.x + clip.width + + rightChildIndent || descent > clip.y + clip.height + + getRowHeight()) + return descent; + + if (mod.isLeaf(node)) + descent += rowHeight; + else + { + if (depth > 0 || tree.isRootVisible()) + descent += rowHeight; + + int max = mod.getChildCount(node); + if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) node) + .getPath()))) + { + if (!node.equals(mod.getRoot())) + ei.paintIcon(tree, g, indentation - rightChildIndent - 3, h); + + for (int i = 0; i < max; ++i) + { + descent = paintControlIcons(g, indentation + rightChildIndent, + descent, i, depth + 1, tree, mod, mod.getChild(node, i)); + } + } + else if (!node.equals(mod.getRoot())) + ci.paintIcon(tree, g, indentation - rightChildIndent - 3, + descent - getRowHeight()); + } + + return descent; + } +} // BasicTreeUI
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java new file mode 100644 index 00000000000..8ce772bedf9 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java @@ -0,0 +1,234 @@ +/* BasicViewportUI.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.ImageObserver; + +import javax.swing.JComponent; +import javax.swing.JViewport; +import javax.swing.ViewportLayout; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ViewportUI; + +public class BasicViewportUI extends ViewportUI +{ + + ChangeListener changeListener; + Image backingStoreImage; + int backingStoreWidth = -1; + int backingStoreHeight = -1; + + class ChangeHandler implements ChangeListener + { + public void stateChanged(ChangeEvent event) + { + JViewport v = (JViewport) event.getSource(); + v.repaint(); + } + } + + void installDefaults(JComponent c) + { + c.setOpaque(true); + } + + void uninstallDefaults(JComponent c) + { + } + + void installListeners(JComponent c) + { + ((JViewport)c).addChangeListener(changeListener); + } + + void uninstallListeners(JComponent c) + { + ((JViewport)c).removeChangeListener(changeListener); + } + + public BasicViewportUI() + { + changeListener = new ChangeHandler(); + } + + public static ComponentUI createUI(JComponent c) + { + return new BasicViewportUI(); + } + + public void installUI(JComponent c) + { + super.installUI(c); + installListeners(c); + } + + public void uninstallUI(JComponent c) + { + uninstallListeners(c); + } + + + public Dimension getPreferredSize(JComponent c) + { + // let the ViewportLayout decide + return null; + } + + public void paint(Graphics g, JComponent c) + { + JViewport port = (JViewport)c; + Component view = port.getView(); + + if (view == null) + return; + + Point pos = port.getViewPosition(); + Rectangle viewBounds = view.getBounds(); + Rectangle portBounds = port.getBounds(); + + if (viewBounds.width == 0 + || viewBounds.height == 0 + || portBounds.width == 0 + || portBounds.height == 0) + return; + + switch (port.getScrollMode()) + { + + case JViewport.BACKINGSTORE_SCROLL_MODE: + paintBackingStore(g, port, view, pos, viewBounds, portBounds); + break; + + case JViewport.BLIT_SCROLL_MODE: + // FIXME: implement separate blit mode + + case JViewport.SIMPLE_SCROLL_MODE: + default: + paintSimple(g, port, view, pos, viewBounds, portBounds); + break; + } + } + + private void paintSimple(Graphics g, + JViewport v, + Component view, + Point pos, + Rectangle viewBounds, + Rectangle portBounds) + { + Rectangle oldClip = g.getClipBounds (); + g.setClip (oldClip.intersection (viewBounds)); + g.translate (-pos.x, -pos.y); + try + { + view.paint(g); + } + finally + { + g.translate (pos.x, pos.y); + g.setClip (oldClip); + } + } + + private void paintBackingStore(Graphics g, + JViewport v, + Component view, + Point pos, + Rectangle viewBounds, + Rectangle portBounds) + { + if (backingStoreImage == null + || backingStoreWidth != viewBounds.width + || backingStoreHeight != viewBounds.height) + { + backingStoreImage = v.createImage(viewBounds.width, viewBounds.height); + backingStoreWidth = viewBounds.width; + backingStoreHeight = viewBounds.height; + } + + Graphics g2 = backingStoreImage.getGraphics(); + + if (v.getBackground() != null) + { + // fill the backing store background + java.awt.Color save = g2.getColor(); + g2.setColor(v.getBackground()); + g2.fillRect (0, 0, backingStoreWidth, backingStoreHeight); + g2.setColor(save); + + // fill the viewport background + save = g.getColor(); + g.setColor(v.getBackground()); + g.fillRect (0, 0, portBounds.width, portBounds.height); + g.setColor(save); + + } + else + { + // clear the backing store background + g2.clearRect(0, 0, backingStoreWidth, backingStoreHeight); + + // clear the viewport background + g.clearRect(0, 0, portBounds.width, portBounds.height); + } + + g2.setClip(g.getClipBounds()); + g2.translate(-pos.x, -pos.y); + try + { + view.paint(g2); + } + finally + { + g2.translate(pos.x, pos.y); + } + g2 = null; + g.drawImage(backingStoreImage, + 0, 0, + (ImageObserver)null); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java new file mode 100644 index 00000000000..8bdcc51b0c0 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/ComboPopup.java @@ -0,0 +1,103 @@ +/* ComboPopup.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.basic; + +import java.awt.event.KeyListener; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; + +import javax.swing.JList; + +public interface ComboPopup +{ + /** + * This method display popup menu containing list of JComboBox's items to + * the screen + */ + void show(); + + /** + * This method hides popup menu with list of JComboBox's item from the + * screen + */ + void hide(); + + /** + * Retursn true if popup menu with JComboBOx's item is currently visible on + * the screen and false otherwise + * + * @return true if JComboBox's popup menu with list of items is currently + * visible on the screen and false otherwise. + */ + boolean isVisible(); + + /** + * Return JList that is used to draw cells of the JComboBox. + * + * @return JList that is used to draw cells of the JcomboBox + */ + JList getList(); + + /** + * This method returns MouseListener that listen's to mouse events occuring + * in the combo box + * + * @return MouseListenere + */ + MouseListener getMouseListener(); + + /** + * This method returns MouseListener that listen's to mouse events occuring + * in the combo box. + * + * @return MouseMotionListener + */ + MouseMotionListener getMouseMotionListener(); + + /** + * This method returns KeyListener that listen's to key events occuring in + * the combo box. + * + * @return KeyListener + */ + KeyListener getKeyListener(); + + /* This method removes any listeners that were installed */ + void uninstallingUI(); +} diff --git a/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java b/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java new file mode 100644 index 00000000000..9760e82a62c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/DefaultMenuLayout.java @@ -0,0 +1,78 @@ +/* DefaultMenuLayout.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Container; +import java.awt.Dimension; + +import javax.swing.BoxLayout; +import javax.swing.plaf.UIResource; + +/** + * The LayoutManager that is used in PopupMenus. This is a derived from + * {@link BoxLayout}. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class DefaultMenuLayout + extends BoxLayout + implements UIResource +{ + + /** + * Creates a new instance of DefaultMenuLayout. + * + * @param target the component that is laid out + * @param axis the axis along which the component is laid out + */ + public DefaultMenuLayout(Container target, int axis) + { + super(target, axis); + } + + /** + * Returns the preferred size for the layout of the menu. + * + * @param target the Container which's preferred size we calculate + */ + public Dimension preferredLayoutSize(Container target) + { + return super.preferredLayoutSize(target); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-1.png Binary files differnew file mode 100644 index 00000000000..daeb16c78eb --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-2.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-2.png Binary files differnew file mode 100644 index 00000000000..60f6a8abe42 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders-2.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png Binary files differnew file mode 100644 index 00000000000..54047dcc17b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ButtonBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.FieldBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.FieldBorder-1.png Binary files differnew file mode 100644 index 00000000000..7c89911062c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.FieldBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png Binary files differnew file mode 100644 index 00000000000..a3841baac54 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MarginBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MenuBarBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MenuBarBorder-1.png Binary files differnew file mode 100644 index 00000000000..13a9fa4e90f --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.MenuBarBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.RadioButtonBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.RadioButtonBorder-1.png Binary files differnew file mode 100644 index 00000000000..a6408ec7e1d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.RadioButtonBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-1.png Binary files differnew file mode 100644 index 00000000000..db283c29a06 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-2.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-2.png Binary files differnew file mode 100644 index 00000000000..65381bd8b4d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneBorder-2.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneDividerBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneDividerBorder-1.png Binary files differnew file mode 100644 index 00000000000..c22763a97df --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.SplitPaneDividerBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ToggleButtonBorder-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ToggleButtonBorder-1.png Binary files differnew file mode 100644 index 00000000000..f898bee8fa7 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicBorders.ToggleButtonBorder-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png Binary files differnew file mode 100644 index 00000000000..99f8c6ec47b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-1.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png Binary files differnew file mode 100644 index 00000000000..59d9a6192e2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-2.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png Binary files differnew file mode 100644 index 00000000000..5b0971c1647 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-3.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png Binary files differnew file mode 100644 index 00000000000..ceba0b6e07a --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-4.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png Binary files differnew file mode 100644 index 00000000000..fa3055f8c5e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-5.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png Binary files differnew file mode 100644 index 00000000000..c760313e080 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-6.png diff --git a/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png Binary files differnew file mode 100644 index 00000000000..6a557a0445b --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/doc-files/BasicGraphicsUtils-7.png diff --git a/libjava/classpath/javax/swing/plaf/basic/package.html b/libjava/classpath/javax/swing/plaf/basic/package.html new file mode 100644 index 00000000000..700c8cdbc3e --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/basic/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.plaf.basic package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.plaf.basic</title></head> + +<body> +<p>Provides a "basic" look and feel implementation.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.dia b/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.dia Binary files differnew file mode 100644 index 00000000000..02bfbbe90f1 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.dia diff --git a/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.png b/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.png Binary files differnew file mode 100644 index 00000000000..def4cbc6c47 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/doc-files/ComponentUI-1.png diff --git a/libjava/classpath/javax/swing/plaf/doc-files/TreeUI-1.png b/libjava/classpath/javax/swing/plaf/doc-files/TreeUI-1.png Binary files differnew file mode 100644 index 00000000000..0f01ab03c23 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/doc-files/TreeUI-1.png diff --git a/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java b/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java new file mode 100644 index 00000000000..673aec1e418 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/DefaultMetalTheme.java @@ -0,0 +1,221 @@ +/* DefaultMetalTheme.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Font; + +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; + +/** + * The default theme for the {@link MetalLookAndFeel}. + * + * @see MetalLookAndFeel#setCurrentTheme(MetalTheme) + */ +public class DefaultMetalTheme extends MetalTheme +{ + private static final ColorUIResource PRIMARY1 = + new ColorUIResource(102, 102, 153); + private static final ColorUIResource PRIMARY2 = + new ColorUIResource(153, 153, 204); + private static final ColorUIResource PRIMARY3 = + new ColorUIResource(204, 204, 255); + private static final ColorUIResource SECONDARY1 = + new ColorUIResource(102, 102, 102); + private static final ColorUIResource SECONDARY2 = + new ColorUIResource(153, 153, 153); + private static final ColorUIResource SECONDARY3 = + new ColorUIResource(204, 204, 204); + + private static final FontUIResource CONTROL_TEXT_FONT = + new FontUIResource("Dialog", Font.BOLD, 12); + private static final FontUIResource MENU_TEXT_FONT = + new FontUIResource("Dialog", Font.BOLD, 12); + private static final FontUIResource SUB_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 10); + private static final FontUIResource SYSTEM_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 12); + private static final FontUIResource USER_TEXT_FONT = + new FontUIResource("Dialog", Font.PLAIN, 12); + private static final FontUIResource WINDOW_TITLE_FONT = + new FontUIResource("Dialog", Font.BOLD, 12); + + /** + * Creates a new instance of this theme. + */ + public DefaultMetalTheme() + { + // Do nothing here. + } + + /** + * Returns the name of the theme. + * + * @return <code>"Steel"</code>. + */ + public String getName() + { + return "Steel"; + } + + /** + * Returns the first primary color for this theme. + * + * @return The first primary color. + */ + protected ColorUIResource getPrimary1() + { + return PRIMARY1; + } + + /** + * Returns the second primary color for this theme. + * + * @return The second primary color. + */ + protected ColorUIResource getPrimary2() + { + return PRIMARY2; + } + + /** + * Returns the third primary color for this theme. + * + * @return The third primary color. + */ + protected ColorUIResource getPrimary3() + { + return PRIMARY3; + } + + /** + * Returns the first secondary color for this theme. + * + * @return The first secondary color. + */ + protected ColorUIResource getSecondary1() + { + return SECONDARY1; + } + + /** + * Returns the second secondary color for this theme. + * + * @return The second secondary color. + */ + protected ColorUIResource getSecondary2() + { + return SECONDARY2; + } + + /** + * Returns the third secondary color for this theme. + * + * @return The third secondary color. + */ + protected ColorUIResource getSecondary3() + { + return SECONDARY3; + } + + /** + * Returns the font used for text on controls. In this case, the font is + * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>. + * + * @return The font. + */ + public FontUIResource getControlTextFont() + { + return CONTROL_TEXT_FONT; + } + /** + * Returns the font used for text in menus. In this case, the font is + * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>. + * + * @return The font used for text in menus. + */ + public FontUIResource getMenuTextFont() + { + return MENU_TEXT_FONT; + } + + /** + * Returns the font used for sub text. In this case, the font is + * <code>FontUIResource("Dialog", Font.PLAIN, 10)</code>. + * + * @return The font used for sub text. + */ + public FontUIResource getSubTextFont() + { + return SUB_TEXT_FONT; + } + + /** + * Returns the font used for system text. In this case, the font is + * <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>. + * + * @return The font used for system text. + */ + public FontUIResource getSystemTextFont() + { + return SYSTEM_TEXT_FONT; + } + + /** + * Returns the font used for user text. In this case, the font is + * <code>FontUIResource("Dialog", Font.PLAIN, 12)</code>. + * + * @return The font used for user text. + */ + public FontUIResource getUserTextFont() + { + return USER_TEXT_FONT; + } + + /** + * Returns the font used for window titles. In this case, the font is + * <code>FontUIResource("Dialog", Font.BOLD, 12)</code>. + * + * @return The font used for window titles. + */ + public FontUIResource getWindowTitleFont() + { + return WINDOW_TITLE_FONT; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java new file mode 100644 index 00000000000..f260ef6e34c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java @@ -0,0 +1,443 @@ +/* MetalBorders.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.border.AbstractBorder; +import javax.swing.border.Border; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicGraphicsUtils; +import javax.swing.plaf.basic.BasicBorders; + +/** + * This factory class creates borders for the different Swing components + * UI. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class MetalBorders +{ + + /** The shared instance for getButtonBorder(). */ + private static Border buttonBorder; + + /** The shared instance for getRolloverButtonBorder(). */ + private static Border toolbarButtonBorder; + + /** + * A MarginBorder that gets shared by multiple components. + * Created on demand by the private helper function {@link + * #getMarginBorder()}. + */ + private static BasicBorders.MarginBorder marginBorder; + + /** + * The border that is drawn around Swing buttons. + */ + public static class ButtonBorder + extends AbstractBorder + implements UIResource + { + /** The borders insets. */ + protected static Insets borderInsets = new Insets(3, 3, 3, 3); + + /** + * Creates a new instance of ButtonBorder. + */ + public ButtonBorder() + { + } + + /** + * Paints the button border. + * + * @param c the component for which we paint the border + * @param g the Graphics context to use + * @param x the X coordinate of the upper left corner of c + * @param y the Y coordinate of the upper left corner of c + * @param w the width of c + * @param h the height of c + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + ButtonModel bmodel = null; + + if (c instanceof AbstractButton) + bmodel = ((AbstractButton) c).getModel(); + + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getWhite(); + Color middle = MetalLookAndFeel.getControl(); + + // draw dark border + g.setColor(darkShadow); + g.drawRect(x, y, w - 2, h - 2); + + if (!bmodel.isPressed()) + { + // draw light border + g.setColor(light); + g.drawRect(x + 1, y + 1, w - 2, h - 2); + + // draw crossing pixels of both borders + g.setColor(middle); + g.drawRect(x + 1, y + h - 2, 0, 0); + g.drawRect(x + w - 2, y + 1, 0, 0); + } + else + { + // draw light border + g.setColor(light); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1); + g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1); + + // draw shadow border + g.setColor(middle); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + + // draw crossing pixels of both borders + g.setColor(shadow); + g.drawRect(x + 1, y + h - 2, 0, 0); + g.drawRect(x + w - 2, y + 1, 0, 0); + } + } + + /** + * Returns the insets of the ButtonBorder. + * + * @param c the component for which the border is used + * + * @return the insets of the ButtonBorder + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the insets of the ButtonBorder in the specified Insets object. + * + * @param c the component for which the border is used + * @param newInsets the insets object where to put the values + * + * @return the insets of the ButtonBorder + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(0, 0, 0, 0); + + AbstractButton b = (AbstractButton) c; + newInsets.bottom = borderInsets.bottom; + newInsets.left = borderInsets.left; + newInsets.right = borderInsets.right; + newInsets.top = borderInsets.top; + return newInsets; + } + } + + /** + * A border for JScrollPanes. + */ + public static class ScrollPaneBorder + extends AbstractBorder + implements UIResource + { + /** The border insets. */ + private static Insets insets = new Insets(1, 1, 2, 2); + + /** + * Constructs a new ScrollPaneBorder. + */ + public ScrollPaneBorder() + { + } + + /** + * Returns the insets of the border for the Component <code>c</code>. + * + * @param c the Component for which we return the border insets + */ + public Insets getBorderInsets(Component c) + { + return insets; + } + + /** + * Paints the border. + * + * @param c the Component for which the border is painted + * @param g the Graphics context + * @param x the X coordinate of the upper left corner of the border + * @param y the Y coordinate of the upper left corner of the border + * @param w the width of the border + * @param h the height of the border + */ + public void paintBorder(Component c, Graphics g, int x, int y, + int w, int h) + { + Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); + Color shadow = MetalLookAndFeel.getControlShadow(); + Color light = MetalLookAndFeel.getWhite(); + Color middle = MetalLookAndFeel.getControl(); + + // paint top border line + g.setColor(darkShadow); + g.drawLine(x, y, x + w - 2, y); + + // paint left border line + g.drawLine(x, y, x, y + h - 2); + + // paint right inner border line + g.drawLine(x + w - 2, y, x + w - 2, y + h + 1); + + // paint bottom inner border line + g.drawLine(x + 2, y + h - 2, x + w - 2, y + h - 2); + + // draw right outer border line + g.setColor(light); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); + + // draw bottom outer border line + g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); + + // paint the lighter points + g.setColor(middle); + g.drawLine(x + w - 1, y, x + w - 1, y); + g.drawLine(x + w - 2, y + 2, x + w - 2, y + 2); + g.drawLine(x, y + h - 1, x, y + h - 1); + g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); + + } + + } + + /** + * This border is used in Toolbar buttons as inner border. + */ + static class RolloverMarginBorder extends AbstractBorder + { + /** The borders insets. */ + protected static Insets borderInsets = new Insets(3, 3, 3, 3); + + /** + * Creates a new instance of RolloverBorder. + */ + public RolloverMarginBorder() + { + } + + /** + * Returns the insets of the RolloverBorder. + * + * @param c the component for which the border is used + * + * @return the insets of the RolloverBorder + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the insets of the RolloverMarginBorder in the specified + * Insets object. + * + * @param c the component for which the border is used + * @param newInsets the insets object where to put the values + * + * @return the insets of the RolloverMarginBorder + */ + public Insets getBorderInsets(Component c, Insets newInsets) + { + if (newInsets == null) + newInsets = new Insets(0, 0, 0, 0); + + AbstractButton b = (AbstractButton) c; + Insets margin = b.getMargin(); + newInsets.bottom = borderInsets.bottom; + newInsets.left = borderInsets.left; + newInsets.right = borderInsets.right; + newInsets.top = borderInsets.top; + return newInsets; + } + } + + /** + * A border implementation for popup menus. + */ + public static class PopupMenuBorder + extends AbstractBorder + implements UIResource + { + + /** The border's insets. */ + protected static Insets borderInsets = new Insets(2, 2, 1, 1); + + /** + * Constructs a new PopupMenuBorder. + */ + public PopupMenuBorder() + { + } + + /** + * Returns the insets of the border, creating a new Insets instance + * with each call. + * + * @param c the component for which we return the border insets + * (not used here) + */ + public Insets getBorderInsets(Component c) + { + return getBorderInsets(c, null); + } + + /** + * Returns the insets of the border, using the supplied Insets instance. + * + * @param c the component for which we return the border insets + * (not used here) + * @param i the Insets instance to fill with the Insets values + */ + public Insets getBorderInsets(Component c, Insets i) + { + Insets insets; + if (i == null) + insets = new Insets(borderInsets.top, borderInsets.left, + borderInsets.bottom, borderInsets.right); + else + { + insets = i; + insets.top = borderInsets.top; + insets.left = borderInsets.left; + insets.bottom = borderInsets.bottom; + insets.right = borderInsets.right; + } + + return insets; + } + + /** + * Paints the border for component <code>c</code> using the + * Graphics context <code>g</code> with the dimension + * <code>x, y, w, h</code>. + * + * @param c the component for which we paint the border + * @param g the Graphics context to use + * @param x the X coordinate of the upper left corner of c + * @param y the Y coordinate of the upper left corner of c + * @param w the width of c + * @param h the height of c + */ + public void paintBorder(Component c, Graphics g, int x, int y, int w, + int h) + { + Color darkShadow = MetalLookAndFeel.getPrimaryControlDarkShadow(); + Color light = MetalLookAndFeel.getPrimaryControlHighlight(); + + // draw dark outer border + g.setColor(darkShadow); + g.drawRect(x, y, w - 1, h - 1); + + // draw highlighted inner border (only top and left) + g.setColor(light); + g.drawLine(x + 1, y + 1, x + 1, y + h - 2); + g.drawLine(x + 1, y + 1, x + w - 2, y + 1); + } + + } + + /** + * Returns a border for Swing buttons in the Metal Look & Feel. + * + * @return a border for Swing buttons in the Metal Look & Feel + */ + public static Border getButtonBorder() + { + if (buttonBorder == null) + { + Border outer = new ButtonBorder(); + Border inner = getMarginBorder(); + buttonBorder = new BorderUIResource.CompoundBorderUIResource + (outer, inner); + } + return buttonBorder; + } + + /** + * Returns a border for Toolbar buttons in the Metal Look & Feel. + * + * @return a border for Toolbar buttons in the Metal Look & Feel + */ + static Border getToolbarButtonBorder() + { + if (toolbarButtonBorder == null) + { + Border outer = new ButtonBorder(); + Border inner = new RolloverMarginBorder(); + toolbarButtonBorder = new BorderUIResource.CompoundBorderUIResource + (outer, inner); + } + return toolbarButtonBorder; + } + + /** + * Returns a shared instance of {@link BasicBorders.MarginBorder}. + * + * @return a shared instance of {@link BasicBorders.MarginBorder} + */ + static Border getMarginBorder() + { + if (marginBorder == null) + marginBorder = new BasicBorders.MarginBorder(); + return marginBorder; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java new file mode 100644 index 00000000000..a7b53c4b430 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java @@ -0,0 +1,101 @@ +/* MetalButtonUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.JToolBar; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicButtonUI; + +/** + * The Metal Look & Feel implementation for + * {@link javax.swing.AbstractButton}s. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class MetalButtonUI + extends BasicButtonUI +{ + + // FIXME: probably substitute with a Map in the future in the case + // that this UI becomes stateful + + /** The cached MetalButtonUI instance. */ + private static MetalButtonUI instance = null; + + /** + * Creates a new instance of MetalButtonUI. + */ + public MetalButtonUI() + { + super(); + } + + /** + * Returns an instance of MetalButtonUI. + * + * @param component a button for which a UI instance should be returned + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalButtonUI(); + return instance; + } + + /** + * Install the Look & Feel defaults for Buttons. + * + * @param button the button for which to install the Look & Feel + */ + public void installDefaults(AbstractButton button) + { + super.installDefaults(button); + + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + button.setFont(defaults.getFont("Button.font")); + + if (button.getParent() instanceof JToolBar) + button.setBorder(MetalBorders.getToolbarButtonBorder()); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java new file mode 100644 index 00000000000..eba21a4bfcf --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxIcon.java @@ -0,0 +1,136 @@ +/* MetalCheckBoxIcon.java -- An icon for JCheckBoxes in the Metal L&F + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; + +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.plaf.UIResource; + +/** + * An {@link Icon} implementation for {@link JCheckBox}es in the + * Metal Look & Feel. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class MetalCheckBoxIcon + implements Icon, UIResource, Serializable +{ + + /** Used to paint the border of the icon. */ + MetalBorders.ButtonBorder border; + + /** + * Creates a new MetalCheckBoxIcon instance. + */ + public MetalCheckBoxIcon() + { + border = new MetalBorders.ButtonBorder(); + } + + /** + * Draws the check in the CheckBox. + * + * @param c the component to draw on + * @param g the Graphics context to draw with + * @param x the X position + * @param y the Y position + */ + protected void drawCheck(Component c, Graphics g, int x, int y) + { + g.setColor(Color.BLACK); + g.drawLine(3, 5, 3, 9); + g.drawLine(4, 5, 4, 9); + g.drawLine(5, 7, 9, 3); + g.drawLine(5, 8, 9, 4); + } + + /** + * Returns the size (both X and Y) of the checkbox icon. + * + * @return the size of the checkbox icon + */ + protected int getControlSize() + { + return 13; + } + + /** + * Returns the width of the icon in pixels. + * + * @return the width of the icon in pixels + */ + public int getIconWidth() + { + return getControlSize(); + } + + /** + * Returns the height of the icon in pixels. + * + * @return the height of the icon in pixels + */ + public int getIconHeight() + { + return getControlSize(); + } + + /** + * Paints the icon. This first paints the border of the CheckBox and + * if the CheckBox is selected it calls {@link #drawCheck} to draw + * the check. + * + * @param c the Component to draw on (gets casted to JCheckBox) + * @param g the Graphics context to draw with + * @param x the X position + * @param x the Y position + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + border.paintBorder(c, g, x, y, getIconWidth(), getIconHeight()); + JCheckBox cb = (JCheckBox) c; + if (cb.isSelected()) + drawCheck(c, g, x, y); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java new file mode 100644 index 00000000000..d59e38c5474 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalCheckBoxUI.java @@ -0,0 +1,74 @@ +/* MetalCheckBoxUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicCheckBoxUI; + +public class MetalCheckBoxUI + extends BasicCheckBoxUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for JCheckBoxes. */ + private static MetalCheckBoxUI instance = null; + + /** + * Constructs a new instance of MetalCheckBoxUI. + */ + public MetalCheckBoxUI() + { + super(); + } + + /** + * Returns an instance of MetalCheckBoxUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalCheckBoxUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalCheckBoxUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java new file mode 100644 index 00000000000..ce4fa7d32ce --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxIcon.java @@ -0,0 +1,100 @@ +/* MetalComboBoxButton.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; + +/** + * An icon used by the {@link MetalComboBoxUI} class. + */ +public class MetalComboBoxIcon implements Icon, Serializable { + + /** + * Creates a new icon. + */ + public MetalComboBoxIcon() + { + // nothing required. + } + + /** + * Returns the icon width, which for this icon is 10 pixels. + * + * @return <code>10</code>. + */ + public int getIconWidth() + { + return 10; + } + + /** + * Returns the icon height, which for this icon is 5 pixels. + * + * @return <code>5</code>. + */ + public int getIconHeight() + { + return 5; + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the combo box (ignored here). + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // TODO: work out whether/how the icon changes with different component + // states (and also different metal themes) + Color savedColor = g.getColor(); + g.setColor(Color.black); + for (int i = 0; i < 5; i++) + g.drawLine(x + i, y + i, x + 9 - i, y + i); + g.setColor(savedColor); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java new file mode 100644 index 00000000000..28c279d8ed6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java @@ -0,0 +1,86 @@ +/* MetalComboBoxUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicComboBoxUI; + +public class MetalComboBoxUI + extends BasicComboBoxUI +{ + + /** The UI instances for JComboBoxes. */ + private static HashMap instances = null; + + /** + * Constructs a new instance of MetalComboBoxUI. + */ + public MetalComboBoxUI() + { + super(); + } + + /** + * Returns an instance of MetalComboBoxUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalComboBoxUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + Object o = instances.get(component); + MetalComboBoxUI instance; + if (o == null) + { + instance = new MetalComboBoxUI(); + instances.put(component, instance); + } + else + instance = (MetalComboBoxUI) o; + + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java new file mode 100644 index 00000000000..00870545bc6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java @@ -0,0 +1,74 @@ +/* MetalDesktopIconUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicDesktopIconUI; + +public class MetalDesktopIconUI + extends BasicDesktopIconUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalDesktopIcons */ + private static MetalDesktopIconUI instance = null; + + /** + * Constructs a new instance of MetalDesktopIconUI. + */ + public MetalDesktopIconUI() + { + super(); + } + + /** + * Returns an instance of MetalDesktopIconUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalDesktopIconUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalDesktopIconUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java new file mode 100644 index 00000000000..e770f474680 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java @@ -0,0 +1,672 @@ +/* MetalIconFactory.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.JSlider; + +/** + * Creates icons for the {@link MetalLookAndFeel}. + */ +public class MetalIconFactory implements Serializable +{ + + /** A constant representing "dark". */ + public static final boolean DARK = false; + + /** A constant representing "light". */ + public static final boolean LIGHT = true; + + /** + * An icon representing a file (drawn as a piece of paper with the top-right + * corner turned down). + */ + public static class FileIcon16 implements Icon, Serializable + { + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the component. + * @param g the graphics context. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // TODO: pick up appropriate UI colors + g.setColor(Color.black); + g.drawLine(x, y, x + 9, y); + g.drawLine(x, y + 1, x, y + 15); + g.drawLine(x, y + 15, x + 12, y + 15); + g.drawLine(x + 12, y + 15, x + 12, y + 6); + g.drawLine(x + 12, y + 6, x + 9, y); + + g.drawLine(x + 7, y + 2, x + 11, y + 6); + g.drawLine(x + 8, y + 1, x + 9, y + 1); + + g.setColor(new Color(204, 204, 255)); + g.drawLine(x + 1, y + 1, x + 7, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + 14); + g.drawLine(x + 1, y + 14, x + 11, y + 14); + g.drawLine(x + 11, y + 14, x + 11, y + 7); + g.drawLine(x + 8, y + 2, x + 10, y + 4); + } + + /** + * Returns the additional height (???). + * + * @return The additional height. + */ + public int getAdditionalHeight() + { + return 0; + } + + /** + * Returns the shift (???). + * + * @return The shift. + */ + public int getShift() + { + return 0; + } + + } + + /** + * An icon representing a folder. + */ + public static class FolderIcon16 implements Icon, Serializable + { + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // TODO: pick up appropriate UI colors + g.setColor(Color.black); + g.drawLine(x, y + 3, x, y + 12); + g.drawLine(x, y + 12, x + 15, y + 12); + g.drawLine(x + 15, y + 12, x + 15, y + 2); + g.drawLine(x + 14, y + 3, x + 9, y + 3); + g.drawLine(x + 8, y + 2, x + 1, y + 2); + g.setColor(new Color(204, 204, 255)); + g.fillRect(x + 2, y + 4, 7, 8); + g.fillRect(x + 9, y + 5, 6, 7); + g.setColor(new Color(102, 102, 153)); + g.drawLine(x + 9, y + 2, x + 14, y + 2); + g.setColor(new Color(50, 50, 120)); + g.drawLine(x + 9, y + 1, x + 15, y + 1); + g.drawLine(x + 10, y, x + 15, y); + } + + /** + * Returns the additional height (???). + * + * @return The additional height. + */ + public int getAdditionalHeight() + { + return 0; + } + + /** + * Returns the shift (???). + * + * @return The shift. + */ + public int getShift() + { + return 0; + } + + } + + /** + * The icon used to display the thumb control on a horizontally oriented + * {@link JSlider} component. + */ + private static class HorizontalSliderThumbIcon + implements Icon, Serializable + { + + /** + * Creates a new instance. + */ + public HorizontalSliderThumbIcon() + { + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 15; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 16; + } + + /** + * Paints the icon, taking into account whether or not the component has + * the focus. + * + * @param c the component. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + boolean focus = false; + if (c != null) + focus = c.hasFocus(); + // TODO: pick up the colors from the look and feel + + // draw the outline + g.setColor(Color.black); + g.drawLine(x + 1, y, x + 13, y); + g.drawLine(x + 14, y + 1, x + 14, y + 7); + g.drawLine(x + 14, y + 8, x + 7, y + 15); + g.drawLine(x + 6, y + 14, x, y + 8); + g.drawLine(x, y + 7, x, y + 1); + + // fill the icon + g.setColor(focus ? new Color(153, 153, 204) : new Color(204, 204, 204)); // medium + g.fillRect(x + 2, y + 2, 12, 7); + g.drawLine(x + 2, y + 9, x + 12, y + 9); + g.drawLine(x + 3, y + 10, x + 11, y + 10); + g.drawLine(x + 4, y + 11, x + 10, y + 11); + g.drawLine(x + 5, y + 12, x + 9, y + 12); + g.drawLine(x + 6, y + 13, x + 8, y + 13); + g.drawLine(x + 7, y + 14, x + 7, y + 14); + + // draw highlights + g.setColor(focus ? new Color(204, 204, 255) : new Color(255, 255, 255)); // light + g.drawLine(x + 1, y + 1, x + 13, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 8); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 6, y + 2, x + 6, y + 2); + g.drawLine(x + 10, y + 2, x + 10, y + 2); + + g.drawLine(x + 4, y + 4, x + 4, y + 4); + g.drawLine(x + 8, y + 4, x + 8, y + 4); + + g.drawLine(x + 2, y + 6, x + 2, y + 6); + g.drawLine(x + 6, y + 6, x + 6, y + 6); + g.drawLine(x + 10, y + 6, x + 10, y + 6); + + // draw dots + g.setColor(focus ? new Color(102, 102, 153) : Color.black); // dark + g.drawLine(x + 3, y + 3, x + 3, y + 3); + g.drawLine(x + 7, y + 3, x + 7, y + 3); + g.drawLine(x + 11, y + 3, x + 11, y + 3); + + g.drawLine(x + 5, y + 5, x + 5, y + 5); + g.drawLine(x + 9, y + 5, x + 9, y + 5); + + g.drawLine(x + 3, y + 7, x + 3, y + 7); + g.drawLine(x + 7, y + 7, x + 7, y + 7); + g.drawLine(x + 11, y + 7, x + 11, y + 7); + + } + } + + /** + * The icon used to display the thumb control on a horizontally oriented + * {@link JSlider} component. + */ + private static class VerticalSliderThumbIcon implements Icon, Serializable + { + /** + * Creates a new instance. + */ + public VerticalSliderThumbIcon() + { + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 16; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 15; + } + + /** + * Paints the icon taking into account whether the slider control has the + * focus or not. + * + * @param c the slider (must be a non-<code>null</code> instance of + * {@link JSlider}. + * @param g the graphics device. + * @param x the x-coordinate. + * @param y the y-coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + boolean focus = false; + if (c != null) + focus = c.hasFocus(); + // TODO: pick up the colors from the look and feel + + // draw the outline + g.setColor(Color.black); + g.drawLine(x + 1, y, x + 7, y); + g.drawLine(x + 8, y, x + 15, y + 7); + g.drawLine(x + 14, y + 8, x + 8, y + 14); + g.drawLine(x + 8, y + 14, x + 1, y + 14); + g.drawLine(x, y + 13, x, y + 1); + + // fill the icon + g.setColor(focus ? new Color(153, 153, 204) : new Color(204, 204, 204)); // medium + g.fillRect(x + 2, y + 2, 7, 12); + g.drawLine(x + 9, y + 2, x + 9, y + 12); + g.drawLine(x + 10, y + 3, x + 10, y + 11); + g.drawLine(x + 11, y + 4, x + 11, y + 10); + g.drawLine(x + 12, y + 5, x + 12, y + 9); + g.drawLine(x + 13, y + 6, x + 13, y + 8); + g.drawLine(x + 14, y + 7, x + 14, y + 7); + + // draw highlights + g.setColor(focus ? new Color(204, 204, 255) : new Color(255, 255, 255)); // light + g.drawLine(x + 1, y + 1, x + 8, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 13); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 2, y + 6, x + 2, y + 6); + g.drawLine(x + 2, y + 10, x + 2, y + 10); + + g.drawLine(x + 4, y + 4, x + 4, y + 4); + g.drawLine(x + 4, y + 8, x + 4, y + 8); + + g.drawLine(x + 6, y + 2, x + 6, y + 2); + g.drawLine(x + 6, y + 6, x + 6, y + 6); + g.drawLine(x + 6, y + 10, x + 6, y + 10); + + // draw dots + g.setColor(focus ? new Color(102, 102, 153) : Color.black); // dark + g.drawLine(x + 3, y + 3, x + 3, y + 3); + g.drawLine(x + 3, y + 7, x + 3, y + 7); + g.drawLine(x + 3, y + 11, x + 3, y + 11); + + g.drawLine(x + 5, y + 5, x + 5, y + 5); + g.drawLine(x + 5, y + 9, x + 5, y + 9); + + g.drawLine(x + 7, y + 3, x + 7, y + 3); + g.drawLine(x + 7, y + 7, x + 7, y + 7); + g.drawLine(x + 7, y + 11, x + 7, y + 11); + } + } + + /** + * A tree control icon. This icon can be in one of two states: expanded and + * collapsed. + */ + public static class TreeControlIcon implements Icon, Serializable + { + + /** ???. */ + protected boolean isLight; + + /** A flag that controls whether or not the icon is collapsed. */ + private boolean collapsed; + + /** + * Creates a new icon. + * + * @param isCollapsed a flag that controls whether the icon is in the + * collapsed state or the expanded state. + */ + public TreeControlIcon(boolean isCollapsed) + { + collapsed = isCollapsed; + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 18; + } + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 18; + } + + /** + * Paints the icon at the location (x, y). + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + x = x + 5; + y = y + 5; + if (collapsed) + { + // TODO: pick up appropriate UI colors + g.setColor(Color.black); + g.drawLine(x + 2, y, x + 5, y); + g.drawLine(x + 6, y + 1, x + 7, y + 2); + g.fillRect(x + 7, y + 3, 5, 2); + g.drawLine(x + 7, y + 5, x + 6, y + 6); + g.drawLine(x + 1, y + 1, x + 1, y + 1); + g.drawLine(x, y + 2, x, y + 5); + g.drawLine(x + 1, y + 6, x + 1, y + 6); + g.drawLine(x + 2, y + 7, x + 5, y + 7); + g.fillRect(x + 3, y + 3, 2, 2); + + g.setColor(new Color(204, 204, 255)); + g.drawLine(x + 3, y + 2, x + 4, y + 2); + g.drawLine(x + 2, y + 3, x + 2, y + 4); + g.drawLine(x + 3, y + 5, x + 3, y + 5); + g.drawLine(x + 5, y + 3, x + 5, y + 3); + + g.setColor(new Color(153, 153, 204)); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 2, y + 5, x + 2, y + 5); + g.drawLine(x + 2, y + 6, x + 5, y + 6); + g.drawLine(x + 5, y + 2, x + 5, y + 2); + g.drawLine(x + 6, y + 2, x + 6, y + 5); + + g.setColor(new Color(102, 102, 153)); + g.drawLine(x + 2, y + 1, x + 5, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 5); + } + else + { + // TODO: pick up appropriate UI colors + g.setColor(Color.black); + g.drawLine(x + 2, y, x + 5, y); + g.drawLine(x + 6, y + 1, x + 7, y + 2); + g.drawLine(x + 7, y + 2, x + 7, y + 5); + g.fillRect(x + 3, y + 7, 2, 5); + g.drawLine(x + 7, y + 5, x + 6, y + 6); + g.drawLine(x + 1, y + 1, x + 1, y + 1); + g.drawLine(x, y + 2, x, y + 5); + g.drawLine(x + 1, y + 6, x + 1, y + 6); + g.drawLine(x + 2, y + 7, x + 5, y + 7); + g.fillRect(x + 3, y + 3, 2, 2); + + g.setColor(new Color(204, 204, 255)); + g.drawLine(x + 3, y + 2, x + 4, y + 2); + g.drawLine(x + 2, y + 3, x + 2, y + 4); + g.drawLine(x + 3, y + 5, x + 3, y + 5); + g.drawLine(x + 5, y + 3, x + 5, y + 3); + + g.setColor(new Color(153, 153, 204)); + g.drawLine(x + 2, y + 2, x + 2, y + 2); + g.drawLine(x + 2, y + 5, x + 2, y + 5); + g.drawLine(x + 2, y + 6, x + 5, y + 6); + g.drawLine(x + 5, y + 2, x + 5, y + 2); + g.drawLine(x + 6, y + 2, x + 6, y + 5); + + g.setColor(new Color(102, 102, 153)); + g.drawLine(x + 2, y + 1, x + 5, y + 1); + g.drawLine(x + 1, y + 2, x + 1, y + 5); + } + } + + /** + * Simply calls {@link #paintIcon(Component, Graphics, int, int)}. + * + * @param c the component. + * @param g the graphics device. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void paintMe(Component c, Graphics g, int x, int y) + { + paintIcon(c, g, x, y); + } + } + + /** + * A tree folder icon. + */ + public static class TreeFolderIcon extends FolderIcon16 + { + /** + * Creates a new instance. + */ + public TreeFolderIcon() + { + } + + /** + * Returns the additional height (???). + * + * @return The additional height. + */ + public int getAdditionalHeight() + { + return 2; + } + + /** + * Returns the shift (???). + * + * @return The shift. + */ + public int getShift() + { + return -1; + } + } + + /** + * A tree leaf icon. + */ + public static class TreeLeafIcon extends FileIcon16 + { + /** + * Creates a new instance. + */ + public TreeLeafIcon() + { + } + + /** + * Returns the additional height (???). + * + * @return The additional height. + */ + public int getAdditionalHeight() + { + return 4; + } + + /** + * Returns the shift (???). + * + * @return The shift. + */ + public int getShift() + { + return 2; + } + } + + /** + * Creates a new instance. All the methods are static, so creating an + * instance isn't necessary. + */ + public MetalIconFactory() + { + } + + /** + * Returns the icon used to display the thumb for a horizontally oriented + * {@link JSlider}. + * + * @return The icon. + */ + public static Icon getHorizontalSliderThumbIcon() + { + return new HorizontalSliderThumbIcon(); + } + + /** + * Returns the icon used to display the thumb for a vertically oriented + * {@link JSlider}. + * + * @return The icon. + */ + public static Icon getVerticalSliderThumbIcon() + { + return new VerticalSliderThumbIcon(); + } + + /** + * Creates and returns a new tree folder icon. + * + * @return A new tree folder icon. + */ + public static Icon getTreeFolderIcon() + { + return new TreeFolderIcon(); + } + + /** + * Creates and returns a new tree leaf icon. + * + * @return A new tree leaf icon. + */ + public static Icon getTreeLeafIcon() + { + return new TreeLeafIcon(); + } + + /** + * Creates and returns a tree control icon. + * + * @param isCollapsed a flag that controls whether the icon is in the + * collapsed or expanded state. + * + * @return A tree control icon. + */ + public static Icon getTreeControlIcon(boolean isCollapsed) + { + return new TreeControlIcon(isCollapsed); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java new file mode 100644 index 00000000000..14143512e67 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameUI.java @@ -0,0 +1,88 @@ +/* MetalInternalFrameUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicInternalFrameUI; + +public class MetalInternalFrameUI + extends BasicInternalFrameUI +{ + + /** The instances of MetalInternalFrameUI*/ + private static HashMap instances; + + /** + * Constructs a new instance of MetalInternalFrameUI. + */ + public MetalInternalFrameUI(JInternalFrame frame) + { + super(frame); + } + + /** + * Returns an instance of MetalInternalFrameUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalInternalFrameUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + + Object o = instances.get(component); + MetalInternalFrameUI instance; + if (o == null) + { + instance = new MetalInternalFrameUI((JInternalFrame) component); + instances.put(component, instance); + } + else + instance = (MetalInternalFrameUI) o; + + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLabelUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalLabelUI.java new file mode 100644 index 00000000000..cdd861227a2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLabelUI.java @@ -0,0 +1,74 @@ +/* MetalLabelUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicLabelUI; + +public class MetalLabelUI + extends BasicLabelUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for JLabels. */ + private static MetalLabelUI instance = null; + + /** + * Constructs a new instance of MetalLabelUI. + */ + public MetalLabelUI() + { + super(); + } + + /** + * Returns an instance of MetalLabelUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalLabelUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalLabelUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java new file mode 100644 index 00000000000..46519fc3f78 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -0,0 +1,853 @@ +/* MetalLookAndFeel.java + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Insets; + +import javax.swing.ImageIcon; +import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.IconUIResource; +import javax.swing.plaf.basic.BasicLookAndFeel; + +/** + * A custom look and feel that is designed to look similar across different + * operating systems. + */ +public class MetalLookAndFeel extends BasicLookAndFeel +{ + private static final long serialVersionUID = 6680646159193457980L; + + /** The current theme. */ + private static MetalTheme theme; + + /** The look and feel defaults. */ + private UIDefaults LAF_defaults; + + /** + * Creates a new instance of the Metal look and feel. + */ + public MetalLookAndFeel() + { + createDefaultTheme(); + } + + /** + * Sets the current theme to a new instance of {@link DefaultMetalTheme}. + */ + protected void createDefaultTheme() + { + setCurrentTheme(new DefaultMetalTheme()); + } + + /** + * Returns <code>false</code> to indicate that this look and feel does not + * attempt to emulate the look and feel of native applications on the host + * platform. + * + * @return <code>false</code>. + */ + public boolean isNativeLookAndFeel() + { + return false; + } + + /** + * Returns <code>true</code> to indicate that this look and feel is supported + * on all platforms. + * + * @return <code>true</code>. + */ + public boolean isSupportedLookAndFeel() + { + return true; + } + + /** + * Returns a string describing the look and feel. In this case, the method + * returns "Metal look and feel". + * + * @return A string describing the look and feel. + */ + public String getDescription() + { + return "Metal look and feel"; + } + + /** + * Returns the look and feel identifier. + * + * @return "MetalLookAndFeel". + */ + public String getID() + { + return "MetalLookAndFeel"; + } + + /** + * Returns the look and feel name. + * + * @return "MetalLookAndFeel". + */ + public String getName() + { + return "MetalLookAndFeel"; + } + + public UIDefaults getDefaults() + { + if (LAF_defaults == null) + { + LAF_defaults = super.getDefaults(); + + // add custom theme entries to the table + theme.addCustomEntriesToTable(LAF_defaults); + } + + // Returns the default values for this look and feel. + return LAF_defaults; + } + + /** + * Returns the accelerator foreground color from the installed theme. + * + * @return The accelerator foreground color. + */ + public static ColorUIResource getAcceleratorForeground() + { + return theme.getAcceleratorForeground(); + } + + /** + * Returns the accelerator selected foreground color from the installed + * theme. + * + * @return The accelerator selected foreground color. + */ + public static ColorUIResource getAcceleratorSelectedForeground() + { + return theme.getAcceleratorSelectedForeground(); + } + + /** + * Returns the color black from the installed theme. + * + * @return The color black. + */ + public static ColorUIResource getBlack() + { + return theme.getBlack(); + } + + /** + * Returns the control color from the installed theme. + * + * @return The control color. + */ + public static ColorUIResource getControl() + { + return theme.getControl(); + } + + /** + * Returns the color used for dark shadows on controls, from the installed + * theme. + * + * @return The color used for dark shadows on controls. + */ + public static ColorUIResource getControlDarkShadow() + { + return theme.getControlDarkShadow(); + } + + /** + * Returns the color used for disabled controls, from the installed theme. + * + * @return The color used for disabled controls. + */ + public static ColorUIResource getControlDisabled() + { + return theme.getControlDisabled(); + } + + /** + * Returns the color used to draw highlights for controls, from the installed + * theme. + * + * @return The color used to draw highlights for controls. + */ + public static ColorUIResource getControlHighlight() + { + return theme.getControlHighlight(); + } + + /** + * Returns the color used to display control info, from the installed + * theme. + * + * @return The color used to display control info. + */ + public static ColorUIResource getControlInfo() + { + return theme.getControlInfo(); + } + + /** + * Returns the color used to draw shadows for controls, from the installed + * theme. + * + * @return The color used to draw shadows for controls. + */ + public static ColorUIResource getControlShadow() + { + return theme.getControlShadow(); + } + + /** + * Returns the color used for text on controls, from the installed theme. + * + * @return The color used for text on controls. + */ + public static ColorUIResource getControlTextColor() + { + return theme.getControlTextColor(); + } + + /** + * Returns the font used for text on controls, from the installed theme. + * + * @return The font used for text on controls. + */ + public static FontUIResource getControlTextFont() + { + return theme.getControlTextFont(); + } + + /** + * Returns the color used for the desktop background, from the installed + * theme. + * + * @return The color used for the desktop background. + */ + public static ColorUIResource getDesktopColor() + { + return theme.getDesktopColor(); + } + + /** + * Returns the color used to draw focus highlights, from the installed + * theme. + * + * @return The color used to draw focus highlights. + */ + public static ColorUIResource getFocusColor() + { + return theme.getFocusColor(); + } + + /** + * Returns the color used to draw highlighted text, from the installed + * theme. + * + * @return The color used to draw highlighted text. + */ + public static ColorUIResource getHighlightedTextColor() + { + return theme.getHighlightedTextColor(); + } + + /** + * Returns the color used to draw text on inactive controls, from the + * installed theme. + * + * @return The color used to draw text on inactive controls. + */ + public static ColorUIResource getInactiveControlTextColor() + { + return theme.getInactiveControlTextColor(); + } + + /** + * Returns the color used to draw inactive system text, from the installed + * theme. + * + * @return The color used to draw inactive system text. + */ + public static ColorUIResource getInactiveSystemTextColor() + { + return theme.getInactiveSystemTextColor(); + } + + /** + * Returns the background color for menu items, from the installed theme. + * + * @return The background color for menu items. + * + * @see #getMenuSelectedBackground() + */ + public static ColorUIResource getMenuBackground() + { + return theme.getMenuBackground(); + } + + /** + * Returns the foreground color for disabled menu items, from the installed + * theme. + * + * @return The foreground color for disabled menu items. + * + * @see #getMenuForeground() + */ + public static ColorUIResource getMenuDisabledForeground() + { + return theme.getMenuDisabledForeground(); + } + + /** + * Returns the foreground color for menu items, from the installed theme. + * + * @return The foreground color for menu items. + * + * @see #getMenuDisabledForeground() + * @see #getMenuSelectedForeground() + */ + public static ColorUIResource getMenuForeground() + { + return theme.getMenuForeground(); + } + + /** + * Returns the background color for selected menu items, from the installed + * theme. + * + * @return The background color for selected menu items. + * + * @see #getMenuBackground() + */ + public static ColorUIResource getMenuSelectedBackground() + { + return theme.getMenuSelectedBackground(); + } + + /** + * Returns the foreground color for selected menu items, from the installed + * theme. + * + * @return The foreground color for selected menu items. + * + * @see #getMenuForeground() + */ + public static ColorUIResource getMenuSelectedForeground() + { + return theme.getMenuSelectedForeground(); + } + + /** + * Returns the font used for text in menus, from the installed theme. + * + * @return The font used for text in menus. + */ + public static FontUIResource getMenuTextFont() + { + return theme.getMenuTextFont(); + } + + /** + * Returns the primary color for controls, from the installed theme. + * + * @return The primary color for controls. + */ + public static ColorUIResource getPrimaryControl() + { + return theme.getPrimaryControl(); + } + + /** + * Returns the primary color for the dark shadow on controls, from the + * installed theme. + * + * @return The primary color for the dark shadow on controls. + */ + public static ColorUIResource getPrimaryControlDarkShadow() + { + return theme.getPrimaryControlDarkShadow(); + } + + /** + * Returns the primary color for the highlight on controls, from the + * installed theme. + * + * @return The primary color for the highlight on controls. + */ + public static ColorUIResource getPrimaryControlHighlight() + { + return theme.getPrimaryControlHighlight(); + } + + /** + * Returns the primary color for the information on controls, from the + * installed theme. + * + * @return The primary color for the information on controls. + */ + public static ColorUIResource getPrimaryControlInfo() + { + return theme.getPrimaryControlInfo(); + } + + /** + * Returns the primary color for the shadow on controls, from the installed + * theme. + * + * @return The primary color for the shadow on controls. + */ + public static ColorUIResource getPrimaryControlShadow() + { + return theme.getPrimaryControlShadow(); + } + + /** + * Returns the background color for separators, from the installed theme. + * + * @return The background color for separators. + */ + public static ColorUIResource getSeparatorBackground() + { + return theme.getSeparatorBackground(); + } + + /** + * Returns the foreground color for separators, from the installed theme. + * + * @return The foreground color for separators. + */ + public static ColorUIResource getSeparatorForeground() + { + return theme.getSeparatorForeground(); + } + + /** + * Returns the font used for sub text, from the installed theme. + * + * @return The font used for sub text. + */ + public static FontUIResource getSubTextFont() + { + return theme.getSubTextFont(); + } + + /** + * Returns the color used for system text, from the installed theme. + * + * @return The color used for system text. + */ + public static ColorUIResource getSystemTextColor() + { + return theme.getSystemTextColor(); + } + + /** + * Returns the font used for system text, from the installed theme. + * + * @return The font used for system text. + */ + public static FontUIResource getSystemTextFont() + { + return theme.getSystemTextFont(); + } + + /** + * Returns the color used to highlight text, from the installed theme. + * + * @return The color used to highlight text. + */ + public static ColorUIResource getTextHighlightColor() + { + return theme.getTextHighlightColor(); + } + + /** + * Returns the color used to display user text, from the installed theme. + * + * @return The color used to display user text. + */ + public static ColorUIResource getUserTextColor() + { + return theme.getUserTextColor(); + } + + /** + * Returns the font used for user text, obtained from the current theme. + * + * @return The font used for user text. + */ + public static FontUIResource getUserTextFont() + { + return theme.getUserTextFont(); + } + + /** + * Returns the color used for white, from the installed theme. + * + * @return The color used for white. + */ + public static ColorUIResource getWhite() + { + return theme.getWhite(); + } + + /** + * Returns the window background color, from the installed theme. + * + * @return The window background color. + */ + public static ColorUIResource getWindowBackground() + { + return theme.getWindowBackground(); + } + + /** + * Returns the window title background color, from the installed theme. + * + * @return The window title background color. + */ + public static ColorUIResource getWindowTitleBackground() + { + return theme.getWindowTitleBackground(); + } + + /** + * Returns the window title font from the current theme. + * + * @return The window title font. + * + * @see MetalTheme + */ + public static FontUIResource getWindowTitleFont() + { + return theme.getWindowTitleFont(); + } + + /** + * Returns the window title foreground color, from the installed theme. + * + * @return The window title foreground color. + */ + public static ColorUIResource getWindowTitleForeground() + { + return theme.getWindowTitleForeground(); + } + + /** + * Returns the background color for an inactive window title, from the + * installed theme. + * + * @return The background color for an inactive window title. + */ + public static ColorUIResource getWindowTitleInactiveBackground() + { + return theme.getWindowTitleInactiveBackground(); + } + + /** + * Returns the foreground color for an inactive window title, from the + * installed theme. + * + * @return The foreground color for an inactive window title. + */ + public static ColorUIResource getWindowTitleInactiveForeground() + { + return theme.getWindowTitleInactiveForeground(); + } + + /** + * Sets the current theme for the look and feel. + * + * @param theme the theme. + */ + public static void setCurrentTheme(MetalTheme theme) + { + MetalLookAndFeel.theme = theme; + } + + /** + * Sets the ComponentUI classes for all Swing components to the Metal + * implementations. + * + * In particular this sets the following keys: + * + * <table> + * <tr> + * <th>Key</th><th>Value</th> + * </tr><tr> + * <td>ButtonUI</td><td>{@link MetalButtonUI}</td> + * </tr><tr> + * <td>CheckBoxUI</td><td>{@link MetalCheckBoxUI}</td> + * </tr><tr> + * <td>ComboBoxUI</td><td>{@link MetalComboBoxUI}</td> + * </tr><tr> + * <td>DesktopIconUI</td><td>{@link MetalDesktopIconUI}</td> + * </tr><tr> + * <td>InternalFrameUI</td><td>{@link MetalInternalFrameUI}</td> + * </tr><tr> + * <td>LabelUI</td><td>{@link MetalLabelUI}</td> + * </tr><tr> + * <td>PopupMenuSeparatorUI</td><td>{@link MetalPopupMenuSeparatorUI}</td> + * </tr><tr> + * <td>ProgressBarUI</td><td>{@link MetalProgressBarUI}</td> + * </tr><tr> + * <td>RadioButtonUI</td><td>{@link MetalRadioButtonUI}</td> + * </tr><tr> + * <td>RootPaneUI</td><td>{@link MetalRootPaneUI}</td> + * </tr><tr> + * <td>ScrollBarUI</td><td>{@link MetalScrollBarUI}</td> + * </tr><tr> + * <td>ScrollPaneUI</td><td>{@link MetalScrollPaneUI}</td> + * </tr><tr> + * <td>SeparatorUI</td><td>{@link MetalSeparatorUI}</td> + * </tr><tr> + * <td>SliderUI</td><td>{@link MetalSliderUI}</td> + * </tr><tr> + * <td>SplitPaneUI</td><td>{@link MetalSplitPaneUI}</td> + * </tr><tr> + * <td>TabbedPaneUI</td><td>{@link MetalTabbedPaneUI}</td> + * </tr><tr> + * <td>TextFieldUI</td><td>{@link MetalTextFieldUI}</td> + * </tr><tr> + * <td>ToggleButtonUI</td><td>{@link MetalToggleButtonUI}</td> + * </tr><tr> + * <td>ToolBarUI</td><td>{@link MetalToolBarUI}</td> + * </tr><tr> + * <td>ToolTipUI</td><td>{@link MetalToolTipUI}</td> + * </tr><tr> + * <td>TreeUI</td><td>{@link MetalTreeUI}</td> + * </tr><tr> + * </table> + * + * @param defaults the UIDefaults where the class defaults are added + */ + protected void initClassDefaults(UIDefaults defaults) + { + super.initClassDefaults(defaults); + + // Variables + Object[] uiDefaults; + // Initialize Class Defaults + uiDefaults = new Object[] { + "ButtonUI", "javax.swing.plaf.metal.MetalButtonUI", + "CheckBoxUI", "javax.swing.plaf.metal.MetalCheckBoxUI", + "ComboBoxUI", "javax.swing.plaf.metal.MetalComboBoxUI", + "DesktopIconUI", "javax.swing.plaf.metal.MetalDesktopIconUI", + "InternalFrameUI", "javax.swing.plaf.metal.MetalInternalFrameUI", + "LabelUI", "javax.swing.plaf.metal.MetalLabelUI", + "PopupMenuSeparatorUI", + "javax.swing.plaf.metal.MetalPopupMenuSeparatorUI", + "ProgressBarUI", "javax.swing.plaf.metal.MetalProgressBarUI", + "RadioButtonUI", "javax.swing.plaf.metal.MetalRadioButtonUI", + "RootPaneUI", "javax.swing.plaf.metal.MetalRootPaneUI", + "ScrollBarUI", "javax.swing.plaf.metal.MetalScrollBarUI", + "ScrollPaneUI", "javax.swing.plaf.metal.MetalScrollPaneUI", + "SeparatorUI", "javax.swing.plaf.metal.MetalSeparatorUI", + "SliderUI", "javax.swing.plaf.metal.MetalSliderUI", + "SplitPaneUI", "javax.swing.plaf.metal.MetalSplitPaneUI", + "TabbedPaneUI", "javax.swing.plaf.metal.MetalTabbedPaneUI", + "TextFieldUI", "javax.swing.plaf.metal.MetalTextFieldUI", + "ToggleButtonUI", "javax.swing.plaf.metal.MetalToggleButtonUI", + "ToolBarUI", "javax.swing.plaf.metal.MetalToolBarUI", + "ToolTipUI", "javax.swing.plaf.metal.MetalToolTipUI", + "TreeUI", "javax.swing.plaf.metal.MetalTreeUI", + }; + // Add Class Defaults to UI Defaults table + defaults.putDefaults(uiDefaults); + } + + /** + * Initializes the component defaults for the Metal Look & Feel. + * + * In particular this sets the following keys (the colors are given + * as RGB hex values): + * + * <table> + * <tr> + * <th>Key</th><th>Value</th> + * </tr><tr> + * <td>Button.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Button.border</td><td>{@link MetalBorders#getButtonBorder()}</td> + * </tr><tr> + * <td>Button.font</td><td>{@link #getControlTextFont}</td> + * </tr><tr> + * <td>Button.margin</td><td><code>new java.awt.Insets(2, 14, 2, 14)</code> + * </td> + * </tr><tr> + * <td>CheckBox.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>CheckBoxMenuItem.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>ToolBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Panel.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Slider.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>OptionPane.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>ProgressBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>TabbedPane.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Label.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>Label.font</td><td>{@link #getControlTextFont}</td> + * </tr><tr> + * <td>Menu.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>MenuBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>MenuItem.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>ScrollBar.background</td><td>0xcccccc</td> + * </tr><tr> + * <td>PopupMenu.border</td> + * <td><code>new javax.swing.plaf.metal.MetalBorders.PopupMenuBorder()</td> + * </tr><tr> + * </table> + * + * @param defaults the UIDefaults instance to which the values are added + */ + protected void initComponentDefaults(UIDefaults defaults) + { + super.initComponentDefaults(defaults); + Object[] myDefaults = new Object[] { + "Button.background", new ColorUIResource(getControl()), + "Button.border", MetalBorders.getButtonBorder(), + "Button.darkShadow", new ColorUIResource(getControlDarkShadow()), + "Button.disabledText", new ColorUIResource(getControlDisabled()), + "Button.focus", new ColorUIResource(getFocusColor()), + "Button.font", getControlTextFont(), + "Button.foreground", new ColorUIResource(getSystemTextColor()), + "Button.highlight", new ColorUIResource(getControlHighlight()), + "Button.light", new ColorUIResource(getControlHighlight()), + "Button.margin", new Insets(2, 14, 2, 14), + "Button.select", new ColorUIResource(getPrimaryControlShadow()), + "Button.shadow", new ColorUIResource(getPrimaryControlShadow()), + "CheckBox.background", new ColorUIResource(getControl()), + "CheckBoxMenuItem.background", new ColorUIResource(getControl()), + "ToolBar.background", new ColorUIResource(getControl()), + "Panel.background", new ColorUIResource(getControl()), + "Slider.background", new ColorUIResource(getControl()), + "OptionPane.background", new ColorUIResource(getControl()), + "ProgressBar.background", new ColorUIResource(getControl()), + "ScrollPane.border", new MetalBorders.ScrollPaneBorder(), + "TabbedPane.background", new ColorUIResource(getControl()), + "Label.background", new ColorUIResource(getControl()), + "Label.font", getControlTextFont(), + "Label.disabledForeground", new ColorUIResource(getControlDisabled()), + "Label.foreground", new ColorUIResource(getSystemTextColor()), + "Menu.background", new ColorUIResource(getControl()), + "Menu.font", getControlTextFont(), + "MenuBar.background", new ColorUIResource(getControl()), + "MenuBar.font", getControlTextFont(), + "MenuItem.background", new ColorUIResource(getControl()), + "MenuItem.font", getControlTextFont(), + "ScrollBar.background", new ColorUIResource(getControl()), + "ScrollBar.shadow", new ColorUIResource(getControlShadow()), + "ScrollBar.thumb", new ColorUIResource(getPrimaryControlShadow()), + "ScrollBar.thumbDarkShadow", + new ColorUIResource(getPrimaryControlDarkShadow()), + "ScrollBar.thumbHighlight", + new ColorUIResource(getPrimaryControl()), + + "SplitPane.darkShadow", + new ColorUIResource(getControlDarkShadow()), + "SplitPane.highlight", + new ColorUIResource(getControlHighlight()), + + "Tree.openIcon", MetalIconFactory.getTreeFolderIcon(), + "Tree.closedIcon", MetalIconFactory.getTreeFolderIcon(), + "Tree.leafIcon", MetalIconFactory.getTreeLeafIcon(), + "Tree.collapsedIcon", MetalIconFactory.getTreeControlIcon(true), + "Tree.expandedIcon", MetalIconFactory.getTreeControlIcon(false), + "Tree.font", new FontUIResource(new Font("Helvetica", Font.PLAIN, 12)), + "Tree.background", new ColorUIResource(Color.white), + "Tree.foreground", new ColorUIResource(new Color(204, 204, 255)), + "Tree.hash", new ColorUIResource(new Color(204, 204, 255)), + "Tree.leftChildIndent", new Integer(7), + "Tree.rightChildIndent", new Integer(13), + "Tree.rowHeight", new Integer(20), + "Tree.scrollsOnExpand", Boolean.TRUE, + "Tree.selectionBackground", new ColorUIResource(new Color(204, 204, 255)), + "Tree.nonSelectionBackground", new ColorUIResource(Color.white), + "Tree.selectionBorderColor", new ColorUIResource(new Color(102, 102, 153)), + "Tree.selectionForeground", new ColorUIResource(Color.black), + "Tree.textBackground", new ColorUIResource(new Color(204, 204, 255)), + "Tree.textForeground", new ColorUIResource(Color.black), + "Tree.selectionForeground", new ColorUIResource(Color.black), + "PopupMenu.border", new MetalBorders.PopupMenuBorder() + }; + defaults.putDefaults(myDefaults); + } + + /** + * Initializes the system color defaults. + * + * In particular this sets the following keys: + * + * <table> + * <tr> + * <th>Key</th><th>Value</th><th>Description</th> + * </tr><tr> + * <td>control</td><td>0xcccccc</td><td>The default color for components</td> + * </tr> + * </table> + */ + protected void initSystemColorDefaults(UIDefaults defaults) + { + super.initSystemColorDefaults(defaults); + Object[] uiDefaults; + uiDefaults = new Object[] { + "control", new ColorUIResource(getControl()) + }; + defaults.putDefaults(uiDefaults); + } + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java new file mode 100644 index 00000000000..ec9bf2b5586 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java @@ -0,0 +1,73 @@ +/* MetalPopupMenuSeparatorUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +public class MetalPopupMenuSeparatorUI + extends MetalSeparatorUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalPopupMenuSeparatorUIs */ + private static MetalPopupMenuSeparatorUI instance = null; + + /** + * Constructs a new instance of MetalPopupMenuSeparatorUI. + */ + public MetalPopupMenuSeparatorUI() + { + super(); + } + + /** + * Returns an instance of MetalPopupMenuSeparatorUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalPopupMenuSeparatorUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalPopupMenuSeparatorUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalProgressBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalProgressBarUI.java new file mode 100644 index 00000000000..96d1988fd3d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalProgressBarUI.java @@ -0,0 +1,74 @@ +/* MetalProgressBarUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicProgressBarUI; + +public class MetalProgressBarUI + extends BasicProgressBarUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalProgressBarUIs */ + private static MetalProgressBarUI instance = null; + + /** + * Constructs a new instance of MetalProgressBarUI. + */ + public MetalProgressBarUI() + { + super(); + } + + /** + * Returns an instance of MetalProgressBarUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalProgressBarUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalProgressBarUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java new file mode 100644 index 00000000000..a668f914e43 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalRadioButtonUI.java @@ -0,0 +1,74 @@ +/* MetalRadioButtonUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicRadioButtonUI; + +public class MetalRadioButtonUI + extends BasicRadioButtonUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for JRadioButtons. */ + private static MetalRadioButtonUI instance = null; + + /** + * Constructs a new instance of MetalRadioButtonUI. + */ + public MetalRadioButtonUI() + { + super(); + } + + /** + * Returns an instance of MetalRadioButtonUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalRadioButtonUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalRadioButtonUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java new file mode 100644 index 00000000000..4196a4e477c --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -0,0 +1,74 @@ +/* MetalRootPaneUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicRootPaneUI; + +public class MetalRootPaneUI + extends BasicRootPaneUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalRootPaneUIs */ + private static MetalRootPaneUI instance = null; + + /** + * Constructs a new instance of MetalRootPaneUI. + */ + public MetalRootPaneUI() + { + super(); + } + + /** + * Returns an instance of MetalRootPaneUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalRootPaneUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalRootPaneUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java new file mode 100644 index 00000000000..526dfb50ae2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -0,0 +1,146 @@ +/* MetalScrollBarUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollBarUI; + +public class MetalScrollBarUI + extends BasicScrollBarUI +{ + + /** The minimum thumb size */ + private static final Dimension MIN_THUMB_SIZE = new Dimension(18, 18); + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for JScrollBars. */ + private static HashMap instances = null; + + /** + * Constructs a new instance of MetalScrollBarUI. + */ + public MetalScrollBarUI() + { + super(); + } + + /** + * Returns an instance of MetalScrollBarUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalScrollBarUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + Object o = instances.get(component); + MetalScrollBarUI instance; + if (o == null) + { + instance = new MetalScrollBarUI(); + instances.put(component, instance); + } + else + instance = (MetalScrollBarUI) o; + + return instance; + } + + /** + * Paints the slider button of the ScrollBar. + * + * @param g the Graphics context to use + * @param c the JComponent on which we paint + * @param thumbBounds the rectangle that is the slider button + */ + protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) + { + // first we fill the background + g.setColor(thumbColor); + g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width, + thumbBounds.height); + + // draw the outer dark line + g.setColor(thumbDarkShadowColor); + g.drawRect(thumbBounds.x, thumbBounds.y, thumbBounds.width - 1, + thumbBounds.height - 1); + + // draw the inner light line + g.setColor(thumbHighlightColor); + g.drawLine(thumbBounds.x + 1, thumbBounds.y + 1, + thumbBounds.x + thumbBounds.width - 2, + thumbBounds.y + 1); + g.drawLine(thumbBounds.x + 1, thumbBounds.y + 1, + thumbBounds.x + 1, + thumbBounds.y + thumbBounds.height - 2); + + // draw the shadow line + UIDefaults def = UIManager.getLookAndFeelDefaults(); + g.setColor(def.getColor("ScrollBar.shadow")); + g.drawLine(thumbBounds.x + 1, thumbBounds.y + thumbBounds.height, + thumbBounds.x + thumbBounds.width, + thumbBounds.y + thumbBounds.height); + + // draw the pattern + MetalUtils.fillMetalPattern(g, thumbBounds.x + 3, thumbBounds.y + 3, + thumbBounds.width - 6, thumbBounds.height - 6, + thumbHighlightColor, thumbDarkShadowColor); + } + + /** + * This method returns the minimum thumb size. + * + * @return The minimum thumb size. + */ + protected Dimension getMinimumThumbSize() + { + return MIN_THUMB_SIZE; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollPaneUI.java new file mode 100644 index 00000000000..3e1198b398d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollPaneUI.java @@ -0,0 +1,74 @@ +/* MetalScrollPaneUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollPaneUI; + +public class MetalScrollPaneUI + extends BasicScrollPaneUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for JScrollPanes. */ + private static MetalScrollPaneUI instance = null; + + /** + * Constructs a new instance of MetalScrollPaneUI. + */ + public MetalScrollPaneUI() + { + super(); + } + + /** + * Returns an instance of MetalScrollPaneUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalScrollPaneUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalScrollPaneUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSeparatorUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSeparatorUI.java new file mode 100644 index 00000000000..6e78ccb7071 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSeparatorUI.java @@ -0,0 +1,74 @@ +/* MetalSeparatorUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSeparatorUI; + +public class MetalSeparatorUI + extends BasicSeparatorUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalSeparatorUIs */ + private static MetalSeparatorUI instance = null; + + /** + * Constructs a new instance of MetalSeparatorUI. + */ + public MetalSeparatorUI() + { + super(); + } + + /** + * Returns an instance of MetalSeparatorUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalSeparatorUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalSeparatorUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java new file mode 100644 index 00000000000..a857d6a9d8d --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java @@ -0,0 +1,87 @@ +/* MetalSliderUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSliderUI; + +public class MetalSliderUI + extends BasicSliderUI +{ + + /** The UI instances for MetalSliderUIs */ + private static HashMap instances; + + /** + * Constructs a new instance of MetalSliderUI. + */ + public MetalSliderUI() + { + super(null); + } + + /** + * Returns an instance of MetalSliderUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalSliderUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + + Object o = instances.get(component); + MetalSliderUI instance; + if (o == null) + { + instance = new MetalSliderUI(); + instances.put(component, instance); + } + else + instance = (MetalSliderUI) o; + + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java new file mode 100644 index 00000000000..60e9c055952 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneDivider.java @@ -0,0 +1,84 @@ +/* MetalSplitPaneDivider.java +Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; + +import javax.swing.plaf.basic.BasicSplitPaneDivider; + +/** + * The divider that is used by the MetalSplitPaneUI. + * + * @author Roman Kennke (roman@kennke.org) + * + */ +class MetalSplitPaneDivider extends BasicSplitPaneDivider +{ + /** The dark color in the pattern. */ + Color dark; + + /** The light color in the pattern. */ + Color light; + + /** + * Creates a new instance of MetalSplitPaneDivider. + * + * @param ui the <code>MetalSplitPaneUI</code> that uses this divider + */ + public MetalSplitPaneDivider(MetalSplitPaneUI ui, Color light, Color dark) + { + super(ui); + this.light = light; + this.dark = dark; + } + + /** + * Paints the divider. + * + * @param g the <code>Graphics</code> context to use for painting + */ + public void paint(Graphics g) + { + //super.paint(g); + Dimension s = getSize(); + MetalUtils.fillMetalPattern(g, 2, 2, s.width - 4, s.height - 4, + light, dark); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneUI.java new file mode 100644 index 00000000000..b7ea8984b43 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalSplitPaneUI.java @@ -0,0 +1,106 @@ +/* MetalSplitPaneUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.plaf.basic.BasicSplitPaneDivider; + +public class MetalSplitPaneUI + extends BasicSplitPaneUI +{ + + /** The UI instances for MetalSplitPaneUIs */ + private static HashMap instances; + + /** + * Constructs a new instance of MetalSplitPaneUI. + */ + public MetalSplitPaneUI() + { + super(); + } + + /** + * Returns an instance of MetalSplitPaneUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalSplitPaneUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + Object o = instances.get(component); + MetalSplitPaneUI instance; + if (o == null) + { + instance = new MetalSplitPaneUI(); + instances.put(component, instance); + } + else + instance = (MetalSplitPaneUI) o; + + return instance; + } + + /** + * Returns the divider that is used by the <code>JSplitPane</code>. + * + * The divider returned by this method is a {@link BasicSplitPaneDivider} + * that is drawn using the Metal look. + * + * @return the default divider to use for <code>JSplitPane</code>s. + */ + public BasicSplitPaneDivider createDefaultDivider() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + Color light = defaults.getColor("SplitPane.highlight"); + Color dark = defaults.getColor("SplitPane.darkShadow"); + return new MetalSplitPaneDivider(this, light, dark); + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java new file mode 100644 index 00000000000..bf50f9172a1 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java @@ -0,0 +1,86 @@ +/* MetalTabbedPaneUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTabbedPaneUI; + +public class MetalTabbedPaneUI + extends BasicTabbedPaneUI +{ + + /** The shared UI instance for JTabbedPanes. */ + private static HashMap instances = null; + + /** + * Constructs a new instance of MetalTabbedPaneUI. + */ + public MetalTabbedPaneUI() + { + super(); + } + + /** + * Returns an instance of MetalTabbedPaneUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalTabbedPaneUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + Object o = instances.get(component); + MetalTabbedPaneUI instance; + if (o == null) + { + instance = new MetalTabbedPaneUI(); + instances.put(component, instance); + } + else + instance = (MetalTabbedPaneUI) o; + + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTextFieldUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTextFieldUI.java new file mode 100644 index 00000000000..d6e50e12239 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTextFieldUI.java @@ -0,0 +1,86 @@ +/* MetalTextFieldUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTextFieldUI; + +public class MetalTextFieldUI + extends BasicTextFieldUI +{ + + /** The UI instances for MetalTextFieldUIs */ + private static HashMap instances = null; + + /** + * Constructs a new instance of MetalTextFieldUI. + */ + public MetalTextFieldUI() + { + super(); + } + + /** + * Returns an instance of MetalTextFieldUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalTextFieldUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + Object o = instances.get(component); + MetalTextFieldUI instance; + if (o == null) + { + instance = new MetalTextFieldUI(); + instances.put(component, instance); + } + else + instance = (MetalTextFieldUI) o; + + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTheme.java b/libjava/classpath/javax/swing/plaf/metal/MetalTheme.java new file mode 100644 index 00000000000..d5131af2e29 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTheme.java @@ -0,0 +1,576 @@ +/* MetalTheme.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + + +package javax.swing.plaf.metal; + +import java.awt.Color; + +import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; + +/** + * The base class for themes used by the {@link MetalLookAndFeel}. A default + * theme ({@link DefaultMetalTheme}) is provided, or you can create and use + * your own. + * + * @see MetalLookAndFeel#setCurrentTheme(MetalTheme) + */ +public abstract class MetalTheme +{ + private ColorUIResource BLACK = new ColorUIResource(Color.BLACK); + private ColorUIResource WHITE = new ColorUIResource(Color.WHITE); + + /** + * Default constructor. + */ + public MetalTheme() + { + // Do nothing here. + } + + /** + * Returns the name of the theme. + * + * @return The name of the theme. + */ + public abstract String getName(); + + /** + * Adds custom entries to the UI defaults table. This method is empty. + * + * @param table the table. + */ + public void addCustomEntriesToTable(UIDefaults table) + { + // Do nothing here. + // This method needs to be overridden to actually do something. + // It is called from MetalLookAndFeel.getDefaults(). + } + + /** + * Returns the accelerator foreground color. The default implementation + * returns the color from {@link #getPrimary1()}. + * + * @return The accelerator foreground color. + */ + public ColorUIResource getAcceleratorForeground() + { + return getPrimary1(); + } + + /** + * Returns the accelerator selected foreground color. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The accelerator selected foreground color. + */ + public ColorUIResource getAcceleratorSelectedForeground() + { + return getBlack(); + } + + /** + * Returns the control color. The default implementation returns the color + * from {@link #getSecondary3()}. + * + * @return The control color. + */ + public ColorUIResource getControl() + { + return getSecondary3(); + } + + /** + * Returns the color used for dark shadows on controls. The default + * implementation returns the color from {@link #getSecondary1()}. + * + * @return The color used for dark shadows on controls. + */ + public ColorUIResource getControlDarkShadow() + { + return getSecondary1(); + } + + /** + * Returns the color used for disabled controls. The default implementation + * returns the color from {@link #getSecondary1()}. + * + * @return The color used for disabled controls. + */ + public ColorUIResource getControlDisabled() + { + return getSecondary2(); + } + + /** + * Returns the color used to draw highlights for controls. The default + * implementation returns the color from {@link #getWhite()}. + * + * @return The color used to draw highlights for controls. + */ + public ColorUIResource getControlHighlight() + { + return getWhite(); + } + + /** + * Returns the color used to display control info. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The color used to display control info. + */ + public ColorUIResource getControlInfo() + { + return getBlack(); + } + + /** + * Returns the color used to draw shadows for controls. The default + * implementation returns the color from {@link #getSecondary2()}. + * + * @return The color used to draw shadows for controls. + */ + public ColorUIResource getControlShadow() + { + return getSecondary2(); + } + + /** + * Returns the color used for text on controls. The default implementation + * returns the color from {@link #getControlInfo()}. + * + * @return The color used for text on controls. + */ + public ColorUIResource getControlTextColor() + { + return getControlInfo(); + } + + /** + * Returns the color used for the desktop background. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The color used for the desktop background. + */ + public ColorUIResource getDesktopColor() + { + return getPrimary2(); + } + + /** + * Returns the color used to draw focus highlights. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The color used to draw focus highlights. + */ + public ColorUIResource getFocusColor() + { + return getPrimary2(); + } + + /** + * Returns the color used to draw highlighted text. The default + * implementation returns the color from {@link #getHighlightedTextColor()}. + * + * @return The color used to draw highlighted text. + */ + public ColorUIResource getHighlightedTextColor() + { + return getControlTextColor(); + } + + /** + * Returns the color used to draw text on inactive controls. The default + * implementation returns the color from {@link #getControlDisabled()}. + * + * @return The color used to draw text on inactive controls. + */ + public ColorUIResource getInactiveControlTextColor() + { + return getControlDisabled(); + } + + /** + * Returns the color used to draw inactive system text. The default + * implementation returns the color from {@link #getSecondary2()}. + * + * @return The color used to draw inactive system text. + */ + public ColorUIResource getInactiveSystemTextColor() + { + return getSecondary2(); + } + + /** + * Returns the background color for menu items. The default implementation + * returns the color from {@link #getSecondary3()}. + * + * @return The background color for menu items. + * + * @see #getMenuSelectedBackground() + */ + public ColorUIResource getMenuBackground() + { + return getSecondary3(); + } + + /** + * Returns the foreground color for disabled menu items. The default + * implementation returns the color from {@link #getSecondary2()}. + * + * @return The foreground color for disabled menu items. + * + * @see #getMenuForeground() + */ + public ColorUIResource getMenuDisabledForeground() + { + return getSecondary2(); + } + + /** + * Returns the foreground color for menu items. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The foreground color for menu items. + * + * @see #getMenuDisabledForeground() + * @see #getMenuSelectedForeground() + */ + public ColorUIResource getMenuForeground() + { + return getBlack(); + } + + /** + * Returns the background color for selected menu items. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The background color for selected menu items. + * + * @see #getMenuBackground() + */ + public ColorUIResource getMenuSelectedBackground() + { + return getPrimary2(); + } + + /** + * Returns the foreground color for selected menu items. The default + * implementation returns the value from {@link #getBlack()}. + * + * @return The foreground color for selected menu items. + * + * @see #getMenuForeground() + */ + public ColorUIResource getMenuSelectedForeground() + { + return getBlack(); + } + + /** + * Returns the primary color for controls. The default implementation + * returns the color from {@link #getPrimary3()}. + * + * @return The primary color for controls. + */ + public ColorUIResource getPrimaryControl() + { + return getPrimary3(); + } + + /** + * Returns the primary color for the dark shadow on controls. The default + * implementation returns the color from {@link #getPrimary1()}. + * + * @return The primary color for the dark shadow on controls. + */ + public ColorUIResource getPrimaryControlDarkShadow() + { + return getPrimary1(); + } + + /** + * Returns the primary color for the highlight on controls. The default + * implementation returns the color from {@link #getWhite()}. + * + * @return The primary color for the highlight on controls. + */ + public ColorUIResource getPrimaryControlHighlight() + { + return getWhite(); + } + + /** + * Returns the primary color for the information on controls. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The primary color for the information on controls. + */ + public ColorUIResource getPrimaryControlInfo() + { + return getBlack(); + } + + /** + * Returns the primary color for the shadow on controls. The default + * implementation returns the color from {@link #getPrimary2()}. + * + * @return The primary color for the shadow on controls. + */ + public ColorUIResource getPrimaryControlShadow() + { + return getPrimary2(); + } + + /** + * Returns the background color for separators. The default implementation + * returns the color from {@link #getWhite()}. + * + * @return The background color for separators. + */ + public ColorUIResource getSeparatorBackground() + { + return getWhite(); + } + + /** + * Returns the foreground color for separators. The default implementation + * returns the value from {@link #getPrimary1()}. + * + * @return The foreground color for separators. + */ + public ColorUIResource getSeparatorForeground() + { + return getPrimary1(); + } + + /** + * Returns the color used for system text. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The color used for system text. + */ + public ColorUIResource getSystemTextColor() + { + return getBlack(); + } + + /** + * Returns the color used to highlight text. The default implementation + * returns the color from {@link #getPrimary3()}. + * + * @return The color used to highlight text. + */ + public ColorUIResource getTextHighlightColor() + { + return getPrimary3(); + } + + /** + * Returns the color used to display user text. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The color used to display user text. + */ + public ColorUIResource getUserTextColor() + { + return getBlack(); + } + + /** + * Returns the window background color. The default implementation returns + * the color from {@link #getWhite()}. + * + * @return The window background color. + */ + public ColorUIResource getWindowBackground() + { + return getWhite(); + } + + /** + * Returns the window title background color. The default implementation + * returns the color from {@link #getPrimary3()}. + * + * @return The window title background color. + */ + public ColorUIResource getWindowTitleBackground() + { + return getPrimary3(); + } + + /** + * Returns the window title foreground color. The default implementation + * returns the color from {@link #getBlack()}. + * + * @return The window title foreground color. + */ + public ColorUIResource getWindowTitleForeground() + { + return getBlack(); + } + + /** + * Returns the background color for an inactive window title. The default + * implementation returns the color from {@link #getSecondary3()}. + * + * @return The background color for an inactive window title. + */ + public ColorUIResource getWindowTitleInactiveBackground() + { + return getSecondary3(); + } + + /** + * Returns the foreground color for an inactive window title. The default + * implementation returns the color from {@link #getBlack()}. + * + * @return The foreground color for an inactive window title. + */ + public ColorUIResource getWindowTitleInactiveForeground() + { + return getBlack(); + } + + /** + * Returns the color used for black. + * + * @return The color used for black. + */ + protected ColorUIResource getBlack() + { + return BLACK; + } + + /** + * Returns the color used for white. + * + * @return The color used for white. + */ + protected ColorUIResource getWhite() + { + return WHITE; + } + + /** + * Returns the first primary color for this theme. + * + * @return The first primary color. + */ + protected abstract ColorUIResource getPrimary1(); + + /** + * Returns the second primary color for this theme. + * + * @return The second primary color. + */ + protected abstract ColorUIResource getPrimary2(); + + /** + * Returns the third primary color for this theme. + * + * @return The third primary color. + */ + protected abstract ColorUIResource getPrimary3(); + + /** + * Returns the first secondary color for this theme. + * + * @return The first secondary color. + */ + protected abstract ColorUIResource getSecondary1(); + + /** + * Returns the second secondary color for this theme. + * + * @return The second secondary color. + */ + protected abstract ColorUIResource getSecondary2(); + + /** + * Returns the third secondary color for this theme. + * + * @return The third secondary color. + */ + protected abstract ColorUIResource getSecondary3(); + + /** + * Returns the font used for text on controls. + * + * @return The font used for text on controls. + */ + public abstract FontUIResource getControlTextFont(); + + /** + * Returns the font used for text in menus. + * + * @return The font used for text in menus. + */ + public abstract FontUIResource getMenuTextFont(); + + /** + * Returns the font used for sub text. + * + * @return The font used for sub text. + */ + public abstract FontUIResource getSubTextFont(); + + /** + * Returns the font used for system text. + * + * @return The font used for system text. + */ + public abstract FontUIResource getSystemTextFont(); + + /** + * Returns the font used for user text. + * + * @return The font used for user text. + */ + public abstract FontUIResource getUserTextFont(); + + /** + * Returns the font used for window titles. + * + * @return The font used for window titles. + */ + public abstract FontUIResource getWindowTitleFont(); + +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java new file mode 100644 index 00000000000..7913cdb83e9 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java @@ -0,0 +1,74 @@ +/* MetalToggleButtonUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicToggleButtonUI; + +public class MetalToggleButtonUI + extends BasicToggleButtonUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalToggleButtonUIs */ + private static MetalToggleButtonUI instance = null; + + /** + * Constructs a new instance of MetalToggleButtonUI. + */ + public MetalToggleButtonUI() + { + super(); + } + + /** + * Returns an instance of MetalToggleButtonUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalToggleButtonUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalToggleButtonUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java new file mode 100644 index 00000000000..39af0011ae6 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java @@ -0,0 +1,74 @@ +/* MetalToolBarUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicToolBarUI; + +public class MetalToolBarUI + extends BasicToolBarUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalToolBarUIs */ + private static MetalToolBarUI instance = null; + + /** + * Constructs a new instance of MetalToolBarUI. + */ + public MetalToolBarUI() + { + super(); + } + + /** + * Returns an instance of MetalToolBarUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalToolBarUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalToolBarUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalToolTipUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToolTipUI.java new file mode 100644 index 00000000000..c88b6534ab7 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalToolTipUI.java @@ -0,0 +1,74 @@ +/* MetalToolTipUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicToolTipUI; + +public class MetalToolTipUI + extends BasicToolTipUI +{ + + // FIXME: maybe replace by a Map of instances when this becomes stateful + /** The shared UI instance for MetalToolTipUIs */ + private static MetalToolTipUI instance = null; + + /** + * Constructs a new instance of MetalToolTipUI. + */ + public MetalToolTipUI() + { + super(); + } + + /** + * Returns an instance of MetalToolTipUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalToolTipUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instance == null) + instance = new MetalToolTipUI(); + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java new file mode 100644 index 00000000000..d85d61c24ca --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java @@ -0,0 +1,86 @@ +/* MetalTreeUI.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.plaf.metal; + +import java.util.HashMap; + +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTreeUI; + +public class MetalTreeUI + extends BasicTreeUI +{ + + /** The UI instances for MetalTreeUIs */ + private static HashMap instances = null; + + /** + * Constructs a new instance of MetalTreeUI. + */ + public MetalTreeUI() + { + super(); + } + + /** + * Returns an instance of MetalTreeUI. + * + * @param component the component for which we return an UI instance + * + * @return an instance of MetalTreeUI + */ + public static ComponentUI createUI(JComponent component) + { + if (instances == null) + instances = new HashMap(); + + Object o = instances.get(component); + MetalTreeUI instance; + if (o == null) + { + instance = new MetalTreeUI(); + instances.put(component, instance); + } + else + instance = (MetalTreeUI) o; + + return instance; + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java new file mode 100644 index 00000000000..a342ee02bd3 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java @@ -0,0 +1,87 @@ +/* Metaltils.java +Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.metal; + +import java.awt.Color; +import java.awt.Graphics; + +/** + * Some utility and helper methods for the Metal Look & Feel. + * + * @author Roman Kennke (roman@kennke.org) + */ +class MetalUtils +{ + + /** + * Fills a rectangle with the typical Metal pattern. + * + * @param g the <code>Graphics</code> context to use + * @param x the X coordinate of the upper left corner of the rectangle to + * fill + * @param y the Y coordinate of the upper left corner of the rectangle to + * fill + * @param w the width of the rectangle to fill + * @param w the height of the rectangle to fill + * @param light the light color to use + * @param dark the dark color to use + */ + static void fillMetalPattern(Graphics g, int x, int y, int w, int h, + Color light, Color dark) + { + int xOff = 0; + for (int mY = y; mY < (y + h); mY++) + { + // set color alternating with every line + if ((mY % 2) == 0) + g.setColor(light); + else + g.setColor(dark); + + for (int mX = x + (xOff); mX < (x + w); mX += 4) + { + g.drawLine(mX, mY, mX, mY); + } + + // increase x offset + xOff++; + if (xOff > 3) + xOff = 0; + } + } +} diff --git a/libjava/classpath/javax/swing/plaf/metal/package.html b/libjava/classpath/javax/swing/plaf/metal/package.html new file mode 100644 index 00000000000..2ea787bb5e2 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/metal/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.plaf.metal package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.plaf.metal</title></head> + +<body> +<p>Provides a cross-platform look and feel known as "Metal".</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/plaf/package.html b/libjava/classpath/javax/swing/plaf/package.html new file mode 100644 index 00000000000..c266074f0b0 --- /dev/null +++ b/libjava/classpath/javax/swing/plaf/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.plaf package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.plaf</title></head> + +<body> +<p>A base package for the "pluggable look and feel" (plaf) mechanism used by +the <code>javax.swing</code> classes.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/table/AbstractTableModel.java b/libjava/classpath/javax/swing/table/AbstractTableModel.java new file mode 100644 index 00000000000..3e9f6e9b382 --- /dev/null +++ b/libjava/classpath/javax/swing/table/AbstractTableModel.java @@ -0,0 +1,301 @@ +/* AbstractTableModel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.EventListenerList; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; + +/** + * A base class that can be used to create implementations of the + * {@link TableModel} interface. + * + * @author Andrew Selkirk + */ +public abstract class AbstractTableModel implements TableModel, Serializable +{ + static final long serialVersionUID = -5798593159423650347L; + + /** + * Storage for the listeners registered with this model. + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * Creates a default instance. + */ + public AbstractTableModel() + { + // no setup required here + } + + /** + * Returns the name of the specified column. This method generates default + * names in a sequence (starting with column 0): A, B, C, ..., Z, AA, AB, + * AC, ..., AZ, BA, BB, BC, and so on. Subclasses may override this method + * to allow column names to be specified on some other basis. + * + * @param columnIndex the column index. + * + * @return The name of the column. + */ + public String getColumnName(int columnIndex) + { + StringBuffer buffer = new StringBuffer(); + while (columnIndex >= 0) + { + buffer.insert (0, (char) ('A' + columnIndex % 26)); + columnIndex = columnIndex / 26 - 1; + } + return buffer.toString(); + } + + /** + * Return the index of the specified column, or <code>-1</code> if there is + * no column with the specified name. + * + * @param columnName the name of the column (<code>null</code> not permitted). + * + * @return The index of the column, -1 if not found. + * + * @see #getColumnName(int) + * @throws NullPointerException if <code>columnName</code> is + * <code>null</code>. + */ + public int findColumn(String columnName) + { + int count = getColumnCount(); + + for (int index = 0; index < count; index++) + { + String name = getColumnName(index); + + if (columnName.equals(name)) + return index; + } + + // Unable to locate. + return -1; + } + + /** + * Returns the <code>Class</code> for all <code>Object</code> instances + * in the specified column. + * + * @param columnIndex the column index. + * + * @return The class. + */ + public Class getColumnClass(int columnIndex) + { + return Object.class; + } + + /** + * Returns <code>true</code> if the specified cell is editable, and + * <code>false</code> if it is not. This implementation returns + * <code>false</code> for all arguments, subclasses should override the + * method if necessary. + * + * @param rowIndex the row index of the cell. + * @param columnIndex the column index of the cell. + * + * @return <code>false</code>. + */ + public boolean isCellEditable(int rowIndex, int columnIndex) + { + return false; + } + + /** + * Sets the value of the given cell. This implementation ignores all + * arguments and does nothing, subclasses should override the + * method if necessary. + * + * @param value the new value (<code>null</code> permitted). + * @param rowIndex the row index of the cell. + * @param columnIndex the column index of the cell. + */ + public void setValueAt(Object value, int rowIndex, int columnIndex) + { + // Do nothing... + } + + /** + * Adds a listener to the table model. The listener will receive notification + * of all changes to the table model. + * + * @param listener the listener. + */ + public void addTableModelListener(TableModelListener listener) + { + listenerList.add(TableModelListener.class, listener); + } + + /** + * Removes a listener from the table model so that it will no longer receive + * notification of changes to the table model. + * + * @param listener the listener to remove. + */ + public void removeTableModelListener(TableModelListener listener) + { + listenerList.remove(TableModelListener.class, listener); + } + + /** + * Returns an array containing the listeners that have been added to the + * table model. + * + * @return Array of {@link TableModelListener} objects. + * + * @since 1.4 + */ + public TableModelListener[] getTableModelListeners() + { + return (TableModelListener[]) + listenerList.getListeners(TableModelListener.class); + } + + /** + * Sends a {@link TableModelEvent} to all registered listeners to inform + * them that the table data has changed. + */ + public void fireTableDataChanged() + { + fireTableChanged(new TableModelEvent(this, 0, Integer.MAX_VALUE)); + } + + /** + * Sends a {@link TableModelEvent} to all registered listeners to inform + * them that the table structure has changed. + */ + public void fireTableStructureChanged() + { + fireTableChanged(new TableModelEvent(this, TableModelEvent.HEADER_ROW)); + } + + /** + * Sends a {@link TableModelEvent} to all registered listeners to inform + * them that some rows have been inserted into the model. + * + * @param firstRow the index of the first row. + * @param lastRow the index of the last row. + */ + public void fireTableRowsInserted (int firstRow, int lastRow) + { + fireTableChanged(new TableModelEvent(this, firstRow, lastRow, + TableModelEvent.ALL_COLUMNS, + TableModelEvent.INSERT)); + } + + /** + * Sends a {@link TableModelEvent} to all registered listeners to inform + * them that some rows have been updated. + * + * @param firstRow the index of the first row. + * @param lastRow the index of the last row. + */ + public void fireTableRowsUpdated (int firstRow, int lastRow) + { + fireTableChanged(new TableModelEvent(this, firstRow, lastRow, + TableModelEvent.ALL_COLUMNS, + TableModelEvent.UPDATE)); + } + + /** + * Sends a {@link TableModelEvent} to all registered listeners to inform + * them that some rows have been deleted from the model. + * + * @param firstRow the index of the first row. + * @param lastRow the index of the last row. + */ + public void fireTableRowsDeleted(int firstRow, int lastRow) + { + fireTableChanged(new TableModelEvent(this, firstRow, lastRow, + TableModelEvent.ALL_COLUMNS, + TableModelEvent.DELETE)); + } + + /** + * Sends a {@link TableModelEvent} to all registered listeners to inform + * them that a single cell has been updated. + * + * @param row the row index. + * @param column the column index. + */ + public void fireTableCellUpdated (int row, int column) + { + fireTableChanged(new TableModelEvent(this, row, row, column)); + } + + /** + * Sends the specified event to all registered listeners. + * + * @param event the event to send. + */ + public void fireTableChanged(TableModelEvent event) + { + int index; + TableModelListener listener; + Object[] list = listenerList.getListenerList(); + + for (index = 0; index < list.length; index += 2) + { + listener = (TableModelListener) list [index + 1]; + listener.tableChanged (event); + } + } + + /** + * Returns an array of listeners of the given type that are registered with + * this model. + * + * @param listenerType the listener class. + * + * @return An array of listeners (possibly empty). + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } +} diff --git a/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java new file mode 100644 index 00000000000..02e9fd7dcb6 --- /dev/null +++ b/libjava/classpath/javax/swing/table/DefaultTableCellRenderer.java @@ -0,0 +1,234 @@ +/* DefaultTableCellRenderer.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.JLabel; +import javax.swing.JTable; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; + +/** + * Class to display every cells. + */ +public class DefaultTableCellRenderer extends JLabel + implements TableCellRenderer, Serializable +{ + static final long serialVersionUID = 7878911414715528324L; + + protected static Border noFocusBorder = new EmptyBorder(0, 0, 0, 0); + + public static class UIResource extends DefaultTableCellRenderer + implements javax.swing.plaf.UIResource + { + public UIResource() + { + } + } + + /** + * Creates a default table cell renderer with an empty border. + */ + public DefaultTableCellRenderer() + { + super(); + } + + /** + * Assign the unselected-foreground. + * + * @param c the color to assign + */ + public void setForeground(Color c) + { + super.setForeground(c); + } + + /** + * Assign the unselected-background. + * + * @param c the color to assign + */ + public void setBackground(Color c) + { + super.setBackground(c); + } + + /** + * Look and feel has changed. + * + * <p>Replaces the current UI object with the latest version from + * the UIManager.</p> + */ + public void updateUI() + { + super.updateUI(); + } + + /** + * Get the string value of the object and pass it to setText(). + * + * @param table the JTable + * @param value the value of the object + * @param isSelected is the cell selected? + * @param hasFocus has the cell the focus? + * @param row the row to render + * @param column the cell to render + * + * @return this component (the default table cell renderer) + */ + public Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, + boolean hasFocus, + int row, int column) + { + if (value != null) + super.setText(value.toString()); + + setOpaque(true); + + if (table == null) + return this; + + if (isSelected) + { + setBackground(table.getSelectionBackground()); + setForeground(table.getSelectionForeground()); + } + else + { + setBackground(table.getBackground()); + setForeground(table.getForeground()); + } + + setEnabled(table.isEnabled()); + setFont(table.getFont()); + return this; + } + + /** + * Overriden for performance. + * + * <p>This method needs to be overridden in a subclass to actually + * do something.</p> + * + * @return always true + */ + public boolean isOpaque() + { + return true; + } + + /** + * Overriden for performance. + * + * <p>This method needs to be overridden in a subclass to actually + * do something.</p> + */ + public void validate() + { + // Does nothing. + } + + public void revalidate() + { + // Does nothing. + } + + /** + * Overriden for performance. + * + * <p>This method needs to be overridden in a subclass to actually + * do something.</p> + */ + public void repaint(long tm, int x, int y, int width, int height) + { + // Does nothing. + } + + /** + * Overriden for performance. + * + * <p>This method needs to be overridden in a subclass to actually + * do something.</p> + */ + public void repaint(Rectangle r) + { + // Does nothing. + } + + /** + * Overriden for performance. + * + * <p>This method needs to be overridden in a subclass to actually + * do something.</p> + */ + protected void firePropertyChange(String propertyName, Object oldValue, + Object newValue) + { + // Does nothing. + } + + /** + * Overriden for performance. + * + * <p>This method needs to be overridden in a subclass to actually + * do something.</p> + */ + public void firePropertyChange(String propertyName, boolean oldValue, + boolean newValue) + { + // Does nothing. + } + + /** + * Sets the String for this cell. + * + * @param value the string value for this cell; if value is null it + * sets the text value to an empty string + */ + protected void setValue(Object value) + { + super.setText((value!=null) ? value.toString() : ""); + } +} diff --git a/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java b/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java new file mode 100644 index 00000000000..10871770de5 --- /dev/null +++ b/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java @@ -0,0 +1,563 @@ +/* DefaultTableColumnModel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.Vector; + +import javax.swing.DefaultListSelectionModel; +import javax.swing.ListSelectionModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.EventListenerList; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableColumnModelEvent; +import javax.swing.event.TableColumnModelListener; + +/** + * DefaultTableColumnModel + * @author Andrew Selkirk + * @version 1.0 + */ +public class DefaultTableColumnModel + implements TableColumnModel, PropertyChangeListener, ListSelectionListener, + Serializable +{ + private static final long serialVersionUID = 6580012493508960512L; + + /** + * Columns that this model keeps track of. + */ + protected Vector tableColumns; + + /** + * Selection Model that keeps track of columns selection + */ + protected ListSelectionModel selectionModel; + + /** + * Space between two columns. By default it is set to 1 + */ + protected int columnMargin; + + /** + * listenerList keeps track of all listeners registered with this model + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * changeEvent is fired when change occurs in one of the columns properties + */ + protected transient ChangeEvent changeEvent = new ChangeEvent(this); + + /** + * Indicates whether columns can be selected + */ + protected boolean columnSelectionAllowed; + + /** + * Total width of all the columns in this model + */ + protected int totalColumnWidth; + + /** + * Constructor DefaultTableColumnModel + */ + public DefaultTableColumnModel() + { + tableColumns = new Vector(); + setSelectionModel(createSelectionModel()); + columnMargin = 1; + columnSelectionAllowed = false; + } + + /** + * addColumn adds column to the model. This method fires ColumnAdded + * event to model's registered TableColumnModelListeners. + * + * @param col column to add + */ + public void addColumn(TableColumn col) + { + if (col == null) + throw new IllegalArgumentException("Null 'col' argument."); + tableColumns.add(col); + invalidateWidthCache(); + fireColumnAdded(new TableColumnModelEvent(this, 0, tableColumns.size() - 1)); + } + + /** + * removeColumn removes table column from the model. This method fires + * ColumnRemoved event to model's registered TableColumnModelListeners. + * + * @param col column to be removed + */ + public void removeColumn(TableColumn col) + { + int index = this.tableColumns.indexOf(col); + if (index < 0) + return; + fireColumnRemoved(new TableColumnModelEvent(this, index, 0)); + tableColumns.remove(col); + invalidateWidthCache(); + } + + /** + * moveColumn moves column at index i to index j. This method fires + * ColumnMoved event to model's registered TableColumnModelListeners. + * + * @param i index of the column that will be moved + * @param j index of column's new location + */ + public void moveColumn(int i, int j) + { + int columnCount = getColumnCount(); + if (i < 0 || i >= columnCount) + throw new IllegalArgumentException("Index 'i' out of range."); + if (j < 0 || j >= columnCount) + throw new IllegalArgumentException("Index 'j' out of range."); + Object column = tableColumns.remove(i); + tableColumns.add(j, column); + fireColumnAdded(new TableColumnModelEvent(this, i, j)); + } + + /** + * setColumnMargin sets margin of the columns. + * @param m new column margin + */ + public void setColumnMargin(int m) + { + columnMargin = m; + fireColumnMarginChanged(); + } + + /** + * getColumnCount returns number of columns in the model + * @return int number of columns in the model + */ + public int getColumnCount() + { + return tableColumns.size(); + } + + /** + * getColumns + * @return Enumeration + */ + public Enumeration getColumns() + { + return tableColumns.elements(); + } + + /** + * Returns the index of the {@link TableColumn} with the given identifier. + * + * @param identifier the identifier (<code>null</code> not permitted). + * + * @return The index of the {@link TableColumn} with the given identifier. + * + * @throws IllegalArgumentException if <code>identifier</code> is + * <code>null</code> or there is no column with that identifier. + */ + public int getColumnIndex(Object identifier) + { + if (identifier == null) + throw new IllegalArgumentException("Null identifier."); + int columnCount = tableColumns.size(); + for (int i = 0; i < columnCount; i++) + { + TableColumn tc = (TableColumn) tableColumns.get(i); + if (identifier.equals(tc.getIdentifier())) + return i; + } + throw new IllegalArgumentException("No TableColumn with that identifier."); + } + + /** + * getColumn returns column at the specified index + * @param i index of the column + * @return TableColumn column at the specified index + */ + public TableColumn getColumn(int i) + { + return (TableColumn) tableColumns.get(i); + } + + /** + * getColumnMargin returns column margin + * @return int column margin + */ + public int getColumnMargin() + { + return columnMargin; + } + + /** + * getColumnIndexAtX returns column that contains specified x-coordinate. + * @param x x-coordinate that column should contain + * @return int index of the column that contains specified x-coordinate relative + * to this column model + */ + public int getColumnIndexAtX(int x) + { + for (int i = 0; i < tableColumns.size(); ++i) + { + int w = ((TableColumn)tableColumns.get(i)).getWidth(); + if (0 <= x && x < w) + return i; + else + x -= w; + } + return -1; + } + + /** + * getTotalColumnWidth returns total width of all the columns including + * column's margins. + * + * @return total width of all the columns + */ + public int getTotalColumnWidth() + { + if (totalColumnWidth == -1) + recalcWidthCache(); + return totalColumnWidth; + } + + /** + * setSelectionModel sets selection model that will be used by this ColumnTableModel + * to keep track of currently selected columns + * + * @param model new selection model + * @exception IllegalArgumentException if model is null + */ + public void setSelectionModel(ListSelectionModel model) + { + if (model == null) + throw new IllegalArgumentException(); + + selectionModel = model; + selectionModel.addListSelectionListener(this); + } + + /** + * getSelectionModel returns selection model + * @return ListSelectionModel selection model + */ + public ListSelectionModel getSelectionModel() + { + return selectionModel; + } + + /** + * setColumnSelectionAllowed sets whether column selection is allowed + * or not. + * + * @param flag true if column selection is allowed and false otherwise + */ + public void setColumnSelectionAllowed(boolean flag) + { + columnSelectionAllowed = flag; + } + + /** + * getColumnSelectionAllowed indicates whether column selection is + * allowed or not. + * + * @return boolean true if column selection is allowed and false otherwise. + */ + public boolean getColumnSelectionAllowed() + { + return columnSelectionAllowed; + } + + /** + * getSelectedColumns returns array containing indexes of currently + * selected columns + * + * @return int[] array containing indexes of currently selected columns + */ + public int[] getSelectedColumns() + { + // FIXME: Implementation of this method was taken from private method + // JTable.getSelections(), which is used in various places in JTable + // including selected row calculations and cannot be simply removed. + // This design should be improved to illuminate duplication of code. + + ListSelectionModel lsm = this.selectionModel; + int sz = getSelectedColumnCount(); + int [] ret = new int[sz]; + + int lo = lsm.getMinSelectionIndex(); + int hi = lsm.getMaxSelectionIndex(); + int j = 0; + java.util.ArrayList ls = new java.util.ArrayList(); + if (lo != -1 && hi != -1) + { + switch (lsm.getSelectionMode()) + { + case ListSelectionModel.SINGLE_SELECTION: + ret[0] = lo; + break; + + case ListSelectionModel.SINGLE_INTERVAL_SELECTION: + for (int i = lo; i <= hi; ++i) + ret[j++] = i; + break; + + case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: + for (int i = lo; i <= hi; ++i) + if (lsm.isSelectedIndex(i)) + ret[j++] = i; + break; + } + } + return ret; + } + + /** + * getSelectedColumnCount returns number of currently selected columns + * @return int number of currently selected columns + */ + public int getSelectedColumnCount() + { + // FIXME: Implementation of this method was taken from private method + // JTable.countSelections(), which is used in various places in JTable + // including selected row calculations and cannot be simply removed. + // This design should be improved to illuminate duplication of code. + + ListSelectionModel lsm = this.selectionModel; + int lo = lsm.getMinSelectionIndex(); + int hi = lsm.getMaxSelectionIndex(); + int sum = 0; + + if (lo != -1 && hi != -1) + { + switch (lsm.getSelectionMode()) + { + case ListSelectionModel.SINGLE_SELECTION: + sum = 1; + break; + + case ListSelectionModel.SINGLE_INTERVAL_SELECTION: + sum = hi - lo + 1; + break; + + case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION: + for (int i = lo; i <= hi; ++i) + if (lsm.isSelectedIndex(i)) + ++sum; + break; + } + } + + return sum; + } + + /** + * addColumnModelListener adds specified listener to the model's + * listener list + * + * @param listener the listener to add + */ + public void addColumnModelListener(TableColumnModelListener listener) + { + listenerList.add(TableColumnModelListener.class, listener); + } + + /** + * removeColumnModelListener removes specified listener from the model's + * listener list. + * + * @param listener the listener to remove + */ + public void removeColumnModelListener(TableColumnModelListener listener) + { + listenerList.remove(TableColumnModelListener.class, listener); + } + + /** + * @since 1.4 + */ + public TableColumnModelListener[] getColumnModelListeners() + { + return (TableColumnModelListener[]) + listenerList.getListeners(TableColumnModelListener.class); + } + + /** + * fireColumnAdded fires TableColumnModelEvent to registered + * TableColumnModelListeners to indicate that column was added + * + * @param e TableColumnModelEvent + */ + protected void fireColumnAdded(TableColumnModelEvent e) + { + TableColumnModelListener[] listeners = getColumnModelListeners(); + + for (int i=0; i< listeners.length; i++) + listeners[i].columnAdded(e); + } + + /** + * fireColumnAdded fires TableColumnModelEvent to registered + * TableColumnModelListeners to indicate that column was removed + * + * @param e TableColumnModelEvent + */ + protected void fireColumnRemoved(TableColumnModelEvent e) + { + TableColumnModelListener[] listeners = getColumnModelListeners(); + + for (int i=0; i< listeners.length; i++) + listeners[i].columnRemoved(e); + } + + /** + * fireColumnAdded fires TableColumnModelEvent to registered + * TableColumnModelListeners to indicate that column was moved + * + * @param e TableColumnModelEvent + */ + protected void fireColumnMoved(TableColumnModelEvent e) + { + TableColumnModelListener[] listeners = getColumnModelListeners(); + + for (int i=0; i< listeners.length; i++) + listeners[i].columnMoved(e); + } + + /** + * fireColumnSelectionChanged fires TableColumnModelEvent to model's + * registered TableColumnModelListeners to indicate that different column + * was selected. + * + * @param evt ListSelectionEvent + */ + protected void fireColumnSelectionChanged(ListSelectionEvent evt) + { + EventListener [] listeners = getListeners(TableColumnModelListener.class); + for (int i = 0; i < listeners.length; ++i) + ((TableColumnModelListener)listeners[i]).columnSelectionChanged(evt); + } + + /** + * fireColumnMarginChanged fires TableColumnModelEvent to model's + * registered TableColumnModelListeners to indicate that column margin + * was changed. + */ + protected void fireColumnMarginChanged() + { + EventListener [] listeners = getListeners(TableColumnModelListener.class); + for (int i = 0; i < listeners.length; ++i) + ((TableColumnModelListener)listeners[i]).columnMarginChanged(changeEvent); + } + + /** + * getListeners returns currently registered listeners with this model. + * @param listenerType type of listeners to return + * + * @return EventListener[] array of model's listeners of the specified type + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * propertyChange handles changes occuring in the properties of the + * model's columns. + * + * @param evt PropertyChangeEvent + */ + public void propertyChange(PropertyChangeEvent evt) + { + if (evt.getPropertyName().equals(TableColumn.COLUMN_WIDTH_PROPERTY)) + invalidateWidthCache(); + } + + /** + * valueChanged handles changes in the selectionModel. + * @param e ListSelectionEvent + */ + public void valueChanged(ListSelectionEvent e) + { + fireColumnSelectionChanged(e); + } + + /** + * createSelectionModel creates selection model that will keep track + * of currently selected column(s) + * + * @return ListSelectionModel selection model of the columns + */ + protected ListSelectionModel createSelectionModel() + { + return new DefaultListSelectionModel(); + } + + /** + * recalcWidthCache calculates total width of the columns. + * If the current cache of the total width is in invalidated state, + * then width is recalculated. Otherwise nothing is done. + */ + protected void recalcWidthCache() + { + if (totalColumnWidth == -1) + { + totalColumnWidth = 0; + for (int i = 0; i < tableColumns.size(); ++i) + { + totalColumnWidth += ((TableColumn)tableColumns.get(i)).getWidth(); + } + } + } + + /** + * invalidateWidthCache + */ + private void invalidateWidthCache() + { + totalColumnWidth = -1; + } +} diff --git a/libjava/classpath/javax/swing/table/DefaultTableModel.java b/libjava/classpath/javax/swing/table/DefaultTableModel.java new file mode 100644 index 00000000000..6844f2a27ec --- /dev/null +++ b/libjava/classpath/javax/swing/table/DefaultTableModel.java @@ -0,0 +1,588 @@ +/* DefaultTableModel.java -- + Copyright (C) 2002, 2004, 2005, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.io.Serializable; +import java.util.Vector; + +import javax.swing.event.TableModelEvent; + +/** + * A two dimensional data structure used to store <code>Object</code> + * instances, usually for display in a <code>JTable</code> component. + * + * @author Andrew Selkirk + */ +public class DefaultTableModel extends AbstractTableModel + implements Serializable +{ + static final long serialVersionUID = 6680042567037222321L; + + /** + * Storage for the rows in the table (each row is itself + * a <code>Vector</code>). + */ + protected Vector dataVector; + + /** + * Storage for the column identifiers. + */ + protected Vector columnIdentifiers; + + /** + * Creates an empty table with zero rows and zero columns. + */ + public DefaultTableModel() + { + this(0, 0); + } + + /** + * Creates a new table with the specified number of rows and columns. + * All cells in the table are initially empty (set to <code>null</code>). + * + * @param numRows the number of rows. + * @param numColumns the number of columns. + */ + public DefaultTableModel(int numRows, int numColumns) + { + Vector defaultNames = new Vector(numColumns); + Vector data = new Vector(numRows); + for (int i = 0; i < numColumns; i++) + { + defaultNames.add(super.getColumnName(i)); + } + for (int r = 0; r < numRows; r++) + { + Vector tmp = new Vector(numColumns); + tmp.setSize(numColumns); + data.add(tmp); + } + setDataVector(data, defaultNames); + } + + /** + * Creates a new table with the specified column names and number of + * rows. The number of columns is determined by the number of column + * names supplied. + * + * @param columnNames the column names. + * @param numRows the number of rows. + */ + public DefaultTableModel(Vector columnNames, int numRows) + { + if (numRows < 0) + throw new IllegalArgumentException("numRows < 0"); + Vector data = new Vector(); + int numColumns = 0; + + if (columnNames != null) + numColumns = columnNames.size(); + + while (0 < numRows--) + { + Vector rowData = new Vector(); + rowData.setSize(numColumns); + data.add(rowData); + } + setDataVector(data, columnNames); + } + + /** + * Creates a new table with the specified column names and row count. + * + * @param columnNames the column names. + * @param numRows the number of rows. + */ + public DefaultTableModel(Object[] columnNames, int numRows) + { + this(convertToVector(columnNames), numRows); + } + + /** + * Creates a new table with the specified data values and column names. + * + * @param data the data values. + * @param columnNames the column names. + */ + public DefaultTableModel(Vector data, Vector columnNames) + { + setDataVector(data, columnNames); + } + + /** + * Creates a new table with the specified data values and column names. + * + * @param data the data values. + * @param columnNames the column names. + */ + public DefaultTableModel(Object[][] data, Object[] columnNames) + { + this(convertToVector(data), convertToVector(columnNames)); + } + + /** + * Returns the vector containing the row data for the table. + * + * @return The data vector. + */ + public Vector getDataVector() + { + return dataVector; + } + + /** + * Sets the data and column identifiers for the table. The data vector + * contains a <code>Vector</code> for each row in the table - if the + * number of objects in each row does not match the number of column + * names specified, the row data is truncated or expanded (by adding + * <code>null</code> values) as required. + * + * @param data the data for the table (a vector of row vectors). + * @param columnNames the column names. + * + * @throws NullPointerException if either argument is <code>null</code>. + */ + public void setDataVector(Vector data, Vector columnNames) + { + if (data == null) + dataVector = new Vector(); + else + dataVector = data; + setColumnIdentifiers(columnNames); + } + + /** + * Sets the data and column identifiers for the table. + * + * @param data the data for the table. + * @param columnNames the column names. + * + * @throws NullPointerException if either argument is <code>null</code>. + */ + public void setDataVector(Object[][] data, Object[] columnNames) + { + setDataVector(convertToVector(data), + convertToVector(columnNames)); + } + + /** + * Sends the specified <code>event</code> to all registered listeners. + * This method is equivalent to + * {@link AbstractTableModel#fireTableChanged(TableModelEvent)}. + * + * @param event the event. + */ + public void newDataAvailable(TableModelEvent event) + { + fireTableChanged(event); + } + + /** + * Sends the specified <code>event</code> to all registered listeners. + * This method is equivalent to + * {@link AbstractTableModel#fireTableChanged(TableModelEvent)}. + * + * @param event the event. + */ + public void newRowsAdded(TableModelEvent event) + { + fireTableChanged(event); + } + + /** + * Sends the specified <code>event</code> to all registered listeners. + * This method is equivalent to + * {@link AbstractTableModel#fireTableChanged(TableModelEvent)}. + * + * @param event the event. + */ + public void rowsRemoved(TableModelEvent event) + { + fireTableChanged(event); + } + + /** + * Sets the column identifiers, updates the data rows (truncating + * or padding each row with <code>null</code> values) to match the + * number of columns, and sends a {@link TableModelEvent} to all + * registered listeners. + * + * @param columnIdentifiers the column identifiers. + */ + public void setColumnIdentifiers(Vector columnIdentifiers) + { + this.columnIdentifiers = columnIdentifiers; + setColumnCount((columnIdentifiers == null ? 0 : columnIdentifiers.size())); + } + + /** + * Sets the column identifiers, updates the data rows (truncating + * or padding each row with <code>null</code> values) to match the + * number of columns, and sends a {@link TableModelEvent} to all + * registered listeners. + * + * @param columnIdentifiers the column identifiers. + */ + public void setColumnIdentifiers(Object[] columnIdentifiers) + { + setColumnIdentifiers(convertToVector(columnIdentifiers)); + } + + /** + * This method is obsolete, use {@link #setRowCount(int)} instead. + * + * @param numRows the number of rows. + */ + public void setNumRows(int numRows) + { + setRowCount(numRows); + } + + /** + * Sets the number of rows in the table. If <code>rowCount</code> is less + * than the current number of rows in the table, rows are discarded. + * If <code>rowCount</code> is greater than the current number of rows in + * the table, new (empty) rows are added. + * + * @param rowCount the row count. + */ + public void setRowCount(int rowCount) + { + int existingRowCount = dataVector.size(); + if (rowCount < existingRowCount) + { + dataVector.setSize(rowCount); + fireTableRowsDeleted(rowCount,existingRowCount-1); + } + else + { + int rowsToAdd = rowCount - existingRowCount; + for (int i = 0; i < rowsToAdd; i++) + { + Vector tmp = new Vector(); + tmp.setSize(columnIdentifiers.size()); + dataVector.add(tmp); + } + fireTableRowsInserted(existingRowCount,rowCount-1); + } + } + + /** + * Sets the number of columns in the table. Existing rows are truncated + * or padded with <code>null</code> values to match the new column count. + * A {@link TableModelEvent} is sent to all registered listeners. + * + * @param columnCount the column count. + */ + public void setColumnCount(int columnCount) + { + for (int i = 0; i < dataVector.size(); ++i) + { + ((Vector) dataVector.get(i)).setSize(columnCount); + } + if (columnIdentifiers != null) + columnIdentifiers.setSize(columnCount); + fireTableStructureChanged(); + } + + /** + * Adds a column with the specified name to the table. All cell values + * for the column are initially set to <code>null</code>. + * + * @param columnName the column name (<code>null</code> permitted). + */ + public void addColumn(Object columnName) + { + addColumn(columnName, (Object[]) null); + } + + /** + * Adds a column with the specified name and data values to the table. + * + * @param columnName the column name (<code>null</code> permitted). + * @param columnData the column data. + */ + public void addColumn(Object columnName, Vector columnData) + { + Object[] dataArray = null; + if (columnData != null) + { + int rowCount = dataVector.size(); + if (columnData.size() < rowCount) + columnData.setSize(rowCount); + dataArray = columnData.toArray(); + } + addColumn(columnName, dataArray); + } + + /** + * Adds a column with the specified name and data values to the table. + * + * @param columnName the column name (<code>null</code> permitted). + * @param columnData the column data. + */ + public void addColumn(Object columnName, Object[] columnData) { + if (columnData != null) + { + // check columnData array for cases where the number of items + // doesn't match the number of rows in the existing table + if (columnData.length > dataVector.size()) + { + int rowsToAdd = columnData.length - dataVector.size(); + for (int i = 0; i < rowsToAdd; i++) + { + Vector tmp = new Vector(); + tmp.setSize(columnIdentifiers.size()); + dataVector.add(tmp); + } + } + else if (columnData.length < dataVector.size()) + { + Object[] tmp = new Object[dataVector.size()]; + System.arraycopy(columnData, 0, tmp, 0, columnData.length); + columnData = tmp; + } + } + for (int i = 0; i < dataVector.size(); ++i) + { + ((Vector) dataVector.get(i)).add(columnData == null ? null : columnData[i]); + } + columnIdentifiers.add(columnName); + fireTableStructureChanged(); + } + + /** + * Adds a new row containing the specified data to the table and sends a + * {@link TableModelEvent} to all registered listeners. + * + * @param rowData the row data (<code>null</code> permitted). + */ + public void addRow(Vector rowData) { + int rowIndex = dataVector.size(); + dataVector.add(rowData); + newRowsAdded(new TableModelEvent( + this, rowIndex, rowIndex, -1, TableModelEvent.INSERT) + ); + } + + /** + * Adds a new row containing the specified data to the table and sends a + * {@link TableModelEvent} to all registered listeners. + * + * @param rowData the row data (<code>null</code> permitted). + */ + public void addRow(Object[] rowData) { + addRow(convertToVector(rowData)); + } + + /** + * Inserts a new row into the table. + * + * @param row the row index. + * @param rowData the row data. + */ + public void insertRow(int row, Vector rowData) { + dataVector.add(row, rowData); + fireTableRowsInserted(row,row); + } + + /** + * Inserts a new row into the table. + * + * @param row the row index. + * @param rowData the row data. + */ + public void insertRow(int row, Object[] rowData) { + insertRow(row, convertToVector(rowData)); + } + + /** + * Moves the rows from <code>startIndex</code> to <code>endIndex</code> + * (inclusive) to the specified row. + * + * @param startIndex the start row. + * @param endIndex the end row. + * @param toIndex the row to move to. + */ + public void moveRow(int startIndex, int endIndex, int toIndex) { + Vector removed = new Vector(); + for (int i = endIndex; i >= startIndex; i--) + { + removed.add(this.dataVector.remove(i)); + } + for (int i = 0; i <= endIndex - startIndex; i++) + { + dataVector.insertElementAt(removed.get(i), toIndex); + } + int firstRow = Math.min(startIndex, toIndex); + int lastRow = Math.max(endIndex, toIndex + (endIndex - startIndex)); + fireTableRowsUpdated(firstRow, lastRow); + } + + /** + * Removes a row from the table and sends a {@link TableModelEvent} to + * all registered listeners. + * + * @param row the row index. + */ + public void removeRow(int row) { + dataVector.remove(row); + fireTableRowsDeleted(row,row); + } + + /** + * Returns the number of rows in the model. + * + * @return The row count. + */ + public int getRowCount() { + return dataVector.size(); + } + + /** + * Returns the number of columns in the model. + * + * @return The column count. + */ + public int getColumnCount() { + return (columnIdentifiers == null ? 0 : columnIdentifiers.size()); + } + + /** + * Returns the name of the specified column. + * + * @param column the column index. + * + * @return The column name. + */ + public String getColumnName(int column) { + String result = ""; + if (columnIdentifiers == null) + result = super.getColumnName(column); + else + { + if (column < getColumnCount()) + { + Object id = columnIdentifiers.get(column); + if (id != null) + result = id.toString(); + else + result = super.getColumnName(column); + } + else + result = super.getColumnName(column); + } + return result; + } + + /** + * Returns <code>true</code> if the specified cell can be modified, and + * <code>false</code> otherwise. For this implementation, the method + * always returns <code>true</code>. + * + * @param row the row index. + * @param column the column index. + * + * @return <code>true</code> in all cases. + */ + public boolean isCellEditable(int row, int column) { + return true; + } + + /** + * Returns the value at the specified cell in the table. + * + * @param row the row index. + * @param column the column index. + * + * @return The value (<code>Object</code>, possibly <code>null</code>) at + * the specified cell in the table. + */ + public Object getValueAt(int row, int column) { + return ((Vector) dataVector.get(row)).get(column); + } + + /** + * Sets the value for the specified cell in the table and sends a + * {@link TableModelEvent} to all registered listeners. + * + * @param value the value (<code>Object</code>, <code>null</code> permitted). + * @param row the row index. + * @param column the column index. + */ + public void setValueAt(Object value, int row, int column) { + ((Vector) dataVector.get(row)).set(column, value); + fireTableCellUpdated(row,column); + } + + /** + * Converts the data array to a <code>Vector</code>. + * + * @param data the data array (<code>null</code> permitted). + * + * @return A vector (or <code>null</code> if the data array + * is <code>null</code>). + */ + protected static Vector convertToVector(Object[] data) { + if (data == null) + return null; + Vector vector = new Vector(data.length); + for (int i = 0; i < data.length; i++) + vector.add(data[i]); + return vector; + } + + /** + * Converts the data array to a <code>Vector</code> of rows. + * + * @param data the data array (<code>null</code> permitted). + * + * @return A vector (or <code>null</code> if the data array + * is <code>null</code>. + */ + protected static Vector convertToVector(Object[][] data) { + if (data == null) + return null; + Vector vector = new Vector(data.length); + for (int i = 0; i < data.length; i++) + vector.add(convertToVector(data[i])); + return vector; + } +} diff --git a/libjava/classpath/javax/swing/table/JTableHeader.java b/libjava/classpath/javax/swing/table/JTableHeader.java new file mode 100644 index 00000000000..45586da2009 --- /dev/null +++ b/libjava/classpath/javax/swing/table/JTableHeader.java @@ -0,0 +1,668 @@ +/* JTableHeader.java -- + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.FocusListener; +import java.beans.PropertyChangeListener; +import java.util.Locale; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleComponent; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleSelection; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.accessibility.AccessibleValue; +import javax.swing.JComponent; +import javax.swing.JTable; +import javax.swing.UIManager; +import javax.swing.plaf.TableHeaderUI; + +public class JTableHeader extends JComponent +{ + protected class AccessibleJTableHeader extends AccessibleJComponent + { + protected class AccessibleJTableHeaderEntry extends AccessibleContext + implements Accessible, AccessibleComponent + { + public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) + { + throw new Error("not implemented"); + } + + public void addFocusListener(FocusListener l) + { + throw new Error("not implemented"); + } + + public void addPropertyChangeListener(PropertyChangeListener l) + { + throw new Error("not implemented"); + } + + public boolean contains(Point p) + { + throw new Error("not implemented"); + } + + public AccessibleAction getAccessibleAction() + { + throw new Error("not implemented"); + } + + public Accessible getAccessibleAt(Point p) + { + throw new Error("not implemented"); + } + + public Accessible getAccessibleChild(int i) + { + throw new Error("not implemented"); + } + + public int getAccessibleChildrenCount() + { + throw new Error("not implemented"); + } + + public AccessibleComponent getAccessibleComponent() + { + throw new Error("not implemented"); + } + + public AccessibleContext getAccessibleContext() + { + throw new Error("not implemented"); + } + + public String getAccessibleDescription() + { + throw new Error("not implemented"); + } + + public int getAccessibleIndexInParent() + { + throw new Error("not implemented"); + } + + public String getAccessibleName() + { + throw new Error("not implemented"); + } + + public AccessibleRole getAccessibleRole() + { + throw new Error("not implemented"); + } + + public AccessibleSelection getAccessibleSelection() + { + throw new Error("not implemented"); + } + + public AccessibleStateSet getAccessibleStateSet() + { + throw new Error("not implemented"); + } + + public AccessibleText getAccessibleText() + { + throw new Error("not implemented"); + } + + public AccessibleValue getAccessibleValue() + { + throw new Error("not implemented"); + } + + public Color getBackground() + { + throw new Error("not implemented"); + } + + public Rectangle getBounds() + { + throw new Error("not implemented"); + } + + public Cursor getCursor() + { + throw new Error("not implemented"); + } + + public Font getFont() + { + throw new Error("not implemented"); + } + + public FontMetrics getFontMetrics(Font f) + { + throw new Error("not implemented"); + } + + public Color getForeground() + { + throw new Error("not implemented"); + } + + public Locale getLocale() + { + throw new Error("not implemented"); + } + + public Point getLocation() + { + throw new Error("not implemented"); + } + + public Point getLocationOnScreen() + { + throw new Error("not implemented"); + } + + public Dimension getSize() + { + throw new Error("not implemented"); + } + + public boolean isEnabled() + { + throw new Error("not implemented"); + } + + public boolean isFocusTraversable() + { + throw new Error("not implemented"); + } + + public boolean isShowing() + { + throw new Error("not implemented"); + } + + public boolean isVisible() + { + throw new Error("not implemented"); + } + + public void removeFocusListener(FocusListener l) + { + throw new Error("not implemented"); + } + + public void removePropertyChangeListener(PropertyChangeListener l) + { + throw new Error("not implemented"); + } + + public void requestFocus() + { + throw new Error("not implemented"); + } + + public void setAccessibleDescription(String s) + { + throw new Error("not implemented"); + } + + public void setAccessibleName(String s) + { + throw new Error("not implemented"); + } + + public void setBackground(Color c) + { + throw new Error("not implemented"); + } + + public void setBounds(Rectangle r) + { + throw new Error("not implemented"); + } + + public void setCursor(Cursor c) + { + throw new Error("not implemented"); + } + + public void setEnabled(boolean b) + { + throw new Error("not implemented"); + } + + public void setFont(Font f) + { + throw new Error("not implemented"); + } + + public void setForeground(Color c) + { + throw new Error("not implemented"); + } + + public void setLocation(Point p) + { + throw new Error("not implemented"); + } + + public void setSize(Dimension d) + { + throw new Error("not implemented"); + } + + public void setVisible(boolean b) + { + throw new Error("not implemented"); + } + }; + } + + private static final long serialVersionUID = 5144633983372967710L; + + /** + * The accessibleContext property. + */ + AccessibleContext accessibleContext; + + /** + * The columnModel property. + */ + protected TableColumnModel columnModel; + + /** + * The draggedColumn property. + */ + protected TableColumn draggedColumn; + + /** + * The draggedDistance property. + */ + protected int draggedDistance; + + /** + * The opaque property. + */ + boolean opaque; + + /** + * The reorderingAllowed property. + */ + protected boolean reorderingAllowed; + + /** + * The resizingAllowed property. + */ + protected boolean resizingAllowed = true; + + /** + * The resizingColumn property. + */ + protected TableColumn resizingColumn; + + /** + * The table property. + */ + protected JTable table; + + /** + * The updateTableInRealTime property. + */ + protected boolean updateTableInRealTime; + + TableCellRenderer cellRenderer; + + /** + * Creates a new default instance. + */ + public JTableHeader() + { + this(null); + } + + /** + * Creates a new header. If <code>cm</code> is <code>null</code>, a new + * table column model is created by calling + * {@link #createDefaultColumnModel()}. + * + * @param cm the table column model (<code>null</code> permitted). + */ + public JTableHeader(TableColumnModel cm) + { + accessibleContext = new AccessibleJTableHeader(); + columnModel = cm == null ? createDefaultColumnModel() : cm; + draggedColumn = null; + draggedDistance = 0; + opaque = true; + reorderingAllowed = true; + resizingAllowed = true; + resizingColumn = null; + table = null; + updateTableInRealTime = true; + cellRenderer = createDefaultRenderer(); + updateUI(); + } + + /** + * Creates a default table column model. + * + * @return A default table column model. + */ + protected TableColumnModel createDefaultColumnModel() + { + return new DefaultTableColumnModel(); + } + + /** + * Get the value of the {@link #accessibleContext} property. + * + * @return The current value of the property + */ + public AccessibleContext getAccessibleContext() + { + return accessibleContext; + } + + /** + * Get the value of the {@link #columnModel} property. + * + * @return The current value of the property + */ + public TableColumnModel getColumnModel() + { + return columnModel; + } + + /** + * Get the value of the {@link #draggedColumn} property. + * + * @return The current value of the property + */ + public TableColumn getDraggedColumn() + { + return draggedColumn; + } + + /** + * Get the value of the {@link #draggedDistance} property. + * + * @return The current value of the property + */ + public int getDraggedDistance() + { + return draggedDistance; + } + + /** + * Get the value of the {@link #reorderingAllowed} property. + * + * @return The current value of the property + */ + public boolean getReorderingAllowed() + { + return reorderingAllowed; + } + + /** + * Get the value of the {@link #resizingAllowed} property. + * + * @return The current value of the property + */ + public boolean getResizingAllowed() + { + return resizingAllowed; + } + + /** + * Get the value of the {@link #resizingColumn} property. + * + * @return The current value of the property + */ + public TableColumn getResizingColumn() + { + return resizingColumn; + } + + /** + * Get the value of the {@link #table} property. + * + * @return The current value of the property + */ + public JTable getTable() + { + return table; + } + + /** + * Get the value of the {@link #updateTableInRealTime} property. + * + * @return The current value of the property + */ + public boolean getUpdateTableInRealTime() + { + return updateTableInRealTime; + } + + /** + * Get the value of the {@link #opaque} property. + * + * @return The current value of the property + */ + public boolean isOpaque() + { + return opaque; + } + + /** + * Set the value of the {@link #columnModel} property. + * + * @param c The new value of the property + */ + public void setColumnModel(TableColumnModel c) + { + columnModel = c; + } + + /** + * Set the value of the {@link #draggedColumn} property. + * + * @param d The new value of the property + */ + public void setDraggedColumn(TableColumn d) + { + draggedColumn = d; + } + + /** + * Set the value of the {@link #draggedDistance} property. + * + * @param d The new value of the property + */ + public void setDraggedDistance(int d) + { + draggedDistance = d; + } + + /** + * Set the value of the {@link #opaque} property. + * + * @param o The new value of the property + */ + public void setOpaque(boolean o) + { + opaque = o; + } + + /** + * Set the value of the {@link #reorderingAllowed} property. + * + * @param r The new value of the property + */ + public void setReorderingAllowed(boolean r) + { + reorderingAllowed = r; + } + + /** + * Set the value of the {@link #resizingAllowed} property. + * + * @param r The new value of the property + */ + public void setResizingAllowed(boolean r) + { + resizingAllowed = r; + } + + /** + * Set the value of the {@link #resizingColumn} property. + * + * @param r The new value of the property + */ + public void setResizingColumn(TableColumn r) + { + resizingColumn = r; + } + + /** + * Set the value of the {@link #table} property. + * + * @param t The new value of the property + */ + public void setTable(JTable t) + { + table = t; + } + + /** + * Set the value of the {@link #updateTableInRealTime} property. + * + * @param u The new value of the property + */ + public void setUpdateTableInRealTime(boolean u) + { + updateTableInRealTime = u; + } + + /** + * Creates a default renderer. + * + * @return A default renderer. + */ + protected TableCellRenderer createDefaultRenderer() + { + return new DefaultTableCellRenderer(); + } + + /** + * Returns the default table cell renderer. + * + * @return The default table cell renderer. + */ + public TableCellRenderer getDefaultRenderer() + { + return cellRenderer; + } + + /** + * Sets the default table cell renderer. + * + * @param cellRenderer the renderer. + */ + public void setDefaultRenderer(TableCellRenderer cellRenderer) + { + this.cellRenderer = cellRenderer; + } + + public Rectangle getHeaderRect(int column) + { + Rectangle r = getTable().getCellRect(-1, column, true); + r.height = getHeight(); + return r; + } + + protected String paramString() + { + return "JTableHeader"; + } + + // UI support + + public String getUIClassID() + { + return "TableHeaderUI"; + } + + public TableHeaderUI getUI() + { + return (TableHeaderUI) ui; + } + + public void setUI(TableHeaderUI u) + { + super.setUI(u); + } + + public void updateUI() + { + setUI((TableHeaderUI) UIManager.getUI(this)); + } + + /** + * Returns the index of the column at the specified point. + * + * @param point the point. + * + * @return The column index, or -1. + */ + public int columnAtPoint(Point point) + { + if (getBounds().contains(point)) + return columnModel.getColumnIndexAtX(point.x); + + return -1; + } +} diff --git a/libjava/classpath/javax/swing/table/TableCellEditor.java b/libjava/classpath/javax/swing/table/TableCellEditor.java new file mode 100644 index 00000000000..b355311dcb2 --- /dev/null +++ b/libjava/classpath/javax/swing/table/TableCellEditor.java @@ -0,0 +1,65 @@ +/* TableCellEditor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.awt.Component; + +import javax.swing.CellEditor; +import javax.swing.JTable; + +/** + * TableCellEditor public interface + * @author Andrew Selkirk + */ +public interface TableCellEditor extends CellEditor { + + /** + * Get table cell editor component + * @param table JTable + * @param value Value of cell + * @param isSelected Cell selected + * @param row Row of cell + * @param column Column of cell + * @returns Component + */ + Component getTableCellEditorComponent(JTable table, + Object value, boolean isSelected, int row, int column); + + +} // TableCellEditor diff --git a/libjava/classpath/javax/swing/table/TableCellRenderer.java b/libjava/classpath/javax/swing/table/TableCellRenderer.java new file mode 100644 index 00000000000..639b4b9ad73 --- /dev/null +++ b/libjava/classpath/javax/swing/table/TableCellRenderer.java @@ -0,0 +1,66 @@ +/* TableCellRenderer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.awt.Component; + +import javax.swing.JTable; + +/** + * TableCellRenderer public interface + * @author Andrew Selkirk + */ +public interface TableCellRenderer { + + /** + * Get table cell renderer component + * @param table JTable + * @param value Value of cell + * @param isSelected Cell selected + * @param hasFocus Cell has focus + * @param row Row of cell + * @param column Column of cell + * @returns Component + */ + Component getTableCellRendererComponent(JTable table, + Object value, boolean isSelected, boolean hasFocus, + int row, int column); + + +} // TableCellRenderer diff --git a/libjava/classpath/javax/swing/table/TableColumn.java b/libjava/classpath/javax/swing/table/TableColumn.java new file mode 100644 index 00000000000..9c36bb05ab0 --- /dev/null +++ b/libjava/classpath/javax/swing/table/TableColumn.java @@ -0,0 +1,573 @@ +/* TableColumn.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.Serializable; + +import javax.swing.event.SwingPropertyChangeSupport; + +/** + * Represents the attributes of a column in a table, including the column index, + * width, minimum width, preferred width and maximum width. + * + * @author Andrew Selkirk + * @version 1.0 + */ +public class TableColumn + implements Serializable +{ + static final long serialVersionUID = -6113660025878112608L; + + /** + * The name for the <code>columnWidth</code> property. Note that the typo + * in the name value is deliberate, to match the specification. + */ + public static final String COLUMN_WIDTH_PROPERTY = "columWidth"; + + /** + * The name for the <code>headerValue</code> property. + */ + public static final String HEADER_VALUE_PROPERTY = "headerValue"; + + /** + * The name for the <code>headerRenderer</code> property. + */ + public static final String HEADER_RENDERER_PROPERTY = "headerRenderer"; + + /** + * The name for the <code>cellRenderer</code> property. + */ + public static final String CELL_RENDERER_PROPERTY = "cellRenderer"; + + /** + * The index of the corresponding column in the table model. + */ + protected int modelIndex; + + /** + * The identifier for the column. + */ + protected Object identifier; + + /** + * The width. + */ + protected int width; + + /** + * The minimum width. + */ + protected int minWidth = 15; + + /** + * The preferred width. + */ + private int preferredWidth; + + /** + * The maximum width. + */ + protected int maxWidth = Integer.MAX_VALUE; + + /** + * headerRenderer + */ + protected TableCellRenderer headerRenderer; + + /** + * The header value. + */ + protected Object headerValue; + + /** + * cellRenderer + */ + protected TableCellRenderer cellRenderer; + + /** + * cellEditor + */ + protected TableCellEditor cellEditor; + + /** + * isResizable + */ + protected boolean isResizable = true; + + /** + * resizedPostingDisableCount + * + * @deprecated 1.3 + */ + protected transient int resizedPostingDisableCount; + + /** + * changeSupport + */ + private SwingPropertyChangeSupport changeSupport = + new SwingPropertyChangeSupport(this); + + /** + * Creates a new <code>TableColumn</code> that maps to column 0 in the + * related table model. The default width is <code>75</code> units. + */ + public TableColumn() + { + this(0, 75, null, null); + } + + /** + * Creates a new <code>TableColumn</code> that maps to the specified column + * in the related table model. The default width is <code>75</code> units. + * + * @param modelIndex the index of the column in the model + */ + public TableColumn(int modelIndex) + { + this(modelIndex, 75, null, null); + } + + /** + * Creates a new <code>TableColumn</code> that maps to the specified column + * in the related table model, and has the specified <code>width</code>. + * + * @param modelIndex the index of the column in the model + * @param width the width + */ + public TableColumn(int modelIndex, int width) + { + this(modelIndex, width, null, null); + } + + /** + * Creates a new <code>TableColumn</code> that maps to the specified column + * in the related table model, and has the specified <code>width</code>, + * <code>cellRenderer</code> and <code>cellEditor</code>. + * + * @param modelIndex the index of the column in the model + * @param width the width + * @param cellRenderer the cell renderer (<code>null</code> permitted). + * @param cellEditor the cell editor (<code>null</code> permitted). + */ + public TableColumn(int modelIndex, int width, + TableCellRenderer cellRenderer, TableCellEditor cellEditor) + { + this.modelIndex = modelIndex; + this.width = width; + this.preferredWidth = width; + this.cellRenderer = cellRenderer; + this.cellEditor = cellEditor; + this.headerValue = null; + this.identifier = null; + } + + /** + * firePropertyChange + * + * @param property the name of the property + * @param oldValue the old value + * @param newValue the new value + */ + private void firePropertyChange(String property, Object oldValue, + Object newValue) + { + changeSupport.firePropertyChange(property, oldValue, newValue); + } + + /** + * firePropertyChange + * + * @param property the name of the property + * @param oldValue the old value + * @param newValue the new value + */ + private void firePropertyChange(String property, int oldValue, int newValue) + { + firePropertyChange(property, new Integer(oldValue), new Integer(newValue)); + } + + /** + * firePropertyChange + * + * @param property the name of the property + * @param oldValue the old value + * @param newValue the new value + */ + private void firePropertyChange(String property, boolean oldValue, + boolean newValue) + { + firePropertyChange(property, Boolean.valueOf(oldValue), + Boolean.valueOf(newValue)); + } + + /** + * Sets the index of the column in the related {@link TableModel} that this + * <code>TableColumn</code> maps to. + * + * @param modelIndex the column index in the model. + */ + public void setModelIndex(int modelIndex) + { + this.modelIndex = modelIndex; + } + + /** + * Returns the index of the column in the related {@link TableModel} that + * this <code>TableColumn</code> maps to. + * + * @return the model index + */ + public int getModelIndex() + { + return modelIndex; + } + + /** + * Sets the identifier for the column. + * + * @param identifier the identifier + */ + public void setIdentifier(Object identifier) + { + this.identifier = identifier; + } + + /** + * Returns the identifier for the column, or {@link #getHeaderValue()} if the + * identifier is <code>null</code>. + * + * @return The identifier (or {@link #getHeaderValue()} if the identifier is + * <code>null</code>). + */ + public Object getIdentifier() + { + if (identifier == null) + return getHeaderValue(); + return identifier; + } + + /** + * Sets the header value and sends a {@link PropertyChangeEvent} to all + * registered listeners. The header value property uses the name + * {@link #HEADER_VALUE_PROPERTY}. + * + * @param headerValue the value of the header + */ + public void setHeaderValue(Object headerValue) + { + if (this.headerValue == headerValue) + return; + + Object oldValue = this.headerValue; + this.headerValue = headerValue; + firePropertyChange(HEADER_VALUE_PROPERTY, oldValue, headerValue); + } + + /** + * Returns the header value. + * + * @return the value of the header + */ + public Object getHeaderValue() + { + return headerValue; + } + + /** + * setHeaderRenderer + * + * @param renderer the renderer to use + */ + public void setHeaderRenderer(TableCellRenderer renderer) + { + if (headerRenderer == renderer) + return; + + TableCellRenderer oldRenderer = headerRenderer; + headerRenderer = renderer; + firePropertyChange(HEADER_RENDERER_PROPERTY, + oldRenderer, headerRenderer); + } + + /** + * getHeaderRenderer + * @return TableCellRenderer + */ + public TableCellRenderer getHeaderRenderer() + { + return headerRenderer; + } + + /** + * Sets the renderer for cells in this column and sends a + * {@link PropertyChangeEvent} to all registered listeners. + * + * @param renderer the cell renderer (<code>null</code> permitted). + */ + public void setCellRenderer(TableCellRenderer renderer) + { + if (cellRenderer == renderer) + return; + + TableCellRenderer oldRenderer = cellRenderer; + cellRenderer = renderer; + firePropertyChange(CELL_RENDERER_PROPERTY, + oldRenderer, cellRenderer); + } + + /** + * Returns the renderer for the table cells in this column. + * + * @return The cell renderer. + */ + public TableCellRenderer getCellRenderer() + { + return cellRenderer; + } + + /** + * setCellEditor + * + * @param cellEditor the cell editor + */ + public void setCellEditor(TableCellEditor cellEditor) + { + this.cellEditor = cellEditor; + } + + /** + * getCellEditor + * + * @return the cell editor + */ + public TableCellEditor getCellEditor() + { + return cellEditor; + } + + /** + * setWidth + * + * @param newWidth the width + */ + public void setWidth(int newWidth) + { + int oldWidth = width; + + if (newWidth < minWidth) + width = minWidth; + else if (newWidth > maxWidth) + width = maxWidth; + else + width = newWidth; + + if (width == oldWidth) + return; + + firePropertyChange(COLUMN_WIDTH_PROPERTY, oldWidth, width); + } + + /** + * getWidth + * + * @return int + */ + public int getWidth() + { + return width; + } + + /** + * setPreferredWidth + * + * @param preferredWidth the preferred width + */ + public void setPreferredWidth(int preferredWidth) + { + if (preferredWidth < minWidth) + this.preferredWidth = minWidth; + else if (preferredWidth > maxWidth) + this.preferredWidth = maxWidth; + else + this.preferredWidth = preferredWidth; + } + + /** + * getPreferredWidth + * + * @return the preferred width + */ + public int getPreferredWidth() + { + return preferredWidth; + } + + /** + * Sets the minimum width for the column and, if necessary, updates the + * <code>width</code> and <code>preferredWidth</code>. + * + * @param minWidth the minimum width + */ + public void setMinWidth(int minWidth) + { + this.minWidth = minWidth; + setWidth(getWidth()); + setPreferredWidth(getPreferredWidth()); + } + + /** + * Returns the <code>TableColumn</code>'s minimum width. + * + * @return The minimum width. + */ + public int getMinWidth() + { + return minWidth; + } + + /** + * Sets the maximum width and, if necessary, updates the <code>width</code> + * and <code>preferredWidth</code>. + * + * @param maxWidth the maximum width + */ + public void setMaxWidth(int maxWidth) + { + this.maxWidth = maxWidth; + setWidth(getWidth()); + setPreferredWidth(getPreferredWidth()); + } + + /** + * Returns the maximum width. + * + * @return The maximum width. + */ + public int getMaxWidth() + { + return maxWidth; + } + + /** + * setResizable + * + * @param isResizable <code>true</code> if this column is resizable, + * <code>false</code> otherwise + */ + public void setResizable(boolean isResizable) + { + this.isResizable = isResizable; + } + + /** + * getResizable + * + * @return <code>true</code> if this column is resizable, + * <code>false</code> otherwise + */ + public boolean getResizable() + { + return isResizable; + } + + /** + * sizeWidthToFit + */ + public void sizeWidthToFit() + { + // TODO + } + + /** + * This method is empty, unused and deprecated. + * @deprecated 1.3 + */ + public void disableResizedPosting() + { + // Does nothing + } + + /** + * This method is empty, unused and deprecated. + * @deprecated 1.3 + */ + public void enableResizedPosting() + { + // Does nothing + } + + /** + * Adds a property change listener. + * + * @param listener the listener to add + */ + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.addPropertyChangeListener(listener); + } + + /** + * removePropertyChangeListener + * @param listener the listener to remove + */ + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns the property change listeners for this <code>TableColumn</code>. + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport.getPropertyChangeListeners(); + } + + /** + * createDefaultHeaderRenderer + * @return TableCellRenderer + */ + protected TableCellRenderer createDefaultHeaderRenderer() + { + return new DefaultTableCellRenderer(); + } +} diff --git a/libjava/classpath/javax/swing/table/TableColumnModel.java b/libjava/classpath/javax/swing/table/TableColumnModel.java new file mode 100644 index 00000000000..76a145604db --- /dev/null +++ b/libjava/classpath/javax/swing/table/TableColumnModel.java @@ -0,0 +1,187 @@ +/* TableColumnModel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.table; + +import java.util.Enumeration; + +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.event.TableColumnModelListener; + +/** + * The interface used by {@link JTable} to access the columns in the table + * view. + * + * @author Andrew Selkirk + */ +public interface TableColumnModel +{ + /** + * Adds a column to the model. + * + * @param column the new column (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>column</code> is + * <code>null</code>. + */ + void addColumn(TableColumn column); + + /** + * Removes a column from the model. If <code>column</code> is not defined + * in the model, this method does nothing. + * + * @param column TableColumn + */ + void removeColumn(TableColumn column); + + /** + * Moves a column. + * + * @param columnIndex Index of column to move + * @param newIndex New index of column + */ + void moveColumn(int columnIndex, int newIndex); + + /** + * setColumnMargin + * @param margin Margin of column + */ + void setColumnMargin(int margin); + + /** + * Returns the number of columns in the model. + * + * @return The column count + */ + int getColumnCount(); + + /** + * getColumns + * @return Enumeration of columns + */ + Enumeration getColumns(); + + /** + * Returns the index of the {@link TableColumn} with the given identifier. + * + * @param identifier the identifier (<code>null</code> not permitted). + * + * @return The index of the {@link TableColumn} with the given identifier. + * + * @throws IllegalArgumentException if <code>identifier</code> is + * <code>null</code> or there is no column with that identifier. + */ + int getColumnIndex(Object columnIdentifier); + + /** + * Returns the <code>TableColumn</code> at the specified index. + * + * @param columnIndex the column index. + * + * @return The table column. + */ + TableColumn getColumn(int columnIndex); + + /** + * Returns the column margin. + * + * @return The column margin. + */ + int getColumnMargin(); + + /** + * getColumnIndexAtX + * @return Column index as position x + */ + int getColumnIndexAtX(int xPosition); + + /** + * getTotalColumnWidth + * @return Total column width + */ + int getTotalColumnWidth(); + + /** + * setColumnSelectionAllowed + * @param value Set column selection + */ + void setColumnSelectionAllowed(boolean value); + + /** + * getColumnSelectionAllowed + * @return true if column selection allowed, false otherwise + */ + boolean getColumnSelectionAllowed(); + + /** + * getSelectedColumns + * @return Selected columns + */ + int[] getSelectedColumns(); + + /** + * getSelectedColumnCount + * @return Count of selected columns + */ + int getSelectedColumnCount(); + + /** + * setSelectionModel + * @param model ListSelectionModel + */ + void setSelectionModel(ListSelectionModel model); + + /** + * getSelectionModel + * @param column TableColumn + */ + ListSelectionModel getSelectionModel(); + + /** + * addColumnModelListener + * @param listener TableColumnModelListener + */ + void addColumnModelListener(TableColumnModelListener listener); + + /** + * removeColumnModelListener + * @param listener TableColumnModelListener + */ + void removeColumnModelListener(TableColumnModelListener listener); +} diff --git a/libjava/classpath/javax/swing/table/TableModel.java b/libjava/classpath/javax/swing/table/TableModel.java new file mode 100644 index 00000000000..016ae171dd4 --- /dev/null +++ b/libjava/classpath/javax/swing/table/TableModel.java @@ -0,0 +1,134 @@ +/* TableModel.java -- + Copyright (C) 2002, 2005, Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.table; + +import javax.swing.event.TableModelListener; + +/** + * A <code>TableModel</code> is a two dimensional data structure that + * can store arbitrary <code>Object</code> instances, usually for the + * purpose of display in a {@link javax.swing.JTable} component. Individual + * objects can be accessed by specifying the row index and column index for + * the object. Each column in the model has a name associated with it. + * <p> + * The {@link DefaultTableModel} class provides one implementation of + * this interface. + * + * @author Andrew Selkirk + */ +public interface TableModel +{ + /** + * Returns the number of rows in the model. + * + * @return The row count. + */ + int getRowCount(); + + /** + * Returns the number of columns in the model. + * + * @return The column count + */ + int getColumnCount(); + + /** + * Returns the name of a column in the model. + * + * @param columnIndex the column index. + * + * @return The column name. + */ + String getColumnName(int columnIndex); + + /** + * Returns the <code>Class</code> for all <code>Object</code> instances + * in the specified column. + * + * @param columnIndex the column index. + * + * @return The class. + */ + Class getColumnClass(int columnIndex); + + /** + * Returns <code>true</code> if the cell is editable, and <code>false</code> + * otherwise. + * + * @param rowIndex the row index. + * @param columnIndex the column index. + * + * @return <code>true</code> if editable, <code>false</code> otherwise. + */ + boolean isCellEditable(int rowIndex, int columnIndex); + + /** + * Returns the value (<code>Object</code>) at a particular cell in the + * table. + * + * @param rowIndex the row index. + * @param columnIndex the column index. + * + * @return The value at the specified cell. + */ + Object getValueAt(int rowIndex, int columnIndex); + + /** + * Sets the value at a particular cell in the table. + * + * @param aValue the value (<code>null</code> permitted). + * @param rowIndex the row index. + * @param columnIndex the column index. + */ + void setValueAt(Object aValue, int rowIndex, int columnIndex); + + /** + * Adds a listener to the model. The listener will receive notification + * of updates to the model. + * + * @param listener the listener. + */ + void addTableModelListener(TableModelListener listener); + + /** + * Removes a listener from the model. + * + * @param listener the listener. + */ + void removeTableModelListener(TableModelListener listener); +} diff --git a/libjava/classpath/javax/swing/table/package.html b/libjava/classpath/javax/swing/table/package.html new file mode 100644 index 00000000000..84e6f1aa3af --- /dev/null +++ b/libjava/classpath/javax/swing/table/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.table package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.table</title></head> + +<body> +<p>Interfaces and classes that support the {@link javax.swing.JTable} +component.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java new file mode 100644 index 00000000000..c3a3d70ae37 --- /dev/null +++ b/libjava/classpath/javax/swing/text/AbstractDocument.java @@ -0,0 +1,912 @@ +/* AbstractDocument.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.io.PrintStream; +import java.io.Serializable; +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.Hashtable; +import java.util.Vector; + +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.EventListenerList; +import javax.swing.event.UndoableEditEvent; +import javax.swing.event.UndoableEditListener; +import javax.swing.tree.TreeNode; +import javax.swing.undo.AbstractUndoableEdit; +import javax.swing.undo.CompoundEdit; +import javax.swing.undo.UndoableEdit; + +public abstract class AbstractDocument + implements Document, Serializable +{ + private static final long serialVersionUID = -116069779446114664L; + + protected static final String BAD_LOCATION = "document location failure"; + + public static final String BidiElementName = "bidi level"; + public static final String ContentElementName = "content"; + public static final String ParagraphElementName = "paragraph"; + public static final String SectionElementName = "section"; + public static final String ElementNameAttribute = "$ename"; + + Content content; + AttributeContext context; + DocumentFilter documentFilter; + + /** The documents properties. */ + Dictionary properties; + + protected EventListenerList listenerList = new EventListenerList(); + + protected AbstractDocument(Content doc) + { + this(doc, StyleContext.getDefaultStyleContext()); + } + + protected AbstractDocument(Content doc, AttributeContext ctx) + { + content = doc; + context = ctx; + } + + // These still need to be implemented by a derived class: + public abstract Element getParagraphElement(int pos); + + public abstract Element getDefaultRootElement(); + + protected Element createBranchElement(Element parent, + AttributeSet attributes) + { + return new BranchElement(parent, attributes); + } + + protected Element createLeafElement(Element parent, AttributeSet attributes, + int start, int end) + { + return new LeafElement(parent, attributes, start, end); + } + + public Position createPosition(final int offset) throws BadLocationException + { + if (offset < 0 || offset > getLength()) + throw new BadLocationException(getText(0, getLength()), offset); + + return new Position() + { + public int getOffset() + { + return offset; + } + }; + } + + protected void fireChangedUpdate(DocumentEvent event) + { + DocumentListener[] listeners = getDocumentListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].changedUpdate(event); + } + + protected void fireInsertUpdate(DocumentEvent event) + { + DocumentListener[] listeners = getDocumentListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].insertUpdate(event); + } + + protected void fireRemoveUpdate(DocumentEvent event) + { + DocumentListener[] listeners = getDocumentListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].removeUpdate(event); + } + + protected void fireUndoableEditUpdate(UndoableEditEvent event) + { + UndoableEditListener[] listeners = getUndoableEditListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].undoableEditHappened(event); + } + + public int getAsynchronousLoadPriority() + { + return 0; + } + + protected AttributeContext getAttributeContext() + { + return context; + } + + public Element getBidiRootElement() + { + return null; + } + + protected Content getContent() + { + return content; + } + + protected Thread getCurrentWriter() + { + return null; + } + + public Dictionary getDocumentProperties() + { + // FIXME: make me thread-safe + if (properties == null) + properties = new Hashtable(); + + return properties; + } + + public Position getEndPosition() + { + return new Position() + { + public int getOffset() + { + return getLength(); + } + }; + } + + public int getLength() + { + return content.length() - 1; + } + + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + public Object getProperty(Object key) + { + // FIXME: make me thread-safe + Object value = null; + if (properties != null) + value = properties.get(key); + + return value; + } + + public Element[] getRootElements() + { + Element[] elements = new Element[1]; + elements[0] = getDefaultRootElement(); + return elements; + } + + public Position getStartPosition() + { + return new Position() + { + public int getOffset() + { + return 0; + } + }; + } + + public String getText(int offset, int length) throws BadLocationException + { + return content.getString(offset, length); + } + + public void getText(int offset, int length, Segment segment) + throws BadLocationException + { + content.getChars(offset, length, segment); + } + + public void insertString(int offset, String text, AttributeSet attributes) + throws BadLocationException + { + // Just return when no text to insert was given. + if (text == null || text.length() == 0) + return; + + DefaultDocumentEvent event = + new DefaultDocumentEvent(offset, text.length(), + DocumentEvent.EventType.INSERT); + content.insertString(offset, text); + insertUpdate(event, attributes); + fireInsertUpdate(event); + } + + protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) + { + } + + protected void postRemoveUpdate(DefaultDocumentEvent chng) + { + } + + public void putProperty(Object key, Object value) + { + // FIXME: make me thread-safe + if (properties == null) + properties = new Hashtable(); + + properties.put(key, value); + } + + public void readLock() + { + } + + public void readUnlock() + { + } + + public void remove(int offset, int length) throws BadLocationException + { + DefaultDocumentEvent event = + new DefaultDocumentEvent(offset, length, + DocumentEvent.EventType.REMOVE); + removeUpdate(event); + content.remove(offset, length); + postRemoveUpdate(event); + fireRemoveUpdate(event); + } + + /** + * Replaces some text in the document. + * + * @since 1.4 + */ + public void replace(int offset, int length, String text, + AttributeSet attributes) + throws BadLocationException + { + remove(offset, length); + insertString(offset, text, attributes); + } + + /** + * Adds a <code>DocumentListener</code> object to this document. + * + * @param listener the listener to add + */ + public void addDocumentListener(DocumentListener listener) + { + listenerList.add(DocumentListener.class, listener); + } + + /** + * Removes a <code>DocumentListener</code> object from this document. + * + * @param listener the listener to remove + */ + public void removeDocumentListener(DocumentListener listener) + { + listenerList.remove(DocumentListener.class, listener); + } + + /** + * Returns add added <code>DocumentListener</code> objects. + * + * @return an array of listeners + */ + public DocumentListener[] getDocumentListeners() + { + return (DocumentListener[]) getListeners(DocumentListener.class); + } + + /** + * Adds a <code>UndoableEditListener</code> object to this document. + * + * @param listener the listener to add + */ + public void addUndoableEditListener(UndoableEditListener listener) + { + listenerList.add(UndoableEditListener.class, listener); + } + + /** + * Removes a <code>UndoableEditListener</code> object from this document. + * + * @param listener the listener to remove + */ + public void removeUndoableEditListener(UndoableEditListener listener) + { + listenerList.remove(UndoableEditListener.class, listener); + } + + /** + * Returns add added <code>UndoableEditListener</code> objects. + * + * @return an array of listeners + */ + public UndoableEditListener[] getUndoableEditListeners() + { + return (UndoableEditListener[]) getListeners(UndoableEditListener.class); + } + + protected void removeUpdate(DefaultDocumentEvent chng) + { + } + + public void render(Runnable r) + { + } + + public void setAsynchronousLoadPriority(int p) + { + } + + public void setDocumentProperties(Dictionary x) + { + // FIXME: make me thread-safe + properties = x; + } + + protected void writeLock() + { + } + + protected void writeUnlock() + { + } + + /** + * @since 1.4 + */ + public DocumentFilter getDocumentFilter() + { + return documentFilter; + } + + /** + * @since 1.4 + */ + public void setDocumentFilter(DocumentFilter filter) + { + this.documentFilter = filter; + } + + public void dump(PrintStream out) + { + ((AbstractElement) getDefaultRootElement()).dump(out, 0); + } + + public interface AttributeContext + { + AttributeSet addAttribute(AttributeSet old, Object name, Object value); + + AttributeSet addAttributes(AttributeSet old, AttributeSet attributes); + + AttributeSet getEmptySet(); + + void reclaim(AttributeSet attributes); + + AttributeSet removeAttribute(AttributeSet old, Object name); + + AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes); + + AttributeSet removeAttributes(AttributeSet old, Enumeration names); + } + + public interface Content + { + Position createPosition(int offset) throws BadLocationException; + + int length(); + + UndoableEdit insertString(int where, String str) + throws BadLocationException; + + UndoableEdit remove(int where, int nitems) throws BadLocationException; + + String getString(int where, int len) throws BadLocationException; + + void getChars(int where, int len, Segment txt) throws BadLocationException; + } + + public abstract class AbstractElement + implements Element, MutableAttributeSet, TreeNode, Serializable + { + private static final long serialVersionUID = 1265312733007397733L; + int count; + int offset; + + AttributeSet attributes; + + Element element_parent; + + TreeNode tree_parent; + Vector tree_children; + + public AbstractElement(Element p, AttributeSet s) + { + element_parent = p; + attributes = s; + } + + // TreeNode implementation + + public abstract Enumeration children(); + + public abstract boolean getAllowsChildren(); + + public TreeNode getChildAt(int index) + { + return (TreeNode) tree_children.get(index); + } + + public int getChildCount() + { + return tree_children.size(); + } + + public int getIndex(TreeNode node) + { + return tree_children.indexOf(node); + } + + public TreeNode getParent() + { + return tree_parent; + } + + public abstract boolean isLeaf(); + + + // MutableAttributeSet support + + public void addAttribute(Object name, Object value) + { + attributes = getAttributeContext().addAttribute(attributes, name, value); + } + + public void addAttributes(AttributeSet attrs) + { + attributes = getAttributeContext().addAttributes(attributes, attrs); + } + + public void removeAttribute(Object name) + { + attributes = getAttributeContext().removeAttribute(attributes, name); + } + + public void removeAttributes(AttributeSet attrs) + { + attributes = getAttributeContext().removeAttributes(attributes, attrs); + } + + public void removeAttributes(Enumeration names) + { + attributes = getAttributeContext().removeAttributes(attributes, names); + } + + public void setResolveParent(AttributeSet parent) + { + attributes = getAttributeContext().addAttribute(attributes, ResolveAttribute, parent); + } + + + // AttributeSet interface support + + public boolean containsAttribute(Object name, Object value) + { + return attributes.containsAttribute(name, value); + } + + public boolean containsAttributes(AttributeSet attrs) + { + return attributes.containsAttributes(attrs); + } + + public AttributeSet copyAttributes() + { + return attributes.copyAttributes(); + } + + public Object getAttribute(Object key) + { + return attributes.getAttribute(key); + } + + public int getAttributeCount() + { + return attributes.getAttributeCount(); + } + + public Enumeration getAttributeNames() + { + return attributes.getAttributeNames(); + } + + public AttributeSet getResolveParent() + { + return attributes.getResolveParent(); + } + + public boolean isDefined(Object attrName) + { + return attributes.isDefined(attrName); + } + + public boolean isEqual(AttributeSet attrs) + { + return attributes.isEqual(attrs); + } + + // Element interface support + + public AttributeSet getAttributes() + { + return attributes; + } + + public Document getDocument() + { + return AbstractDocument.this; + } + + public abstract Element getElement(int index); + + public String getName() + { + return (String) getAttribute(NameAttribute); + } + + public Element getParentElement() + { + return element_parent; + } + + public abstract int getEndOffset(); + + public abstract int getElementCount(); + + public abstract int getElementIndex(int offset); + + public abstract int getStartOffset(); + + private void dumpElement(PrintStream stream, String indent, Element element) + { + System.out.println(indent + "<" + element.getName() +">"); + + if (element.isLeaf()) + { + int start = element.getStartOffset(); + int end = element.getEndOffset(); + String text = ""; + try + { + text = getContent().getString(start, end - start); + } + catch (BadLocationException e) + { + } + System.out.println(indent + " [" + + start + "," + + end + "][" + + text + "]"); + } + else + { + for (int i = 0; i < element.getElementCount(); ++i) + dumpElement(stream, indent + " ", element.getElement(i)); + } + } + + public void dump(PrintStream stream, int indent) + { + String indentStr = ""; + for (int i = 0; i < indent; ++i) + indentStr += " "; + dumpElement(stream, indentStr, this); + } + } + + public class BranchElement extends AbstractElement + { + private static final long serialVersionUID = -8595176318868717313L; + + private Element[] children = new Element[0]; + + public BranchElement(Element parent, AttributeSet attributes) + { + super(parent, attributes); + } + + public Enumeration children() + { + if (children.length == 0) + return null; + + Vector tmp = new Vector(); + + for (int index = 0; index < children.length; ++index) + tmp.add(children[index]); + + return tmp.elements(); + } + + public boolean getAllowsChildren() + { + return true; + } + + public Element getElement(int index) + { + if (index < 0 || index >= children.length) + return null; + + return children[index]; + } + + public int getElementCount() + { + return children.length; + } + + public int getElementIndex(int offset) + { + // XXX: There is surely a better algorithm + // as beginning from first element each time. + for (int index = 0; index < children.length; ++index) + { + Element elem = children[index]; + + if ((elem.getStartOffset() <= offset) + && (offset < elem.getEndOffset())) + return index; + } + + return 0; + } + + public int getEndOffset() + { + return children[children.length - 1].getEndOffset(); + } + + public String getName() + { + return ParagraphElementName; + } + + public int getStartOffset() + { + return children[0].getStartOffset(); + } + + public boolean isLeaf() + { + return false; + } + + public Element positionToElement(int position) + { + // XXX: There is surely a better algorithm + // as beginning from first element each time. + for (int index = 0; index < children.length; ++index) + { + Element elem = children[index]; + + if ((elem.getStartOffset() <= position) + && (position < elem.getEndOffset())) + return elem; + } + + return null; + } + + public void replace(int offset, int length, Element[] elements) + { + Element[] target = new Element[children.length - length + + elements.length]; + System.arraycopy(children, 0, target, 0, offset); + System.arraycopy(elements, 0, target, offset, elements.length); + System.arraycopy(children, offset + length, target, + offset + elements.length, + children.length - offset - length); + children = target; + } + + public String toString() + { + return ("BranchElement(" + getName() + ") " + + getStartOffset() + "," + getEndOffset() + "\n"); + } + } + + public class DefaultDocumentEvent extends CompoundEdit + implements DocumentEvent + { + private static final long serialVersionUID = -7406103236022413522L; + + private int offset; + private int length; + private DocumentEvent.EventType type; + + public DefaultDocumentEvent(int offset, int length, + DocumentEvent.EventType type) + { + this.offset = offset; + this.length = length; + this.type = type; + } + + public Document getDocument() + { + return AbstractDocument.this; + } + + public int getLength() + { + return length; + } + + public int getOffset() + { + return offset; + } + + public DocumentEvent.EventType getType() + { + return type; + } + + public DocumentEvent.ElementChange getChange(Element elem) + { + return null; + } + } + + public static class ElementEdit extends AbstractUndoableEdit + implements DocumentEvent.ElementChange + { + private static final long serialVersionUID = -1216620962142928304L; + + private Element elem; + private int index; + private Element[] removed; + private Element[] added; + + public ElementEdit(Element elem, int index, + Element[] removed, Element[] added) + { + this.elem = elem; + this.index = index; + this.removed = removed; + this.added = added; + } + + public Element[] getChildrenAdded() + { + return added; + } + + public Element[] getChildrenRemoved() + { + return removed; + } + + public Element getElement() + { + return elem; + } + + public int getIndex() + { + return index; + } + } + + public class LeafElement extends AbstractElement + { + private static final long serialVersionUID = 5115368706941283802L; + int start; + int end; + + public LeafElement(Element parent, AttributeSet attributes, int start, + int end) + { + super(parent, attributes); + this.start = start; + this.end = end; + } + + public Enumeration children() + { + return null; + } + + public boolean getAllowsChildren() + { + return false; + } + + public Element getElement(int index) + { + return null; + } + + public int getElementCount() + { + return 0; + } + + public int getElementIndex(int offset) + { + return -1; + } + + public int getEndOffset() + { + return end; + } + + public String getName() + { + return ContentElementName; + } + + public int getStartOffset() + { + return start; + } + + public boolean isLeaf() + { + return true; + } + + public String toString() + { + return ("LeafElement(" + getName() + ") " + + getStartOffset() + "," + getEndOffset() + "\n"); + } + } +} diff --git a/libjava/classpath/javax/swing/text/AttributeSet.java b/libjava/classpath/javax/swing/text/AttributeSet.java new file mode 100644 index 00000000000..87e7b98af22 --- /dev/null +++ b/libjava/classpath/javax/swing/text/AttributeSet.java @@ -0,0 +1,72 @@ +/* AttributeSet.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.util.Enumeration; + +public interface AttributeSet +{ + static interface CharacterAttribute + { + } + + static interface ColorAttribute + { + } + + static interface FontAttribute + { + } + + static interface ParagraphAttribute + { + } + + Object NameAttribute = StyleConstants.NameAttribute; + Object ResolveAttribute = StyleConstants.ResolveAttribute; + + boolean containsAttribute(Object name, Object value); + boolean containsAttributes(AttributeSet attributes); + AttributeSet copyAttributes(); + Object getAttribute(Object key); + int getAttributeCount(); + Enumeration getAttributeNames(); + AttributeSet getResolveParent(); + boolean isDefined(Object attrName); + boolean isEqual(AttributeSet attr); +} diff --git a/libjava/classpath/javax/swing/text/BadLocationException.java b/libjava/classpath/javax/swing/text/BadLocationException.java new file mode 100644 index 00000000000..e1a2ebcc604 --- /dev/null +++ b/libjava/classpath/javax/swing/text/BadLocationException.java @@ -0,0 +1,65 @@ +/* BadLocationException.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +public class BadLocationException extends Exception +{ + private static final long serialVersionUID = -7712259886815656766L; + + int offset; + + /** + * Constructs a <code>BadLocationException</code> + * + * @param str A string indicating what was wrong with the arguments + * @param offset Offset within the document that was requested >= 0 + */ + public BadLocationException(String str, int offset) + { + super(str); + this.offset = offset; + } + + /** + * Returns the offset into the document that was not legal + */ + public int offsetRequested() + { + return offset; + } +} diff --git a/libjava/classpath/javax/swing/text/Caret.java b/libjava/classpath/javax/swing/text/Caret.java new file mode 100644 index 00000000000..46072ef19c5 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Caret.java @@ -0,0 +1,81 @@ +/* Caret.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Graphics; +import java.awt.Point; + +import javax.swing.event.ChangeListener; + +public interface Caret +{ + void addChangeListener(ChangeListener l); + + void deinstall(JTextComponent c); + + int getBlinkRate(); + + int getDot(); + + Point getMagicCaretPosition(); + + int getMark(); + + void install(JTextComponent c); + + boolean isSelectionVisible(); + + boolean isVisible(); + + void moveDot(int dot); + + void paint(Graphics g); + + void removeChangeListener(ChangeListener l); + + void setBlinkRate(int rate); + + void setDot(int dot); + + void setMagicCaretPosition(Point p); + + void setSelectionVisible(boolean v); + + void setVisible(boolean v); +} diff --git a/libjava/classpath/javax/swing/text/ChangedCharSetException.java b/libjava/classpath/javax/swing/text/ChangedCharSetException.java new file mode 100644 index 00000000000..7fba29a309f --- /dev/null +++ b/libjava/classpath/javax/swing/text/ChangedCharSetException.java @@ -0,0 +1,100 @@ +/* ChangedCharSetException.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.io.IOException; +import java.io.Serializable; + +/** + * The exception is thrown when the document charset is changed. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ChangedCharSetException + extends IOException + implements Serializable +{ + /** + * Use serialVersionUID for interoperability. + * This value corresponds the version 1.4. + */ + private static final long serialVersionUID = 9119851554465432389L; + + /** + * The char set specification. + */ + private final String m_charSetSpec; + + /** + * The char set key. + */ + private final boolean m_charSetKey; + + /** + * Constructs a new char set exception with two additional parameters, + * defining the circumstances under that the exception was raised. + */ + public ChangedCharSetException(String charSetSpec, boolean charSetKey) + { + m_charSetSpec = charSetSpec; + m_charSetKey = charSetKey; + } + + /** + * Get the value of the first parameter, previously passed to the + * constructor. + * + * @return the value of the first parameter + */ + public String getCharSetSpec() + { + return m_charSetSpec; + } + + /** + * Get the value of the second parameter, previously passed to the + * constructor. + * + * @return the value of the second parameter + */ + public boolean keyEqualsCharSet() + { + return m_charSetKey; + } +} diff --git a/libjava/classpath/javax/swing/text/ComponentView.java b/libjava/classpath/javax/swing/text/ComponentView.java new file mode 100644 index 00000000000..744d537aec6 --- /dev/null +++ b/libjava/classpath/javax/swing/text/ComponentView.java @@ -0,0 +1,103 @@ +/* ComponentView.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Shape; + +public class ComponentView extends View +{ + public ComponentView(Element elem) + { + super(elem); + } + + protected Component createComponent() + { + return null; + } + + public float getAlignment(int axis) + { + return 0; + } + + public final Component getComponent() + { + return null; + } + + public float getMaximumSpan(int axis) + { + return 0; + } + + public float getMinimumSpan(int axis) + { + return 0; + } + + public float getPreferredSpan(int axis) + { + return 0; + } + + public Shape modelToView(int pos, Shape a, Position.Bias b) + throws BadLocationException + { + return null; + } + + public void paint(Graphics g, Shape a) + { + } + + public void setParent(View p) + { + } + + public void setSize(float width, float height) + { + } + + public int viewToModel(float x, float y, Shape a, Position.Bias[] bias) + { + return 0; + } +} diff --git a/libjava/classpath/javax/swing/text/DateFormatter.java b/libjava/classpath/javax/swing/text/DateFormatter.java new file mode 100644 index 00000000000..0e20b771b45 --- /dev/null +++ b/libjava/classpath/javax/swing/text/DateFormatter.java @@ -0,0 +1,85 @@ +/* DateFormatter.java -- +Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.text.DateFormat; + +/** + * <code>DateFormatter</code> is an {@link InternationalFormatter} + * that implements value to string and string to value conversion via + * an instance of {@link DateFormat}. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class DateFormatter extends InternationalFormatter +{ + + /** The serialVersoinUID. */ + private static final long serialVersionUID = 5423279572591848797L; + + /** + * Creates a new instance using the default {@link DateFormat} object + * returned by {@link DateFormat#getDateInstance}. + */ + public DateFormatter() + { + this(DateFormat.getDateInstance()); + } + + /** + * Creates a new instance of <code>DateFormatter</code> using the + * specified <code>DateFormat</code> + * + * @param format the <code>DateFormat</code> to use + */ + public DateFormatter(DateFormat format) + { + super(); + setFormat(format); + } + + /** + * Sets the format that is used by this <code>DateFormatter</code>. + * + * @param format the <code>DateFormat</code> to use + */ + public void setFormat(DateFormat format) + { + super.setFormat(format); + } +} diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java new file mode 100644 index 00000000000..b57b3656384 --- /dev/null +++ b/libjava/classpath/javax/swing/text/DefaultCaret.java @@ -0,0 +1,315 @@ +/* DefaultCaret.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.util.EventListener; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + + +public class DefaultCaret extends Rectangle + implements Caret, FocusListener, MouseListener, MouseMotionListener +{ + private static final long serialVersionUID = 228155774675466193L; + + protected ChangeEvent changeEvent = new ChangeEvent(this); + protected EventListenerList listenerList = new EventListenerList(); + + private JTextComponent textComponent; + + private boolean selectionVisible = true; + private int blinkRate = 500; + private int dot = 0; + private int mark = 0; + private Point magicCaretPosition = null; + private boolean visible = true; + private Object highlightEntry; + + public void mouseDragged(MouseEvent event) + { + } + + public void mouseMoved(MouseEvent event) + { + } + + public void mouseClicked(MouseEvent event) + { + } + + public void mouseEntered(MouseEvent event) + { + } + + public void mouseExited(MouseEvent event) + { + } + + public void mousePressed(MouseEvent event) + { + } + + public void mouseReleased(MouseEvent event) + { + } + + public void focusGained(FocusEvent event) + { + } + + public void focusLost(FocusEvent event) + { + } + + protected void moveCaret(MouseEvent event) + { + } + + protected void positionCaret(MouseEvent event) + { + } + + public void deinstall(JTextComponent c) + { + textComponent.removeFocusListener(this); + textComponent.removeMouseListener(this); + textComponent.removeMouseMotionListener(this); + textComponent = null; + } + + public void install(JTextComponent c) + { + textComponent = c; + textComponent.addFocusListener(this); + textComponent.addMouseListener(this); + textComponent.addMouseMotionListener(this); + repaint(); + } + + public void setMagicCaretPosition(Point p) + { + magicCaretPosition = p; + } + + public Point getMagicCaretPosition() + { + return magicCaretPosition; + } + + public int getMark() + { + return mark; + } + + private void handleHighlight() + { + Highlighter highlighter = textComponent.getHighlighter(); + + if (highlighter == null) + return; + + int p0 = Math.min(dot, mark); + int p1 = Math.max(dot, mark); + + if (selectionVisible && p0 != p1) + { + try + { + if (highlightEntry == null) + highlightEntry = highlighter.addHighlight(p0, p1, getSelectionPainter()); + else + highlighter.changeHighlight(highlightEntry, p0, p1); + } + catch (BadLocationException e) + { + // This should never happen. + throw new InternalError(); + } + } + else + { + if (highlightEntry != null) + { + highlighter.removeHighlight(highlightEntry); + highlightEntry = null; + } + } + } + + public void setSelectionVisible(boolean v) + { + if (selectionVisible == v) + return; + + selectionVisible = v; + handleHighlight(); + repaint(); + } + + public boolean isSelectionVisible() + { + return selectionVisible; + } + + protected final void repaint() + { + if (textComponent != null) + textComponent.repaint(); + } + + public void paint(Graphics g) + { + if (textComponent == null) + return; + + int dot = getDot(); + Rectangle rect = null; + + try + { + rect = textComponent.modelToView(dot); + } + catch (BadLocationException e) + { + // This should never happen as dot should be always valid. + return; + } + + if (rect == null) + return; + + // First we need to delete the old caret. + // FIXME: Implement deleting of old caret. + + // Now draw the caret on the new position if visible. + if (visible) + { + g.setColor(textComponent.getCaretColor()); + g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); + } + } + + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) getListeners(ChangeListener.class); + } + + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].stateChanged(changeEvent); + } + + protected final JTextComponent getComponent() + { + return textComponent; + } + + public int getBlinkRate() + { + return blinkRate; + } + + public void setBlinkRate(int rate) + { + blinkRate = rate; + } + + public int getDot() + { + return dot; + } + + public void moveDot(int dot) + { + this.dot = dot; + handleHighlight(); + repaint(); + } + + public void setDot(int dot) + { + this.dot = dot; + this.mark = dot; + handleHighlight(); + repaint(); + } + + public boolean isVisible() + { + return visible; + } + + public void setVisible(boolean v) + { + visible = v; + repaint(); + } + + protected Highlighter.HighlightPainter getSelectionPainter() + { + return DefaultHighlighter.DefaultPainter; + } +} diff --git a/libjava/classpath/javax/swing/text/DefaultEditorKit.java b/libjava/classpath/javax/swing/text/DefaultEditorKit.java new file mode 100644 index 00000000000..aa2fbe8509a --- /dev/null +++ b/libjava/classpath/javax/swing/text/DefaultEditorKit.java @@ -0,0 +1,418 @@ +/* DefaultEditorKit.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; + +import javax.swing.Action; + +public class DefaultEditorKit extends EditorKit +{ + public static class BeepAction + extends TextAction + { + public BeepAction() + { + super(beepAction); + } + + public void actionPerformed(ActionEvent event) + { + Toolkit.getDefaultToolkit().beep(); + } + } + + public static class CopyAction + extends TextAction + { + public CopyAction() + { + super(copyAction); + } + public void actionPerformed(ActionEvent event) + { + } + } + + public static class CutAction + extends TextAction + { + public CutAction() + { + super(cutAction); + } + + public void actionPerformed(ActionEvent event) + { + } + } + + /** + * This action is executed as default action when a KEY_TYPED + * event is received and no keymap entry exists for that. The purpose + * of this action is to filter out a couple of characters. This includes + * the control characters and characters with the ALT-modifier. + * + * If an event does not get filtered, it is inserted into the document + * of the text component. If there is some text selected in the text component, + * this text will be replaced. + */ + public static class DefaultKeyTypedAction + extends TextAction + { + public DefaultKeyTypedAction() + { + super(defaultKeyTypedAction); + } + + public void actionPerformed(ActionEvent event) + { + // first we filter the following events: + // - control characters + // - key events with the ALT modifier (FIXME: filter that too!) + char c = event.getActionCommand().charAt(0); + if (Character.isISOControl(c)) + return; + + JTextComponent t = getTextComponent(event); + if (t != null) + { + try + { + t.getDocument().insertString(t.getCaret().getDot(), event.getActionCommand(), null); + t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1, + t.getDocument().getEndPosition().getOffset())); + } + catch (BadLocationException be) + { + // FIXME: we're not authorized to throw this.. swallow it? + } + } + } + } + + /** + * This action inserts a newline character into the document + * of the text component. This is typically triggered by hitting + * ENTER on the keyboard. + */ + public static class InsertBreakAction + extends TextAction + { + public InsertBreakAction() + { + super(insertBreakAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + t.replaceSelection("\n"); + } + } + + public static class InsertContentAction + extends TextAction + { + public InsertContentAction() + { + super(insertContentAction); + } + public void actionPerformed(ActionEvent event) + { + } + } + + public static class InsertTabAction + extends TextAction + { + public InsertTabAction() + { + super(insertTabAction); + } + + public void actionPerformed(ActionEvent event) + { + } + } + + public static class PasteAction + extends TextAction + { + public PasteAction() + { + super(pasteAction); + } + + public void actionPerformed(ActionEvent event) + { + } + } + + private static final long serialVersionUID = 9017245433028523428L; + + public static final String backwardAction = "caret-backward"; + public static final String beepAction = "beep"; + public static final String beginAction = "caret-begin"; + public static final String beginLineAction = "caret-begin-line"; + public static final String beginParagraphAction = "caret-begin-paragraph"; + public static final String beginWordAction = "caret-begin-word"; + public static final String copyAction = "copy-to-clipboard"; + public static final String cutAction = "cut-to-clipboard"; + public static final String defaultKeyTypedAction = "default-typed"; + public static final String deleteNextCharAction = "delete-next"; + public static final String deletePrevCharAction = "delete-previous"; + public static final String downAction = "caret-down"; + public static final String endAction = "caret-end"; + public static final String endLineAction = "caret-end-line"; + public static final String EndOfLineStringProperty = "__EndOfLine__"; + public static final String endParagraphAction = "caret-end-paragraph"; + public static final String endWordAction = "caret-end-word"; + public static final String forwardAction = "caret-forward"; + public static final String insertBreakAction = "insert-break"; + public static final String insertContentAction = "insert-content"; + public static final String insertTabAction = "insert-tab"; + public static final String nextWordAction = "caret-next-word"; + public static final String pageDownAction = "page-down"; + public static final String pageUpAction = "page-up"; + public static final String pasteAction = "paste-from-clipboard"; + public static final String previousWordAction = "caret-previous-word"; + public static final String readOnlyAction = "set-read-only"; + public static final String selectAllAction = "select-all"; + public static final String selectionBackwardAction = "selection-backward"; + public static final String selectionBeginAction = "selection-begin"; + public static final String selectionBeginLineAction = "selection-begin-line"; + public static final String selectionBeginParagraphAction = + "selection-begin-paragraph"; + public static final String selectionBeginWordAction = "selection-begin-word"; + public static final String selectionDownAction = "selection-down"; + public static final String selectionEndAction = "selection-end"; + public static final String selectionEndLineAction = "selection-end-line"; + public static final String selectionEndParagraphAction = + "selection-end-paragraph"; + public static final String selectionEndWordAction = "selection-end-word"; + public static final String selectionForwardAction = "selection-forward"; + public static final String selectionNextWordAction = "selection-next-word"; + public static final String selectionPreviousWordAction = + "selection-previous-word"; + public static final String selectionUpAction = "selection-up"; + public static final String selectLineAction = "select-line"; + public static final String selectParagraphAction = "select-paragraph"; + public static final String selectWordAction = "select-word"; + public static final String upAction = "caret-up"; + public static final String writableAction = "set-writable"; + + public DefaultEditorKit() + { + } + + private static Action[] defaultActions = + new Action[] { + new BeepAction(), + new CopyAction(), + new CutAction(), + new DefaultKeyTypedAction(), + new InsertBreakAction(), + new InsertContentAction(), + new InsertTabAction(), + new PasteAction(), + new TextAction(deleteNextCharAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + try + { + int pos = t.getCaret().getDot(); + if (pos < t.getDocument().getEndPosition().getOffset()) + { + t.getDocument().remove(t.getCaret().getDot(), 1); + } + } + catch (BadLocationException e) + { + // FIXME: we're not authorized to throw this.. swallow it? + } + } + } + }, + new TextAction(deletePrevCharAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + try + { + int pos = t.getCaret().getDot(); + if (pos > t.getDocument().getStartPosition().getOffset()) + { + t.getDocument().remove(pos - 1, 1); + t.getCaret().setDot(pos - 1); + } + } + catch (BadLocationException e) + { + // FIXME: we're not authorized to throw this.. swallow it? + } + } + } + }, + new TextAction(backwardAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + t.getCaret().setDot(Math.max(t.getCaret().getDot() - 1, + t.getDocument().getStartPosition().getOffset())); + } + } + }, + new TextAction(forwardAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1, + t.getDocument().getEndPosition().getOffset())); + } + } + }, + new TextAction(selectionBackwardAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + t.getCaret().moveDot(Math.max(t.getCaret().getDot() - 1, + t.getDocument().getStartPosition().getOffset())); + } + } + }, + new TextAction(selectionForwardAction) + { + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + if (t != null) + { + t.getCaret().moveDot(Math.min(t.getCaret().getDot() + 1, + t.getDocument().getEndPosition().getOffset())); + } + } + }, + }; + + public Caret createCaret() + { + return new DefaultCaret(); + } + + public Document createDefaultDocument() + { + return new PlainDocument(); + } + + public Action[] getActions() + { + return defaultActions; + } + + public String getContentType() + { + return "text/plain"; + } + + public ViewFactory getViewFactory() + { + return null; + } + + public void read(InputStream in, Document document, int offset) + throws BadLocationException, IOException + { + read(new InputStreamReader(in), document, offset); + } + + public void read(Reader in, Document document, int offset) + throws BadLocationException, IOException + { + BufferedReader reader = new BufferedReader(in); + + String line; + StringBuffer content = new StringBuffer(); + + while ((line = reader.readLine()) != null) + { + content.append(line); + content.append("\n"); + } + + document.insertString(offset, content.toString(), + SimpleAttributeSet.EMPTY); + } + + public void write(OutputStream out, Document document, int offset, int len) + throws BadLocationException, IOException + { + write(new OutputStreamWriter(out), document, offset, len); + } + + public void write(Writer out, Document document, int offset, int len) + throws BadLocationException, IOException + { + } +} diff --git a/libjava/classpath/javax/swing/text/DefaultFormatter.java b/libjava/classpath/javax/swing/text/DefaultFormatter.java new file mode 100644 index 00000000000..c97d90703c7 --- /dev/null +++ b/libjava/classpath/javax/swing/text/DefaultFormatter.java @@ -0,0 +1,429 @@ +/* DefaultFormatter.java -- +Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.text.ParseException; + +import javax.swing.JFormattedTextField; + +/** + * The <code>DefaultFormatter</code> is a concrete formatter for use in + * {@link JFormattedTextField}s. + * + * It can format arbitrary values by invoking + * their {@link Object#toString} method. + * + * In order to convert a String back to + * a value, the value class must provide a single argument constructor that + * takes a String object as argument value. If no such constructor is found, + * the String itself is passed back by #stringToValue. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class DefaultFormatter + extends JFormattedTextField.AbstractFormatter + implements Cloneable, Serializable +{ + + /** + * A {@link DocumentFilter} that intercepts modification of the + * JFormattedTextField's Document and commits the value depending + * on the value of the <code>commitsOnValidEdit</code> property. + * + */ + // FIXME: Handle allowsInvalid and overwriteMode properties + private class FormatterDocumentFilter + extends DocumentFilter + { + /** + * Invoked when text is removed from a text component. + * + * @param bypass the FilterBypass to use to mutate the document + * @param offset the start position of the modification + * @param length the length of the removed text + * + * @throws BadLocationException if offset or lenght are invalid in + * the Document + */ + public void remove(DocumentFilter.FilterBypass bypass, int offset, + int length) + throws BadLocationException + { + super.remove(bypass, offset, length); + checkValidInput(); + commitIfAllowed(); + } + + /** + * Invoked when text is inserted into a text component. + * + * @param bypass the FilterBypass to use to mutate the document + * @param offset the start position of the modification + * @param text the inserted text + * @param attributes the attributes of the inserted text + * + * @throws BadLocationException if offset or lenght are invalid in + * the Document + */ + public void insertString(DocumentFilter.FilterBypass bypass, int offset, + String text, AttributeSet attributes) + throws BadLocationException + { + if (overwriteMode == true) + replace(bypass, offset, text.length(), text, attributes); + else + super.insertString(bypass, offset, text, attributes); + checkValidInput(); + commitIfAllowed(); + } + + /** + * Invoked when text is replaced in a text component. + * + * @param bypass the FilterBypass to use to mutate the document + * @param offset the start position of the modification + * @param length the length of the removed text + * @param text the inserted text + * @param attributes the attributes of the inserted text + * + * @throws BadLocationException if offset or lenght are invalid in + * the Document + */ + public void replace(DocumentFilter.FilterBypass bypass, int offset, + int length, String text, AttributeSet attributes) + throws BadLocationException + { + super.replace(bypass, offset, length, text, attributes); + checkValidInput(); + commitIfAllowed(); + } + + /** + * Commits the value to the JTextTextField if the property + * <code>commitsOnValidEdit</code> is set to <code>true</code>. + */ + private void commitIfAllowed() + { + if (commitsOnValidEdit == true) + try + { + getFormattedTextField().commitEdit(); + } + catch (ParseException ex) + { + // ignore invalid edits + } + } + + /** + * Checks if the value in the input field is valid. If the + * property allowsInvalid is set to <code>false</code>, then + * the string in the input field is not allowed to be entered. + * + * @param doc the document of the input field + * @param value the current (old) value of the input field + */ + private void checkValidInput() + { + JFormattedTextField ftf = getFormattedTextField(); + try + { + Object newval = stringToValue(ftf.getText()); + } + catch (ParseException ex) + { + if (!allowsInvalid) + { + // roll back the input if invalid edits are not allowed + try + { + ftf.setText(valueToString(ftf.getValue())); + } + catch (ParseException pe) + { + // if that happens, something serious must be wrong + throw new AssertionError("values must be parseable"); + } + } + } + } + } + + /** The serialVersoinUID. */ + private static final long serialVersionUID = -7369196326612908900L; + + /** + * Indicates if the value should be committed after every + * valid modification of the Document. + */ + boolean commitsOnValidEdit; + + /** + * If <code>true</code> newly inserted characters overwrite existing + * values, otherwise insertion is done the normal way. + */ + boolean overwriteMode; + + /** + * If <code>true</code> invalid edits are allowed for a limited + * time. + */ + boolean allowsInvalid; + + /** + * The class that is used for values. + */ + Class valueClass; + + /** + * Creates a new instance of <code>DefaultFormatter</code>. + */ + public DefaultFormatter() + { + commitsOnValidEdit = true; + overwriteMode = true; + allowsInvalid = true; + valueClass = Object.class; + } + + /** + * Installs the formatter on the specified {@link JFormattedTextField}. + * + * This method does the following things: + * <ul> + * <li>Display the value of #valueToString in the + * <code>JFormattedTextField</code></li> + * <li>Install the Actions from #getActions on the <code>JTextField</code> + * </li> + * <li>Install the DocumentFilter returned by #getDocumentFilter</li> + * <li>Install the NavigationFilter returned by #getNavigationFilter</li> + * </ul> + * + * This method is typically not overridden by subclasses. Instead override + * one of the mentioned methods in order to customize behaviour. + * + * @param ftf the {@link JFormattedTextField} in which this formatter + * is installed + */ + public void install(JFormattedTextField ftf) + { + super.install(ftf); + } + + /** + * Returns <code>true</code> if the value should be committed after + * each valid modification of the input field, <code>false</code> if + * it should never be committed by this formatter. + * + * @return the state of the <code>commitsOnValidEdit</code> property + * + * @see #setCommitsOnValidEdit + */ + public boolean getCommitsOnValidEdit() + { + return commitsOnValidEdit; + } + + /** + * Sets the value of the <code>commitsOnValidEdit</code> property. + * + * @param commitsOnValidEdit the new state of the + * <code>commitsOnValidEdit</code> property + * + * @see #getCommitsOnValidEdit + */ + public void setCommitsOnValidEdit(boolean commitsOnValidEdit) + { + this.commitsOnValidEdit = commitsOnValidEdit; + } + + /** + * Returns the value of the <code>overwriteMode</code> property. + * If that is set to <code>true</code> then newly inserted characters + * overwrite existing values, otherwise the characters are inserted like + * normal. The default is <code>true</code>. + * + * @return the value of the <code>overwriteMode</code> property + */ + public boolean getOverwriteMode() + { + return overwriteMode; + } + + /** + * Sets the value of the <code>overwriteMode</code> property. + * + * If that is set to <code>true</code> then newly inserted characters + * overwrite existing values, otherwise the characters are inserted like + * normal. The default is <code>true</code>. + * + * @param overwriteMode the new value for the <code>overwriteMode</code> + * property + */ + public void setOverwriteMode(boolean overwriteMode) + { + this.overwriteMode = overwriteMode; + } + + /** + * Returns whether or not invalid edits are allowed or not. If invalid + * edits are allowed, the JFormattedTextField may temporarily contain invalid + * characters. + * + * @return the value of the allowsInvalid property + */ + public boolean getAllowsInvalid() + { + return allowsInvalid; + } + + /** + * Sets the value of the <code>allowsInvalid</code> property. + * + * @param allowsInvalid the new value for the property + * + * @see #getAllowsInvalid() + */ + public void setAllowsInvalid(boolean allowsInvalid) + { + this.allowsInvalid = allowsInvalid; + } + + /** + * Returns the class that is used for values. When Strings are converted + * back to values, this class is used to create new value objects. + * + * @return the class that is used for values + */ + public Class getValueClass() + { + return valueClass; + } + + /** + * Sets the class that is used for values. + * + * @param valueClass the class that is used for values + * + * @see #getValueClass() + */ + public void setValueClass(Class valueClass) + { + this.valueClass = valueClass; + } + + /** + * Converts a String (from the JFormattedTextField input) to a value. + * In order to achieve this, the formatter tries to instantiate an object + * of the class returned by #getValueClass() using a single argument + * constructor that takes a String argument. If such a constructor cannot + * be found, the String itself is returned. + * + * @param string the string to convert + * + * @return the value for the string + * + * @throws ParseException if the string cannot be converted into + * a value object (e.g. invalid input) + */ + public Object stringToValue(String string) + throws ParseException + { + Object value = string; + Class valueClass = getValueClass(); + if (valueClass == null) + valueClass = getFormattedTextField().getValue().getClass(); + if (valueClass != null) + try + { + Constructor constr = valueClass.getConstructor + (new Class[]{String.class}); + value = constr.newInstance(new Object[]{ string }); + } + catch (NoSuchMethodException ex) + { + // leave value as string + } + catch (Exception ex) + { + throw new ParseException(string, 0); + } + return value; + } + + /** + * Converts a value object into a String. This is done by invoking the + * {@link Object#toString()} method on the value. + * + * @param value the value to be converted + * + * @return the string representation of the value + * + * @throws ParseException if the value cannot be converted + */ + public String valueToString(Object value) + throws ParseException + { + return value.toString(); + } + + /** + * Creates and returns a clone of this DefaultFormatter. + * + * @return a clone of this object + * + * @throws CloneNotSupportedException not thrown here + */ + public Object clone() + throws CloneNotSupportedException + { + return super.clone(); + } + + /** + * Returns the DocumentFilter that is used to restrict input. + * + * @return the DocumentFilter that is used to restrict input + */ + protected DocumentFilter getDocumentFilter() + { + return new FormatterDocumentFilter(); + } +} diff --git a/libjava/classpath/javax/swing/text/DefaultHighlighter.java b/libjava/classpath/javax/swing/text/DefaultHighlighter.java new file mode 100644 index 00000000000..c8d874caa51 --- /dev/null +++ b/libjava/classpath/javax/swing/text/DefaultHighlighter.java @@ -0,0 +1,257 @@ +/* DefaultHighlighter.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; +import java.util.Vector; + +public class DefaultHighlighter extends LayeredHighlighter +{ + public static class DefaultHighlightPainter + extends LayerPainter + { + private Color color; + + public DefaultHighlightPainter(Color c) + { + super(); + color = c; + } + + public Color getColor() + { + return color; + } + + private void paintHighlight(Graphics g, Rectangle rect) + { + g.fillRect(rect.x, rect.y, rect.width, rect.height); + } + + public void paint(Graphics g, int p0, int p1, Shape bounds, + JTextComponent c) + { + Rectangle r0 = null; + Rectangle r1 = null; + Rectangle rect = bounds.getBounds(); + + try + { + r0 = c.modelToView(p0); + r1 = c.modelToView(p1); + } + catch (BadLocationException e) + { + // This should never occur. + return; + } + + if (r0 == null || r1 == null) + return; + + if (color == null) + g.setColor(c.getSelectionColor()); + else + g.setColor(color); + + // Check if only one line to highlight. + if (r0.y == r1.y) + { + r0.width = r1.x - r0.x; + paintHighlight(g, r0); + return; + } + + // First line, from p0 to end-of-line. + r0.width = rect.x + rect.width - r0.x; + paintHighlight(g, r0); + + // FIXME: All the full lines in between, if any (assumes that all lines + // have the same height -- not a good assumption with JEditorPane/JTextPane). + r0.y += r0.height; + r0.x = rect.x; + + while (r0.y < r1.y) + { + paintHighlight(g, r0); + r0.y += r0.height; + } + + // Last line, from beginnin-of-line to p1. + paintHighlight(g, r1); + } + + public Shape paintLayer(Graphics g, int p0, int p1, Shape bounds, + JTextComponent c, View view) + { + throw new InternalError(); + } + } + + private class HighlightEntry + { + int p0; + int p1; + Highlighter.HighlightPainter painter; + + public HighlightEntry(int p0, int p1, Highlighter.HighlightPainter painter) + { + this.p0 = p0; + this.p1 = p1; + this.painter = painter; + } + + public int getStartPosition() + { + return p0; + } + + public int getEndPosition() + { + return p1; + } + + public Highlighter.HighlightPainter getPainter() + { + return painter; + } + } + + /** + * @specnote final as of 1.4 + */ + public static final LayeredHighlighter.LayerPainter DefaultPainter = + new DefaultHighlightPainter(null); + + private JTextComponent textComponent; + private Vector highlights = new Vector(); + private boolean drawsLayeredHighlights = true; + + public DefaultHighlighter() + { + } + + public boolean getDrawsLayeredHighlights() + { + return drawsLayeredHighlights; + } + + public void setDrawsLayeredHighlights(boolean newValue) + { + drawsLayeredHighlights = newValue; + } + + private void checkPositions(int p0, int p1) + throws BadLocationException + { + if (p0 < 0) + throw new BadLocationException("DefaultHighlighter", p0); + + if (p1 < p0) + throw new BadLocationException("DefaultHighlighter", p1); + } + + public void install(JTextComponent c) + { + textComponent = c; + removeAllHighlights(); + } + + public void deinstall(JTextComponent c) + { + textComponent = null; + } + + public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter painter) + throws BadLocationException + { + checkPositions(p0, p1); + HighlightEntry entry = new HighlightEntry(p0, p1, painter); + highlights.add(entry); + return entry; + } + + public void removeHighlight(Object tag) + { + highlights.remove(tag); + } + + public void removeAllHighlights() + { + highlights.clear(); + } + + public Highlighter.Highlight[] getHighlights() + { + return null; + } + + public void changeHighlight(Object tag, int p0, int p1) + throws BadLocationException + { + checkPositions(p0, p1); + HighlightEntry entry = (HighlightEntry) tag; + entry.p0 = p0; + entry.p1 = p1; + } + + public void paintLayeredHighlights(Graphics g, int p0, int p1, + Shape viewBounds, JTextComponent editor, + View view) + { + } + + public void paint(Graphics g) + { + // Check if there are any highlights. + if (highlights.size() == 0) + return; + + Shape bounds = textComponent.getBounds(); + + for (int index = 0; index < highlights.size(); ++index) + { + HighlightEntry entry = (HighlightEntry) highlights.get(index); + entry.painter.paint(g, entry.p0, entry.p1, bounds, textComponent); + } + } +} diff --git a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java new file mode 100644 index 00000000000..6fe206a8453 --- /dev/null +++ b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java @@ -0,0 +1,202 @@ +/* DefaultStyledDocument.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Font; +import java.io.Serializable; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +public class DefaultStyledDocument extends AbstractDocument + implements StyledDocument +{ + public class ElementBuffer + implements Serializable + { + private Element root; + + public ElementBuffer(Element root) + { + this.root = root; + } + + public Element getRootElement() + { + return root; + } + } + + public static final int BUFFER_SIZE_DEFAULT = 4096; + + protected DefaultStyledDocument.ElementBuffer buffer; + + public DefaultStyledDocument() + { + this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleContext()); + } + + public DefaultStyledDocument(StyleContext context) + { + this(new GapContent(BUFFER_SIZE_DEFAULT), context); + } + + public DefaultStyledDocument(AbstractDocument.Content content, + StyleContext context) + { + super(content, context); + buffer = new ElementBuffer(createDefaultRoot()); + setLogicalStyle(0, context.getStyle(StyleContext.DEFAULT_STYLE)); + } + + public Style addStyle(String nm, Style parent) + { + StyleContext context = (StyleContext) getAttributeContext(); + return context.addStyle(nm, parent); + } + + protected AbstractDocument.AbstractElement createDefaultRoot() + { + Element[] tmp; + BranchElement section = new BranchElement(null, null); + + BranchElement paragraph = new BranchElement(section, null); + tmp = new Element[1]; + tmp[0] = paragraph; + section.replace(0, 0, tmp); + + LeafElement leaf = new LeafElement(paragraph, null, 0, 1); + tmp = new Element[1]; + tmp[0] = leaf; + paragraph.replace(0, 0, tmp); + + return section; + } + + public Element getCharacterElement(int position) + { + Element element = getDefaultRootElement(); + + while (! element.isLeaf()) + { + int index = element.getElementIndex(position); + element = element.getElement(index); + } + + return element; + } + + public Color getBackground(AttributeSet attributes) + { + StyleContext context = (StyleContext) getAttributeContext(); + return context.getBackground(attributes); + } + + public Element getDefaultRootElement() + { + return buffer.getRootElement(); + } + + public Font getFont(AttributeSet attributes) + { + StyleContext context = (StyleContext) getAttributeContext(); + return context.getFont(attributes); + } + + public Color getForeground(AttributeSet attributes) + { + StyleContext context = (StyleContext) getAttributeContext(); + return context.getForeground(attributes); + } + + public Style getLogicalStyle(int position) + { + Element paragraph = getParagraphElement(position); + AttributeSet attributes = paragraph.getAttributes(); + return (Style) attributes.getResolveParent(); + } + + public Element getParagraphElement(int position) + { + Element element = getCharacterElement(position); + return element.getParentElement(); + } + + public Style getStyle(String nm) + { + StyleContext context = (StyleContext) getAttributeContext(); + return context.getStyle(nm); + } + + public void removeStyle(String nm) + { + StyleContext context = (StyleContext) getAttributeContext(); + context.removeStyle(nm); + } + + public void setCharacterAttributes(int offset, int length, + AttributeSet attributes, + boolean replace) + { + // FIXME: Implement me. + throw new Error("not implemented"); + } + + public void setLogicalStyle(int position, Style style) + { + Element el = getParagraphElement(position); + if (el instanceof AbstractElement) + { + AbstractElement ael = (AbstractElement) el; + ael.setResolveParent(style); + } + else + throw new AssertionError("paragraph elements are expected to be" + + "instances of javax.swing.text.AbstractDocument.AbstractElement"); + } + + public void setParagraphAttributes(int offset, int length, + AttributeSet attributes, + boolean replace) + { + // FIXME: Implement me. + throw new Error("not implemented"); + } +} diff --git a/libjava/classpath/javax/swing/text/Document.java b/libjava/classpath/javax/swing/text/Document.java new file mode 100644 index 00000000000..f23767f58ef --- /dev/null +++ b/libjava/classpath/javax/swing/text/Document.java @@ -0,0 +1,221 @@ +/* Document.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import javax.swing.event.DocumentListener; +import javax.swing.event.UndoableEditListener; + +/** + * A Document is the model that backs up all text components in Swing. + * This interface supports different kinds of implementations, from + * simple plain text model up to complex styled HTML or RTF models. + */ +public interface Document +{ + /** + * The key for the property that describes the source of a document. + */ + String StreamDescriptionProperty = "stream"; + + /** + * The key for the property that is the title of a document. + */ + String TitleProperty = "title"; + + /** + * Adds a {@link DocumentListener} to this document. + * + * @param listener the DocumentListener to add + */ + void addDocumentListener(DocumentListener listener); + + /** + * Adds an {@link UndoableEditListener} to this document. + * + * @param listener the UndoableEditListener to add + */ + void addUndoableEditListener(UndoableEditListener listener); + + /** + * Creates a mark in the character content at the specified offset. + * + * @param offs the offset where to place the mark + * + * @return the created Position object + * + * @throws BadLocationException of the specified offset is not a valid + * position in the documents content + */ + Position createPosition(int offs) + throws BadLocationException; + + /** + * Returns the default root element. Views should be using this element + * unless other mechanisms for assigning views to element structure is + * provided. + * + * @return the default root element + */ + Element getDefaultRootElement(); + + /** + * Returns the position that marks the end of the document. + * + * @return the position that marks the end of the document + */ + Position getEndPosition(); + + /** + * Returns the length of the document content. + * + * @return the length of the document content + */ + int getLength(); + + /** + * Returns a document property with the specified key. + * + * @param key the (non-null) key for the property to fetch + * + * @return the property for <code>key</code> or null if no such property + * is stored + */ + Object getProperty(Object key); + + /** + * Returns the root elements of the document content. + * + * @return the root elements of the document content + */ + Element[] getRootElements(); + + /** + * Returns the position that marks the beginning of the document + * content. + * + * @return the start position + */ + Position getStartPosition(); + + /** + * Returns the textual content starting at <code>offset</code> with + * a length of <code>length</code>. + * + * @param offset the beginning of the text fragment to fetch + * @param length the length of the text fragment to fetch + * + * @return the text fragment starting at <code>offset</code> with + * a length of <code>length</code> + * + * @throws BadLocationException if <code>offset</code> or <code>length</code> + * are no valid locations in the document content + */ + String getText(int offset, int length) + throws BadLocationException; + + /** + * Fetch the textual content starting at <code>offset</code> with + * a length of <code>length</code> and store it in <code>txt</code>. + * + * @param offset the beginning of the text fragment to fetch + * @param length the length of the text fragment to fetch + * @param txt the Segment where to store the text fragment + * + * @throws BadLocationException if <code>offset</code> or <code>length</code> + * are no valid locations in the document content + */ + void getText(int offset, int length, Segment txt) + throws BadLocationException; + + /** + * Inserts a piece of text with an AttributeSet at the specified + * <code>offset</code>. + * + * @param offset the location where to insert the content + * @param str the textual content to insert + * @param a the Attributes associated with the piece of text + * + * @throws BadLocationException if <code>offset</code> + * is not a valid location in the document content + */ + void insertString(int offset, String str, AttributeSet a) + throws BadLocationException; + + /** + * Sets a document property. + * + * @param key the key of the property + * @param value the value of the property + */ + void putProperty(Object key, Object value); + + /** + * Removes a piece of content. + * + * @param offs the location of the fragment to remove + * @param len the length of the fragment to remove + * + * @throws BadLocationException if <code>offs</code> or <code>len</code> + * are no valid locations in the document content + */ + void remove(int offs, int len) + throws BadLocationException; + + /** + * Removes a DocumentListener from this Document. + * + * @param listener the DocumentListener to remove + */ + void removeDocumentListener(DocumentListener listener); + + /** + * Removes an UndoableEditListener from this Document. + * + * @param listener the UndoableEditListener to remove + */ + void removeUndoableEditListener(UndoableEditListener listener); + + /** + * This allows the Document to be rendered safely. It is made sure that + * the Runnable can read the document without any changes while reading. + * The Runnable is not allowed to change the Document itself. + * + * @param r the Runnable that renders the Document + */ + void render(Runnable r); +} diff --git a/libjava/classpath/javax/swing/text/DocumentFilter.java b/libjava/classpath/javax/swing/text/DocumentFilter.java new file mode 100644 index 00000000000..f86f41ca6c0 --- /dev/null +++ b/libjava/classpath/javax/swing/text/DocumentFilter.java @@ -0,0 +1,83 @@ +/* DocumentFilter.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +public class DocumentFilter +{ + public abstract static class FilterBypass + { + public FilterBypass() + { + // Do nothing here. + } + + public abstract Document getDocument(); + + public abstract void insertString(int offset, String string, + AttributeSet attr) + throws BadLocationException; + + public abstract void remove(int offset, int length) + throws BadLocationException; + + public abstract void replace(int offset, int length, String string, + AttributeSet attrs) + throws BadLocationException; + } + + public void insertString(DocumentFilter.FilterBypass fb, int offset, + String string, AttributeSet attr) + throws BadLocationException + { + fb.insertString(offset, string, attr); + } + + public void remove(DocumentFilter.FilterBypass fb, int offset, int length) + throws BadLocationException + { + fb.remove(offset, length); + } + + public void replace(DocumentFilter.FilterBypass fb, int offset, int length, + String text, AttributeSet attr) + throws BadLocationException + { + fb.replace(offset, length, text, attr); + } +} diff --git a/libjava/classpath/javax/swing/text/EditorKit.java b/libjava/classpath/javax/swing/text/EditorKit.java new file mode 100644 index 00000000000..bd51a866f68 --- /dev/null +++ b/libjava/classpath/javax/swing/text/EditorKit.java @@ -0,0 +1,96 @@ +/* EditorKit.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Serializable; +import java.io.Writer; + +import javax.swing.Action; +import javax.swing.JEditorPane; + +public abstract class EditorKit + implements Cloneable, Serializable +{ + private static final long serialVersionUID = -5044124649345887822L; + + public EditorKit() + { + } + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + return null; + } + } + + /** + * Called when the kit is being removed from the JEditorPane. + */ + public void deinstall(JEditorPane c) + { + } + + public void install(JEditorPane c) + { + } + + public abstract Caret createCaret(); + public abstract Document createDefaultDocument(); + public abstract Action[] getActions(); + public abstract String getContentType(); + public abstract ViewFactory getViewFactory(); + public abstract void read(InputStream in, Document doc, int pos) + throws BadLocationException, IOException; + public abstract void read(Reader in, Document doc, int pos) + throws BadLocationException, IOException; + public abstract void write(OutputStream out, Document doc, int pos, int len) + throws BadLocationException, IOException; + public abstract void write(Writer out, Document doc, int pos, int len) + throws BadLocationException, IOException; +} diff --git a/libjava/classpath/javax/swing/text/Element.java b/libjava/classpath/javax/swing/text/Element.java new file mode 100644 index 00000000000..eb53ee9d3e1 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Element.java @@ -0,0 +1,54 @@ +/* Element.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + + + +public interface Element +{ + AttributeSet getAttributes(); + Document getDocument(); + Element getElement(int index); + int getElementCount(); + int getElementIndex(int offset); + int getEndOffset(); + String getName(); + Element getParentElement(); + int getStartOffset(); + boolean isLeaf(); + } diff --git a/libjava/classpath/javax/swing/text/FieldView.java b/libjava/classpath/javax/swing/text/FieldView.java new file mode 100644 index 00000000000..4d5c51cebb4 --- /dev/null +++ b/libjava/classpath/javax/swing/text/FieldView.java @@ -0,0 +1,176 @@ +/* FieldView.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.JTextField; +import javax.swing.event.DocumentEvent; + +public class FieldView extends PlainView +{ + public FieldView(Element elem) + { + super(elem); + } + + protected FontMetrics getFontMetrics() + { + Component container = getContainer(); + return container.getFontMetrics(container.getFont()); + } + + /** + * Vertically centers the single line of text within the + * bounds of the input shape. The returned Rectangle is centered + * vertically within <code>shape</code> and has a height of the + * preferred span along the Y axis. Horizontal adjustment is done according + * to the horizontalAligment property of the component that is rendered. + * + * @param shape the shape within which the line is beeing centered + */ + protected Shape adjustAllocation(Shape shape) + { + Rectangle rectIn = shape.getBounds(); + // vertical adjustment + int height = (int) getPreferredSpan(Y_AXIS); + int y = rectIn.y + (rectIn.height - height) / 2; + // horizontal adjustment + JTextField textField = (JTextField) getContainer(); + int halign = textField.getHorizontalAlignment(); + int width = (int) getPreferredSpan(X_AXIS); + int x; + ComponentOrientation orientation = textField.getComponentOrientation(); + switch (halign) + { + case JTextField.CENTER: + x = rectIn.x + (rectIn.width - width) / 2; + break; + case JTextField.RIGHT: + x = rectIn.x + (rectIn.width - width); + break; + case JTextField.TRAILING: + if (orientation.isLeftToRight()) + x = rectIn.x + (rectIn.width - width); + else + x = rectIn.x; + break; + case JTextField.LEADING: + if (orientation.isLeftToRight()) + x = rectIn.x; + else + x = rectIn.x + (rectIn.width - width); + break; + case JTextField.LEFT: + default: + x = rectIn.x; + break; + } + return new Rectangle(x, y, width, height); + } + + public float getPreferredSpan(int axis) + { + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException(); + + FontMetrics fm = getFontMetrics(); + + if (axis == Y_AXIS) + return fm.getHeight(); + + String text; + Element elem = getElement(); + + try + { + text = elem.getDocument().getText(elem.getStartOffset(), + elem.getEndOffset()); + } + catch (BadLocationException e) + { + // This should never happen. + text = ""; + } + + return fm.stringWidth(text); + } + + public int getResizeWeight(int axis) + { + return axis = axis == X_AXIS ? 1 : 0; + } + + public Shape modelToView(int pos, Shape a, Position.Bias bias) + throws BadLocationException + { + Shape newAlloc = adjustAllocation(a); + return super.modelToView(pos, newAlloc, bias); + } + + public void paint(Graphics g, Shape s) + { + Shape newAlloc = adjustAllocation(s); + super.paint(g, newAlloc); + } + + public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + Shape newAlloc = adjustAllocation(shape); + super.insertUpdate(ev, newAlloc, vf); + } + + public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + Shape newAlloc = adjustAllocation(shape); + super.removeUpdate(ev, newAlloc, vf); + } + + public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + Shape newAlloc = adjustAllocation(shape); + super.removeUpdate(ev, newAlloc, vf); + } + +} diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java new file mode 100644 index 00000000000..1bbef8f93d6 --- /dev/null +++ b/libjava/classpath/javax/swing/text/GapContent.java @@ -0,0 +1,356 @@ +/* GapContent.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.io.Serializable; + +import javax.swing.undo.UndoableEdit; + +/** + * This implementation of {@link AbstractDocument.Content} uses a gapped + * buffer. This takes advantage of the fact that text area content is + * mostly inserted sequentially. The buffer is a char array that maintains + * a gap at the current insertion point. If characters a inserted at + * gap boundaries, the cost is minimal (simple array access). The array only + * has to be shifted around when the insertion point moves (then the gap also + * moves and one array copy is necessary) or when the gap is filled up and + * the buffer has to be enlarged. + * + * TODO: Implement UndoableEdit support stuff + */ +public class GapContent + implements AbstractDocument.Content, Serializable +{ + private static final long serialVersionUID = 8374645204155842629L; + + /** + * This is the default buffer size and the amount of bytes that + * a buffer is extended if it is full. + */ + static final int DEFAULT_BUFSIZE = 64; + + /** + * The text buffer. + */ + char[] buffer; + + /** + * The index of the first character of the gap. + */ + int gapStart; + + /** + * The index of the character after the last character of the gap. + */ + int gapEnd; + + /** + * Creates a new GapContent object. + */ + public GapContent() + { + this(DEFAULT_BUFSIZE); + } + + /** + * Creates a new GapContent object with a specified initial size. + * + * @param size the initial size of the buffer + */ + public GapContent(int size) + { + buffer = (char[]) allocateArray(size); + gapStart = 0; + gapEnd = size - 1; + buffer[size - 1] = '\n'; + } + + /** + * Allocates an array of the specified length that can then be used as + * buffer. + * + * @param size the size of the array to be allocated + * + * @return the allocated array + */ + protected Object allocateArray(int size) + { + return new char[size]; + } + + /** + * Returns the length of the allocated buffer array. + * + * @return the length of the allocated buffer array + */ + protected int getArrayLength() + { + return buffer.length; + } + + /** + * Returns the length of the content. + * + * @return the length of the content + */ + public int length() + { + return buffer.length - (gapEnd - gapStart); + } + + /** + * Inserts a string at the specified position. + * + * @param where the position where the string is inserted + * @param str the string that is to be inserted + * + * @return an UndoableEdit object (currently not supported, so + * <code>null</code> is returned) + * + * @throws BadLocationException if <code>where</code> is not a valid location + * in the buffer + */ + public UndoableEdit insertString(int where, String str) + throws BadLocationException + { + // check arguments + int length = length(); + int strLen = str.length(); + + if (where >= length) + throw new BadLocationException("the where argument cannot be greater" + + " than the content length", where); + + // check if the gap is big enough to hold the string + if ((gapEnd - gapStart) < strLen) + // make room for this string and some more + shiftEnd(strLen + DEFAULT_BUFSIZE); + + // are we at the gap boundary? + if (where != gapStart) + shiftGap(where); + + // now we can simple copy the string into the gap and adjust the + // gap boundaries + System.arraycopy(str.toCharArray(), 0, buffer, gapStart, strLen); + gapStart += strLen; + return null; + } + + /** + * Removes a piece of content at th specified position. + * + * @param where the position where the content is to be removed + * @param nitems number of characters to be removed + * + * @return an UndoableEdit object (currently not supported, so + * <code>null</code> is returned) + * + * @throws BadLocationException if <code>where</code> is not a valid location + * in the buffer + */ + public UndoableEdit remove(int where, int nitems) + throws BadLocationException + { + // check arguments + int length = length(); + + if (where >= length) + throw new BadLocationException("the where argument cannot be greater" + + " than the content length", where); + if ((where + nitems) > length) + throw new BadLocationException("where + nitems cannot be greater" + + " than the content length", + where + nitems); + + // check if we are at the gap boundary + if (where != gapStart) + shiftGap(where); + + // now we simply have to enlarge the gap + gapEnd += nitems; + return null; + } + + /** + * Returns a piece of content as String. + * + * @param where the start location of the fragment + * @param len the length of the fragment + * + * @throws BadLocationException if <code>where</code> or + * <code>where + len</code> are no valid locations in the buffer + */ + public String getString(int where, int len) throws BadLocationException + { + Segment seg = new Segment(); + getChars(where, len, seg); + return new String(seg.array, seg.offset, seg.count); + } + + /** + * Fetches a piece of content and stores it in a {@link Segment} object. + * + * If the requested piece of text spans the gap, the content is copied + * into a new array. If it doesn't then it is contiguous and the + * actual content store is returned. + * + * @param where the start location of the fragment + * @param len the length of the fragment + * @param txt the Segment object to store the fragment in + * + * @throws BadLocationException if <code>where</code> or + * <code>where + len</code> are no valid locations in the buffer + */ + public void getChars(int where, int len, Segment txt) + throws BadLocationException + { + // check arguments + int length = length(); + if (where >= length) + throw new BadLocationException("the where argument cannot be greater" + + " than the content length", where); + if ((where + len) > length) + throw new BadLocationException("len plus where cannot be greater" + + " than the content length", + len + where); + + // check if requested segment is contiguous + if ((where < gapStart) && ((gapStart - where) < len)) + { + // requested segment is not contiguous -> copy the pieces together + char[] copy = new char[len]; + int lenFirst = gapStart - where; // the length of the first segment + System.arraycopy(buffer, where, copy, 0, lenFirst); + System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst); + txt.array = copy; + txt.offset = 0; + txt.count = len; + } + else + { + // requested segment is contiguous -> we can simply return the + // actual content + txt.array = buffer; + if (where < gapStart) + txt.offset = where; + else + txt.offset = where + (gapEnd - gapStart); + txt.count = len; + } + } + + /** + * Creates and returns a mark at the specified position. + * + * @param offset the position at which to create the mark + * + * @return the create Position object for the mark + * + * @throws BadLocationException if the offset is not a valid position in + * the buffer + */ + public Position createPosition(final int offset) throws BadLocationException + { + return new Position() + { + int off = offset; + + public int getOffset() + { + return off; + } + }; + } + + /** + * Enlarges the gap. This allocates a new bigger buffer array, copy the + * segment before the gap as it is and the segment after the gap at + * the end of the new buffer array. This does change the gapEnd mark + * but not the gapStart mark. + * + * @param newSize the new size of the gap + */ + protected void shiftEnd(int newSize) + { + char[] newBuf = (char[]) allocateArray(length() + newSize); + System.arraycopy(buffer, 0, newBuf, 0, gapStart); + System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, + buffer.length - gapEnd); + gapEnd = gapStart + newSize; + buffer = newBuf; + } + + /** + * Shifts the gap to the specified position. + * + * @param newGapStart the new start position of the gap + */ + protected void shiftGap(int newGapStart) + { + int newGapEnd = newGapStart + (gapEnd - gapStart); + + if (newGapStart == gapStart) + return; + else if (newGapStart < gapStart) + { + System.arraycopy(buffer, newGapStart, buffer, newGapEnd, + gapStart - newGapStart); + gapStart = newGapStart; + gapEnd = newGapEnd; + } + else + { + System.arraycopy(buffer, gapEnd, buffer, gapStart, + newGapStart - gapStart); + gapStart = newGapStart; + gapEnd = newGapEnd; + } + } + + /** + * Returns the allocated buffer array. + * + * @return the allocated buffer array + */ + protected Object getArray() + { + return buffer; + } +} diff --git a/libjava/classpath/javax/swing/text/Highlighter.java b/libjava/classpath/javax/swing/text/Highlighter.java new file mode 100644 index 00000000000..91f3b7903d0 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Highlighter.java @@ -0,0 +1,79 @@ +/* Highlighter.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Graphics; +import java.awt.Shape; + + +public interface Highlighter +{ + public interface Highlight + { + int getEndOffset(); + + int getStartOffset(); + + HighlightPainter getPainter(); + } + + public interface HighlightPainter + { + void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c); + } + + void install(JTextComponent c); + + void deinstall(JTextComponent c); + + Object addHighlight(int p0, int p1, HighlightPainter p) + throws BadLocationException; + + void removeAllHighlights(); + + void removeHighlight(Object tag); + + void changeHighlight(Object tag, int p0, int p1) + throws BadLocationException; + + Highlight[] getHighlights(); + + void paint(Graphics g); +} + diff --git a/libjava/classpath/javax/swing/text/InternationalFormatter.java b/libjava/classpath/javax/swing/text/InternationalFormatter.java new file mode 100644 index 00000000000..531a4c1aa10 --- /dev/null +++ b/libjava/classpath/javax/swing/text/InternationalFormatter.java @@ -0,0 +1,354 @@ +/* InternationalFormatter.java -- +Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.text.AttributedCharacterIterator; +import java.text.Format; +import java.text.ParseException; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.swing.Action; +import javax.swing.JFormattedTextField; + +/** + * This extends {@link DefaultFormatter} so that the value to string + * conversion is done via a {@link Format} object. This allows + * various additional formats to be handled by JFormattedField. + * + * @author Roman Kennke (roman@kennke.org) + */ +public class InternationalFormatter + extends DefaultFormatter +{ + + /** The serialVersoinUID. */ + private static final long serialVersionUID = 6941977820906408656L; + + /** The format that handles value to string conversion. */ + Format format; + + /** The minimal permissable value. */ + Comparable minimum; + + /** The maximal permissable value. */ + Comparable maximum; + + /** + * Creates a new InternationalFormatter with no Format specified. + */ + public InternationalFormatter() + { + super(); + minimum = null; + maximum = null; + format = null; + } + + /** + * Creates a new InternationalFormatter that uses the specified + * Format object for value to string conversion. + * + * @param format the Format object to use for value to string conversion + */ + public InternationalFormatter(Format format) + { + this(); + setFormat(format); + } + + /** + * Sets the Format object that is used to convert values to strings. + * + * @param format the Format to use for value to string conversion + * + * @see Format + */ + public void setFormat(Format format) + { + this.format = format; + } + + /** + * Returns the currently used Format object that is used to format + * the JFormattedField. + * + * @return the current Format + */ + public Format getFormat() + { + return format; + } + + /** + * Sets the minimum value that is allowed by this Formatter. The minimum + * value is given as an object that implements the {@link Comparable} + * interface. + * + * If <code>minValue</code> is null, then the Formatter has no restrictions + * at the lower end. + * + * If value class is not yet specified and <code>minValue</code> is not + * null, then <code>valueClass</code> is set to the class of the minimum + * value. + * + * @param minValue the minimum permissable value + * + * @see Comparable + */ + public void setMinimum(Comparable minValue) + { + minimum = minValue; + if (valueClass == null && minValue != null) + valueClass = minValue.getClass(); + } + + /** + * Returns the minimal value that is allowed by this Formatter. + * + * A <code>null</code> value means that there is no restriction. + * + * @return the minimal value that is allowed by this Formatter or + * <code>null</code> if there is no restriction + */ + public Comparable getMinimum() + { + return minimum; + } + + /** + * Sets the maximum value that is allowed by this Formatter. The maximum + * value is given as an object that implements the {@link Comparable} + * interface. + * + * If <code>maxValue</code> is null, then the Formatter has no restrictions + * at the upper end. + * + * If value class is not yet specified and <code>maxValue</code> is not + * null, then <code>valueClass</code> is set to the class of the maximum + * value. + * + * @param maxValue the maximum permissable value + * + * @see Comparable + */ + public void setMaximum(Comparable maxValue) + { + maximum = maxValue; + if (valueClass == null && maxValue != null) + valueClass = maxValue.getClass(); + } + + /** + * Returns the maximal value that is allowed by this Formatter. + * + * A <code>null</code> value means that there is no restriction. + * + * @return the maximal value that is allowed by this Formatter or + * <code>null</code> if there is no restriction + */ + public Comparable getMaximum() + { + return maximum; + } + + /** + * Installs the formatter on the specified {@link JFormattedTextField}. + * + * This method does the following things: + * <ul> + * <li>Display the value of #valueToString in the + * <code>JFormattedTextField</code></li> + * <li>Install the Actions from #getActions on the <code>JTextField</code> + * </li> + * <li>Install the DocumentFilter returned by #getDocumentFilter</li> + * <li>Install the NavigationFilter returned by #getNavigationFilter</li> + * </ul> + * + * This method is typically not overridden by subclasses. Instead override + * one of the mentioned methods in order to customize behaviour. + * + * @param ftf the {@link JFormattedTextField} in which this formatter + * is installed + */ + public void install(JFormattedTextField ftf) + { + super.install(ftf); + } + + /** + * Converts a value object into a String. This is done by invoking + * {@link Format#format} on the specified <code>Format</code> object. + * If no format is set, then {@link DefaultFormatter#valueToString(Object)} + * is called as a fallback. + * + * @param value the value to be converted + * + * @return the string representation of the value + * + * @throws ParseException if the value cannot be converted + */ + public String valueToString(Object value) + throws ParseException + { + if (format != null) + return format.format(value); + else + return super.valueToString(value); + } + + /** + * Converts a String (from the JFormattedTextField input) to a value. + * This is achieved by invoking {@link Format#parseObject(String)} on + * the specified <code>Format</code> object. + * + * This implementation differs slightly from {@link DefaultFormatter}, + * it does: + * <ol> + * <li>Convert the string to an <code>Object</code> using the + * <code>Formatter</code>.</li> + * <li>If a <code>valueClass</code> has been set, this object is passed to + * {@link DefaultFormatter#stringToValue(String)} so that the value + * has the correct type. This may or may not work correctly, depending on + * the implementation of toString() in the value class and if the class + * implements a constructor that takes one String as argument.</li> + * <li>If no {@link ParseException} has been thrown so far, we check if the + * value exceeds either <code>minimum</code> or <code>maximum</code> if + * one of those has been specified and throw a <code>ParseException</code> + * if it does.</li> + * <li>Return the value.</li> + * </ol> + * + * If no format has been specified, then + * {@link DefaultFormatter#stringToValue(String)} is invoked as fallback. + * + * @param string the string to convert + * + * @return the value for the string + * + * @throws ParseException if the string cannot be converted into + * a value object (e.g. invalid input) + */ + public Object stringToValue(String string) + throws ParseException + { + if (format != null) + { + Object o = format.parseObject(string); + + // If a value class has been set, call super in order to get + // the class right. That is what the JDK API docs suggest, so we do + // it that way. + if (valueClass != null) + o = super.stringToValue(o.toString()); + + // Check for minimum and maximum bounds + if (minimum != null && minimum.compareTo(o) > 0) + throw new ParseException("The value may not be less than the" + + " specified minimum", 0); + if (maximum != null && minimum.compareTo(o) < 0) + throw new ParseException("The value may not be greater than the" + + " specified maximum", 0); + return o; + } + else + return super.stringToValue(string); + } + + /** + * Returns the {@link Format.Field} constants that are associated with + * the specified position in the text. + * + * If <code>offset</code> is not a valid location in the input field, + * an empty array of fields is returned. + * + * @param offset the position in the text from which we want to fetch + * the fields constants + * + * @return the field values associated with the specified position in + * the text + */ + public Format.Field[] getFields(int offset) + { + // TODO: don't know if this is correct + AttributedCharacterIterator aci = format.formatToCharacterIterator + (getFormattedTextField().getValue()); + aci.setIndex(offset); + Map atts = aci.getAttributes(); + Set keys = atts.keySet(); + Format.Field[] fields = new Format.Field[keys.size()]; + int index = 0; + for (Iterator i = keys.iterator(); i.hasNext(); index++) + fields[index] = (Format.Field) i.next(); + return fields; + } + + /** + * This creates and returns a clone of this Formatter. + * + * @return a clone of this formatter + * + * @throws CloneNotSupportedException not thrown here, since cloning is + * supported + * XXX - FIXME - Whole method disabled as workaround for gcj bug #22060. + public Object clone() + throws CloneNotSupportedException + { + // TODO: it has to be considered, if we should return a deep or shallow + // clone here. for now we return a shallow clone + Object clone = super.clone(); + return clone; + } + */ + + /** + * Returns the Actions that are supported by this Formatter. + * + * @specnote the JDK API docs say here: <cite>If + * <code>getSupportsIncrement</code> returns true, this returns two + * Actions suitable for incrementing/decrementing the value.</cite> + * The questsion is, which method <code>getSupportsIncrement</code>? + * There is no such method in the whole API! So we just call + * super.getActions here. + */ + public Action[] getActions() + { + return super.getActions(); + } +} diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java new file mode 100644 index 00000000000..f2ef4d77ffe --- /dev/null +++ b/libjava/classpath/javax/swing/text/JTextComponent.java @@ -0,0 +1,1674 @@ +/* JTextComponent.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.AWTEvent; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputMethodListener; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.util.Enumeration; +import java.util.Hashtable; + +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleText; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JViewport; +import javax.swing.KeyStroke; +import javax.swing.Scrollable; +import javax.swing.SwingConstants; +import javax.swing.Timer; +import javax.swing.TransferHandler; +import javax.swing.UIManager; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.InputMapUIResource; +import javax.swing.plaf.TextUI; + +public abstract class JTextComponent extends JComponent + implements Scrollable, Accessible +{ + /** + * AccessibleJTextComponent + */ + public class AccessibleJTextComponent extends AccessibleJComponent + implements AccessibleText, CaretListener, DocumentListener + { + private static final long serialVersionUID = 7664188944091413696L; + + /** + * Constructor AccessibleJTextComponent + * @param component TODO + */ + public AccessibleJTextComponent() + { + } + + /** + * getCaretPosition + * @return int + */ + public int getCaretPosition() + { + return 0; // TODO + } + + /** + * getSelectedText + * @return String + */ + public String getSelectedText() + { + return null; // TODO + } + + /** + * getSelectionStart + * @return int + */ + public int getSelectionStart() + { + return 0; // TODO + } + + /** + * getSelectionEnd + * @return int + */ + public int getSelectionEnd() + { + return 0; // TODO + } + + /** + * caretUpdate + * @param value0 TODO + */ + public void caretUpdate(CaretEvent value0) + { + // TODO + } + + /** + * getAccessibleStateSet + * @return AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; // TODO + } + + /** + * getAccessibleRole + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return null; // TODO + } + + /** + * getAccessibleText + * @return AccessibleText + */ + public AccessibleText getAccessibleText() + { + return null; // TODO + } + + /** + * insertUpdate + * @param value0 TODO + */ + public void insertUpdate(DocumentEvent value0) + { + // TODO + } + + /** + * removeUpdate + * @param value0 TODO + */ + public void removeUpdate(DocumentEvent value0) + { + // TODO + } + + /** + * changedUpdate + * @param value0 TODO + */ + public void changedUpdate(DocumentEvent value0) + { + // TODO + } + + /** + * getIndexAtPoint + * @param value0 TODO + * @return int + */ + public int getIndexAtPoint(Point value0) + { + return 0; // TODO + } + + /** + * getRootEditorRect + * @return Rectangle + */ + Rectangle getRootEditorRect() + { + return null; + } + + /** + * getCharacterBounds + * @param value0 TODO + * @return Rectangle + */ + public Rectangle getCharacterBounds(int value0) + { + return null; // TODO + } + + /** + * getCharCount + * @return int + */ + public int getCharCount() + { + return 0; // TODO + } + + /** + * getCharacterAttribute + * @param value0 TODO + * @return AttributeSet + */ + public AttributeSet getCharacterAttribute(int value0) + { + return null; // TODO + } + + /** + * getAtIndex + * @param value0 TODO + * @param value1 TODO + * @return String + */ + public String getAtIndex(int value0, int value1) + { + return null; // TODO + } + + /** + * getAfterIndex + * @param value0 TODO + * @param value1 TODO + * @return String + */ + public String getAfterIndex(int value0, int value1) + { + return null; // TODO + } + + /** + * getBeforeIndex + * @param value0 TODO + * @param value1 TODO + * @return String + */ + public String getBeforeIndex(int value0, int value1) + { + return null; // TODO + } + } + + public static class KeyBinding + { + public KeyStroke key; + public String actionName; + + /** + * Creates a new <code>KeyBinding</code> instance. + * + * @param key a <code>KeyStroke</code> value + * @param actionName a <code>String</code> value + */ + public KeyBinding(KeyStroke key, String actionName) + { + this.key = key; + this.actionName = actionName; + } + } + + /** + * The timer that lets the caret blink. + */ + private class CaretBlinkTimer + extends Timer + implements ActionListener + { + /** + * Creates a new CaretBlinkTimer object with a default delay of 1 second. + */ + public CaretBlinkTimer() + { + super(1000, null); + addActionListener(this); + } + + /** + * Lets the caret blink. + */ + public void actionPerformed(ActionEvent ev) + { + Caret c = caret; + if (c != null) + c.setVisible(!c.isVisible()); + } + + /** + * Updates the blink delay according to the current caret. + */ + public void update() + { + stop(); + Caret c = caret; + if (c != null) + { + setDelay(c.getBlinkRate()); + if (editable) + start(); + else + c.setVisible(false); + } + } + } + + /** + * According to <a + * href="http://java.sun.com/products/jfc/tsc/special_report/kestrel/keybindings.html">this + * report</a>, a pair of private classes wraps a {@link + * javax.swing.text.Keymap} in the new {@link InputMap} / {@link + * ActionMap} interfaces, such that old Keymap-using code can make use of + * the new framework. + * + * <p>A little bit of experimentation with these classes reveals the following + * structure: + * + * <ul> + * + * <li>KeymapWrapper extends {@link InputMap} and holds a reference to + * the underlying {@link Keymap}.</li> + * + * <li>KeymapWrapper maps {@link KeyStroke} objects to {@link Action} + * objects, by delegation to the underlying {@link Keymap}.</li> + * + * <li>KeymapActionMap extends {@link ActionMap} also holds a reference to + * the underlying {@link Keymap} but only appears to use it for listing + * its keys. </li> + * + * <li>KeymapActionMap maps all {@link Action} objects to + * <em>themselves</em>, whether they exist in the underlying {@link + * Keymap} or not, and passes other objects to the parent {@link + * ActionMap} for resolving. + * + * </ul> + */ + + private class KeymapWrapper extends InputMap + { + Keymap map; + + public KeymapWrapper(Keymap k) + { + map = k; + } + + public int size() + { + return map.getBoundKeyStrokes().length + super.size(); + } + + public Object get(KeyStroke ks) + { + Action mapped = null; + Keymap m = map; + while(mapped == null && m != null) + { + mapped = m.getAction(ks); + if (mapped == null && ks.getKeyEventType() == KeyEvent.KEY_TYPED) + mapped = m.getDefaultAction(); + if (mapped == null) + m = m.getResolveParent(); + } + + if (mapped == null) + return super.get(ks); + else + return mapped; + } + + public KeyStroke[] keys() + { + KeyStroke[] superKeys = super.keys(); + KeyStroke[] mapKeys = map.getBoundKeyStrokes(); + KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length]; + for (int i = 0; i < superKeys.length; ++i) + bothKeys[i] = superKeys[i]; + for (int i = 0; i < mapKeys.length; ++i) + bothKeys[i + superKeys.length] = mapKeys[i]; + return bothKeys; + } + + public KeyStroke[] allKeys() + { + KeyStroke[] superKeys = super.allKeys(); + KeyStroke[] mapKeys = map.getBoundKeyStrokes(); + KeyStroke[] bothKeys = new KeyStroke[superKeys.length + mapKeys.length]; + for (int i = 0; i < superKeys.length; ++i) + bothKeys[i] = superKeys[i]; + for (int i = 0; i < mapKeys.length; ++i) + bothKeys[i + superKeys.length] = mapKeys[i]; + return bothKeys; + } + } + + private class KeymapActionMap extends ActionMap + { + Keymap map; + + public KeymapActionMap(Keymap k) + { + map = k; + } + + public Action get(Object cmd) + { + if (cmd instanceof Action) + return (Action) cmd; + else + return super.get(cmd); + } + + public int size() + { + return map.getBoundKeyStrokes().length + super.size(); + } + + public Object[] keys() + { + Object[] superKeys = super.keys(); + Object[] mapKeys = map.getBoundKeyStrokes(); + Object[] bothKeys = new Object[superKeys.length + mapKeys.length]; + for (int i = 0; i < superKeys.length; ++i) + bothKeys[i] = superKeys[i]; + for (int i = 0; i < mapKeys.length; ++i) + bothKeys[i + superKeys.length] = mapKeys[i]; + return bothKeys; + } + + public Object[] allKeys() + { + Object[] superKeys = super.allKeys(); + Object[] mapKeys = map.getBoundKeyStrokes(); + Object[] bothKeys = new Object[superKeys.length + mapKeys.length]; + for (int i = 0; i < superKeys.length; ++i) + bothKeys[i] = superKeys[i]; + for (int i = 0; i < mapKeys.length; ++i) + bothKeys[i + superKeys.length] = mapKeys[i]; + return bothKeys; + } + + } + + static class DefaultKeymap implements Keymap + { + String name; + Keymap parent; + Hashtable map; + Action defaultAction; + + public DefaultKeymap(String name) + { + this.name = name; + this.map = new Hashtable(); + } + + public void addActionForKeyStroke(KeyStroke key, Action a) + { + map.put(key, a); + } + + /** + * Looks up a KeyStroke either in the current map or the parent Keymap; + * does <em>not</em> return the default action if lookup fails. + * + * @param key The KeyStroke to look up an Action for. + * + * @return The mapping for <code>key</code>, or <code>null</code> + * if no mapping exists in this Keymap or any of its parents. + */ + public Action getAction(KeyStroke key) + { + if (map.containsKey(key)) + return (Action) map.get(key); + else if (parent != null) + return parent.getAction(key); + else + return null; + } + + public Action[] getBoundActions() + { + Action [] ret = new Action[map.size()]; + Enumeration e = map.elements(); + int i = 0; + while (e.hasMoreElements()) + { + ret[i++] = (Action) e.nextElement(); + } + return ret; + } + + public KeyStroke[] getBoundKeyStrokes() + { + KeyStroke [] ret = new KeyStroke[map.size()]; + Enumeration e = map.keys(); + int i = 0; + while (e.hasMoreElements()) + { + ret[i++] = (KeyStroke) e.nextElement(); + } + return ret; + } + + public Action getDefaultAction() + { + return defaultAction; + } + + public KeyStroke[] getKeyStrokesForAction(Action a) + { + int i = 0; + Enumeration e = map.keys(); + while (e.hasMoreElements()) + { + if (map.get(e.nextElement()).equals(a)) + ++i; + } + KeyStroke [] ret = new KeyStroke[i]; + i = 0; + e = map.keys(); + while (e.hasMoreElements()) + { + KeyStroke k = (KeyStroke) e.nextElement(); + if (map.get(k).equals(a)) + ret[i++] = k; + } + return ret; + } + + public String getName() + { + return name; + } + + public Keymap getResolveParent() + { + return parent; + } + + public boolean isLocallyDefined(KeyStroke key) + { + return map.containsKey(key); + } + + public void removeBindings() + { + map.clear(); + } + + public void removeKeyStrokeBinding(KeyStroke key) + { + map.remove(key); + } + + public void setDefaultAction(Action a) + { + defaultAction = a; + } + + public void setResolveParent(Keymap p) + { + parent = p; + } + } + + class DefaultTransferHandler + extends TransferHandler + { + public boolean canImport(JComponent component, DataFlavor[] flavors) + { + JTextComponent textComponent = (JTextComponent) component; + + if (! (textComponent.isEnabled() + && textComponent.isEditable() + && flavors != null)) + return false; + + for (int i = 0; i < flavors.length; ++i) + if (flavors[i].equals(DataFlavor.stringFlavor)) + return true; + + return false; + } + + public void exportToClipboard(JComponent component, Clipboard clipboard, + int action) + { + JTextComponent textComponent = (JTextComponent) component; + int start = textComponent.getSelectionStart(); + int end = textComponent.getSelectionEnd(); + + if (start == end) + return; + + try + { + // Copy text to clipboard. + String data = textComponent.getDocument().getText(start, end); + StringSelection selection = new StringSelection(data); + clipboard.setContents(selection, null); + + // Delete selected text on cut action. + if (action == MOVE) + doc.remove(start, end - start); + } + catch (BadLocationException e) + { + // Ignore this and do nothing. + } + } + + public int getSourceActions() + { + return NONE; + } + + public boolean importData(JComponent component, Transferable transferable) + { + DataFlavor flavor = null; + DataFlavor[] flavors = transferable.getTransferDataFlavors(); + + if (flavors == null) + return false; + + for (int i = 0; i < flavors.length; ++i) + if (flavors[i].equals(DataFlavor.stringFlavor)) + flavor = flavors[i]; + + if (flavor == null) + return false; + + try + { + JTextComponent textComponent = (JTextComponent) component; + String data = (String) transferable.getTransferData(flavor); + textComponent.replaceSelection(data); + return true; + } + catch (IOException e) + { + // Ignored. + } + catch (UnsupportedFlavorException e) + { + // Ignored. + } + + return false; + } + } + + private static final long serialVersionUID = -8796518220218978795L; + + public static final String DEFAULT_KEYMAP = "default"; + public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey"; + + private static DefaultTransferHandler defaultTransferHandler; + private static Hashtable keymaps = new Hashtable(); + private Keymap keymap; + private char focusAccelerator = '\0'; + private NavigationFilter navigationFilter; + + private CaretBlinkTimer caretBlinkTimer; + + /** + * Get a Keymap from the global keymap table, by name. + * + * @param n The name of the Keymap to look up + * + * @return A Keymap associated with the provided name, or + * <code>null</code> if no such Keymap exists + * + * @see #addKeymap() + * @see #removeKeymap() + * @see #keymaps + */ + public static Keymap getKeymap(String n) + { + return (Keymap) keymaps.get(n); + } + + /** + * Remove a Keymap from the global Keymap table, by name. + * + * @param n The name of the Keymap to remove + * + * @return The keymap removed from the global table + * + * @see #addKeymap() + * @see #getKeymap() + * @see #keymaps + */ + public static Keymap removeKeymap(String n) + { + Keymap km = (Keymap) keymaps.get(n); + keymaps.remove(n); + return km; + } + + /** + * Create a new Keymap with a specific name and parent, and add the new + * Keymap to the global keymap table. The name may be <code>null</code>, + * in which case the new Keymap will <em>not</em> be added to the global + * Keymap table. The parent may also be <code>null</code>, which is + * harmless. + * + * @param n The name of the new Keymap, or <code>null</code> + * @param parent The parent of the new Keymap, or <code>null</code> + * + * @return The newly created Keymap + * + * @see #removeKeymap() + * @see #getKeymap() + * @see #keymaps + */ + public static Keymap addKeymap(String n, Keymap parent) + { + Keymap k = new DefaultKeymap(n); + k.setResolveParent(parent); + if (n != null) + keymaps.put(n, k); + return k; + } + + /** + * Get the current Keymap of this component. + * + * @return The component's current Keymap + * + * @see #setKeymap() + * @see #keymap + */ + public Keymap getKeymap() + { + return keymap; + } + + /** + * Set the current Keymap of this component, installing appropriate + * {@link KeymapWrapper} and {@link KeymapActionMap} objects in the + * {@link InputMap} and {@link ActionMap} parent chains, respectively, + * and fire a property change event with name <code>"keymap"</code>. + * + * @see #getKeymap() + * @see #keymap + */ + public void setKeymap(Keymap k) + { + + // phase 1: replace the KeymapWrapper entry in the InputMap chain. + // the goal here is to always maintain the following ordering: + // + // [InputMap]? -> [KeymapWrapper]? -> [InputMapUIResource]* + // + // that is to say, component-specific InputMaps need to remain children + // of Keymaps, and Keymaps need to remain children of UI-installed + // InputMaps (and the order of each group needs to be preserved, of + // course). + + KeymapWrapper kw = (k == null ? null : new KeymapWrapper(k)); + InputMap childInputMap = getInputMap(JComponent.WHEN_FOCUSED); + if (childInputMap == null) + setInputMap(JComponent.WHEN_FOCUSED, kw); + else + { + while (childInputMap.getParent() != null + && !(childInputMap.getParent() instanceof KeymapWrapper) + && !(childInputMap.getParent() instanceof InputMapUIResource)) + childInputMap = childInputMap.getParent(); + + // option 1: there is nobody to replace at the end of the chain + if (childInputMap.getParent() == null) + childInputMap.setParent(kw); + + // option 2: there is already a KeymapWrapper in the chain which + // needs replacing (possibly with its own parents, possibly without) + else if (childInputMap.getParent() instanceof KeymapWrapper) + { + if (kw == null) + childInputMap.setParent(childInputMap.getParent().getParent()); + else + { + kw.setParent(childInputMap.getParent().getParent()); + childInputMap.setParent(kw); + } + } + + // option 3: there is an InputMapUIResource in the chain, which marks + // the place where we need to stop and insert ourselves + else if (childInputMap.getParent() instanceof InputMapUIResource) + { + if (kw != null) + { + kw.setParent(childInputMap.getParent()); + childInputMap.setParent(kw); + } + } + } + + // phase 2: replace the KeymapActionMap entry in the ActionMap chain + + KeymapActionMap kam = (k == null ? null : new KeymapActionMap(k)); + ActionMap childActionMap = getActionMap(); + if (childActionMap == null) + setActionMap(kam); + else + { + while (childActionMap.getParent() != null + && !(childActionMap.getParent() instanceof KeymapActionMap) + && !(childActionMap.getParent() instanceof ActionMapUIResource)) + childActionMap = childActionMap.getParent(); + + // option 1: there is nobody to replace at the end of the chain + if (childActionMap.getParent() == null) + childActionMap.setParent(kam); + + // option 2: there is already a KeymapActionMap in the chain which + // needs replacing (possibly with its own parents, possibly without) + else if (childActionMap.getParent() instanceof KeymapActionMap) + { + if (kam == null) + childActionMap.setParent(childActionMap.getParent().getParent()); + else + { + kam.setParent(childActionMap.getParent().getParent()); + childActionMap.setParent(kam); + } + } + + // option 3: there is an ActionMapUIResource in the chain, which marks + // the place where we need to stop and insert ourselves + else if (childActionMap.getParent() instanceof ActionMapUIResource) + { + if (kam != null) + { + kam.setParent(childActionMap.getParent()); + childActionMap.setParent(kam); + } + } + } + + // phase 3: update the explicit keymap field + + Keymap old = keymap; + keymap = k; + firePropertyChange("keymap", old, k); + } + + /** + * Resolves a set of bindings against a set of actions and inserts the + * results into a {@link Keymap}. Specifically, for each provided binding + * <code>b</code>, if there exists a provided action <code>a</code> such + * that <code>a.getValue(Action.NAME) == b.ActionName</code> then an + * entry is added to the Keymap mapping <code>b</code> to + * <code>a</code>. + * + * @param map The Keymap to add new mappings to + * @param bindings The set of bindings to add to the Keymap + * @param actions The set of actions to resolve binding names against + * + * @see Action#NAME + * @see Action#getValue() + * @see KeyBinding#ActionName + */ + public static void loadKeymap(Keymap map, + JTextComponent.KeyBinding[] bindings, + Action[] actions) + { + Hashtable acts = new Hashtable(actions.length); + for (int i = 0; i < actions.length; ++i) + acts.put(actions[i].getValue(Action.NAME), actions[i]); + for (int i = 0; i < bindings.length; ++i) + if (acts.containsKey(bindings[i].actionName)) + map.addActionForKeyStroke(bindings[i].key, (Action) acts.get(bindings[i].actionName)); + } + + /** + * Returns the set of available Actions this component's associated + * editor can run. Equivalent to calling + * <code>getUI().getEditorKit().getActions()</code>. This set of Actions + * is a reasonable value to provide as a parameter to {@link + * #loadKeymap()}, when resolving a set of {@link #KeyBinding} objects + * against this component. + * + * @return The set of available Actions on this component's {@link EditorKit} + * + * @see TextUI#getEditorKit() + * @see EditorKit#getActions() + */ + public Action[] getActions() + { + return getUI().getEditorKit(this).getActions(); + } + + // These are package-private to avoid an accessor method. + Document doc; + Caret caret; + boolean editable; + + private Highlighter highlighter; + private Color caretColor; + private Color disabledTextColor; + private Color selectedTextColor; + private Color selectionColor; + private Insets margin; + private boolean dragEnabled; + + /** + * Creates a new <code>JTextComponent</code> instance. + */ + public JTextComponent() + { + Keymap defkeymap = getKeymap(DEFAULT_KEYMAP); + boolean creatingKeymap = false; + if (defkeymap == null) + { + defkeymap = addKeymap(DEFAULT_KEYMAP, null); + defkeymap.setDefaultAction(new DefaultEditorKit.DefaultKeyTypedAction()); + creatingKeymap = true; + } + + caretBlinkTimer = new CaretBlinkTimer(); + + setFocusable(true); + setEditable(true); + enableEvents(AWTEvent.KEY_EVENT_MASK); + updateUI(); + + // need to do this after updateUI() + if (creatingKeymap) + loadKeymap(defkeymap, + new KeyBinding[] { + new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), + DefaultEditorKit.backwardAction), + new KeyBinding(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), + DefaultEditorKit.forwardAction), + new KeyBinding(KeyStroke.getKeyStroke("typed \b"), + DefaultEditorKit.deletePrevCharAction), + new KeyBinding(KeyStroke.getKeyStroke("typed \u007f"), + DefaultEditorKit.deleteNextCharAction) + }, + getActions()); + } + + public void setDocument(Document newDoc) + { + Document oldDoc = doc; + doc = newDoc; + firePropertyChange("document", oldDoc, newDoc); + revalidate(); + repaint(); + } + + public Document getDocument() + { + return doc; + } + + /** + * Get the <code>AccessibleContext</code> of this object. + * + * @return an <code>AccessibleContext</code> object + */ + public AccessibleContext getAccessibleContext() + { + return null; + } + + public void setMargin(Insets m) + { + margin = m; + } + + public Insets getMargin() + { + return margin; + } + + public void setText(String text) + { + try + { + doc.remove(0, doc.getLength()); + doc.insertString(0, text, null); + } + catch (BadLocationException e) + { + // This can never happen. + } + } + + /** + * Retrieves the current text in this text document. + * + * @return the text + * + * @exception NullPointerException if the underlaying document is null + */ + public String getText() + { + if (doc == null) + return null; + + try + { + return doc.getText(0, doc.getLength()); + } + catch (BadLocationException e) + { + // This should never happen. + return ""; + } + } + + /** + * Retrieves a part of the current text in this document. + * + * @param offset the postion of the first character + * @param length the length of the text to retrieve + * + * @return the text + * + * @exception BadLocationException if arguments do not hold pre-conditions + */ + public String getText(int offset, int length) + throws BadLocationException + { + return getDocument().getText(offset, length); + } + + /** + * Retrieves the currently selected text in this text document. + * + * @return the selected text + * + * @exception NullPointerException if the underlaying document is null + */ + public String getSelectedText() + { + try + { + return doc.getText(getSelectionStart(), getSelectionEnd()); + } + catch (BadLocationException e) + { + // This should never happen. + return null; + } + } + + /** + * Returns a string that specifies the name of the Look and Feel class + * that renders this component. + * + * @return the string "TextComponentUI" + */ + public String getUIClassID() + { + return "TextComponentUI"; + } + + /** + * Returns a string representation of this JTextComponent. + */ + protected String paramString() + { + return "JTextComponent"; + } + + /** + * This method returns the label's UI delegate. + * + * @return The label's UI delegate. + */ + public TextUI getUI() + { + return (TextUI) ui; + } + + /** + * This method sets the label's UI delegate. + * + * @param ui The label's UI delegate. + */ + public void setUI(TextUI newUI) + { + super.setUI(newUI); + } + + /** + * This method resets the label's UI delegate to the default UI for the + * current look and feel. + */ + public void updateUI() + { + setUI((TextUI) UIManager.getUI(this)); + } + + public Dimension getPreferredScrollableViewportSize() + { + return getPreferredSize(); + } + + public int getScrollableUnitIncrement(Rectangle visible, int orientation, + int direction) + { + // We return 1/10 of the visible area as documented in Sun's API docs. + if (orientation == SwingConstants.HORIZONTAL) + return visible.width / 10; + else if (orientation == SwingConstants.VERTICAL) + return visible.height / 10; + else + throw new IllegalArgumentException("orientation must be either " + + "javax.swing.SwingConstants.VERTICAL " + + "or " + + "javax.swing.SwingConstants.HORIZONTAL" + ); + } + + public int getScrollableBlockIncrement(Rectangle visible, int orientation, + int direction) + { + // We return the whole visible area as documented in Sun's API docs. + if (orientation == SwingConstants.HORIZONTAL) + return visible.width; + else if (orientation == SwingConstants.VERTICAL) + return visible.height; + else + throw new IllegalArgumentException("orientation must be either " + + "javax.swing.SwingConstants.VERTICAL " + + "or " + + "javax.swing.SwingConstants.HORIZONTAL" + ); + } + + /** + * Checks whether this text component it editable. + * + * @return true if editable, false otherwise + */ + public boolean isEditable() + { + return editable; + } + + /** + * Enables/disabled this text component's editability. + * + * @param newValue true to make it editable, false otherwise. + */ + public void setEditable(boolean newValue) + { + if (editable == newValue) + return; + + if (newValue == true) + caretBlinkTimer.start(); + else + { + caretBlinkTimer.stop(); + caret.setVisible(false); + } + + boolean oldValue = editable; + editable = newValue; + firePropertyChange("editable", oldValue, newValue); + } + + /** + * The <code>Caret</code> object used in this text component. + * + * @return the caret object + */ + public Caret getCaret() + { + return caret; + } + + /** + * Sets a new <code>Caret</code> for this text component. + * + * @param newCaret the new <code>Caret</code> to set + */ + public void setCaret(Caret newCaret) + { + if (caret != null) + caret.deinstall(this); + + Caret oldCaret = caret; + caret = newCaret; + + caretBlinkTimer.update(); + + if (caret != null) + caret.install(this); + + firePropertyChange("caret", oldCaret, newCaret); + } + + public Color getCaretColor() + { + return caretColor; + } + + public void setCaretColor(Color newColor) + { + Color oldCaretColor = caretColor; + caretColor = newColor; + firePropertyChange("caretColor", oldCaretColor, newColor); + } + + public Color getDisabledTextColor() + { + return disabledTextColor; + } + + public void setDisabledTextColor(Color newColor) + { + Color oldColor = disabledTextColor; + disabledTextColor = newColor; + firePropertyChange("disabledTextColor", oldColor, newColor); + } + + public Color getSelectedTextColor() + { + return selectedTextColor; + } + + public void setSelectedTextColor(Color newColor) + { + Color oldColor = selectedTextColor; + selectedTextColor = newColor; + firePropertyChange("selectedTextColor", oldColor, newColor); + } + + public Color getSelectionColor() + { + return selectionColor; + } + + public void setSelectionColor(Color newColor) + { + Color oldColor = selectionColor; + selectionColor = newColor; + firePropertyChange("selectionColor", oldColor, newColor); + } + + /** + * Retrisves the current caret position. + * + * @return the current position + */ + public int getCaretPosition() + { + return caret.getDot(); + } + + /** + * Sets the caret to a new position. + * + * @param position the new position + */ + public void setCaretPosition(int position) + { + if (doc == null) + return; + + if (position < 0 || position > doc.getLength()) + throw new IllegalArgumentException(); + + caret.setDot(position); + } + + /** + * Moves the caret to a given position. This selects the text between + * the old and the new position of the caret. + */ + public void moveCaretPosition(int position) + { + if (doc == null) + return; + + if (position < 0 || position > doc.getLength()) + throw new IllegalArgumentException(); + + caret.moveDot(position); + } + + public Highlighter getHighlighter() + { + return highlighter; + } + + public void setHighlighter(Highlighter newHighlighter) + { + if (highlighter != null) + highlighter.deinstall(this); + + Highlighter oldHighlighter = highlighter; + highlighter = newHighlighter; + + if (highlighter != null) + highlighter.install(this); + + firePropertyChange("highlighter", oldHighlighter, newHighlighter); + } + + /** + * Returns the start postion of the currently selected text. + * + * @return the start postion + */ + public int getSelectionStart() + { + return Math.min(caret.getDot(), caret.getMark()); + } + + /** + * Selects the text from the given postion to the selection end position. + * + * @param end the start positon of the selected text. + */ + public void setSelectionStart(int start) + { + select(start, getSelectionEnd()); + } + + /** + * Returns the end postion of the currently selected text. + * + * @return the end postion + */ + public int getSelectionEnd() + { + return Math.max(caret.getDot(), caret.getMark()); + } + + /** + * Selects the text from the selection start postion to the given position. + * + * @param end the end positon of the selected text. + */ + public void setSelectionEnd(int end) + { + select(getSelectionStart(), end); + } + + /** + * Selects a part of the content of the text component. + * + * @param start the start position of the selected text + * @param ent the end position of the selected text + */ + public void select(int start, int end) + { + int length = doc.getLength(); + + start = Math.max(start, 0); + start = Math.min(start, length); + + end = Math.max(end, 0); + end = Math.min(end, length); + + setCaretPosition(start); + moveCaretPosition(end); + } + + /** + * Selects the whole content of the text component. + */ + public void selectAll() + { + select(0, doc.getLength()); + } + + public synchronized void replaceSelection(String content) + { + int dot = caret.getDot(); + int mark = caret.getMark(); + + // If content is empty delete selection. + if (content == null) + { + caret.setDot(dot); + return; + } + + try + { + int start = getSelectionStart(); + int end = getSelectionEnd(); + + // Remove selected text. + if (dot != mark) + doc.remove(start, end - start); + + // Insert new text. + doc.insertString(start, content, null); + + // Set dot to new position. + setCaretPosition(start + content.length()); + } + catch (BadLocationException e) + { + // This should never happen. + } + } + + public boolean getScrollableTracksViewportHeight() + { + if (getParent() instanceof JViewport) + return ((JViewport) getParent()).getHeight() > getPreferredSize().height; + + return false; + } + + public boolean getScrollableTracksViewportWidth() + { + if (getParent() instanceof JViewport) + return ((JViewport) getParent()).getWidth() > getPreferredSize().width; + + return false; + } + + /** + * Adds a <code>CaretListener</code> object to this text component. + * + * @param listener the listener to add + */ + public void addCaretListener(CaretListener listener) + { + listenerList.add(CaretListener.class, listener); + } + + /** + * Removed a <code>CaretListener</code> object from this text component. + * + * @param listener the listener to remove + */ + public void removeCaretListener(CaretListener listener) + { + listenerList.remove(CaretListener.class, listener); + } + + /** + * Returns all added <code>CaretListener</code> objects. + * + * @return an array of listeners + */ + public CaretListener[] getCaretListeners() + { + return (CaretListener[]) getListeners(CaretListener.class); + } + + /** + * Notifies all registered <code>CaretListener</code> objects that the caret + * was updated. + * + * @param event the event to send + */ + protected void fireCaretUpdate(CaretEvent event) + { + CaretListener[] listeners = getCaretListeners(); + + for (int index = 0; index < listeners.length; ++index) + listeners[index].caretUpdate(event); + } + + /** + * Adds an <code>InputListener</code> object to this text component. + * + * @param listener the listener to add + */ + public void addInputMethodListener(InputMethodListener listener) + { + listenerList.add(InputMethodListener.class, listener); + } + + /** + * Removes an <code>InputListener</code> object from this text component. + * + * @param listener the listener to remove + */ + public void removeInputMethodListener(InputMethodListener listener) + { + listenerList.remove(InputMethodListener.class, listener); + } + + /** + * Returns all added <code>InputMethodListener</code> objects. + * + * @return an array of listeners + */ + public InputMethodListener[] getInputMethodListeners() + { + return (InputMethodListener[]) getListeners(InputMethodListener.class); + } + + public Rectangle modelToView(int position) throws BadLocationException + { + return getUI().modelToView(this, position); + } + + public boolean getDragEnabled() + { + return dragEnabled; + } + + public void setDragEnabled(boolean enabled) + { + dragEnabled = enabled; + } + + public int viewToModel(Point pt) + { + return getUI().viewToModel(this, pt); + } + + public void copy() + { + doTransferAction("copy", TransferHandler.getCopyAction()); + } + + public void cut() + { + doTransferAction("cut", TransferHandler.getCutAction()); + } + + public void paste() + { + doTransferAction("paste", TransferHandler.getPasteAction()); + } + + private void doTransferAction(String name, Action action) + { + // Install default TransferHandler if none set. + if (getTransferHandler() == null) + { + if (defaultTransferHandler == null) + defaultTransferHandler = new DefaultTransferHandler(); + + setTransferHandler(defaultTransferHandler); + } + + // Perform action. + ActionEvent event = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, + action.getValue(Action.NAME).toString()); + action.actionPerformed(event); + } + + public void setFocusAccelerator(char newKey) + { + if (focusAccelerator == newKey) + return; + + char oldKey = focusAccelerator; + focusAccelerator = newKey; + firePropertyChange(FOCUS_ACCELERATOR_KEY, oldKey, newKey); + } + + public char getFocusAccelerator() + { + return focusAccelerator; + } + + /** + * @since 1.4 + */ + public NavigationFilter getNavigationFilter() + { + return navigationFilter; + } + + /** + * @since 1.4 + */ + public void setNavigationFilter(NavigationFilter filter) + { + navigationFilter = filter; + } + + /** + * Read and set the content this component. If not overridden, the + * method reads the component content as a plain text. + * + * The second parameter of this method describes the input stream. It can + * be String, URL, File and so on. If not null, this object is added to + * the properties of the associated document under the key + * {@link Document#StreamDescriptionProperty}. + * + * @param input an input stream to read from. + * @param streamDescription an object, describing the stream. + * + * @throws IOException if the reader throws it. + * + * @see getDocument() + * @see Document#getProperty(Object) + */ + public void read(Reader input, Object streamDescription) + throws IOException + { + if (streamDescription != null) + { + Document d = getDocument(); + if (d != null) + d.putProperty(Document.StreamDescriptionProperty, streamDescription); + } + + StringBuffer b = new StringBuffer(); + int c; + + // Read till -1 (EOF). + while ((c = input.read()) >= 0) + b.append((char) c); + + setText(b.toString()); + } + + /** + * Write the content of this component to the given stream. If not + * overridden, the method writes the component content as a plain text. + * + * @param output the writer to write into. + * + * @throws IOException if the writer throws it. + */ + public void write(Writer output) + throws IOException + { + output.write(getText()); + } +} diff --git a/libjava/classpath/javax/swing/text/Keymap.java b/libjava/classpath/javax/swing/text/Keymap.java new file mode 100644 index 00000000000..c3f61d88e07 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Keymap.java @@ -0,0 +1,60 @@ +/* Keymap.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import javax.swing.Action; +import javax.swing.KeyStroke; + +public interface Keymap +{ + void addActionForKeyStroke(KeyStroke key, Action a); + Action getAction(KeyStroke key); + Action[] getBoundActions(); + KeyStroke[] getBoundKeyStrokes(); + Action getDefaultAction(); + KeyStroke[] getKeyStrokesForAction(Action a); + String getName(); + Keymap getResolveParent(); + boolean isLocallyDefined(KeyStroke key); + void removeBindings(); + void removeKeyStrokeBinding(KeyStroke keys); + void setDefaultAction(Action a); + void setResolveParent(Keymap parent); +} + + diff --git a/libjava/classpath/javax/swing/text/LayeredHighlighter.java b/libjava/classpath/javax/swing/text/LayeredHighlighter.java new file mode 100644 index 00000000000..dcaf1c504c6 --- /dev/null +++ b/libjava/classpath/javax/swing/text/LayeredHighlighter.java @@ -0,0 +1,57 @@ +/* LayeredHighlighter.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.awt.Graphics; +import java.awt.Shape; + +public abstract class LayeredHighlighter + implements Highlighter +{ + public abstract static class LayerPainter + implements Highlighter.HighlightPainter + { + public abstract Shape paintLayer(Graphics g, int p0, int p1, + Shape viewBounds, JTextComponent editor, + View view); + } + + public abstract void paintLayeredHighlights(Graphics g, int p0, int p1, + Shape viewBounds, + JTextComponent editor, View view); +} diff --git a/libjava/classpath/javax/swing/text/MutableAttributeSet.java b/libjava/classpath/javax/swing/text/MutableAttributeSet.java new file mode 100644 index 00000000000..2fe9ad50f67 --- /dev/null +++ b/libjava/classpath/javax/swing/text/MutableAttributeSet.java @@ -0,0 +1,85 @@ +/* MutableAttributeSet.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.util.Enumeration; + +/** + * MutableAttributeSet + * @author Andrew Selkirk + * @version 1.0 + */ +public interface MutableAttributeSet extends AttributeSet +{ + /** + * addAttribute + * @param name TODO + * @param value TODO + */ + void addAttribute(Object name, Object value); + + /** + * addAttributes + * @param attributes TODO + */ + void addAttributes(AttributeSet attributes); + + /** + * removeAttribute + * @param name TODO + */ + void removeAttribute(Object name); + + /** + * removeAttributes + * @param names TODO + */ + void removeAttributes(Enumeration names); + + /** + * removeAttributes + * @param attributes TODO + */ + void removeAttributes(AttributeSet attributes); + + /** + * setResolveParent + * @param parent TODO + */ + void setResolveParent(AttributeSet parent); +} diff --git a/libjava/classpath/javax/swing/text/NavigationFilter.java b/libjava/classpath/javax/swing/text/NavigationFilter.java new file mode 100644 index 00000000000..45f58f9e229 --- /dev/null +++ b/libjava/classpath/javax/swing/text/NavigationFilter.java @@ -0,0 +1,71 @@ +/* NavigationFilter.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +public class NavigationFilter +{ + public abstract static class FilterBypass + { + public FilterBypass() + { + // Do nothing here. + } + + public abstract Caret getCaret(); + public abstract void moveDot(int dot, Position.Bias bias); + public abstract void setDot(int dot, Position.Bias bias); + } + + public NavigationFilter() + { + // Do nothing here. + } + + public void moveDot(NavigationFilter.FilterBypass fb, int dot, + Position.Bias bias) + { + fb.moveDot(dot, bias); + } + + public void setDot(NavigationFilter.FilterBypass fb, int dot, + Position.Bias bias) + { + fb.setDot(dot, bias); + } +} diff --git a/libjava/classpath/javax/swing/text/PasswordView.java b/libjava/classpath/javax/swing/text/PasswordView.java new file mode 100644 index 00000000000..229fd2b508d --- /dev/null +++ b/libjava/classpath/javax/swing/text/PasswordView.java @@ -0,0 +1,170 @@ +/* PasswordView.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Graphics; + +import javax.swing.JPasswordField; + +public class PasswordView extends FieldView +{ + /** + * Buffer for putting the echo char into it and + * then using it to draw it into the view. + */ + private char[] oneCharBuffer = new char[1]; + + public PasswordView(Element elem) + { + super(elem); + } + + /** + * Draws one echo character at a given position. + * + * @param g the <code>Graphics</code> object to draw to + * @param x the x-position + * @param y the y-position + * @param ch the echo character + * + * @return the next x position right of the drawn character + */ + protected int drawEchoCharacter(Graphics g, int x, int y, char ch) + { + // Update font metrics. + updateMetrics(); + + // Draw character. + oneCharBuffer[0] = ch; + g.drawChars(oneCharBuffer, 0, 1, x, y); + + // Return new x position right of drawn character. + return x + metrics.charWidth(ch); + } + + private char getEchoChar() + { + char ch = ((JPasswordField) getContainer()).getEchoChar(); + + if (ch == 0) + ch = '*'; + + return ch; + } + + /** + * Draws selected text at a given position. + * + * @param g the <code>Graphics</code> object to draw to + * @param x the x-position + * @param y the y-position + * @param p0 the position of the first character to draw + * @param p1 the position of the first character not to draw + * + * @return the next x position right of the drawn character + */ + protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) + throws BadLocationException + { + // FIXME: Throw BadLocationException somehow. + + // Update font metrics. + updateMetrics(); + + // Get echo character. + char ch = getEchoChar(); + + // Set color for selected text. + g.setColor(selectedColor); + g.setColor(Color.BLACK); + + // Initialize buffer for faster drawing of all characters. + int len = p1 - p0; + char[] buffer = new char[len]; + for (int index = 0; index < len; ++index) + buffer[index] = ch; + + // Draw echo charaters. + g.drawChars(buffer, 0, len, x, y); + + // Return new x position right of all drawn characters. + return x + len * metrics.charWidth(ch); + } + + /** + * Draws unselected text at a given position. + * + * @param g the <code>Graphics</code> object to draw to + * @param x the x-position + * @param y the y-position + * @param p0 the position of the first character to draw + * @param p1 the position of the first character not to draw + * + * @return the next x position right of the drawn character + */ + protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) + throws BadLocationException + { + // FIXME: Throw BadLocationException somehow. + + // Update font metrics. + updateMetrics(); + + // Get echo character. + char ch = getEchoChar(); + + // Set color for unselected text. + g.setColor(unselectedColor); + g.setColor(Color.BLACK); + + // Initialize buffer for faster drawing of all characters. + int len = p1 - p0; + char[] buffer = new char[len]; + for (int index = 0; index < len; ++index) + buffer[index] = ch; + + // Draw echo charaters. + g.drawChars(buffer, 0, len, x, y); + + // Return new x position right of all drawn characters. + return x + len * metrics.charWidth(ch); + } +} + diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java new file mode 100644 index 00000000000..c3f59e436cb --- /dev/null +++ b/libjava/classpath/javax/swing/text/PlainDocument.java @@ -0,0 +1,166 @@ +/* PlainDocument.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.util.ArrayList; + +public class PlainDocument extends AbstractDocument +{ + private static final long serialVersionUID = 4758290289196893664L; + + public static final String lineLimitAttribute = "lineLimit"; + public static final String tabSizeAttribute = "tabSize"; + + private BranchElement rootElement; + private int tabSize; + + public PlainDocument() + { + this(new GapContent()); + } + + public PlainDocument(AbstractDocument.Content content) + { + super(content); + tabSize = 8; + rootElement = (BranchElement) createDefaultRoot(); + } + + private void reindex() + { + Element[] lines; + try + { + String str = content.getString(0, content.length()); + + ArrayList elts = new ArrayList(); + int j = 0; + for (int i = str.indexOf('\n', 0); i != -1; i = str.indexOf('\n', i + 1)) + { + elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, i + 1)); + j = i + 1; + } + + if (j < content.length()) + elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, content.length())); + + lines = new Element[elts.size()]; + for (int i = 0; i < elts.size(); ++i) + lines[i] = (Element) elts.get(i); + } + catch (BadLocationException e) + { + lines = new Element[1]; + lines[0] = createLeafElement(rootElement, SimpleAttributeSet.EMPTY, 0, 1); + } + + ((BranchElement) rootElement).replace(0, rootElement.getElementCount(), lines); + } + + protected AbstractDocument.AbstractElement createDefaultRoot() + { + BranchElement root = + (BranchElement) createBranchElement(null, SimpleAttributeSet.EMPTY); + + Element[] array = new Element[1]; + array[0] = createLeafElement(root, SimpleAttributeSet.EMPTY, 0, 1); + root.replace(0, 0, array); + + return root; + } + + protected void insertUpdate(DefaultDocumentEvent event, AttributeSet attributes) + { + reindex(); + + super.insertUpdate(event, attributes); + } + + protected void removeUpdate(DefaultDocumentEvent event) + { + super.removeUpdate(event); + + int p0 = event.getOffset(); + int len = event.getLength(); + int p1 = len + p0; + + // check if we must collapse some elements + int i1 = rootElement.getElementIndex(p0); + int i2 = rootElement.getElementIndex(p1); + if (i1 != i2) + { + Element el1 = rootElement.getElement(i1); + Element el2 = rootElement.getElement(i2); + int start = el1.getStartOffset(); + int end = el2.getEndOffset(); + // collapse elements if the removal spans more than 1 line + Element newEl = createLeafElement(rootElement, + SimpleAttributeSet.EMPTY, + start, end - len); + rootElement.replace(i1, i2 - i1, new Element[]{ newEl }); + } + else + { + // otherwise only adjust indices of the element + LeafElement el1 = (LeafElement) rootElement.getElement(i1); + el1.end -= len; + } + + // reindex remaining elements + for (int i = rootElement.getElementIndex(p0) + 1; + i < rootElement.getElementCount(); i++) + { + LeafElement el = (LeafElement) rootElement.getElement(i); + el.start -= len; + el.end -= len; + } + + } + + public Element getDefaultRootElement() + { + return rootElement; + } + + public Element getParagraphElement(int pos) + { + Element root = getDefaultRootElement(); + return root.getElement(root.getElementIndex(pos)); + } +} diff --git a/libjava/classpath/javax/swing/text/PlainView.java b/libjava/classpath/javax/swing/text/PlainView.java new file mode 100644 index 00000000000..5d1fab00032 --- /dev/null +++ b/libjava/classpath/javax/swing/text/PlainView.java @@ -0,0 +1,241 @@ +/* PlainView.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +public class PlainView extends View + implements TabExpander +{ + Color selectedColor; + Color unselectedColor; + Font font; + + protected FontMetrics metrics; + + public PlainView(Element elem) + { + super(elem); + } + + /** + * @since 1.4 + */ + protected void updateMetrics() + { + Component component = getContainer(); + Font font = component.getFont(); + + if (this.font != font) + { + this.font = font; + metrics = component.getFontMetrics(font); + } + } + + /** + * @since 1.4 + */ + protected Rectangle lineToRect(Shape a, int line) + { + // Ensure metrics are up-to-date. + updateMetrics(); + + Rectangle rect = a.getBounds(); + int fontHeight = metrics.getHeight(); + return new Rectangle(rect.x, rect.y + (line * fontHeight), + rect.width, fontHeight); + } + + public Shape modelToView(int position, Shape a, Position.Bias b) + throws BadLocationException + { + // Ensure metrics are up-to-date. + updateMetrics(); + + Document document = getDocument(); + + // Get rectangle of the line containing position. + int lineIndex = getElement().getElementIndex(position); + Rectangle rect = lineToRect(a, lineIndex); + + // Get the rectangle for position. + Element line = getElement().getElement(lineIndex); + int lineStart = line.getStartOffset(); + Segment segment = new Segment(); + document.getText(lineStart, position - lineStart, segment); + int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x, + this, lineStart); + + // Calc the real rectangle. + rect.x += xoffset; + rect.width = 1; + rect.height = metrics.getHeight(); + + return rect; + } + + protected void drawLine(int lineIndex, Graphics g, int x, int y) + { + try + { + metrics = g.getFontMetrics(); + // FIXME: Selected text are not drawn yet. + Element line = getElement().getElement(lineIndex); + drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset()); + //drawSelectedText(g, , , , ); + } + catch (BadLocationException e) + { + // This should never happen. + } + } + + protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) + throws BadLocationException + { + g.setColor(selectedColor); + Segment segment = new Segment(); + getDocument().getText(p0, p1 - p0, segment); + return Utilities.drawTabbedText(segment, x, y, g, this, 0); + } + + protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) + throws BadLocationException + { + g.setColor(unselectedColor); + Segment segment = new Segment(); + getDocument().getText(p0, p1 - p0, segment); + return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset); + } + + public void paint(Graphics g, Shape s) + { + // Ensure metrics are up-to-date. + updateMetrics(); + + JTextComponent textComponent = (JTextComponent) getContainer(); + + g.setFont(textComponent.getFont()); + selectedColor = textComponent.getSelectedTextColor(); + unselectedColor = textComponent.getForeground(); + + Rectangle rect = s.getBounds(); + + // FIXME: Text may be scrolled. + Document document = textComponent.getDocument(); + Element root = document.getDefaultRootElement(); + int y = rect.y; + + for (int i = 0; i < root.getElementCount(); i++) + { + drawLine(i, g, rect.x, y); + y += metrics.getHeight(); + } + } + + protected int getTabSize() + { + return 8; + } + + /** + * Returns the next tab stop position after a given reference position. + * + * This implementation ignores the <code>tabStop</code> argument. + * + * @param x the current x position in pixels + * @param tabStop the position within the text stream that the tab occured at + */ + public float nextTabStop(float x, int tabStop) + { + float tabSizePixels = getTabSize() + metrics.charWidth('m'); + return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels; + } + + public float getPreferredSpan(int axis) + { + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException(); + + // make sure we have the metrics + updateMetrics(); + + float span = 0; + Element el = getElement(); + Document doc = el.getDocument(); + Segment seg = new Segment(); + + switch (axis) + { + case X_AXIS: + // calculate the maximum of the line's widths + for (int i = 0; i < el.getElementCount(); i++) + { + Element child = el.getElement(i); + int start = child.getStartOffset(); + int end = child.getEndOffset(); + try { + doc.getText(start, start + end, seg); + } + catch (BadLocationException ex) + { + // throw new ClasspathAssertionError + // ("no BadLocationException should be thrown here"); + } + int width = metrics.charsWidth(seg.array, seg.offset, seg.count); + span = Math.max(span, width); + } + break; + case Y_AXIS: + default: + span = metrics.getHeight() * el.getElementCount(); + break; + } + + return span; + } +} + diff --git a/libjava/classpath/javax/swing/text/Position.java b/libjava/classpath/javax/swing/text/Position.java new file mode 100644 index 00000000000..a9d3d09d764 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Position.java @@ -0,0 +1,62 @@ +/* Position.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + + +public interface Position +{ + static class Bias + { + public static final Bias Backward = new Bias("backward"); + public static final Bias Forward = new Bias("forward"); + + private String name; + + private Bias(String n) + { + name = n; + } + + public String toString() + { + return name; + } + } + + int getOffset(); +} diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java new file mode 100644 index 00000000000..92d850016d9 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Segment.java @@ -0,0 +1,176 @@ +/* Segment.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.text.CharacterIterator; + +public class Segment + implements Cloneable, CharacterIterator +{ + private boolean partialReturn; + private int current; + + public char[] array; + public int count; + public int offset; + + public Segment() + { + } + + public Segment(char[] array, int offset, int count) + { + this.array = array; + this.offset = offset; + this.count = count; + } + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException e) + { + return null; + } + } + + public char current() + { + if (count == 0 + || current >= getEndIndex()) + return DONE; + + return array[current]; + } + + public char first() + { + if (count == 0) + return DONE; + + current = getBeginIndex(); + return array[current]; + } + + public int getBeginIndex() + { + return offset; + } + + public int getEndIndex() + { + return offset + count; + } + + public int getIndex() + { + return current; + } + + public char last() + { + if (count == 0) + return DONE; + + current = getEndIndex() - 1; + return array[current]; + } + + public char next() + { + if (count == 0) + return DONE; + + if ((current + 1) >= getEndIndex()) + { + current = getEndIndex(); + return DONE; + } + + current++; + return array[current]; + } + + public char previous() + { + if (count == 0 + || current == getBeginIndex()) + return DONE; + + current--; + return array[current]; + } + + public char setIndex(int position) + { + if (position < getBeginIndex() + || position > getEndIndex()) + throw new IllegalArgumentException(); + + current = position; + + if (position == getEndIndex()) + return DONE; + + return array[current]; + } + + public String toString() + { + return new String(array, offset, count); + } + + /** + * @since 1.4 + */ + public void setPartialReturn(boolean p) + { + partialReturn = p; + } + + /** + * @since 1.4 + */ + public boolean isPartialReturn() + { + return partialReturn; + } +} diff --git a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java new file mode 100644 index 00000000000..3ef5db61d43 --- /dev/null +++ b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java @@ -0,0 +1,193 @@ +/* SimpleAttributeSet.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; + +public class SimpleAttributeSet + implements MutableAttributeSet, Serializable, Cloneable +{ + public static final AttributeSet EMPTY = new SimpleAttributeSet(); + + Hashtable tab; + + public SimpleAttributeSet() + { + this(null); + } + + public SimpleAttributeSet(AttributeSet a) + { + tab = new Hashtable(); + if (a != null) + addAttributes(a); + } + + public void addAttribute(Object name, Object value) + { + tab.put(name, value); + } + + public void addAttributes(AttributeSet attributes) + { + Enumeration e = attributes.getAttributeNames(); + while (e.hasMoreElements()) + { + Object name = e.nextElement(); + Object val = attributes.getAttribute(name); + tab.put(name, val); + } + } + + public Object clone() + { + SimpleAttributeSet s = new SimpleAttributeSet(); + s.tab = (Hashtable) tab.clone(); + return s; + } + + public boolean containsAttribute(Object name, Object value) + { + return tab.containsKey(name) + && tab.get(name).equals(value); + } + + public boolean containsAttributes(AttributeSet attributes) + { + Enumeration e = attributes.getAttributeNames(); + while (e.hasMoreElements()) + { + Object name = e.nextElement(); + Object val = attributes.getAttribute(name); + if (! containsAttribute(name, val)) + return false; + } + return true; + } + + public AttributeSet copyAttributes() + { + return (AttributeSet) clone(); + } + + public boolean equals(Object obj) + { + return (obj != null) + && (obj instanceof SimpleAttributeSet) + && ((SimpleAttributeSet)obj).tab.equals(this.tab); + } + + public Object getAttribute(Object name) + { + Object val = tab.get(name); + if (val != null) + return val; + + Object p = getResolveParent(); + if (p != null && p instanceof AttributeSet) + return (((AttributeSet)p).getAttribute(name)); + + return null; + } + + public int getAttributeCount() + { + return tab.size(); + } + + public Enumeration getAttributeNames() + { + return tab.keys(); + } + + public AttributeSet getResolveParent() + { + return (AttributeSet) tab.get(ResolveAttribute); + } + + public int hashCode() + { + return tab.hashCode(); + } + + public boolean isDefined(Object attrName) + { + return tab.containsKey(attrName); + } + + public boolean isEmpty() + { + return tab.isEmpty(); + } + + public boolean isEqual(AttributeSet attr) + { + return this.equals(attr); + } + + public void removeAttribute(Object name) + { + tab.remove(name); + } + + public void removeAttributes(AttributeSet attributes) + { + removeAttributes(attributes.getAttributeNames()); + } + + public void removeAttributes(Enumeration names) + { + while (names.hasMoreElements()) + { + removeAttribute(names.nextElement()); + } + } + + public void setResolveParent(AttributeSet parent) + { + addAttribute(ResolveAttribute, parent); + } + + public String toString() + { + return tab.toString(); + } +} diff --git a/libjava/classpath/javax/swing/text/StringContent.java b/libjava/classpath/javax/swing/text/StringContent.java new file mode 100644 index 00000000000..bedf480d4ec --- /dev/null +++ b/libjava/classpath/javax/swing/text/StringContent.java @@ -0,0 +1,307 @@ +/* StringContent.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.undo.AbstractUndoableEdit; +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; +import javax.swing.undo.UndoableEdit; + +/** + * An implementation of the <code>AbstractDocument.Content</code> + * interface useful for small documents or debugging. The character + * content is a simple character array. It's not really efficient. + * + * <p>Do not use this class for large size.</p> + */ +public final class StringContent implements AbstractDocument.Content, Serializable +{ + // This is package-private to avoid an accessor method. + char[] content; + + private int count; + + private Vector positions = new Vector(); + + private class InsertUndo extends AbstractUndoableEdit + { + private int start; + + private int length; + + private String redoContent; + + public InsertUndo(int start, int length) + { + super(); + this.start = start; + this.length = length; + } + + public void undo() + { + super.undo(); + try + { + StringContent.this.checkLocation(this.start, this.length); + this.redoContent = new String(StringContent.this.content, this.start, this.length); + StringContent.this.remove(this.start, this.length); + } + catch (BadLocationException b) + { + throw new CannotUndoException(); + } + } + + public void redo() + { + super.redo(); + try + { + StringContent.this.insertString(this.start, this.redoContent); + } + catch (BadLocationException b) + { + throw new CannotRedoException(); + } + } + } + + private class RemoveUndo extends AbstractUndoableEdit + { + private int start; + + private String undoString; + + public RemoveUndo(int start, String str) + { + super(); + this.start = start; + this.undoString = str; + } + + public void undo() + { + super.undo(); + try + { + StringContent.this.insertString(this.start, this.undoString); + } + catch (BadLocationException bad) + { + throw new CannotUndoException(); + } + } + + public void redo() + { + super.redo(); + try + { + int end = this.undoString.length(); + StringContent.this.remove(this.start, end); + } + catch (BadLocationException bad) + { + throw new CannotRedoException(); + } + } + } + + private class StickyPosition implements Position + { + private int offset = -1; + + public StickyPosition(int offset) + { + this.offset = offset; + } + + // This is package-private to avoid an accessor method. + void setOffset(int offset) + { + this.offset = this.offset >= 0 ? offset : -1; + } + + /** + * Should be >=0. + */ + public int getOffset() + { + return offset < 0 ? 0 : offset; + } + } + + public StringContent() + { + this(1); + } + + public StringContent(int initialLength) + { + super(); + if (initialLength < 1) + initialLength = 1; + this.content = new char[initialLength]; + this.content[0] = '\n'; + this.count = 1; + } + + protected Vector getPositionsInRange(Vector v, + int offset, + int length) + { + Vector refPos = new Vector(); + Iterator iter = this.positions.iterator(); + while(iter.hasNext()) + { + Position p = (Position)iter.next(); + if ((offset <= p.getOffset()) + && (p.getOffset() <= (offset + length))) + refPos.add(p); + } + return refPos; + } + + public Position createPosition(int offset) throws BadLocationException + { + if (offset < this.count || offset > this.count) + checkLocation(offset, 0); + StickyPosition sp = new StickyPosition(offset); + this.positions.add(sp); + return sp; + } + + public int length() + { + return this.count; + } + + public UndoableEdit insertString(int where, String str) + throws BadLocationException + { + checkLocation(where, 0); + if (where == this.count) + throw new BadLocationException("Invalid location", 1); + if (str == null) + throw new NullPointerException(); + char[] insert = str.toCharArray(); + char[] temp = new char[this.content.length + insert.length]; + this.count += insert.length; + // Copy array and insert the string. + if (where > 0) + System.arraycopy(this.content, 0, temp, 0, where); + System.arraycopy(insert, 0, temp, where, insert.length); + System.arraycopy(this.content, where, temp, (where + insert.length), (temp.length - where - insert.length)); + if (this.content.length < temp.length) + this.content = new char[temp.length]; + // Copy the result in the original char array. + System.arraycopy(temp, 0, this.content, 0, temp.length); + // Move all the positions. + Vector refPos = getPositionsInRange(this.positions, where, temp.length - where); + Iterator iter = refPos.iterator(); + while (iter.hasNext()) + { + StickyPosition p = (StickyPosition)iter.next(); + p.setOffset(p.getOffset() + str.length()); + } + InsertUndo iundo = new InsertUndo(where, insert.length); + return iundo; + } + + public UndoableEdit remove(int where, int nitems) throws BadLocationException + { + checkLocation(where, nitems); + char[] temp = new char[(this.content.length - nitems)]; + this.count = this.count - nitems; + RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, nitems)); + // Copy array. + System.arraycopy(this.content, 0, temp, 0, where); + System.arraycopy(this.content, where + nitems, temp, where, this.content.length - where - nitems); + this.content = new char[temp.length]; + // Then copy the result in the original char array. + System.arraycopy(temp, 0, this.content, 0, this.content.length); + // Move all the positions. + Vector refPos = getPositionsInRange(this.positions, where, this.content.length + nitems - where); + Iterator iter = refPos.iterator(); + while (iter.hasNext()) + { + StickyPosition p = (StickyPosition)iter.next(); + int result = p.getOffset() - nitems; + p.setOffset(result); + if (result < 0) + this.positions.remove(p); + } + return rundo; + } + + public String getString(int where, int len) throws BadLocationException + { + checkLocation(where, len); + return new String (this.content, where, len); + } + + public void getChars(int where, int len, Segment txt) throws BadLocationException + { + checkLocation(where, len); + if (txt != null) + { + txt.array = this.content; + txt.offset = where; + txt.count = len; + } + } + + // This is package-private to avoid an accessor method. + void checkLocation(int where, int len) throws BadLocationException + { + if (where < 0) + throw new BadLocationException("Invalid location", 1); + else if (where > this.count) + throw new BadLocationException("Invalid location", this.count); + else if ((where + len)>this.count) + throw new BadLocationException("Invalid range", this.count); + } + +} + diff --git a/libjava/classpath/javax/swing/text/Style.java b/libjava/classpath/javax/swing/text/Style.java new file mode 100644 index 00000000000..851ac021947 --- /dev/null +++ b/libjava/classpath/javax/swing/text/Style.java @@ -0,0 +1,64 @@ +/* Style.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import javax.swing.event.ChangeListener; + +public interface Style extends MutableAttributeSet +{ + /** + * Returns the name of the style. + * + * @return the name + */ + String getName(); + + /** + * Adds a <code>ChangeListener</code> object to the style. + * + * @param listener the listener object to add + */ + void addChangeListener(ChangeListener listener); + + /** + * Removes a <code>ChangeListener</code> from to the style. + * + * @param listener the listener object to remove, + */ + void removeChangeListener(ChangeListener listener); +} diff --git a/libjava/classpath/javax/swing/text/StyleConstants.java b/libjava/classpath/javax/swing/text/StyleConstants.java new file mode 100644 index 00000000000..3f973f22631 --- /dev/null +++ b/libjava/classpath/javax/swing/text/StyleConstants.java @@ -0,0 +1,443 @@ +/* StyleConstants.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Component; + +import javax.swing.Icon; + +public class StyleConstants +{ + public static final int ALIGN_LEFT = 0; + public static final int ALIGN_CENTER = 1; + public static final int ALIGN_RIGHT = 2; + public static final int ALIGN_JUSTIFIED = 3; + + public static final Object Background = CharacterConstants.Background; + public static final Object BidiLevel = CharacterConstants.BidiLevel; + public static final Object Bold = CharacterConstants.Bold; + public static final Object ComponentAttribute = CharacterConstants.ComponentAttribute; + public static final Object FontFamily = CharacterConstants.Family; + public static final Object FontSize = CharacterConstants.Size; + public static final Object Foreground = CharacterConstants.Foreground; + public static final Object IconAttribute = CharacterConstants.IconAttribute; + public static final Object Italic = CharacterConstants.Italic; + public static final Object StrikeThrough = CharacterConstants.StrikeThrough; + public static final Object Subscript = CharacterConstants.Subscript; + public static final Object Superscript = CharacterConstants.Superscript; + public static final Object Underline = CharacterConstants.Underline; + + public static final Object Alignment = ParagraphConstants.Alignment; + public static final Object FirstLineIndent = ParagraphConstants.FirstLineIndent; + public static final Object LeftIndent = ParagraphConstants.LeftIndent; + public static final Object LineSpacing = ParagraphConstants.LineSpacing; + public static final Object Orientation = ParagraphConstants.Orientation; + public static final Object RightIndent = ParagraphConstants.RightIndent; + public static final Object SpaceAbove = ParagraphConstants.SpaceAbove; + public static final Object SpaceBelow = ParagraphConstants.SpaceBelow; + public static final Object TabSet = ParagraphConstants.TabSet; + + public static final String ComponentElementName = "component"; + public static final String IconElementName = "icon"; + + public static final Object ComposedTextAttribute = new StyleConstants("composed text"); + public static final Object ModelAttribute = new StyleConstants("model"); + public static final Object NameAttribute = new StyleConstants("name"); + public static final Object ResolveAttribute = new StyleConstants("resolver"); + + String keyname; + + // Package-private to avoid accessor constructor for use by + // subclasses. + StyleConstants(String k) + { + keyname = k; + } + + public String toString() + { + return keyname; + } + + public static int getAlignment(AttributeSet a) + { + if (a.isDefined(Alignment)) + return ((Integer)a.getAttribute(Alignment)).intValue(); + else + return ALIGN_LEFT; + } + + public static Color getBackground(AttributeSet a) + { + if (a.isDefined(Background)) + return (Color) a.getAttribute(Background); + else + return Color.BLACK; + } + + public static int getBidiLevel(AttributeSet a) + { + if (a.isDefined(BidiLevel)) + return ((Integer)a.getAttribute(BidiLevel)).intValue(); + else + return 0; + } + + public static Component getComponent(AttributeSet a) + { + if (a.isDefined(ComponentAttribute)) + return (Component) a.getAttribute(ComponentAttribute); + else + return (Component) null; + } + + public static float getFirstLineIndent(AttributeSet a) + { + if (a.isDefined(FirstLineIndent)) + return ((Float)a.getAttribute(FirstLineIndent)).floatValue(); + else + return 0.f; + } + + public static String getFontFamily(AttributeSet a) + { + if (a.isDefined(FontFamily)) + return (String) a.getAttribute(FontFamily); + else + return "Monospaced"; + } + + public static int getFontSize(AttributeSet a) + { + if (a.isDefined(FontSize)) + return ((Integer)a.getAttribute(FontSize)).intValue(); + else + return 12; + } + + public static Color getForeground(AttributeSet a) + { + if (a.isDefined(Foreground)) + return (Color) a.getAttribute(Foreground); + else + return Color.BLACK; + } + + public static Icon getIcon(AttributeSet a) + { + if (a.isDefined(IconAttribute)) + return (Icon) a.getAttribute(IconAttribute); + else + return (Icon) null; + } + + public static float getLeftIndent(AttributeSet a) + { + if (a.isDefined(LeftIndent)) + return ((Float)a.getAttribute(LeftIndent)).floatValue(); + else + return 0.f; + } + + public static float getLineSpacing(AttributeSet a) + { + if (a.isDefined(LineSpacing)) + return ((Float)a.getAttribute(LineSpacing)).floatValue(); + else + return 0.f; + } + + public static float getRightIndent(AttributeSet a) + { + if (a.isDefined(RightIndent)) + return ((Float)a.getAttribute(RightIndent)).floatValue(); + else + return 0.f; + } + + public static float getSpaceAbove(AttributeSet a) + { + if (a.isDefined(SpaceAbove)) + return ((Float)a.getAttribute(SpaceAbove)).floatValue(); + else + return 0.f; + } + + public static float getSpaceBelow(AttributeSet a) + { + if (a.isDefined(SpaceBelow)) + return ((Float)a.getAttribute(SpaceBelow)).floatValue(); + else + return 0.f; + } + + public static javax.swing.text.TabSet getTabSet(AttributeSet a) + { + if (a.isDefined(StyleConstants.TabSet)) + return (javax.swing.text.TabSet) a.getAttribute(StyleConstants.TabSet); + else + return (javax.swing.text.TabSet) null; + } + + public static boolean isBold(AttributeSet a) + { + if (a.isDefined(Bold)) + return ((Boolean) a.getAttribute(Bold)).booleanValue(); + else + return false; + } + + public static boolean isItalic(AttributeSet a) + { + if (a.isDefined(Italic)) + return ((Boolean) a.getAttribute(Italic)).booleanValue(); + else + return false; + } + + public static boolean isStrikeThrough(AttributeSet a) + { + if (a.isDefined(StrikeThrough)) + return ((Boolean) a.getAttribute(StrikeThrough)).booleanValue(); + else + return false; + } + + public static boolean isSubscript(AttributeSet a) + { + if (a.isDefined(Subscript)) + return ((Boolean) a.getAttribute(Subscript)).booleanValue(); + else + return false; + } + + public static boolean isSuperscript(AttributeSet a) + { + if (a.isDefined(Superscript)) + return ((Boolean) a.getAttribute(Superscript)).booleanValue(); + else + return false; + } + + public static boolean isUnderline(AttributeSet a) + { + if (a.isDefined(Underline)) + return ((Boolean) a.getAttribute(Underline)).booleanValue(); + else + return false; + } + + public static void setAlignment(MutableAttributeSet a, int align) + { + a.addAttribute(Alignment, new Integer(align)); + } + + public static void setBackground(MutableAttributeSet a, Color fg) + { + a.addAttribute(Background, fg); + } + + public static void setBidiLevel(MutableAttributeSet a, int lev) + { + a.addAttribute(BidiLevel, new Integer(lev)); + } + + public static void setBold(MutableAttributeSet a, boolean b) + { + a.addAttribute(Bold, Boolean.valueOf(b)); + } + + public static void setComponent(MutableAttributeSet a, Component c) + { + a.addAttribute(ComponentAttribute, c); + } + + public static void setFirstLineIndent(MutableAttributeSet a, float i) + { + a.addAttribute(FirstLineIndent, new Float(i)); + } + + public static void setFontFamily(MutableAttributeSet a, String fam) + { + a.addAttribute(FontFamily, fam); + } + + public static void setFontSize(MutableAttributeSet a, int s) + { + a.addAttribute(FontSize, new Integer(s)); + } + + public static void setForeground(MutableAttributeSet a, Color fg) + { + a.addAttribute(Foreground, fg); + } + + public static void setIcon(MutableAttributeSet a, Icon c) + { + a.addAttribute(IconAttribute, c); + } + + public static void setItalic(MutableAttributeSet a, boolean b) + { + a.addAttribute(Italic, Boolean.valueOf(b)); + } + + public static void setLeftIndent(MutableAttributeSet a, float i) + { + a.addAttribute(LeftIndent, new Float(i)); + } + + public static void setLineSpacing(MutableAttributeSet a, float i) + { + a.addAttribute(LineSpacing, new Float(i)); + } + + public static void setRightIndent(MutableAttributeSet a, float i) + { + a.addAttribute(RightIndent, new Float(i)); + } + + public static void setSpaceAbove(MutableAttributeSet a, float i) + { + a.addAttribute(SpaceAbove, new Float(i)); + } + + public static void setSpaceBelow(MutableAttributeSet a, float i) + { + a.addAttribute(SpaceBelow, new Float(i)); + } + + public static void setStrikeThrough(MutableAttributeSet a, boolean b) + { + a.addAttribute(StrikeThrough, Boolean.valueOf(b)); + } + + public static void setSubscript(MutableAttributeSet a, boolean b) + { + a.addAttribute(Subscript, Boolean.valueOf(b)); + } + + public static void setSuperscript(MutableAttributeSet a, boolean b) + { + a.addAttribute(Superscript, Boolean.valueOf(b)); + } + + public static void setTabSet(MutableAttributeSet a, javax.swing.text.TabSet tabs) + { + a.addAttribute(StyleConstants.TabSet, tabs); + } + + public static void setUnderline(MutableAttributeSet a, boolean b) + { + a.addAttribute(Underline, Boolean.valueOf(b)); + } + + // The remainder are so-called "typesafe enumerations" which + // alias subsets of the above constants. + public static class CharacterConstants + extends StyleConstants + implements AttributeSet.CharacterAttribute + { + private CharacterConstants(String k) + { + super(k); + } + + public static Object Background = ColorConstants.Background; + public static Object BidiLevel = new CharacterConstants("bidiLevel"); + public static Object Bold = FontConstants.Bold; + public static Object ComponentAttribute = new CharacterConstants("component"); + public static Object Family = FontConstants.Family; + public static Object Size = FontConstants.Size; + public static Object Foreground = ColorConstants.Foreground; + public static Object IconAttribute = new CharacterConstants("icon"); + public static Object Italic = FontConstants.Italic; + public static Object StrikeThrough = new CharacterConstants("strikethrough"); + public static Object Subscript = new CharacterConstants("subscript"); + public static Object Superscript = new CharacterConstants("superscript"); + public static Object Underline = new CharacterConstants("underline"); + } + + public static class ColorConstants + extends StyleConstants + implements AttributeSet.ColorAttribute, AttributeSet.CharacterAttribute + { + private ColorConstants(String k) + { + super(k); + } + public static Object Foreground = new ColorConstants("foreground"); + public static Object Background = new ColorConstants("background"); + } + + public static class FontConstants + extends StyleConstants + implements AttributeSet.FontAttribute, AttributeSet.CharacterAttribute + { + private FontConstants(String k) + { + super(k); + } + public static Object Bold = new FontConstants("bold"); + public static Object Family = new FontConstants("family"); + public static Object Italic = new FontConstants("italic"); + public static Object Size = new FontConstants("size"); + } + + public static class ParagraphConstants + extends StyleConstants + implements AttributeSet.ParagraphAttribute + { + private ParagraphConstants(String k) + { + super(k); + } + public static Object Alignment = new ParagraphConstants("Alignment"); + public static Object FirstLineIndent = new ParagraphConstants("FirstLineIndent"); + public static Object LeftIndent = new ParagraphConstants("LeftIndent"); + public static Object LineSpacing = new ParagraphConstants("LineSpacing"); + public static Object Orientation = new ParagraphConstants("Orientation"); + public static Object RightIndent = new ParagraphConstants("RightIndent"); + public static Object SpaceAbove = new ParagraphConstants("SpaceAbove"); + public static Object SpaceBelow = new ParagraphConstants("SpaceBelow"); + public static Object TabSet = new ParagraphConstants("TabSet"); + } + +} diff --git a/libjava/classpath/javax/swing/text/StyleContext.java b/libjava/classpath/javax/swing/text/StyleContext.java new file mode 100644 index 00000000000..ae11622ffc6 --- /dev/null +++ b/libjava/classpath/javax/swing/text/StyleContext.java @@ -0,0 +1,730 @@ +/* StyleContext.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Toolkit; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Enumeration; +import java.util.EventListener; +import java.util.Hashtable; + +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; + +public class StyleContext + implements Serializable, AbstractDocument.AttributeContext +{ + public class NamedStyle + implements Serializable, Style + { + protected ChangeEvent changeEvent; + protected EventListenerList listenerList; + + AttributeSet attributes; + String name; + + public NamedStyle() + { + this(null, null); + } + + public NamedStyle(Style parent) + { + this(null, parent); + } + + public NamedStyle(String name, Style parent) + { + this.name = name; + this.attributes = getEmptySet(); + this.changeEvent = new ChangeEvent(this); + this.listenerList = new EventListenerList(); + setResolveParent(parent); + } + + public String getName() + { + return name; + } + + public void setName(String n) + { + name = n; + fireStateChanged(); + } + + public void addChangeListener(ChangeListener l) + { + listenerList.add(ChangeListener.class, l); + } + + public void removeChangeListener(ChangeListener l) + { + listenerList.remove(ChangeListener.class, l); + } + + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) getListeners(ChangeListener.class); + } + + protected void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + for (int i = 0; i < listeners.length; ++i) + { + listeners[i].stateChanged(changeEvent); + } + } + + public void addAttribute(Object name, Object value) + { + attributes = StyleContext.this.addAttribute(attributes, name, value); + fireStateChanged(); + } + + public void addAttributes(AttributeSet attr) + { + attributes = StyleContext.this.addAttributes(attributes, attr); + fireStateChanged(); + } + + public boolean containsAttribute(Object name, Object value) + { + return attributes.containsAttribute(name, value); + } + + public boolean containsAttributes(AttributeSet attrs) + { + return attributes.containsAttributes(attrs); + } + + public AttributeSet copyAttributes() + { + return attributes.copyAttributes(); + } + + public Object getAttribute(Object attrName) + { + return attributes.getAttribute(attrName); + } + + public int getAttributeCount() + { + return attributes.getAttributeCount(); + } + + public Enumeration getAttributeNames() + { + return attributes.getAttributeNames(); + } + + public boolean isDefined(Object attrName) + { + return attributes.isDefined(attrName); + } + + public boolean isEqual(AttributeSet attr) + { + return attributes.isEqual(attr); + } + + public void removeAttribute(Object name) + { + attributes = StyleContext.this.removeAttribute(attributes, name); + fireStateChanged(); + } + + public void removeAttributes(AttributeSet attrs) + { + attributes = StyleContext.this.removeAttributes(attributes, attrs); + fireStateChanged(); + } + + public void removeAttributes(Enumeration names) + { + attributes = StyleContext.this.removeAttributes(attributes, names); + fireStateChanged(); + } + + + public AttributeSet getResolveParent() + { + return attributes.getResolveParent(); + } + + public void setResolveParent(AttributeSet parent) + { + if (parent != null) + { + attributes = StyleContext.this.addAttribute + (attributes, ResolveAttribute, parent); + } + fireStateChanged(); + } + + public String toString() + { + return ("[NamedStyle: name=" + name + ", attrs=" + attributes.toString() + "]"); + } + } + + public class SmallAttributeSet + implements AttributeSet + { + final Object [] attrs; + public SmallAttributeSet(AttributeSet a) + { + if (a == null) + attrs = new Object[0]; + else + { + int n = a.getAttributeCount(); + int i = 0; + attrs = new Object[n * 2]; + Enumeration e = a.getAttributeNames(); + while (e.hasMoreElements()) + { + Object name = e.nextElement(); + attrs[i++] = name; + attrs[i++] = a.getAttribute(name); + } + } + } + + public SmallAttributeSet(Object [] a) + { + if (a == null) + attrs = new Object[0]; + else + { + attrs = new Object[a.length]; + System.arraycopy(a, 0, attrs, 0, a.length); + } + } + + public Object clone() + { + return new SmallAttributeSet(this.attrs); + } + + public boolean containsAttribute(Object name, Object value) + { + for (int i = 0; i < attrs.length; i += 2) + { + if (attrs[i].equals(name) && + attrs[i+1].equals(value)) + return true; + } + return false; + } + + public boolean containsAttributes(AttributeSet a) + { + Enumeration e = a.getAttributeNames(); + while (e.hasMoreElements()) + { + Object name = e.nextElement(); + Object val = a.getAttribute(name); + if (!containsAttribute(name, val)) + return false; + } + return true; + } + + public AttributeSet copyAttributes() + { + return (AttributeSet) clone(); + } + + public boolean equals(Object obj) + { + return + (obj instanceof SmallAttributeSet) + && this.isEqual((AttributeSet)obj); + } + + public Object getAttribute(Object key) + { + for (int i = 0; i < attrs.length; i += 2) + { + if (attrs[i].equals(key)) + return attrs[i+1]; + } + + Object p = getResolveParent(); + if (p != null && p instanceof AttributeSet) + return (((AttributeSet)p).getAttribute(key)); + + return null; + } + + public int getAttributeCount() + { + return attrs.length / 2; + } + + public Enumeration getAttributeNames() + { + return new Enumeration() + { + int i = 0; + public boolean hasMoreElements() + { + return i < attrs.length; + } + public Object nextElement() + { + i += 2; + return attrs[i-2]; + } + }; + } + + public AttributeSet getResolveParent() + { + return (AttributeSet) getAttribute(ResolveAttribute); + } + + public int hashCode() + { + return java.util.Arrays.asList(attrs).hashCode(); + } + + public boolean isDefined(Object key) + { + for (int i = 0; i < attrs.length; i += 2) + { + if (attrs[i].equals(key)) + return true; + } + return false; + } + + public boolean isEqual(AttributeSet attr) + { + return attr != null + && attr.containsAttributes(this) + && this.containsAttributes(attr); + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("[StyleContext.SmallattributeSet:"); + for (int i = 0; i < attrs.length; ++i) + { + sb.append(" ("); + sb.append(attrs[i].toString()); + sb.append("="); + sb.append(attrs[i+1].toString()); + sb.append(")"); + } + sb.append("]"); + return sb.toString(); + } + } + + // FIXME: official javadocs suggest that these might be more usefully + // implemented using a WeakHashMap, but not sure if that works most + // places or whether it really matters anyways. + // + // FIXME: also not sure if these tables ought to be static (singletons), + // shared across all StyleContexts. I think so, but it's not clear in + // docs. revert to non-shared if you think it matters. + + /** + * The name of the default style. + */ + public static final String DEFAULT_STYLE = "default"; + + /** + * The default style for this style context. + */ + NamedStyle defaultStyle = new NamedStyle(DEFAULT_STYLE, null); + + static Hashtable sharedAttributeSets = new Hashtable(); + static Hashtable sharedFonts = new Hashtable(); + + static StyleContext defaultStyleContext = new StyleContext(); + static final int compressionThreshold = 9; + + EventListenerList listenerList; + Hashtable styleTable; + + /** + * Creates a new instance of the style context. Add the default style + * to the style table. + */ + public StyleContext() + { + listenerList = new EventListenerList(); + styleTable = new Hashtable(); + styleTable.put(DEFAULT_STYLE, defaultStyle); + } + + protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) + { + return new SmallAttributeSet(a); + } + + protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) + { + return new SimpleAttributeSet(a); + } + + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + public Style addStyle(String name, Style parent) + { + Style newStyle = new NamedStyle(name, parent); + if (name != null) + styleTable.put(name, newStyle); + return newStyle; + } + + public void removeStyle(String name) + { + styleTable.remove(name); + } + + /** + * Get the style from the style table. If the passed name + * matches {@link #DEFAULT_STYLE}, returns the default style. + * Otherwise returns the previously defined style of + * <code>null</code> if the style with the given name is not defined. + * + * @param name the name of the style. + * + * @return the style with the given name or null if no such defined. + */ + public Style getStyle(String name) + { + return (Style) styleTable.get(name); + } + + /** + * Get the names of the style. The returned enumeration always + * contains at least one member, the default style. + */ + public Enumeration getStyleNames() + { + return styleTable.keys(); + } + + // + // StyleContexts only understand the "simple" model of fonts present in + // pre-java2d systems: fonts are a family name, a size (integral number + // of points), and a mask of style parameters (plain, bold, italic, or + // bold|italic). We have an inner class here called SimpleFontSpec which + // holds such triples. + // + // A SimpleFontSpec can be built for *any* AttributeSet because the size, + // family, and style keys in an AttributeSet have default values (defined + // over in StyleConstants). + // + // We keep a static cache mapping SimpleFontSpecs to java.awt.Fonts, so + // that we reuse Fonts between styles and style contexts. + // + + private static class SimpleFontSpec + { + String family; + int style; + int size; + public SimpleFontSpec(String family, + int style, + int size) + { + this.family = family; + this.style = style; + this.size = size; + } + public boolean equals(Object obj) + { + return (obj != null) + && (obj instanceof SimpleFontSpec) + && (((SimpleFontSpec)obj).family.equals(this.family)) + && (((SimpleFontSpec)obj).style == this.style) + && (((SimpleFontSpec)obj).size == this.size); + } + public int hashCode() + { + return family.hashCode() + style + size; + } + } + + public Font getFont(AttributeSet attr) + { + String family = StyleConstants.getFontFamily(attr); + int style = Font.PLAIN; + if (StyleConstants.isBold(attr)) + style += Font.BOLD; + if (StyleConstants.isItalic(attr)) + style += Font.ITALIC; + int size = StyleConstants.getFontSize(attr); + return getFont(family, style, size); + } + + public Font getFont(String family, int style, int size) + { + SimpleFontSpec spec = new SimpleFontSpec(family, style, size); + if (sharedFonts.containsKey(spec)) + return (Font) sharedFonts.get(spec); + else + { + Font tmp = new Font(family, style, size); + sharedFonts.put(spec, tmp); + return tmp; + } + } + + public FontMetrics getFontMetrics(Font f) + { + return Toolkit.getDefaultToolkit().getFontMetrics(f); + } + + public Color getForeground(AttributeSet a) + { + return StyleConstants.getForeground(a); + } + + public Color getBackground(AttributeSet a) + { + return StyleConstants.getBackground(a); + } + + protected int getCompressionThreshold() + { + return compressionThreshold; + } + + public static StyleContext getDefaultStyleContext() + { + return defaultStyleContext; + } + + public AttributeSet addAttribute(AttributeSet old, Object name, Object value) + { + if (old instanceof MutableAttributeSet) + { + ((MutableAttributeSet)old).addAttribute(name, value); + return old; + } + else + { + MutableAttributeSet mutable = createLargeAttributeSet(old); + mutable.addAttribute(name, value); + if (mutable.getAttributeCount() >= getCompressionThreshold()) + return mutable; + else + { + SmallAttributeSet small = createSmallAttributeSet(mutable); + if (sharedAttributeSets.containsKey(small)) + small = (SmallAttributeSet) sharedAttributeSets.get(small); + else + sharedAttributeSets.put(small,small); + return small; + } + } + } + + public AttributeSet addAttributes(AttributeSet old, AttributeSet attributes) + { + if (old instanceof MutableAttributeSet) + { + ((MutableAttributeSet)old).addAttributes(attributes); + return old; + } + else + { + MutableAttributeSet mutable = createLargeAttributeSet(old); + mutable.addAttributes(attributes); + if (mutable.getAttributeCount() >= getCompressionThreshold()) + return mutable; + else + { + SmallAttributeSet small = createSmallAttributeSet(mutable); + if (sharedAttributeSets.containsKey(small)) + small = (SmallAttributeSet) sharedAttributeSets.get(small); + else + sharedAttributeSets.put(small,small); + return small; + } + } + } + + public AttributeSet getEmptySet() + { + AttributeSet e = createSmallAttributeSet(null); + if (sharedAttributeSets.containsKey(e)) + e = (AttributeSet) sharedAttributeSets.get(e); + else + sharedAttributeSets.put(e, e); + return e; + } + + public void reclaim(AttributeSet attributes) + { + if (sharedAttributeSets.containsKey(attributes)) + sharedAttributeSets.remove(attributes); + } + + public AttributeSet removeAttribute(AttributeSet old, Object name) + { + if (old instanceof MutableAttributeSet) + { + ((MutableAttributeSet)old).removeAttribute(name); + if (old.getAttributeCount() < getCompressionThreshold()) + { + SmallAttributeSet small = createSmallAttributeSet(old); + if (!sharedAttributeSets.containsKey(small)) + sharedAttributeSets.put(small,small); + old = (AttributeSet) sharedAttributeSets.get(small); + } + return old; + } + else + { + MutableAttributeSet mutable = createLargeAttributeSet(old); + mutable.removeAttribute(name); + SmallAttributeSet small = createSmallAttributeSet(mutable); + if (sharedAttributeSets.containsKey(small)) + small = (SmallAttributeSet) sharedAttributeSets.get(small); + else + sharedAttributeSets.put(small,small); + return small; + } + } + + public AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes) + { + return removeAttributes(old, attributes.getAttributeNames()); + } + + public AttributeSet removeAttributes(AttributeSet old, Enumeration names) + { + if (old instanceof MutableAttributeSet) + { + ((MutableAttributeSet)old).removeAttributes(names); + if (old.getAttributeCount() < getCompressionThreshold()) + { + SmallAttributeSet small = createSmallAttributeSet(old); + if (!sharedAttributeSets.containsKey(small)) + sharedAttributeSets.put(small,small); + old = (AttributeSet) sharedAttributeSets.get(small); + } + return old; + } + else + { + MutableAttributeSet mutable = createLargeAttributeSet(old); + mutable.removeAttributes(names); + SmallAttributeSet small = createSmallAttributeSet(mutable); + if (sharedAttributeSets.containsKey(small)) + small = (SmallAttributeSet) sharedAttributeSets.get(small); + else + sharedAttributeSets.put(small,small); + return small; + } + } + + + // FIXME: there's some sort of quasi-serialization stuff in here which I + // have left incomplete; I'm not sure I understand the intent properly. + + public static Object getStaticAttribute(Object key) + { + throw new InternalError("not implemented"); + } + + public static Object getStaticAttributeKey(Object key) + { + throw new InternalError("not implemented"); + } + + public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a) + throws ClassNotFoundException, IOException + { + throw new InternalError("not implemented"); + } + + public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a) + throws IOException + { + throw new InternalError("not implemented"); + } + + public void readAttributes(ObjectInputStream in, MutableAttributeSet a) + throws ClassNotFoundException, IOException + { + throw new InternalError("not implemented"); + } + + public void writeAttributes(ObjectOutputStream out, AttributeSet a) + throws IOException + { + throw new InternalError("not implemented"); + } +} diff --git a/libjava/classpath/javax/swing/text/StyledDocument.java b/libjava/classpath/javax/swing/text/StyledDocument.java new file mode 100644 index 00000000000..ea277540f23 --- /dev/null +++ b/libjava/classpath/javax/swing/text/StyledDocument.java @@ -0,0 +1,145 @@ +/* StyledDcoument.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.awt.Color; +import java.awt.Font; + +/** + * StyledDocument + * @author Andrew Selkirk + * @version 1.0 + */ +public interface StyledDocument extends Document { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * addStyle + * @param nm TODO + * @param rent TODO + * @returns Style + */ + Style addStyle(String nm, Style parent); + + /** + * removeStyle + * @param nm TODO + */ + void removeStyle(String nm); + + /** + * getStyle + * @param nm TODO + * @returns Style + */ + Style getStyle(String nm); + + /** + * setCharacterAttributes + * @param offset TODO + * @param length TODO + * @param set TODO + * @param replace TODO + */ + void setCharacterAttributes(int offset, int length, + AttributeSet set, boolean replace); + + /** + * setParagraphAttributes + * @param offset TODO + * @param length TODO + * @param set TODO + * @param replace TODO + */ + void setParagraphAttributes(int offset, int length, + AttributeSet set, boolean replace); + + /** + * getLogicalStyle + * @param position TODO + * @returns Style + */ + Style getLogicalStyle(int position); + + /** + * setLogicalStyle + * @param position TODO + * @param style TODO + */ + void setLogicalStyle(int position, Style style); + + /** + * getParagraphElement + * @param position TODO + * @returns Element + */ + Element getParagraphElement(int position); + + /** + * getCharacterElement + * @param position TODO + * @returns Element + */ + Element getCharacterElement(int position); + + /** + * getForeground + * @param set TODO + * @returns Color + */ + Color getForeground(AttributeSet set); + + /** + * getBackground + * @param set TODO + * @returns Color + */ + Color getBackground(AttributeSet set); + + /** + * getFont + * @param set TODO + * @returns Font + */ + Font getFont(AttributeSet set); + + +} // StyledDocument diff --git a/libjava/classpath/javax/swing/text/StyledEditorKit.java b/libjava/classpath/javax/swing/text/StyledEditorKit.java new file mode 100644 index 00000000000..459f2438679 --- /dev/null +++ b/libjava/classpath/javax/swing/text/StyledEditorKit.java @@ -0,0 +1,503 @@ +/* StyledEditorKit.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Color; +import java.awt.event.ActionEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.Serializable; + +import javax.swing.Action; +import javax.swing.JEditorPane; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; + +/** + * StyledEditorKit + * + * @author Andrew Selkirk + */ +public class StyledEditorKit extends DefaultEditorKit +{ + private static final long serialVersionUID = 7002391892985555948L; + + /** + * UnderlineAction + */ + public static class UnderlineAction extends StyledEditorKit.StyledTextAction + { + /** + * Constructor UnderlineAction + */ + public UnderlineAction() + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * ItalicAction + */ + public static class ItalicAction extends StyledEditorKit.StyledTextAction + { + /** + * Constructor ItalicAction + */ + public ItalicAction() + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * BoldAction + */ + public static class BoldAction extends StyledEditorKit.StyledTextAction + { + /** + * Constructor BoldAction + */ + public BoldAction() + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * AlignmentAction + */ + public static class AlignmentAction extends StyledEditorKit.StyledTextAction + { + /** + * a + */ + private int a; + + /** + * Constructor AlignmentAction + * @param nm TODO + * @param a TODO + */ + public AlignmentAction(String nm, int a) + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * ForegroundAction + */ + public static class ForegroundAction extends StyledEditorKit.StyledTextAction + { + /** + * fg + */ + private Color fg; + + /** + * Constructor ForegroundAction + * @param nm TODO + * @param fg TODO + */ + public ForegroundAction(String nm, Color fg) + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * FontSizeAction + */ + public static class FontSizeAction extends StyledEditorKit.StyledTextAction + { + /** + * size + */ + private int size; + + /** + * Constructor FontSizeAction + * @param nm TODO + * @param size TODO + */ + public FontSizeAction(String nm, int size) + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * FontFamilyAction + */ + public static class FontFamilyAction extends StyledEditorKit.StyledTextAction + { + /** + * family + */ + private String family; + + /** + * Constructor FontFamilyAction + * @param nm TODO + * @param family TODO + */ + public FontFamilyAction(String nm, String family) + { + super("TODO"); + // TODO + } + + /** + * actionPerformed + * @param event TODO + */ + public void actionPerformed(ActionEvent event) + { + // TODO + } + } + + /** + * StyledTextAction + */ + public abstract static class StyledTextAction extends TextAction + { + /** + * Constructor StyledTextAction + * @param nm TODO + */ + public StyledTextAction(String nm) + { + super(nm); + // TODO + } + + /** + * getEditor + * @param event TODO + * @returns JEditorPane + */ + protected final JEditorPane getEditor(ActionEvent event) + { + return null; // TODO + } + + /** + * setCharacterAttributes + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + protected final void setCharacterAttributes(JEditorPane value0, + AttributeSet value1, + boolean value2) + { + // TODO + } + + /** + * getStyledDocument + * @param value0 TODO + * @returns StyledDocument + */ + protected final StyledDocument getStyledDocument(JEditorPane value0) + { + return null; // TODO + } + + /** + * getStyledEditorKit + * @param value0 TODO + * @returns StyledEditorKit + */ + protected final StyledEditorKit getStyledEditorKit(JEditorPane value0) + { + return null; // TODO + } + + /** + * setParagraphAttributes + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + protected final void setParagraphAttributes(JEditorPane value0, + AttributeSet value1, + boolean value2) + { + // TODO + } + } + + /** + * StyledViewFactory + */ + static class StyledViewFactory + implements ViewFactory + { + /** + * Constructor StyledViewFactory + */ + StyledViewFactory() + { + // TODO + } + + /** + * create + * @param value0 TODO + * @returns View + */ + public View create(Element value0) + { + return null; // TODO + } + } + + /** + * AttributeTracker + */ + class AttributeTracker + implements CaretListener, PropertyChangeListener, Serializable + { + /** + * Constructor AttributeTracker + * @param value0 TODO + */ + AttributeTracker(StyledEditorKit value0) + { + // TODO + } + + /** + * updateInputAttributes + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + void updateInputAttributes(int value0, int value1, JTextComponent value2) + { + // TODO + } + + /** + * propertyChange + * @param value0 TODO + */ + public void propertyChange(PropertyChangeEvent value0) + { + // TODO + } + + /** + * caretUpdate + * @param value0 TODO + */ + public void caretUpdate(CaretEvent value0) + { + // TODO + } + } + + /** + * currentRun + */ + Element currentRun; + + /** + * currentParagraph + */ + Element currentParagraph; + + /** + * inputAttributes + */ + MutableAttributeSet inputAttributes; + + /** + * Constructor StyledEditorKit + */ + public StyledEditorKit() + { + // TODO + } + + /** + * clone + * @returns Object + */ + public Object clone() + { + return null; // TODO + } + + /** + * getActions + * @returns Action[] + */ + public Action[] getActions() + { + return null; // TODO + } + + /** + * getInputAttributes + * @returns MutableAttributeSet + */ + public MutableAttributeSet getInputAttributes() + { + return null; // TODO + } + + /** + * getCharacterAttributeRun + * @returns Element + */ + public Element getCharacterAttributeRun() + { + return null; // TODO + } + + /** + * createDefaultDocument + * @returns Document + */ + public Document createDefaultDocument() + { + return null; // TODO + } + + /** + * install + * @param component TODO + */ + public void install(JEditorPane component) + { + // TODO + } + + /** + * deinstall + * @param component TODO + */ + public void deinstall(JEditorPane component) + { + // TODO + } + + /** + * getViewFactory + * @returns ViewFactory + */ + public ViewFactory getViewFactory() + { + return null; // TODO + } + + /** + * createInputAttributes + * @param element TODO + * @param set TODO + */ + protected void createInputAttributes(Element element, MutableAttributeSet set) + { + // TODO + } +} diff --git a/libjava/classpath/javax/swing/text/TabExpander.java b/libjava/classpath/javax/swing/text/TabExpander.java new file mode 100644 index 00000000000..d70dd4604e5 --- /dev/null +++ b/libjava/classpath/javax/swing/text/TabExpander.java @@ -0,0 +1,43 @@ +/* TabExpander.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +public interface TabExpander +{ + float nextTabStop(float x, int tabOffset); +}
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/text/TabSet.java b/libjava/classpath/javax/swing/text/TabSet.java new file mode 100644 index 00000000000..146f545aac7 --- /dev/null +++ b/libjava/classpath/javax/swing/text/TabSet.java @@ -0,0 +1,102 @@ +/* TabSet.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.io.Serializable; + +public class TabSet implements Serializable +{ + TabStop[] tabs; + + public TabSet(TabStop[] t) + { + tabs = t; + } + + public TabStop getTab(int i) + { + return tabs[i]; + } + + public TabStop getTabAfter(float location) + { + int idx = getTabIndexAfter(location); + if (idx == -1) + return null; + else + return tabs[idx]; + } + + public int getTabCount() + { + return tabs.length; + } + + public int getTabIndex(TabStop tab) + { + for (int i = 0; i < tabs.length; ++i) + if (tabs[i] == tab) + return i; + return -1; + } + + public int getTabIndexAfter(float location) + { + int idx = -1; + for (int i = 0; i < tabs.length; ++i) + { + if (location < tabs[i].getPosition()) + idx = i; + } + return idx; + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("["); + for (int i = 0; i < tabs.length; ++i) + { + if (i != 0) + sb.append(" - "); + sb.append(tabs[i].toString()); + } + sb.append("]"); + return sb.toString(); + } +} diff --git a/libjava/classpath/javax/swing/text/TabStop.java b/libjava/classpath/javax/swing/text/TabStop.java new file mode 100644 index 00000000000..032da8bca46 --- /dev/null +++ b/libjava/classpath/javax/swing/text/TabStop.java @@ -0,0 +1,133 @@ +/* TabSet.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +import java.io.Serializable; + +public class TabStop implements Serializable +{ + public static final int ALIGN_LEFT = 0; + public static final int ALIGN_RIGHT = 1; + public static final int ALIGN_CENTER = 2; + public static final int ALIGN_DECIMAL = 4; + public static final int ALIGN_BAR = 5; + + public static final int LEAD_NONE = 0; + public static final int LEAD_DOTS = 1; + public static final int LEAD_HYPHENS = 2; + public static final int LEAD_UNDERLINE = 3; + public static final int LEAD_THICKLINE = 4; + public static final int LEAD_EQUALS = 5; + + float pos; + int align; + int leader; + + public TabStop(float pos) + { + this(pos, ALIGN_LEFT, LEAD_NONE); + } + + public TabStop(float pos, int align, int leader) + { + this.pos = pos; + this.align = align; + this.leader = leader; + } + + public boolean equals(Object other) + { + return (other != null) + && (other instanceof TabStop) + && (((TabStop)other).getPosition() == this.getPosition()) + && (((TabStop)other).getLeader() == this.getLeader()) + && (((TabStop)other).getAlignment() == this.getAlignment()); + } + + public int getAlignment() + { + return align; + } + + public int getLeader() + { + return leader; + } + + public float getPosition() + { + return pos; + } + + public int hashCode() + { + return (int) pos + (int) leader + (int) align; + } + + public String toString() + { + String prefix = ""; + switch (align) + { + case ALIGN_LEFT: + prefix = "left "; + break; + case ALIGN_RIGHT: + prefix = "right "; + break; + + case ALIGN_CENTER: + prefix = "center "; + break; + + case ALIGN_DECIMAL: + prefix = "decimal "; + break; + + case ALIGN_BAR: + prefix = "bar "; + break; + + default: + break; + } + + return (prefix + "tab @" + pos + ((leader == LEAD_NONE) ? "" : "(w/leaders)")); + } + +} diff --git a/libjava/classpath/javax/swing/text/TabableView.java b/libjava/classpath/javax/swing/text/TabableView.java new file mode 100644 index 00000000000..2a96ea94d81 --- /dev/null +++ b/libjava/classpath/javax/swing/text/TabableView.java @@ -0,0 +1,44 @@ +/* TabableView.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +public interface TabableView +{ + float getPartialSpan(int p0, int p1); + float getTabbedSpan(float x, TabExpander expander); +} diff --git a/libjava/classpath/javax/swing/text/TextAction.java b/libjava/classpath/javax/swing/text/TextAction.java new file mode 100644 index 00000000000..8588e3cd202 --- /dev/null +++ b/libjava/classpath/javax/swing/text/TextAction.java @@ -0,0 +1,111 @@ +/* TextAction.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.HashSet; + +import javax.swing.AbstractAction; +import javax.swing.Action; + +/** + * TextAction + * @author Andrew Selkirk + */ +public abstract class TextAction extends AbstractAction +{ + /** + * Constructor TextAction + * @param name TODO + */ + public TextAction(String name) + { + super(name); + } + + /** + * Returns the <code>JTextComponent</code> object associated with the given + * <code>ActionEvent</code>. If the source of the event is not a + * <code>JTextComponent</code> the currently focused text component is returned. + * + * @param event the action event + * + * @return the <code>JTextComponent</code> + */ + protected final JTextComponent getTextComponent(ActionEvent event) + { + if (event.getSource() instanceof JTextComponent) + return (JTextComponent) event.getSource(); + + return getFocusedComponent(); + } + + /** + * Creates a new array of <code>Action</code> containing both given arrays. + * + * @param list1 the first action array + * @param list2 the second action array + * + * @return the augmented array of actions + */ + public static final Action[] augmentList(Action[] list1, Action[] list2) + { + HashSet actionSet = new HashSet(); + + for (int i = 0; i < list1.length; ++i) + actionSet.add(list1[i]); + + for (int i = 0; i < list2.length; ++i) + actionSet.add(list2[i]); + + ArrayList list = new ArrayList(actionSet); + return (Action[]) list.toArray(new Action[actionSet.size()]); + } + + /** + * Returns the current focused <code>JTextComponent</code> object. + * + * @return the <code>JTextComponent</code> + */ + protected final JTextComponent getFocusedComponent() + { + return null; // TODO + } +} diff --git a/libjava/classpath/javax/swing/text/Utilities.java b/libjava/classpath/javax/swing/text/Utilities.java new file mode 100644 index 00000000000..d40408ddc3f --- /dev/null +++ b/libjava/classpath/javax/swing/text/Utilities.java @@ -0,0 +1,198 @@ +/* Utilities.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.FontMetrics; +import java.awt.Graphics; + +/** + * A set of utilities to deal with text. This is used by several other classes + * inside this package. + * + * @author Roman Kennke (roman@ontographics.com) + */ +public class Utilities +{ + /** + * The length of the char buffer that holds the characters to be drawn. + */ + private static final int BUF_LENGTH = 64; + + /** + * Creates a new <code>Utilities</code> object. + */ + public Utilities() + { + // Nothing to be done here. + } + + /** + * Draws the given text segment. Contained tabs and newline characters + * are taken into account. Tabs are expanded using the + * specified {@link TabExpander}. + * + * @param s the text fragment to be drawn. + * @param x the x position for drawing. + * @param y the y position for drawing. + * @param g the {@link Graphics} context for drawing. + * @param e the {@link TabExpander} which specifies the Tab-expanding + * technique. + * @param startOffset starting offset in the text. + * @return the x coordinate at the end of the drawn text. + */ + public static final int drawTabbedText(Segment s, int x, int y, Graphics g, + TabExpander e, int startOffset) + { + // This buffers the chars to be drawn. + char[] buffer = s.array; + + + // The current x and y pixel coordinates. + int pixelX = x; + int pixelY = y; + + // The font metrics of the current selected font. + FontMetrics metrics = g.getFontMetrics(); + int ascent = metrics.getAscent(); + + int pixelWidth = 0; + int pos = s.offset; + int len = 0; + + for (int offset = s.offset; offset < (s.offset + s.count); ++offset) + { + char c = buffer[offset]; + if (c == '\t' || c == '\n') + { + if (len > 0) { + g.drawChars(buffer, pos, len, pixelX, pixelY + ascent); + pixelX += pixelWidth; + pixelWidth = 0; + } + pos = offset+1; + len = 0; + } + + switch (c) + { + case '\t': + // In case we have a tab, we just 'jump' over the tab. + // When we have no tab expander we just use the width of ' '. + if (e != null) + pixelX = (int) e.nextTabStop((float) pixelX, + startOffset + offset - s.offset); + else + pixelX += metrics.charWidth(' '); + break; + case '\n': + // In case we have a newline, we must jump to the next line. + pixelY += metrics.getHeight(); + pixelX = x; + break; + default: + ++len; + pixelWidth += metrics.charWidth(buffer[offset]); + break; + } + } + + if (len > 0) + g.drawChars(buffer, pos, len, pixelX, pixelY + ascent); + + return pixelX; + } + + /** + * Determines the width, that the given text <code>s</code> would take + * if it was printed with the given {@link java.awt.FontMetrics} on the + * specified screen position. + * @param s the text fragment + * @param metrics the font metrics of the font to be used + * @param x the x coordinate of the point at which drawing should be done + * @param e the {@link TabExpander} to be used + * @param startOffset the index in <code>s</code> where to start + * @returns the width of the given text s. This takes tabs and newlines + * into account. + */ + public static final int getTabbedTextWidth(Segment s, FontMetrics metrics, + int x, TabExpander e, + int startOffset) + { + // This buffers the chars to be drawn. + char[] buffer = s.array; + + // The current x coordinate. + int pixelX = x; + + // The current maximum width. + int maxWidth = 0; + + for (int offset = s.offset; offset < (s.offset + s.count); ++offset) + { + switch (buffer[offset]) + { + case '\t': + // In case we have a tab, we just 'jump' over the tab. + // When we have no tab expander we just use the width of 'm'. + if (e != null) + pixelX = (int) e.nextTabStop((float) pixelX, + startOffset + offset - s.offset); + else + pixelX += metrics.charWidth(' '); + break; + case '\n': + // In case we have a newline, we must 'draw' + // the buffer and jump on the next line. + pixelX += metrics.charWidth(buffer[offset]); + maxWidth = Math.max(maxWidth, pixelX - x); + pixelX = x; + break; + default: + // Here we draw the char. + pixelX += metrics.charWidth(buffer[offset]); + break; + } + } + + // Take the last line into account. + maxWidth = Math.max(maxWidth, pixelX - x); + + return maxWidth; + } +} diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java new file mode 100644 index 00000000000..4d9ed7b3122 --- /dev/null +++ b/libjava/classpath/javax/swing/text/View.java @@ -0,0 +1,463 @@ +/* View.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text; + +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.JComponent; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; + +public abstract class View implements SwingConstants +{ + public static final int BadBreakWeight = 0; + public static final int ExcellentBreakWeight = 2000; + public static final int ForcedBreakWeight = 3000; + public static final int GoodBreakWeight = 1000; + + public static final int X_AXIS = 0; + public static final int Y_AXIS = 1; + + private float width, height; + private Element elt; + private View parent; + + /** + * The child views. + */ + View[] children; + + /** + * Creates a new <code>View</code> instance. + * + * @param elem an <code>Element</code> value + */ + public View(Element elem) + { + elt = elem; + children = new View[0]; + } + + public abstract void paint(Graphics g, Shape s); + + public void setParent(View parent) + { + this.parent = parent; + } + + public View getParent() + { + return parent; + } + + public Container getContainer() + { + View parent = getParent(); + return parent != null ? parent.getContainer() : null; + } + + public Document getDocument() + { + return getElement().getDocument(); + } + + public Element getElement() + { + return elt; + } + + public abstract float getPreferredSpan(int axis); + + public int getResizeWeight(int axis) + { + return 0; + } + + public float getMaximumSpan(int axis) + { + if (getResizeWeight(axis) <= 0) + return getPreferredSpan(axis); + + return Integer.MAX_VALUE; + } + + public float getMinimumSpan(int axis) + { + if (getResizeWeight(axis) <= 0) + return getPreferredSpan(axis); + + return Integer.MAX_VALUE; + } + + public void setSize(float width, float height) + { + // The default implementation does nothing. + } + + public float getAlignment(int axis) + { + return 0.5f; + } + + public AttributeSet getAttributes() + { + return getElement().getAttributes(); + } + + public boolean isVisible() + { + return true; + } + + public int getViewCount() + { + return 0; + } + + public View getView(int index) + { + return null; + } + + public ViewFactory getViewFactory() + { + View parent = getParent(); + return parent != null ? parent.getViewFactory() : null; + } + + public void replace(int offset, int length, View[] views) + { + // Default implementation does nothing. + } + + public void insert(int offset, View view) + { + View[] array = { view }; + replace(offset, 1, array); + } + + public void append(View view) + { + View[] array = { view }; + replace(getViewCount(), 1, array); + } + + public void removeAll() + { + replace(0, getViewCount(), null); + } + + public void remove(int index) + { + replace(index, 1, null); + } + + public View createFragment(int p0, int p1) + { + // The default implementation doesn't support fragmentation. + return this; + } + + public int getStartOffset() + { + return getElement().getStartOffset(); + } + + public int getEndOffset() + { + return getElement().getEndOffset(); + } + + public Shape getChildAllocation(int index, Shape a) + { + return null; + } + + /** + * @since 1.4 + */ + public int getViewIndex(float x, float y, Shape allocation) + { + return -1; + } + + /** + * @since 1.4 + */ + public String getToolTipText(float x, float y, Shape allocation) + { + int index = getViewIndex(x, y, allocation); + + if (index < -1) + return null; + + Shape childAllocation = getChildAllocation(index, allocation); + + if (childAllocation.getBounds().contains(x, y)) + return getView(index).getToolTipText(x, y, childAllocation); + + return null; + } + + /** + * @since 1.3 + */ + public Graphics getGraphics() + { + return getContainer().getGraphics(); + } + + public void preferenceChanged(View child, boolean width, boolean height) + { + if (parent != null) + parent.preferenceChanged(this, width, height); + else + ((JComponent) getContainer()).revalidate(); + } + + public int getBreakWeight(int axis, float pos, float len) + { + return BadBreakWeight; + } + + public View breakView(int axis, int offset, float pos, float len) + { + return this; + } + + /** + * @since 1.3 + */ + public int getViewIndex(int pos, Position.Bias b) + { + return -1; + } + + /** + * Receive notification about an insert update to the text model. + * + * The default implementation of this method does the following: + * <ul> + * <li>Call {@link #updateChildren} if the element that this view is + * responsible for has changed. This makes sure that the children can + * correctly represent the model.<li> + * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to + * the child views.<li> + * <li>Call {@link #updateLayout}. Gives the view a chance to either + * repair its layout, reschedule layout or do nothing at all.</li> + * </ul> + * + * @param ev the DocumentEvent that describes the change + * @param shape the shape of the view + * @param vf the ViewFactory for creating child views + */ + public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + Element el = getElement(); + DocumentEvent.ElementChange ec = ev.getChange(el); + if (ec != null) + updateChildren(ec, ev, vf); + forwardUpdate(ec, ev, shape, vf); + updateLayout(ec, ev, shape); + } + + /** + * Receive notification about a remove update to the text model. + * + * The default implementation of this method does the following: + * <ul> + * <li>Call {@link #updateChildren} if the element that this view is + * responsible for has changed. This makes sure that the children can + * correctly represent the model.<li> + * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to + * the child views.<li> + * <li>Call {@link #updateLayout}. Gives the view a chance to either + * repair its layout, reschedule layout or do nothing at all.</li> + * </ul> + * + * @param ev the DocumentEvent that describes the change + * @param shape the shape of the view + * @param vf the ViewFactory for creating child views + */ + public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + Element el = getElement(); + DocumentEvent.ElementChange ec = ev.getChange(el); + if (ec != null) + updateChildren(ec, ev, vf); + forwardUpdate(ec, ev, shape, vf); + updateLayout(ec, ev, shape); + } + + /** + * Receive notification about a change update to the text model. + * + * The default implementation of this method does the following: + * <ul> + * <li>Call {@link #updateChildren} if the element that this view is + * responsible for has changed. This makes sure that the children can + * correctly represent the model.<li> + * <li>Call {@link #forwardUpdate}. This forwards the DocumentEvent to + * the child views.<li> + * <li>Call {@link #updateLayout}. Gives the view a chance to either + * repair its layout, reschedule layout or do nothing at all.</li> + * </ul> + * + * @param ev the DocumentEvent that describes the change + * @param shape the shape of the view + * @param vf the ViewFactory for creating child views + */ + public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + Element el = getElement(); + DocumentEvent.ElementChange ec = ev.getChange(el); + if (ec != null) + updateChildren(ec, ev, vf); + forwardUpdate(ec, ev, shape, vf); + updateLayout(ec, ev, shape); + } + + /** + * Updates the list of children that is returned by {@link #getView} + * and {@link #getViewCount}. + * + * Element that are specified as beeing added in the ElementChange record are + * assigned a view for using the ViewFactory. Views of Elements that + * are specified as beeing removed are removed from the list. + * + * @param ec the ElementChange record that describes the change of the + * element + * @param ev the DocumentEvent describing the change of the document model + * @param vf the ViewFactory to use for creating new views + * + * @return whether or not the child views represent the child elements of + * the element that this view is responsible for. Some views may + * create views that are responsible only for parts of the element + * that they are responsible for and should then return false. + * + * @since 1.3 + */ + protected boolean updateChildren(DocumentEvent.ElementChange ec, + DocumentEvent ev, + ViewFactory vf) + { + Element[] added = ec.getChildrenAdded(); + Element[] removed = ec.getChildrenRemoved(); + View[] newChildren = new View[children.length + added.length + - removed.length]; + int index = ec.getIndex(); + System.arraycopy(children, 0, newChildren, 0, index); + System.arraycopy(children, index, added, 0, added.length); + int index2 = index + removed.length; + int len2 = children.length - index2; + System.arraycopy(children, index2, newChildren, index + added.length, + len2); + children = newChildren; + + return true; + } + + /** + * Forwards the DocumentEvent to child views that need to get notified + * of the change to the model. This calles {@link #forwardUpdateToView} + * for each View that must be forwarded to. + * + * @param ec the ElementChange describing the element changes (may be + * <code>null</code> if there were no changes) + * @param ev the DocumentEvent describing the changes to the model + * @param shape the current allocation of the view + * @param vf the ViewFactory used to create new Views + * + * @since 1.3 + */ + protected void forwardUpdate(DocumentEvent.ElementChange ec, + DocumentEvent ev, Shape shape, ViewFactory vf) + { + for (int i = 0; i < children.length; i++) + { + View child = children[i]; + forwardUpdateToView(child, ev, shape, vf); + } + } + + /** + * Forwards an update event to the given child view. This calls + * {@link #insertUpdate}, {@link #removeUpdate} or {@link #changedUpdate}, + * depending on the type of document event. + * + * @param view the View to forward the event to + * @param ev the DocumentEvent to forward + * @param shape the current allocation of the View + * @param vf the ViewFactory used to create new Views + * + * @since 1.3 + */ + protected void forwardUpdateToView(View view, DocumentEvent ev, Shape shape, + ViewFactory vf) + { + DocumentEvent.EventType type = ev.getType(); + if (type == DocumentEvent.EventType.INSERT) + view.insertUpdate(ev, shape, vf); + else if (type == DocumentEvent.EventType.REMOVE) + view.removeUpdate(ev, shape, vf); + else if (type == DocumentEvent.EventType.CHANGE) + view.changedUpdate(ev, shape, vf); + } + + /** + * Updates the layout. + * + * @param ec the ElementChange that describes the changes to the element + * @param ev the DocumentEvent that describes the changes to the model + * @param shape the current allocation for this view + * + * @since 1.3 + */ + protected void updateLayout(DocumentEvent.ElementChange ec, + DocumentEvent ev, Shape shape) + { + Rectangle b = shape.getBounds(); + if (ec != null) + preferenceChanged(this, true, true); + } +} + diff --git a/libjava/classpath/javax/swing/text/ViewFactory.java b/libjava/classpath/javax/swing/text/ViewFactory.java new file mode 100644 index 00000000000..079488017b6 --- /dev/null +++ b/libjava/classpath/javax/swing/text/ViewFactory.java @@ -0,0 +1,50 @@ +/* ViewFactory.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text; + +public interface ViewFactory +{ + /** + * Creates a view for a given element. + * + * @param elem them element to create view for + * + * @return a new created view + */ + View create(Element elem); +} diff --git a/libjava/classpath/javax/swing/text/html/HTML.java b/libjava/classpath/javax/swing/text/html/HTML.java new file mode 100644 index 00000000000..3c03a63a471 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/HTML.java @@ -0,0 +1,1309 @@ +/* HTML.java -- HTML document tag constants + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.io.Serializable; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import java.util.Map; +import java.util.TreeMap; + +import javax.swing.text.AttributeSet; + +/** + * HTML attribute and tag definitions. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class HTML +{ + /** + * Represents a HTML attribute. + */ + public static class Attribute + implements Serializable + { + /** + * The action attribute + */ + public static final Attribute ACTION = new Attribute("action"); + + /** + * The align attribute + */ + public static final Attribute ALIGN = new Attribute("align"); + + /** + * The alink attribute + */ + public static final Attribute ALINK = new Attribute("alink"); + + /** + * The alt attribute + */ + public static final Attribute ALT = new Attribute("alt"); + + /** + * The archive attribute + */ + public static final Attribute ARCHIVE = new Attribute("archive"); + + /** + * The background attribute + */ + public static final Attribute BACKGROUND = new Attribute("background"); + + /** + * The bgcolor attribute + */ + public static final Attribute BGCOLOR = new Attribute("bgcolor"); + + /** + * The border attribute + */ + public static final Attribute BORDER = new Attribute("border"); + + /** + * The cellpadding attribute + */ + public static final Attribute CELLPADDING = new Attribute("cellpadding"); + + /** + * The cellspacing attribute + */ + public static final Attribute CELLSPACING = new Attribute("cellspacing"); + + /** + * The checked attribute + */ + public static final Attribute CHECKED = new Attribute("checked"); + + /** + * The class attribute + */ + public static final Attribute CLASS = new Attribute("class"); + + /** + * The classid attribute + */ + public static final Attribute CLASSID = new Attribute("classid"); + + /** + * The clear attribute + */ + public static final Attribute CLEAR = new Attribute("clear"); + + /** + * The code attribute + */ + public static final Attribute CODE = new Attribute("code"); + + /** + * The codebase attribute + */ + public static final Attribute CODEBASE = new Attribute("codebase"); + + /** + * The codetype attribute + */ + public static final Attribute CODETYPE = new Attribute("codetype"); + + /** + * The color attribute + */ + public static final Attribute COLOR = new Attribute("color"); + + /** + * The cols attribute + */ + public static final Attribute COLS = new Attribute("cols"); + + /** + * The colspan attribute + */ + public static final Attribute COLSPAN = new Attribute("colspan"); + + /** + * The comment attribute + */ + public static final Attribute COMMENT = new Attribute("comment"); + + /** + * The compact attribute + */ + public static final Attribute COMPACT = new Attribute("compact"); + + /** + * The content attribute + */ + public static final Attribute CONTENT = new Attribute("content"); + + /** + * The coords attribute + */ + public static final Attribute COORDS = new Attribute("coords"); + + /** + * The data attribute + */ + public static final Attribute DATA = new Attribute("data"); + + /** + * The declare attribute + */ + public static final Attribute DECLARE = new Attribute("declare"); + + /** + * The dir attribute + */ + public static final Attribute DIR = new Attribute("dir"); + + /** + * The dummy attribute + */ + public static final Attribute DUMMY = new Attribute("dummy"); + + /** + * The enctype attribute + */ + public static final Attribute ENCTYPE = new Attribute("enctype"); + + /** + * The endtag attribute + */ + public static final Attribute ENDTAG = new Attribute("endtag"); + + /** + * The face attribute + */ + public static final Attribute FACE = new Attribute("face"); + + /** + * The frameborder attribute + */ + public static final Attribute FRAMEBORDER = new Attribute("frameborder"); + + /** + * The halign attribute + */ + public static final Attribute HALIGN = new Attribute("halign"); + + /** + * The height attribute + */ + public static final Attribute HEIGHT = new Attribute("height"); + + /** + * The href attribute + */ + public static final Attribute HREF = new Attribute("href"); + + /** + * The hspace attribute + */ + public static final Attribute HSPACE = new Attribute("hspace"); + + /** + * The http-equiv attribute + */ + public static final Attribute HTTPEQUIV = new Attribute("http-equiv"); + + /** + * The id attribute + */ + public static final Attribute ID = new Attribute("id"); + + /** + * The ismap attribute + */ + public static final Attribute ISMAP = new Attribute("ismap"); + + /** + * The lang attribute + */ + public static final Attribute LANG = new Attribute("lang"); + + /** + * The language attribute + */ + public static final Attribute LANGUAGE = new Attribute("language"); + + /** + * The link attribute + */ + public static final Attribute LINK = new Attribute("link"); + + /** + * The lowsrc attribute + */ + public static final Attribute LOWSRC = new Attribute("lowsrc"); + + /** + * The marginheight attribute + */ + public static final Attribute MARGINHEIGHT = new Attribute("marginheight"); + + /** + * The marginwidth attribute + */ + public static final Attribute MARGINWIDTH = new Attribute("marginwidth"); + + /** + * The maxlength attribute + */ + public static final Attribute MAXLENGTH = new Attribute("maxlength"); + + /** + * The media attribute + */ + public static final Attribute MEDIA = new Attribute("media"); + + /** + * The method attribute + */ + public static final Attribute METHOD = new Attribute("method"); + + /** + * The multiple attribute + */ + public static final Attribute MULTIPLE = new Attribute("multiple"); + + /** + * The n attribute + */ + public static final Attribute N = new Attribute("n"); + + /** + * The name attribute + */ + public static final Attribute NAME = new Attribute("name"); + + /** + * The nohref attribute + */ + public static final Attribute NOHREF = new Attribute("nohref"); + + /** + * The noresize attribute + */ + public static final Attribute NORESIZE = new Attribute("noresize"); + + /** + * The noshade attribute + */ + public static final Attribute NOSHADE = new Attribute("noshade"); + + /** + * The nowrap attribute + */ + public static final Attribute NOWRAP = new Attribute("nowrap"); + + /** + * The prompt attribute + */ + public static final Attribute PROMPT = new Attribute("prompt"); + + /** + * The rel attribute + */ + public static final Attribute REL = new Attribute("rel"); + + /** + * The rev attribute + */ + public static final Attribute REV = new Attribute("rev"); + + /** + * The rows attribute + */ + public static final Attribute ROWS = new Attribute("rows"); + + /** + * The rowspan attribute + */ + public static final Attribute ROWSPAN = new Attribute("rowspan"); + + /** + * The scrolling attribute + */ + public static final Attribute SCROLLING = new Attribute("scrolling"); + + /** + * The selected attribute + */ + public static final Attribute SELECTED = new Attribute("selected"); + + /** + * The shape attribute + */ + public static final Attribute SHAPE = new Attribute("shape"); + + /** + * The shapes attribute + */ + public static final Attribute SHAPES = new Attribute("shapes"); + + /** + * The size attribute + */ + public static final Attribute SIZE = new Attribute("size"); + + /** + * The src attribute + */ + public static final Attribute SRC = new Attribute("src"); + + /** + * The standby attribute + */ + public static final Attribute STANDBY = new Attribute("standby"); + + /** + * The start attribute + */ + public static final Attribute START = new Attribute("start"); + + /** + * The style attribute + */ + public static final Attribute STYLE = new Attribute("style"); + + /** + * The target attribute + */ + public static final Attribute TARGET = new Attribute("target"); + + /** + * The text attribute + */ + public static final Attribute TEXT = new Attribute("text"); + + /** + * The title attribute + */ + public static final Attribute TITLE = new Attribute("title"); + + /** + * The type attribute + */ + public static final Attribute TYPE = new Attribute("type"); + + /** + * The usemap attribute + */ + public static final Attribute USEMAP = new Attribute("usemap"); + + /** + * The valign attribute + */ + public static final Attribute VALIGN = new Attribute("valign"); + + /** + * The value attribute + */ + public static final Attribute VALUE = new Attribute("value"); + + /** + * The valuetype attribute + */ + public static final Attribute VALUETYPE = new Attribute("valuetype"); + + /** + * The version attribute + */ + public static final Attribute VERSION = new Attribute("version"); + + /** + * The vlink attribute + */ + public static final Attribute VLINK = new Attribute("vlink"); + + /** + * The vspace attribute + */ + public static final Attribute VSPACE = new Attribute("vspace"); + + /** + * The width attribute + */ + public static final Attribute WIDTH = new Attribute("width"); + private final String name; + + /** + * Creates the attribute with the given name. + */ + protected Attribute(String a_name) + { + name = a_name; + } + + /** + * Calls compareTo on the tag names (Strings) + */ + public int compareTo(Object other) + { + return name.compareTo(((Attribute) other).name); + } + + /** + * The attributes are equal if the names are equal + * (ignoring case) + */ + public boolean equals(Object other) + { + if (other == this) + return true; + + if (!(other instanceof Attribute)) + return false; + + Attribute that = (Attribute) other; + + return that.name.equalsIgnoreCase(name); + } + + /** + * Returns the hash code which corresponds to the string for this tag. + */ + public int hashCode() + { + return name == null ? 0 : name.hashCode(); + } + + /** + * Returns the attribute name. The names of the built-in attributes + * are always returned in lowercase. + */ + public String toString() + { + return name; + } + + /** + * Return an array of all attributes, declared in the HTML.Attribute + * class. WARNING: attributes are the only public fields, + * expected in this class. + */ + static Attribute[] getAllAttributes() + { + Field[] f = Attribute.class.getFields(); + Attribute[] attrs = new Attribute[ f.length ]; + Field x; + int p = 0; + Attribute a; + + for (int i = 0; i < f.length; i++) + { + x = f [ i ]; + + if ((x.getModifiers() & Modifier.STATIC) != 0) + { + if (x.getType().equals(Attribute.class)) + { + try + { + a = (Attribute) x.get(null); + attrs [ p++ ] = a; + } + catch (Exception ex) + { + ex.printStackTrace(System.err); + throw new Error("This should never happen, report a bug"); + } + } + } + } + + return attrs; + } + } + + /** + * Represents a HTML tag. + */ + public static class Tag + implements Comparable, Serializable + { + /** + * The <a> tag + */ + public static final Tag A = new Tag("a"); + + /** + * The <address> tag + */ + public static final Tag ADDRESS = new Tag("address"); + + /** + * The <applet> tag + */ + public static final Tag APPLET = new Tag("applet"); + + /** + * The <area> tag + */ + public static final Tag AREA = new Tag("area"); + + /** + * The <b> tag + */ + public static final Tag B = new Tag("b"); + + /** + * The <base> tag + */ + public static final Tag BASE = new Tag("base"); + + /** + * The <basefont> tag + */ + public static final Tag BASEFONT = new Tag("basefont"); + + /** + * The <big> tag + */ + public static final Tag BIG = new Tag("big"); + + /** + * The <blockquote> tag , breaks flow, block tag. + */ + public static final Tag BLOCKQUOTE = new Tag("blockquote", BREAKS | BLOCK); + + /** + * The <body> tag , breaks flow, block tag. + */ + public static final Tag BODY = new Tag("body", BREAKS | BLOCK); + + /** + * The <br> tag , breaks flow. + */ + public static final Tag BR = new Tag("br", BREAKS); + + /** + * The <caption> tag + */ + public static final Tag CAPTION = new Tag("caption"); + + /** + * The <center> tag , breaks flow. + */ + public static final Tag CENTER = new Tag("center", BREAKS); + + /** + * The <cite> tag + */ + public static final Tag CITE = new Tag("cite"); + + /** + * The <code> tag + */ + public static final Tag CODE = new Tag("code"); + + /** + * The <dd> tag , breaks flow, block tag. + */ + public static final Tag DD = new Tag("dd", BREAKS | BLOCK); + + /** + * The <dfn> tag + */ + public static final Tag DFN = new Tag("dfn"); + + /** + * The <dir> tag , breaks flow, block tag. + */ + public static final Tag DIR = new Tag("dir", BREAKS | BLOCK); + + /** + * The <div> tag , breaks flow, block tag. + */ + public static final Tag DIV = new Tag("div", BREAKS | BLOCK); + + /** + * The <dl> tag , breaks flow, block tag. + */ + public static final Tag DL = new Tag("dl", BREAKS | BLOCK); + + /** + * The <dt> tag , breaks flow, block tag. + */ + public static final Tag DT = new Tag("dt", BREAKS | BLOCK); + + /** + * The <em> tag + */ + public static final Tag EM = new Tag("em"); + + /** + * The <font> tag + */ + public static final Tag FONT = new Tag("font"); + + /** + * The <form> tag , breaks flow. + */ + public static final Tag FORM = new Tag("form", BREAKS); + + /** + * The <frame> tag + */ + public static final Tag FRAME = new Tag("frame"); + + /** + * The <frameset> tag + */ + public static final Tag FRAMESET = new Tag("frameset"); + + /** + * The <h1> tag , breaks flow, block tag. + */ + public static final Tag H1 = new Tag("h1", BREAKS | BLOCK); + + /** + * The <h2> tag , breaks flow, block tag. + */ + public static final Tag H2 = new Tag("h2", BREAKS | BLOCK); + + /** + * The <h3> tag , breaks flow, block tag. + */ + public static final Tag H3 = new Tag("h3", BREAKS | BLOCK); + + /** + * The <h4> tag , breaks flow, block tag. + */ + public static final Tag H4 = new Tag("h4", BREAKS | BLOCK); + + /** + * The <h5> tag , breaks flow, block tag. + */ + public static final Tag H5 = new Tag("h5", BREAKS | BLOCK); + + /** + * The <h6> tag , breaks flow, block tag. + */ + public static final Tag H6 = new Tag("h6", BREAKS | BLOCK); + + /** + * The <head> tag , breaks flow, block tag. + */ + public static final Tag HEAD = new Tag("head", BREAKS | BLOCK); + + /** + * The <hr> tag , breaks flow. + */ + public static final Tag HR = new Tag("hr", BREAKS); + + /** + * The <html> tag , breaks flow. + */ + public static final Tag HTML = new Tag("html", BREAKS); + + /** + * The <i> tag + */ + public static final Tag I = new Tag("i"); + + /** + * The <img> tag + */ + public static final Tag IMG = new Tag("img"); + + /** + * The <input> tag + */ + public static final Tag INPUT = new Tag("input"); + + /** + * The <isindex> tag , breaks flow. + */ + public static final Tag ISINDEX = new Tag("isindex", BREAKS); + + /** + * The <kbd> tag + */ + public static final Tag KBD = new Tag("kbd"); + + /** + * The <li> tag , breaks flow, block tag. + */ + public static final Tag LI = new Tag("li", BREAKS | BLOCK); + + /** + * The <link> tag + */ + public static final Tag LINK = new Tag("link"); + + /** + * The <map> tag + */ + public static final Tag MAP = new Tag("map"); + + /** + * The <menu> tag , breaks flow, block tag. + */ + public static final Tag MENU = new Tag("menu", BREAKS | BLOCK); + + /** + * The <meta> tag + */ + public static final Tag META = new Tag("meta"); + + /** + * The <nobr> tag + */ + public static final Tag NOBR = new Tag("nobr"); + + /** + * The <noframes> tag , breaks flow, block tag. + */ + public static final Tag NOFRAMES = new Tag("noframes", BREAKS | BLOCK); + + /** + * The <object> tag + */ + public static final Tag OBJECT = new Tag("object"); + + /** + * The <ol> tag , breaks flow, block tag. + */ + public static final Tag OL = new Tag("ol", BREAKS | BLOCK); + + /** + * The <option> tag + */ + public static final Tag OPTION = new Tag("option"); + + /** + * The <p> tag , breaks flow, block tag. + */ + public static final Tag P = new Tag("p", BREAKS | BLOCK); + + /** + * The <param> tag + */ + public static final Tag PARAM = new Tag("param"); + + /** + * The <pre> tag , breaks flow, block tag, preformatted. + */ + public static final Tag PRE = new Tag("pre", BREAKS | BLOCK | PREFORMATTED); + + /** + * The <s> tag + */ + public static final Tag S = new Tag("s"); + + /** + * The <samp> tag + */ + public static final Tag SAMP = new Tag("samp"); + + /** + * The <script> tag + */ + public static final Tag SCRIPT = new Tag("script"); + + /** + * The <select> tag + */ + public static final Tag SELECT = new Tag("select"); + + /** + * The <small> tag + */ + public static final Tag SMALL = new Tag("small"); + + /** + * The <span> tag + */ + public static final Tag SPAN = new Tag("span"); + + /** + * The <strike> tag + */ + public static final Tag STRIKE = new Tag("strike"); + + /** + * The <strong> tag + */ + public static final Tag STRONG = new Tag("strong"); + + /** + * The <style> tag + */ + public static final Tag STYLE = new Tag("style"); + + /** + * The <sub> tag + */ + public static final Tag SUB = new Tag("sub"); + + /** + * The <sup> tag + */ + public static final Tag SUP = new Tag("sup"); + + /** + * The <table> tag , block tag. + */ + public static final Tag TABLE = new Tag("table", BLOCK); + + /** + * The <td> tag , breaks flow, block tag. + */ + public static final Tag TD = new Tag("td", BREAKS | BLOCK); + + /** + * The <textarea> tag , preformatted. + */ + public static final Tag TEXTAREA = new Tag("textarea", PREFORMATTED); + + /** + * The <th> tag , breaks flow, block tag. + */ + public static final Tag TH = new Tag("th", BREAKS | BLOCK); + + /** + * The <title> tag , breaks flow, block tag. + */ + public static final Tag TITLE = new Tag("title", BREAKS | BLOCK); + + /** + * The <tr> tag , block tag. + */ + public static final Tag TR = new Tag("tr", BLOCK); + + /** + * The <tt> tag + */ + public static final Tag TT = new Tag("tt"); + + /** + * The <u> tag + */ + public static final Tag U = new Tag("u"); + + /** + * The <ul> tag , breaks flow, block tag. + */ + public static final Tag UL = new Tag("ul", BREAKS | BLOCK); + + /** + * The <var> tag + */ + public static final Tag VAR = new Tag("var"); + + /* Special tags */ + + /** + * Total number of syntetic tags, delared in the Tag class. + * This must be adjusted if the new synthetic tags are declared. + * Otherwise the HTML.getAllTags() will not work as expected. + */ + private static final int TOTAL_SYNTHETIC_TAGS = 3; + + /** + * All comments are labeled with this tag. + * This tag is not included into the array, returned by getAllTags(). + * toString() returns 'comment'. HTML reader synthesizes this tag. + */ + public static final Tag COMMENT = new Tag("comment", SYNTETIC); + + /** + * All text content is labeled with this tag. + * This tag is not included into the array, returned by getAllTags(). + * toString() returns 'content'. HTML reader synthesizes this tag. + */ + public static final Tag CONTENT = new Tag("content", SYNTETIC); + + /** + * All text content must be in a paragraph element. + * If a paragraph didn't exist when content was encountered, + * a paragraph is manufactured. + * toString() returns 'implied'. HTML reader synthesizes this tag. + */ + public static final Tag IMPLIED = new Tag("implied", SYNTETIC); + final String name; + final int flags; + + /** + * Create the unitialised instance of HTML.Tag. + * + * The {@link #breaksFlow()}, {@link #isBlock()} + * and {@link #isPreformatted()} will always return false. + * The {@link #toString()} will return <code>null</code>. + * + * @since 1.3 + */ + public Tag() + { + name = null; + flags = 0; + } + + /** + * Creates a new Tag with the specified id, and with causesBreak + * and isBlock set to false. + */ + protected Tag(String id) + { + name = id; + flags = 0; + } + + /** + * Creates a new Tag with the specified tag name and + * causesBreak and isBlock properties. + */ + protected Tag(String id, boolean causesBreak, boolean isBlock) + { + int f = 0; + + if (causesBreak) + { + f |= BREAKS; + } + + if (isBlock) + { + f |= BLOCK; + } + + flags = f; + name = id; + } + + /** + * Create a tag taking flags. + */ + Tag(String id, int a_flags) + { + name = id; + flags = a_flags; + } + + /** + * Returns true if this tag is a block tag, which is a tag used to + * add structure to a document. + */ + public boolean isBlock() + { + return (flags & BLOCK) != 0; + } + + /** + * Returns true if this tag is pre-formatted, which is true if + * the tag is either PRE or TEXTAREA + */ + public boolean isPreformatted() + { + return (flags & PREFORMATTED) != 0; + } + + /** + * Returns true if this tag causes a line break to the flow of text + */ + public boolean breaksFlow() + { + return (flags & BREAKS) != 0; + } + + /** + * Calls compareTo on the tag names (Strings) + */ + public int compareTo(Object other) + { + return name.compareTo(((Tag) other).name); + } + + /** + * The tags are equal if the names are equal (ignoring case). + */ + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof Tag)) + { + return false; + } + + Tag that = (Tag) other; + + return that.name.equalsIgnoreCase(name); + } + + /** + * Returns the hash code which corresponds to the string for this tag. + */ + public int hashCode() + { + return name == null ? 0 : name.hashCode(); + } + + /** + * Returns the tag name. The names of the built-in tags are always + * returned in lowercase. + */ + public String toString() + { + return name; + } + + /** + * Return an array of HTML tags, declared in HTML.Tag class. + * WARNING: This method expects that the Tags are the only + * public fields declared in the Tag class. + */ + static Tag[] getAllTags() + { + Field[] f = Tag.class.getFields(); + Field x; + + // The syntetic tags are not included. + Tag[] tags = new Tag[ f.length - TOTAL_SYNTHETIC_TAGS ]; + int p = 0; + Tag t; + + for (int i = 0; i < f.length; i++) + { + x = f [ i ]; + + if ((x.getModifiers() & Modifier.STATIC) != 0) + { + if (x.getType().equals(Tag.class)) + { + try + { + t = (Tag) x.get(null); + + if (!t.isSyntetic()) + { + tags [ p++ ] = t; + } + } + catch (IllegalAccessException ex) + { + unexpected(ex); + } + catch (IllegalArgumentException ex) + { + unexpected(ex); + } + } + } + } + + return tags; + } + + /** + * Returns true for tags, generated by the html reader + * (COMMENT, CONTENT and IMPLIED). + */ + boolean isSyntetic() + { + return (flags & SYNTETIC) != 0; + } + + private static void unexpected(Exception ex) + throws Error + { + throw new Error("This should never happen, report a bug", ex); + } + } + + /** + * Represents an unknown HTML tag. + * @author Mark Wielaard (mark@klomp.org) + */ + public static class UnknownTag + extends Tag + implements Serializable + { + private static final long serialVersionUID = -1534369342247250625L; + + /** + * Creates a new UnknownTag with the specified name + * @param name The tag name. + * + */ + public UnknownTag(String name) + { + super(name); + } + } + + /** + * This value is returned for attributes without value that have no + * default value defined in the DTD. + */ + public static final String NULL_ATTRIBUTE_VALUE = "#DEFAULT"; + + /* Package level html tag flags */ + static final int BREAKS = 1; + static final int BLOCK = 2; + static final int PREFORMATTED = 4; + static final int SYNTETIC = 8; + private static Map tagMap; + private static Map attrMap; + + /** + * The public constructor (does nothing). It it seldom required to have + * an instance of this class, because all public fields and methods + * are static. + */ + public HTML() + { + } + + /** + * Returns the set of the recognized HTML attributes. + */ + public static HTML.Attribute[] getAllAttributeKeys() + { + return Attribute.getAllAttributes(); + } + + /** + * Returns the set of actual HTML tags that are recognized by + * the default HTML reader. The returned array does not include the + * COMMENT, CONTENT and IMPLIED tags. + */ + public static HTML.Tag[] getAllTags() + { + return Tag.getAllTags(); + } + + /** + * Returns an htl attribute constant for the given attribute name. + * @param attName the attribute name, case insensitive + */ + public static Attribute getAttributeKey(String attName) + { + if (attrMap == null) + { + // Create the map on demand. + attrMap = new TreeMap(); + + Attribute[] attrs = getAllAttributeKeys(); + + for (int i = 0; i < attrs.length; i++) + { + attrMap.put(attrs [ i ].toString(), attrs [ i ]); + } + } + + return (Attribute) attrMap.get(attName.toLowerCase()); + } + + /** + * Searches the value of given attribute in the provided set. + * If the value is found (String type expected), tries to parse it as + * an integer value. If succeded, returns the obtained integer value. + * + * For example:<p><code> + * SimpleAttributeSet ase = new SimpleAttributeSet(); + * ase.addAttribute(HTML.getAttributeKey("size"),"222"); + * System.out.println( + * HTML.getIntegerAttributeValue + * (ase, HTML.getAttributeKey("size"), 333)); // prints "222" + * System.out.println( + * HTML.getIntegerAttributeValue + * (ase, HTML.getAttributeKey("width"), 333)); // prints "333". + * </code></p> + * + * + * @param set The attribute set to search in. If the set contains the + * given attribute, it must by a type of String. + * @param attribute The html attribute to search in + * @param defaultValue The value that is returned if the attribute is not + * found in the given set or if the NumberFormatException was thrown + * during the parsing. + */ + public static int getIntegerAttributeValue(AttributeSet set, + HTML.Attribute attribute, + int defaultValue + ) + { + Object v = set.getAttribute(attribute); + + if (v == null) + { + return defaultValue; + } + + try + { + return Integer.parseInt(v.toString().trim()); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns a HTML tag constant for the given HTML attribute name. + * If the tag is unknown, the null is returned. + * @param tagName the tag name, case insensitive + */ + public static Tag getTag(String tagName) + { + if (tagMap == null) + { + // Create the mao on demand. + tagMap = new TreeMap(); + + Tag[] tags = getAllTags(); + + for (int i = 0; i < tags.length; i++) + { + tagMap.put(tags [ i ].toString(), tags [ i ]); + } + } + + return (Tag) tagMap.get(tagName.toLowerCase()); + } +} diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java new file mode 100644 index 00000000000..a95e496ec4d --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java @@ -0,0 +1,53 @@ +/* HTMLDocument.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import javax.swing.text.DefaultStyledDocument; + +/** + * TODO: This class is not yet completetely implemented. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class HTMLDocument extends DefaultStyledDocument +{ + public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event) + { + } +} diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java new file mode 100644 index 00000000000..7ae78ec0725 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java @@ -0,0 +1,249 @@ +/* HTMLEditorKit.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.io.Reader; +import java.io.Serializable; + +import javax.swing.text.BadLocationException; +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.StyledEditorKit; + +/** + * This class is NOT implemented. This file currently holds only + * declarations of the two enclosing classes, necessary for testing + * the implemented javax.swing.text.html.parser package. + * + * @author No authorship is taken, implement the class and be! + * TODO: replace this header after implementing the class. + */ +public class HTMLEditorKit + extends StyledEditorKit + implements Serializable, Cloneable +{ + /** + * The abstract HTML parser declaration. + */ + public abstract static class Parser + { + /** + * Parse the HTML text, calling various methods of the provided callback + * in response to the occurence of the corresponding HTML constructions. + * @param reader The reader to read the source HTML from. + * @param callback The callback to receive information about the parsed + * HTML structures + * @param ignoreCharSet If true, the parser ignores all charset information + * that may be present in HTML documents. + * @throws IOException, normally if the reader throws one. + */ + public abstract void parse(Reader reader, ParserCallback callback, + boolean ignoreCharSet + ) + throws java.io.IOException; + } + + /** + * The "hook" that receives all information about the HTML document + * structure while parsing it. The methods are invoked by parser + * and should be normally overridden. + */ + public static class ParserCallback + { + /** + * If the tag does not occurs in the html stream directly, but + * is supposed by parser, the tag attribute set contains this additional + * attribute, having value Boolean.True. + */ + public static final Object IMPLIED = "_implied_"; + + /** + * The parser calls this method after it finishes parsing the document. + */ + public void flush() + throws BadLocationException + { + } + + /** + * Handle HTML comment, present in the given position. + * @param comment the comment + * @position the position of the comment in the text being parsed. + */ + public void handleComment(char[] comment, int position) + { + } + + /** + * Notifies about the character sequences, used to separate lines in + * this document. The parser calls this method after it finishes + * parsing the document, but before flush(). + * @param end_of_line The "end of line sequence", one of: \r or \n or \r\n. + */ + public void handleEndOfLineString(String end_of_line) + { + } + + /** + * The method is called when the HTML closing tag ((like </table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag being handled + * @position the tag position in the text being parsed. + */ + public void handleEndTag(HTML.Tag tag, int position) + { + } + + /** + * Handle the error. + * @param message The message, explaining the error. + * @param position The starting position of the fragment that has caused + * the error in the html document being parsed. + */ + public void handleError(String message, int position) + { + } + + /** + * Handle the tag with no content, like <br>. The method is + * called for the elements that, in accordance with the current DTD, + * has an empty content. + * @param tag The tag being handled. + * @param position The tag position in the text being parsed. + */ + public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attributes, + int position + ) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param tag The tag being handled + * @param position The tag position in the text being parsed + */ + public void handleStartTag(HTML.Tag tag, MutableAttributeSet attributes, + int position + ) + { + } + + /** + * Handle the text section. + * @param text A section text. + * @param position The text position in the HTML document text being parsed. + */ + public void handleText(char[] text, int position) + { + } + } + + /** + * Use serialVersionUID (v1.4) for interoperability. + */ + private static final long serialVersionUID = 8751997116710384592L; + + /** + * Default cascading stylesheed file ("default.css"). + */ + public static final String DEFAULT_CSS = "default.css"; + + /** + * The <b>bold</b> action identifier. + */ + public static final String BOLD_ACTION = "html-bold-action"; + + /** + * The <i>italic</i> action identifier. + */ + public static final String ITALIC_ACTION = "html-italic-action"; + + /** + * The <font color="#FF0000">color</font> action indentifier + * (passing the color as an argument). + */ + public static final String COLOR_ACTION = "html-color-action"; + + /** + * The <font size="+1">increase</font> font action identifier. + */ + public static final String FONT_CHANGE_BIGGER = "html-font-bigger"; + + /** + * The <font size="-1">decrease</font> font action identifier. + */ + public static final String FONT_CHANGE_SMALLER = "html-font-smaller"; + + /** + * Align images at the bottom. + */ + public static final String IMG_ALIGN_BOTTOM = "html-image-align-bottom"; + + /** + * Align images at the middle. + */ + public static final String IMG_ALIGN_MIDDLE = "html-image-align-middle"; + + /** + * Align images at the top. + */ + public static final String IMG_ALIGN_TOP = "html-image-align-top"; + + /** + * Align images at the border. + */ + public static final String IMG_BORDER = "html-image-border"; + + /** + * The "logical style" action identifier, passing that style as parameter. + */ + public static final String LOGICAL_STYLE_ACTION = "html-logical-style-action"; + + /** + * The "ident paragraph left" action. + */ + public static final String PARA_INDENT_LEFT = "html-para-indent-left"; + + /** + * The "ident paragraph right" action. + */ + public static final String PARA_INDENT_RIGHT = "html-para-indent-right"; +}
\ No newline at end of file diff --git a/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java b/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java new file mode 100644 index 00000000000..dc0ab10a8f7 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/HTMLFrameHyperlinkEvent.java @@ -0,0 +1,132 @@ +/* HTMLFrameHyperlinkEvent.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html; + +import java.net.URL; + +import javax.swing.event.HyperlinkEvent; +import javax.swing.event.HyperlinkEvent.EventType; +import javax.swing.text.Element; + +/** + * HTMLFrameHyperlinkEvent transfers information about the link that was + * activated in a frame. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class HTMLFrameHyperlinkEvent + extends HyperlinkEvent +{ + private final String target_frame; + + /** + * Creates a new hypertext link event. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + * @param element The element in the document representing the anchor. + * @param frame - the Frame to display the document in. + */ + public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url, + Element element, String frame) + { + super(source, type, url, frame, element); + target_frame = frame; + } + + /** + * Creates a new hypertext link event. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + * @param frame - the Frame to display the document in. + */ + public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url, + String frame) + { + super(source, type, url, frame); + target_frame = frame; + } + + /** + * Creates a new hypertext link event. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + * @param description The description for this link. + * @param element The element in the document representing the anchor. + * @param frame - the Frame to display the document in. + */ + public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url, + String description, Element element, + String frame) + { + super(source, type, url, description, element); + target_frame = frame; + } + + /** + * Creates a new hypertext link event. + * + * @param source The object this link is associated to. + * @param type The type of event. + * @param url The URL this link pointing too. + * @param description The description for this link. + * @param frame - the Frame to display the document in. + */ + public HTMLFrameHyperlinkEvent(Object source, EventType type, URL url, + String description, String frame) + { + super(source, type, url, description); + target_frame = frame; + } + + /** + * Gets the string, passed as the target frame identifier. + * + * @return the target for the link. + */ + public String getTarget() + { + return target_frame; + } +} diff --git a/libjava/classpath/javax/swing/text/html/package.html b/libjava/classpath/javax/swing/text/html/package.html new file mode 100644 index 00000000000..c7e7744282c --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/package.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.text.html package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.text.html</title></head> + +<body> +<p> Provides supporting classes for web browsers, + web robots, web page content analysers, web editors and + other applications applications working with Hypertext + Markup Language (HTML). +</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/text/html/parser/AttributeList.java b/libjava/classpath/javax/swing/text/html/parser/AttributeList.java new file mode 100644 index 00000000000..5bca0bfa7db --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/AttributeList.java @@ -0,0 +1,294 @@ +/* AttributeList.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.support.gnuStringIntMapper; + +import java.io.Serializable; + +import java.util.Enumeration; +import java.util.Vector; + +/** + * <p> + * Stores the attribute information, obtained by parsing SGML (DTD) tag + * <code><!ATTLIST .. ></code></p> + * <p> + * Elements can have a associated named properties (attributes) having the + * assigned values. The element start tag can have any number of attribute + * value pairs, separated by spaces. They can appear in any order. + * SGML requires you to delimit the attribute values using either double (") + * or single (') quotation marks. In HTML, it is possible + * (but not recommended) to specify the value of an attribute without + * quotation marks. Such attribute value may only contain + * letters, digits, hyphens (-) and periods (.) . + * </p> + * <p> + * The <code>AttributeList</code> defines a single attribute that additionally + * has a pointer referencing the possible subsequent attribute. + * The whole structure is just a simple linked list, storing all attributes of + * some <code>Element</code>. + * Use the <code>getNext()</code> method repeatedly to see all attributes in + * the list. + * </p> + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public final class AttributeList + implements DTDConstants, Serializable +{ + /** Maps between type names and they string values. */ + private static final gnuStringIntMapper mapper = + new gnuStringIntMapper() + { + protected void create() + { + add("CDATA", DTDConstants.CDATA); + add("ENTITY", DTDConstants.ENTITY); + add("ENTITIES", DTDConstants.ENTITIES); + add("ID", DTDConstants.ID); + add("IDREF", DTDConstants.IDREF); + add("IDREFS", DTDConstants.IDREFS); + add("NAME", DTDConstants.NAME); + add("NAMES", DTDConstants.NAMES); + add("NMTOKEN", DTDConstants.NMTOKEN); + add("NMTOKENS", DTDConstants.NMTOKENS); + add("NOTATION", DTDConstants.NOTATION); + add("NUMBER", DTDConstants.NUMBER); + add("NUMBERS", DTDConstants.NUMBERS); + add("NUTOKEN", DTDConstants.NUTOKEN); + add("NUTOKENS", DTDConstants.NUTOKENS); + } + }; + + /** Use serialVersionUID for interoperability. */ + private static final long serialVersionUID = -1361214058742015233L; + + /** + * The value of ( = pointer to ) the next attribute in the linked list, + * storing all attributes of some Element. Contains null for the + * last attribute. + */ + public AttributeList next; + + /** + * The name of the attribute. The attribute names are case insensitive. + */ + public String name; + + /** + * The default value of this attribute. Equals to null if no default value + * is specified. + */ + public String value; + + /** + * The explicit set of the allowed values of this attribute. Equals to + * null, if this parameter was not specified. + * Values, defined in DTD, are case insensitive. + */ + public Vector values; + + /** + * The modifier of this attribute. This field contains one of the + * following DTD constants: + * <ul> + * <li> REQUIRED if the attribute value is always required,</li> + * <li> IMPLIED if the user agent must supply the default value itself,</li> + * <li> FIXED if the attribute value is fixed to some value and cannot + * be changed.</li> + * <li> DEFAULT if the attribute default value has been supplied.</li> + * <li> CURRENT the value that at any point in the document is + * the last value supplied for that element. A value is required to be + * supplied for the first* occurrence of an element</li> + * <li> CONREF specifies the IDREF value of + * the reference to content in another location of the document. + * The element with this attribute is empty, the content from + * that another location must be used instead.</li> + * </ul> + */ + public int modifier; + + /** + * The type of the attribute. The possible values of this field + * (NUMBER, NAME, ID, CDATA and so on) are defined in DTDConstants. + */ + public int type; + + /** + * Creates the attribute with the given name, initializing other fields + * to the default values ( 0 and null ). + * + * @param a_name The name of the attribute. + */ + public AttributeList(String a_name) + { + name = a_name; + } + + /** + * Creates the attribute with the given properties. + * @param a_name The name of the attribute + * @param a_type The type of the attribute. The possible values are defined + * in <code> DTDConstants</code>. + * @param a_modifier The modifier of this attribute. The possible values + * are defined in <code> DTDConstants</code>. + * @param a_default The default value of this attribute + * @param allowed_values The explicit set of the allowed values of + * this attribute + * @param a_next The value of the subsequent instance of the AttributeList, + * representing the next attribute definition for the same element. + * Equals to null for the last attribute definition. + */ + public AttributeList(String a_name, int a_type, int a_modifier, + String a_default, Vector allowed_values, + AttributeList a_next + ) + { + this(a_name); + type = a_type; + modifier = a_modifier; + value = a_default; + values = allowed_values; + next = a_next; + } + + /** + * Get the modifier of this attribute. This field contains one of the + * following DTD constants: + * <ul> + * <li> REQUIRED if the attribute value is always required,</li> + * <li> IMPLIED if the user agent must supply the default value itself,</li> + * <li> FIXED if the attribute value is fixed to some value and cannot + * be changed.</li> + * <li> DEFAULT if the attribute default value has been supplied.</li> + * <li> CURRENT the value that at any point in the document is + * the last value supplied for that element. A value is required to be + * supplied for the first* occurrence of an element</li> + * <li> CONREF specifies the IDREF value of + * the reference to content in another location of the document. + * The element with this attribute is empty, the content from + * that another location must be used instead.</li> + * </ul> + */ + public int getModifier() + { + return modifier; + } + + /** + * Get the name of the attribute. + * The value is returned as it was supplied to a + * constructor, preserving the character case. + */ + public String getName() + { + return name; + } + + /** + * Get the value of ( = pointer to ) the next attribute in the linked list, + * storing all attributes of some Element. Contains null for the + * last attribute. + */ + public AttributeList getNext() + { + return next; + } + + /** + * Get the type of the attribute. The possible values of this field + * (NUMBER, NAME, ID, CDATA and so on) are defined in DTDConstants. + */ + public int getType() + { + return type; + } + + /** + * Get the default value of this attribute. + */ + public String getValue() + { + return value; + } + + /** + * Get the allowed values of this attribute. + */ + public Enumeration getValues() + { + return values.elements(); + } + + /** + * Converts a string value, representing a valid SGLM attribute type, + * into the corresponding value, defined in DTDConstants. + * @param typeName the name of the type (character case is ignored). + * @return a value from DTDConstants or DTDConstants.ANY if the + * string is not representing a known type. The known attribute types + * in this implementation are CDATA, ENTITY, ENTITIES, ID, IDREF, IDREFS, + * NAME, NAMES, NMTOKEN, NMTOKENS, NOTATION, NUMBER, NUMBERS, NUTOKEN and + * NUTOKENS. + * @throws NullPointerException if the passed parameter is null. + */ + public static int name2type(String typeName) + { + return mapper.get(typeName.toUpperCase()); + } + + /** + * Returns the attribute name. + */ + public String toString() + { + return name; + } + + /** + * Converts a value from DTDConstants into the string representation. + * @param type - an integer value of the public static integer field, + * defined in the DTDConstants class. + * @return a corresponding SGML DTD keyword (UPPERCASE) or null if there + * are no attribute type constant having the given value. + */ + public static String type2name(int type) + { + return mapper.get(type); + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/ContentModel.java b/libjava/classpath/javax/swing/text/html/parser/ContentModel.java new file mode 100644 index 00000000000..deb7b1602bb --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/ContentModel.java @@ -0,0 +1,218 @@ +/* ContentModel.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.models.transformer; + +import java.io.Serializable; + +import java.util.Vector; + +/** + * A representation of the element content. The instances of this class + * can be arranged into the linked list, representing a BNF expression. + * The content model is constructed as a branched tree structure in the + * following way: + * <pre> + * a = new ContentModel('+', A, null); // a reprensents A+ + * b = new ContentModel('&', B, a); // b represents B & A+ + * c = new ContentModel('*', b, null); // c represents ( B & A+) * + * d = new ContentModel('|', new ContentModel('*', A, null), + * new ContentModel('?', B, null)); // d represents ( A* | B? ) + * </pre> + * where the valid operations are: + * <ul> + * <li><code>E* </code> E occurs zero or more times</li> + * <li><code>E+ </code> E occurs one or more times</li> + * <li><code>E? </code> E occurs once or not atl all</li> + * <li><code>A,B</code> A occurs before B</li> + * <li><code>A|B</code> both A and B are permitted in any order. + * The '|' alone does not permit the repetetive occurence of A or B + * (use <code>(A|B)*</code>.</li> + * <li><code>A&B</code> both A and B must occur once (in any order)</li> + * </ul> + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public final class ContentModel + implements Serializable +{ + /** Use serialVersionUID for interoperability. */ + private static final long serialVersionUID = -1130825523866321257L; + + /** + * The next content model model ( = pointer to the next element of + * the linked list) for the binary expression (',','&' or '|'). Null + * for the last element in the list. + */ + public ContentModel next; + + /** + * The document content, containing either Element or the enclosed + * content model (that would be in the parentheses in BNF expression). + */ + public Object content; + + /** + * Specifies the BNF operation between this node and the node, + * stored in the field <code>next</code> (or for this node, if it is + * an unary operation. + */ + public int type; + + /** Create a content model initializing all fields to default values. */ + public ContentModel() + { + } + + /** + * Create a content model, consisting of the single element. + * Examples: + *<code> + * a = new ContentModel('+', A, null); // a reprensents A+ + * b = new ContentModel('&', B, a); // b represents B & A+ + * c = new ContentModel('*', b, null); // c represents ( B & A+) * + * d = new ContentModel('|', A, + * new ContentModel('?',b, null); + * // d represents + * </code> + */ + public ContentModel(Element a_content) + { + content = a_content; + } + + /** + * Create a content model, involving expression of the given type. + * @param a_type The expression operation type ('*','?' or '+' + * @param a_content The content for that the expression is applied. + */ + public ContentModel(int a_type, ContentModel a_content) + { + content = a_content; + type = a_type; + } + + /** + * Create a content model, involving binary expression of the given type. + * @param a_type The expression operation type ( ',', '|' or '&'). + * @param a_content The content of the left part of the expression. + * @param a_next The content model, representing the right part of the + * expression. + */ + public ContentModel(int a_type, Object a_content, ContentModel a_next) + { + content = a_content; + type = a_type; + next = a_next; + } + + /** + * Adds all list elements to the given vector, ignoring the + * operations between the elements. The old vector values are not + * discarded. + * @param elements - a vector to add the values to. + */ + public void getElements(Vector elements) + { + ContentModel c = this; + + while (c != null) + { + elements.add(c.content); + c = c.next; + } + } + + /** + * Checks if the content model matches an empty input stream. + * The empty content is created using SGML DTD keyword EMPTY. + * The empty model is a model with the content field equal to null. + * + * @return true if the content field is equal to null. + */ + public boolean empty() + { + return content == null; + } + + /** + * Get the element, stored in the <code>next.content</code>. + * The method is programmed as the part of the standard API, but not + * used in this implementation. + * @return the value of the field <code>next</code>. + */ + public Element first() + { + return (Element) next.content; + } + + /** + * Checks if this object can potentially be the first token in the + * ContenModel list. The method is programmed as the part of the + * standard API, but not used in this implementation. + */ + public boolean first(Object token) + { + ContentModel c = this; + while (c.next != null) + { + if (c.content != null && c.content.toString().equals(token.toString()) && + c.type != ',' + ) + + // Agree if the operation with the preceeding element + // is not the comma operation. + return true; + c = c.next; + } + return false; + } + + /** + * Returns a string representation (an expression) of this content model. + * The expression has BNF-like syntax, except the absence of the + * unary operator is additionally indicated by " ' ". It is + * advisable to check the created models for correctness using this + * method. + */ + public String toString() + { + return transformer.transform(this).toString(); + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/DTD.java b/libjava/classpath/javax/swing/text/html/parser/DTD.java new file mode 100644 index 00000000000..63d03eaccf0 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/DTD.java @@ -0,0 +1,607 @@ +/* DTD.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.BitSet; +import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * <p>Representation or the SGML DTD document. + * Provides basis for describing a syntax of the + * HTML documents. The fields of this class are NOT initialized in + * constructor. You need to do this separately before passing this data + * structure to the HTML parser. The subclasses with the fields, pre- + * initialized, for example, for HTML 4.01, can be available only between + * the implementation specific classes + * ( for example, {@link gnu.javax.swing.text.html.parser.HTML_401F } + * in this implementation).</p> + * <p> + * If you need more information about SGML DTD documents, + * the author suggests to read SGML tutorial on + * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * We also recommend Goldfarb C.F (1991) <i>The SGML Handbook</i>, + * Oxford University Press, 688 p, ISBN: 0198537379. + * </p> + * <p> + * Warning: the html, head and other tag fields will only be automatically + * assigned if the VM has the correctly implemented reflection mechanism. + * As these fields are not used anywhere in the implementation, not + * exception will be thrown in the opposite case. + * </p> + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DTD + implements DTDConstants +{ + /** + * The version of the persistent data format. + */ + public static int FILE_VERSION = 1; + + /** + * The table of existing available DTDs. + */ + static Hashtable dtdHash = new Hashtable(); + + /** + * The applet element for this DTD. + */ + public Element applet; + + /** + * The base element for this DTD. + */ + public Element base; + + /** + * The body element for this DTD. + */ + public Element body; + + /** + * The head element for this DTD. + */ + public Element head; + + /** + * The html element for this DTD. + */ + public Element html; + + /** + * The isindex element of for this DTD. + */ + public Element isindex; + + /** + * The meta element for this DTD. + */ + public Element meta; + + /** + * The p element for this DTD. + */ + public Element p; + + /** + * The param element for this DTD. + */ + public Element param; + + /** + * The pcdata for this DTD. + */ + public Element pcdata; + + /** + * The title element for this DTD. + */ + public Element title; + + /** + * The element for accessing all DTD elements by name. + */ + public Hashtable elementHash = new Hashtable(); + + /** + * The entity table for accessing all DTD entities by name. + */ + public Hashtable entityHash = new Hashtable(); + + /** + * The name of this DTD. + */ + public String name; + + /** + * Contains all elements in this DTD. The + * javax.swing.text.html.parser.Element#index field of all elements + * in this vector is set to the element position in this vector. + */ + public Vector elements = new Vector(); + + /** Create a new DTD with the specified name. */ + protected DTD(String a_name) + { + name = a_name; + } + + /** Get this DTD by name. The current implementation + * only looks in the internal table of DTD documents. If no corresponding + * entry is found, the new entry is created, placed into + * the table and returned. */ + public static DTD getDTD(String name) + throws IOException + { + DTD d = (DTD) dtdHash.get(name); + + if (d == null) + { + d = new DTD(name); + dtdHash.put(d.name, d); + } + + return d; + } + + /** + * Get the element by the element name. If the element is not yet + * defined, it is newly created and placed into the element table. + * If the element name matches (ingoring case) a public non static + * element field in this class, this field is assigned to the value + * of the newly created element. + */ + public Element getElement(String element_name) + { + return newElement(element_name); + } + + /** + * Get the element by the value of its + * {@link javax.swing.text.html.parser.Element#index} field. + */ + public Element getElement(int index) + { + return (Element) elements.get(index); + } + + /** + * Get the entity with the given identifier. + * @param id that can be returned by + * {@link javax.swing.text.html.parser.Entity#name2type(String an_entity)} + * @return The entity from this DTD or null if there is no entity with + * such id or such entity is not present in the table of this instance. + */ + public Entity getEntity(int id) + { + String name = Entity.mapper.get(id); + + if (name != null) + return (Entity) entityHash.get(name); + else + return null; + } + + /** + * Get the named entity by its name. + */ + public Entity getEntity(String entity_name) + { + return (Entity) entityHash.get(entity_name); + } + + /** + * Get the name of this instance of DTD + */ + public String getName() + { + return name; + } + + /** + * Creates, adds into the entity table and returns the + * character entity like <code>&lt;</code> + * (means '<code><</code>' ); + * @param name The entity name (without heading & and closing ;) + * @param type The entity type + * @param character The entity value (single character) + * @return The created entity + */ + public Entity defEntity(String name, int type, int character) + { + Entity e = newEntity(name, type); + e.data = new char[] { (char) character }; + return e; + } + + /** + * Define the attributes for the element with the given name. + * If the element is not exist, it is created. + * @param forElement + * @param attributes + */ + public void defineAttributes(String forElement, AttributeList attributes) + { + Element e = (Element) elementHash.get(forElement.toLowerCase()); + + if (e == null) + e = newElement(forElement); + + e.atts = attributes; + } + + /** + * Defines the element and adds it to the element table. Sets the + * <code>Element.index</code> field to the value, unique for this + * instance of DTD. If the element with the given name already exists, + * replaces all other its settings by the method argument values. + * @param name the name of the element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * (should not occur in HTML). + * @param tailless true if the element needs no ending tag (like + * <code><hr></code> + * @param content the element content + * @param exclusions the set of elements that must not occur inside + * this element. The <code>Element.index</code> value defines which + * bit in this bitset corresponds to that element. + * @param inclusions the set of elements that can occur inside this + * element. the <code>Element.index</code> value defines which + * bit in this bitset corresponds to that element. + * @param attributes the element attributes. + * @return the newly defined element. + */ + public Element defineElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + BitSet exclusions, BitSet inclusions, + AttributeList attributes + ) + { + Element e = newElement(name); + e.type = type; + e.oStart = headless; + e.oEnd = tailless; + e.content = content; + e.exclusions = exclusions; + e.inclusions = inclusions; + e.atts = attributes; + + return e; + } + + /** + * Creates, intializes and adds to the entity table the new + * entity. + * @param name the name of the entity + * @param type the type of the entity + * @param data the data section of the entity + * @return the created entity + */ + public Entity defineEntity(String name, int type, char[] data) + { + Entity e = newEntity(name, type); + e.data = data; + + return e; + } + + /** Place this DTD into the DTD table. */ + public static void putDTDHash(String name, DTD dtd) + { + dtdHash.put(name, dtd); + } + + /** + * <p>Reads DTD from an archived format. This format is not standardized + * and differs between implementations.</p><p> This implementation + * reads and defines all entities and elements using + * ObjectInputStream. The elements and entities can be written into the + * stream in any order. The objects other than elements and entities + * are ignored.</p> + * @param stream A data stream to read from. + * @throws java.io.IOException If one is thrown by the input stream + */ + public void read(DataInputStream stream) + throws java.io.IOException + { + ObjectInputStream oi = new ObjectInputStream(stream); + Object def; + try + { + while (true) + { + def = oi.readObject(); + if (def instanceof Element) + { + Element e = (Element) def; + elementHash.put(e.name.toLowerCase(), e); + assignField(e); + } + else if (def instanceof Entity) + { + Entity e = (Entity) def; + entityHash.put(e.name, e); + } + } + } + catch (ClassNotFoundException ex) + { + throw new IOException(ex.getMessage()); + } + catch (EOFException ex) + { + // ok EOF + } + } + + /** + * Returns the name of this instance of DTD. + */ + public String toString() + { + return name; + } + + /** + * Creates and returns new attribute (not an attribute list). + * @param name the name of this attribute + * @param type the type of this attribute (FIXED, IMPLIED or + * REQUIRED from <code>DTDConstants</code>). + * @param modifier the modifier of this attribute + * @param default_value the default value of this attribute + * @param allowed_values the allowed values of this attribute. The multiple + * possible values in this parameter are supposed to be separated by + * '|', same as in SGML DTD <code><!ATTLIST </code>tag. This parameter + * can be null if no list of allowed values is specified. + * @param atts the previous attribute of this element. This is + * placed to the field + * {@link javax.swing.text.html.parser.AttributeList#next }, + * creating a linked list. + * @return + */ + protected AttributeList defAttributeList(String name, int type, int modifier, + String default_value, + String allowed_values, + AttributeList atts + ) + { + AttributeList al = new AttributeList(name); + al.modifier = modifier; + al.value = default_value; + al.next = atts; + + if (allowed_values != null) + { + StringTokenizer st = new StringTokenizer(allowed_values, " \t|"); + Vector v = new Vector(st.countTokens()); + + while (st.hasMoreTokens()) + v.add(st.nextToken()); + + al.values = v; + } + + return al; + } + + /** + * Creates a new content model. + * @param type specifies the BNF operation for this content model. + * The valid operations are documented in the + * {@link javax.swing.text.html.parser.ContentModel#type }. + * @param content the content of this content model + * @param next if the content model is specified by BNF-like + * expression, contains the rest of this expression. + * @return The newly created content model. + */ + protected ContentModel defContentModel(int type, Object content, + ContentModel next + ) + { + ContentModel model = new ContentModel(); + model.type = type; + model.next = next; + model.content = content; + + return model; + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes. + * @return the created or updated element. + */ + protected Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + String[] exclusions, String[] inclusions, + AttributeList attributes + ) + { + // compute the bit sets + BitSet exclude = bitSet(exclusions); + BitSet include = bitSet(inclusions); + + Element e = + defineElement(name, type, headless, tailless, content, exclude, include, + attributes + ); + + return e; + } + + /** + * Creates, intializes and adds to the entity table the new + * entity. + * @param name the name of the entity + * @param type the type of the entity + * @param data the data section of the entity + * @return the created entity + */ + protected Entity defEntity(String name, int type, String data) + { + Entity e = newEntity(name, type); + e.data = data.toCharArray(); + + return e; + } + + private void assignField(Element e) + { + String element_name = e.name; + try + { + // Assign the field via reflection. + Field f = getClass().getField(element_name.toLowerCase()); + if ((f.getModifiers() & Modifier.PUBLIC) != 0) + if ((f.getModifiers() & Modifier.STATIC) == 0) + if (f.getType().isAssignableFrom(e.getClass())) + f.set(this, e); + } + catch (IllegalAccessException ex) + { + unexpected(ex); + } + catch (NoSuchFieldException ex) + { + // This is ok. + } + + // Some virtual machines may still lack the proper + // implementation of reflection. As the tag fields + // are not used anywhere in this implementation, + // (and this class is also rarely used by the end user), + // it may be better not to crash everything by throwing an error + // for each case when the HTML parsing is required. + catch (Throwable t) + { + // This VM has no reflection mechanism implemented! + if (t instanceof OutOfMemoryError) + throw (Error) t; + } + } + + /** + * Create the bit set for this array of elements. + * The unknown elements are automatically defined and added + * to the element table. + * @param elements + * @return + */ + private BitSet bitSet(String[] elements) + { + BitSet b = new BitSet(); + + for (int i = 0; i < elements.length; i++) + { + Element e = getElement(elements [ i ]); + + if (e == null) + e = newElement(elements [ i ]); + + b.set(e.index); + } + + return b; + } + + /** + * Find the element with the given name in the element table. + * If not find, create a new element with this name and add to the + * table. + * @param name the name of the element + * @return the found or created element. + */ + private Element newElement(String name) + { + Element e = (Element) elementHash.get(name.toLowerCase()); + + if (e == null) + { + e = new Element(); + e.name = name; + e.index = elements.size(); + elements.add(e); + elementHash.put(e.name.toLowerCase(), e); + assignField(e); + } + return e; + } + + /** + * Creates and adds to the element table the entity with an + * unitialized data section. Used internally. + * @param name the name of the entity + * @param type the type of the entity, a bitwise combination + * of GENERAL, PARAMETER, SYSTEM and PUBLIC. + * @throws an error if the parameter is both GENERAL and PARAMETER + * of both PUBLIC and SYSTEM. + * @return the created entity + */ + private Entity newEntity(String name, int type) + { + Entity e = new Entity(name, type, null); + entityHash.put(e.name, e); + return e; + } + + private void unexpected(Exception ex) + { + throw new Error("This should never happen, report a bug", ex); + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java b/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java new file mode 100644 index 00000000000..a771264a1ad --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java @@ -0,0 +1,290 @@ +/* DTDConstants.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +/** + * <p>This class defines the SGML basic types, used for describing HTML 4.01 + * at {@link http://www.w3.org/TR/html4/types.html }. Not all constants, + * defined here, are actually used in HTML 4.01 SGML specification. Some others + * are defined just as part of the required implementation. + * </p> + * <p> + * If you need more information about SGML DTD documents, + * the author suggests to read SGML tutorial on + * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * We also recommend Goldfarb C.F (1991) <i>The SGML Handbook</i>, + * Oxford University Press, 688 p, ISBN: 0198537379. + * </p> + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface DTDConstants +{ + /* ----- The data types, used in HTML 4.01 SGML definition: ---- */ + + /** + * The CDATA (Character data) constant, specifes the content model, + * consisting of characters only. In SGML for HTML 4.01, the character + * entities must be replaced by characters, the line feeds must be + * ignored and any number of the subsequent carriage returns or tabs + * must be replaced by a single space. + */ + int CDATA = 1; + + /** + * The EMPTY constant, means the element with no content. + */ + int EMPTY = 17; + + /** + * The ID constant, means that the token is the unique identifier. + * This identifier can be referenced by attribute with value of IDREF. + * The identifier must begin with letter, followed by any number of + * letters, digits, hyphens, underscores, colons and periods. + */ + int ID = 4; + + /** + * The IDREF constant, specifies reference to a valid ID within + * the document. + */ + int IDREF = 5; + + /** + * The IDREFS constant, a space separated list of IDREFs + */ + int IDREFS = 6; + + /** + * The NAME constant, means the token that + * must begin with letter, followed by any number of + * letters, digits, hyphens, underscores, colons and periods. + */ + int NAME = 7; + + /** + * The NAMES constant, specifies a space separated of NAMEs. + */ + int NAMES = 8; + + /** + * The NMTOKEN constant, specifies the attribute, consisting of + * characters that can be either digits or alphabetic characters). + */ + int NMTOKEN = 9; + + /** + * The NMTOKENS constant, specifies a list of NMTOKENs. + */ + int NMTOKENS = 10; + + /** + * The NOTATION constant, a previously defined data type. + */ + int NOTATION = 11; + + /** + * The NUMBER constant (means that the attribute consists of at least + * one decimal digit). + */ + int NUMBER = 12; + + /** + * The NUMBERS constant, specifies a space separated list of NUMBERs. + */ + int NUMBERS = 13; + + /** + * The NUTOKEN constant. + */ + int NUTOKEN = 14; + + /** + * The NUTOKENS constant. + */ + int NUTOKENS = 15; + + /* ------- + The entity scope constants. + As these four constants are combined with the bitwise OR, + they are defined in the hexadecimal notation. + The reason of setting the two bits at once (for PUBLIC and SYSTEM) + is probably historical. ----- */ + + /** + * The PUBLIC constant, specifies the public entity. The PUBLIC entities + * are assumed to be known to many systems so that a full declaration + * need not be transmitted. For example, + * <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0//EN"> + */ + int PUBLIC = 0xA; + + /** + * The SYSTEM constant, specifies the system entitiy. The system entities + * are assumed to be known but require the clear identifer + * (like the file path), where they can be found in the system. + * For example, <code> + * <DOCTYPE html SYSTEM "/path/to/file.dtd"> </code>. + */ + int SYSTEM = 0x11; + + /** + * The PARAMETER constant, specifies that entity is only valid + * inside SGML DTD scope. + */ + int PARAMETER = 0x40000; + + /** + * The GENERAL constant, specifies theat the entity is valid in the + * whole HTML document scope. + */ + int GENERAL = 0x10000; + + /* ---- The constants, defining if the element attribute is required, + fixed or implied. ---- */ + + /** + * The attribute modifier #REQUIRED constant, indicates that the + * value must be supplied. + */ + int REQUIRED = 2; + + /** + * The attribute modifier #FIXED constant, means that the attribute has + * the fixed value that cannot be changed. + */ + int FIXED = 1; + + /** + * The attribute modifier #IMPLIED constant, + * indicating that for this attribute the user agent must provide + * the value itself. + */ + int IMPLIED = 5; + + /** + * The attribute modifier #CURRENT constant, specifies the value + * that at any point in the document is the last value supplied for + * that element. A value is required to be supplied for the first + * occurrence of an element + */ + int CURRENT = 3; + + /** + * The attribute modifier #CONREF constant, specifies the IDREF value of + * the reference to content in another location of the document. + * The element with this attribute is empty, the content from + * that another location must be used instead. + */ + int CONREF = 4; + + /* ----- Constants, defining if the element + start and end tags are required. ---- */ + + /** + * The STARTTAG, meaning that the element needs a starting tag. + */ + int STARTTAG = 13; + + /** + * The ENDTAG constant, meaning that the element needs a closing tag. + */ + int ENDTAG = 14; + + /* ----- Other constants: ----- */ + + /** + * The ANY constant, specifies + * an attribute, consisting from arbitrary characters. + */ + int ANY = 19; + + /** + * The DEFAULT constant, specifies the default value. + */ + int DEFAULT = 131072; + + /** + * The ENTITIES constant (list of ENTITYes) + */ + int ENTITIES = 3; + + /** + * The ENTITY constant, meaning the numeric or symbolic name of some + * HTML data. + */ + int ENTITY = 2; + + /** + * The MD constant. + */ + int MD = 16; + + /** + * The MODEL constant. + */ + int MODEL = 18; + + /** + * The MS constant. + */ + int MS = 15; + + /** + * The PI (Processing Instruction) constant, specifies a processing + * instruction. Processing instructions are used to embed information + * intended for specific applications. + */ + int PI = 12; + + /** + * The RCDATA constant (Entity References and Character Data), specifies + * the content model, consisting of characters AND entities. The + * "<" is threated as an ordinary character, but + * "<code>&name;</code>" still means the general entity with + * the given name. + */ + int RCDATA = 16; + + /** + * The SDATA constant. Means that the value contains the entity name + * and the replacement value of a character entity reference. + */ + int SDATA = 11; +} diff --git a/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java new file mode 100644 index 00000000000..c706f4d0f0b --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java @@ -0,0 +1,261 @@ +/* DocumentParser.java -- A parser for HTML documents. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; +import javax.swing.text.html.parser.Parser; + +import java.io.IOException; +import java.io.Reader; + +import javax.swing.text.BadLocationException; +import javax.swing.text.html.HTMLEditorKit; + +/** + * <p>A simple error-tolerant HTML parser that uses a DTD document + * to access data on the possible tokens, arguments and syntax.</p> + * <p> The parser reads an HTML content from a Reader and calls various + * notifying methods (which should be overridden in a subclass) + * when tags or data are encountered.</p> + * <p>Some HTML elements need no opening or closing tags. The + * task of this parser is to invoke the tag handling methods also when + * the tags are not explicitly specified and must be supposed using + * information, stored in the DTD. + * For example, parsing the document + * <p><table><tr><td>a<td>b<td>c</tr> <br> + * will invoke exactly the handling methods exactly in the same order + * (and with the same parameters) as if parsing the document: <br> + * <em><html><head></head><body><table>< + * tbody></em><tr><td>a<em></td></em><td>b<em> + * </td></em><td>c<em></td></tr></em>< + * <em>/tbody></table></body></html></em></p> + * (supposed tags are given in italics). The parser also supports + * obsolete elements of HTML syntax.<p> + * </p> + * In this implementation, DocumentParser is directly derived from its + * ancestor without changes of functionality. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DocumentParser + extends Parser + implements DTDConstants +{ + /** + * The enclosed working parser class. + */ + private class gnuParser + extends gnu.javax.swing.text.html.parser.support.Parser + { + private gnuParser(DTD d) + { + super(d); + } + + protected final void handleComment(char[] comment) + { + parser.handleComment(comment); + callBack.handleComment(comment, hTag.where.startPosition); + } + + protected final void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + parser.handleEmptyTag(tag); + callBack.handleSimpleTag(tag.getHTMLTag(), getAttributes(), + hTag.where.startPosition + ); + } + + protected final void handleEndTag(TagElement tag) + { + parser.handleEndTag(tag); + callBack.handleEndTag(tag.getHTMLTag(), hTag.where.startPosition); + } + + protected final void handleError(int line, String message) + { + parser.handleError(line, message); + callBack.handleError(message, hTag.where.startPosition); + } + + protected final void handleStartTag(TagElement tag) + { + parser.handleStartTag(tag); + htmlAttributeSet attributes = gnu.getAttributes(); + + if (tag.fictional()) + attributes.addAttribute(HTMLEditorKit.ParserCallback.IMPLIED, + Boolean.TRUE + ); + + callBack.handleStartTag(tag.getHTMLTag(), attributes, + hTag.where.startPosition + ); + } + + protected final void handleText(char[] text) + { + parser.handleText(text); + callBack.handleText(text, hTag.where.startPosition); + } + + DTD getDTD() + { + return dtd; + } + } + + /** + * This field is used to access the identically named + * methods of the outer class. + * This is package-private to avoid an accessor method. + */ + DocumentParser parser = this; + + /** + * The callback. + * This is package-private to avoid an accessor method. + */ + HTMLEditorKit.ParserCallback callBack; + + /** + * The reference to the working class of HTML parser that is + * actually used to parse the document. + * This is package-private to avoid an accessor method. + */ + gnuParser gnu; + + /** + * Creates a new parser that uses the given DTD to access data on the + * possible tokens, arguments and syntax. There is no single - step way + * to get a default DTD; you must either refer to the implementation - + * specific packages, write your own DTD or obtain the working instance + * of parser in other way, for example, by calling + * {@link javax.swing.text.html.HTMLEditorKit#getParser() }. + * @param a_dtd a DTD to use. + */ + public DocumentParser(DTD a_dtd) + { + super(a_dtd); + gnu = new gnuParser(a_dtd); + } + + /** + * Parses the HTML document, calling methods of the provided + * callback. This method must be multithread - safe. + * @param reader The reader to read the HTML document from + * @param callback The callback that is notifyed about the presence + * of HTML elements in the document. + * @param ignoreCharSet If thrue, any charset changes during parsing + * are ignored. + * @throws java.io.IOException + */ + public void parse(Reader reader, HTMLEditorKit.ParserCallback a_callback, + boolean ignoreCharSet + ) + throws IOException + { + callBack = a_callback; + gnu.parse(reader); + + callBack.handleEndOfLineString(gnu.getEndOfLineSequence()); + try + { + callBack.flush(); + } + catch (BadLocationException ex) + { + // Convert this into the supported type of exception. + throw new IOException(ex.getMessage()); + } + } + + /** + * Handle HTML comment. The default method returns without action. + * @param comment the comment being handled + */ + protected void handleComment(char[] comment) + { + } + + /** + * Handle the tag with no content, like <br>. The method is + * called for the elements that, in accordance with the current DTD, + * has an empty content. + * @param tag the tag being handled. + * @throws javax.swing.text.ChangedCharSetException + */ + protected void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + } + + /** + * The method is called when the HTML closing tag ((like </table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag being handled + */ + protected void handleEndTag(TagElement tag) + { + } + + /* Handle error that has occured in the given line. */ + protected void handleError(int line, String message) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag being handled + */ + protected void handleStartTag(TagElement tag) + { + } + + /** + * Handle the text section. + * @param text a section text. + */ + protected void handleText(char[] text) + { + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/Element.java b/libjava/classpath/javax/swing/text/html/parser/Element.java new file mode 100644 index 00000000000..f0a0f3303cb --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/Element.java @@ -0,0 +1,317 @@ +/* Element.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.support.gnuStringIntMapper; + +import java.io.Serializable; + +import java.util.BitSet; + +/** + * <p> + * Stores the element information, obtained by parsing SGML DTD + * tag <code><!ELEMENT .. ></code>. This class has no public + * constructor and can only be instantiated using the + * {@link javax.swing.text.html.parser.DTD } methods</p> + * + * <p>SGML defines elements that represent structures or + * behavior. An element typically consists of a start tag, content, and an + * end tag. Hence the elements are not tags. The HTML 4.0 definition specifies + * that some elements are not required to have the end tags. Also, some + * HTML elements (like <code><hr></code>) have no content. Element names + * are case sensitive.</p> + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public final class Element + implements DTDConstants, Serializable +{ + /** + * Package level mapper between type names and they string values. + */ + static final gnuStringIntMapper mapper = + new gnuStringIntMapper() + { + protected void create() + { + add("CDATA", DTDConstants.CDATA); + add("RCDATA", DTDConstants.RCDATA); + add("EMPTY", DTDConstants.EMPTY); + add("ANY", DTDConstants.ANY); + } + }; + + /** Use serialVersionUID for interoperability. */ + private static final long serialVersionUID = -6717939384601675586L; + + /** + * The element attributes. + */ + public AttributeList atts; + + /** + * Contains refernces to elements that must NOT occur inside this element, + * at any level of hierarchy. + */ + public BitSet exclusions; + + /** + * Contains refernces to elements that must CAN occur inside this element, + * at any level of hierarchy. + */ + public BitSet inclusions; + + /** + * The content model, defining elements, entities and DTD text + * that may/may not occur inside this element. + */ + public ContentModel content; + + /** + * A field to store additional user data for this Element. + */ + public Object data; + + /** + * The element name. + */ + public String name; + + /** + * True is this element need not to have the closing tag, false + * otherwise. The HTML 4.0 definition specifies + * that some elements (like <code><hr></code>are + * not required to have the end tags. + */ + public boolean oEnd; + + /** + * True is this element need not to have the starting tag, false + * otherwise. The HTML 4.0 definition specifies + * that some elements (like <code><head></code> or + * <code><body></code>) are + * not required to have the start tags. + + */ + public boolean oStart; + + /** + * This field contains the unique integer identifier of this Element, + * used to refer the element (more exactly, the element flag) + * in <code>inclusions</code> and <code>exclusions</code> bit set. + */ + public int index; + + /** + * The element type, containing value, defined in DTDConstants. + * In this implementation, the element type can be + * CDATA, RCDATA, EMPTY or ANY. + */ + public int type; + + /** + * The default constructor must have package level access in this + * class. Use DTD.defineElement(..) to create an element when required. + * @todo MAKE THIS PACKAGE in the final version. Now the Parser needs it! + */ + Element() + { + } + + /** + * Converts the string representation of the element type + * into its unique integer identifier, defined in DTDConstants. + * @param a_type A name of the type + * @return DTDConstants.CDATA, DTDConstants.RCDATA, DTDConstants.EMPTY, + * DTDConstants.ANY or null if the type name is not + * "CDATA", "RCDATA", "EMPTY" or "ANY". This function is case sensitive. + * @throws NullPointerException if <code>a_type</code> is null. + */ + public static int name2type(String a_type) + { + return mapper.get(a_type); + } + + /** + * Get the element attribute by name. + * @param attribute the attribute name, case insensitive. + * @return the correspoding attribute of this element. The class, + * for storing as attribute list, as a single attribute, is used to + * store a single attribute in this case. + * @throws NullPointerException if the attribute name is null. + */ + public AttributeList getAttribute(String attribute) + { + AttributeList a = atts; + + while (a != null && !attribute.equalsIgnoreCase(a.name)) + a = a.next; + + return a; + } + + /** + * Get the element attribute by its value. + * @param a_value the attribute value, case insensitive. + * @return the correspoding attribute of this element. The class, + * for storing as attribute list, as a single attribute, is used to + * store a single attribute in this case. If there are several + * attributes with the same value, there is no garranty, which one + * is returned. + */ + public AttributeList getAttributeByValue(String a_value) + { + AttributeList a = atts; + + if (a_value == null) + { + while (a != null) + { + if (a.value == null) + return a; + + a = a.next; + } + } + else + { + while (a != null) + { + if (a.value != null && a_value.equalsIgnoreCase(a.value)) + return a; + + a = a.next; + } + } + + return null; + } + + /** + * Get all attributes of this document as an attribute list. + * @return + */ + public AttributeList getAttributes() + { + return atts; + } + + /** + * Get the content model, defining elements, entities and DTD text + * that may/may not occur inside this element. + */ + public ContentModel getContent() + { + return content; + } + + /** + * Returns true for the element with no content. + * Empty elements are defined with the SGML DTD keyword "EMPTY". + * @return true if content model field (content) method is equal to + * null or its method empty() returns true. + */ + public boolean isEmpty() + { + return content == null || content.empty(); + } + + /** + * Get the unique integer identifier of this Element, + * used to refer the element (more exactly, the element flag) + * in <code>inclusions</code> and <code>exclusions</code> bit set. + * WARNING: This value may not be the same between different + * implementations. + */ + public int getIndex() + { + return index; + } + + /** + * Get the element name. + */ + public String getName() + { + return name; + } + + /** + * Get the element type. + * @return one of the values, defined DTDConstants. + * In this implementation, the element type can be + * CDATA, RCDATA, EMPTY or ANY. + */ + public int getType() + { + return type; + } + + /** + * True is this element need not to have the starting tag, false + * otherwise.s element need not to have the closing tag, false + * otherwise. The HTML 4.0 definition specifies + * that some elements (like <code><hr></code>are + * not required to have the end tags. + */ + public boolean omitEnd() + { + return oEnd; + } + + /** + * True is this element need not to have the closing tag, false + * otherwise. The HTML 4.0 definition specifies + * that some elements (like <code><head></code> or + * <code><body></code>) are + * not required to have the start tags. + */ + public boolean omitStart() + { + return oStart; + } + + /** + * Returns the name of this element. + */ + public String toString() + { + return name; + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/Entity.java b/libjava/classpath/javax/swing/text/html/parser/Entity.java new file mode 100644 index 00000000000..766984f9c79 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/Entity.java @@ -0,0 +1,185 @@ +/* Entity.java -- Stores information, obtained by parsing SGML DTL + * <!ENTITY % .. > tag + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.support.gnuStringIntMapper; + +import java.io.Serializable; + +/** + * <p>Stores information, obtained by parsing SGML DTL + * <!ENTITY % .. > tag.</p> + * <p> + * The entity defines some kind of macro that can be used elsewhere in + * the document. + * When the macro is referred to by the name in the DTD, it is expanded into + * a string + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public final class Entity + implements DTDConstants, Serializable +{ + /** + * Package level mapper between type names and they string values. + */ + final static gnuStringIntMapper mapper = + new gnuStringIntMapper() + { + protected void create() + { + add("ANY", DTDConstants.ANY); + add("CDATA", DTDConstants.CDATA); + add("PUBLIC", DTDConstants.PUBLIC); + add("SDATA", DTDConstants.SDATA); + add("PI", DTDConstants.PI); + add("STARTTAG", DTDConstants.STARTTAG); + add("ENDTAG", DTDConstants.ENDTAG); + add("MS", DTDConstants.MS); + add("MD", DTDConstants.MD); + add("SYSTEM", DTDConstants.SYSTEM); + } + }; + + /** + * The entity name. + */ + public String name; + + /** + * The entity data + */ + public char[] data; + + /** + * The entity type. + */ + public int type; + + /** + * String representation of the entity data. + */ + private String sdata; + + /** + * Create a new entity + * @param a_name the entity name + * @param a_type the entity type + * @param a_data the data replacing the entity reference + */ + public Entity(String a_name, int a_type, char[] a_data) + { + name = a_name; + type = a_type; + data = a_data; + } + + /** + * Converts a given string to the corresponding entity type. + * @return a value, defined in DTDConstants (one of + * PUBLIC, CDATA, SDATA, PI, STARTTAG, ENDTAG, MS, MD, SYSTEM) + * or CDATA if the parameter is not a valid entity type. + */ + public static int name2type(String an_entity) + { + int r = mapper.get(an_entity); + return (r == 0) ? DTDConstants.CDATA : r; + } + + /** + * Get the entity data. + */ + public char[] getData() + { + return data; + } + + /** + * Returns true for general entities. Each general entity can be + * referenced as <code>&entity-name;</code>. Such entities are + * defined by the SGML DTD tag + * <code><!ENTITY <i>name</i> "<i>value</i>"></code>. The general + * entities can be used anywhere in the document. + */ + public boolean isGeneral() + { + return (type & DTDConstants.GENERAL) != 0; + } + + /** + * Get the entity name. + */ + public String getName() + { + return name; + } + + /** + * Returns true for parameter entities. Each parameter entity can be + * referenced as <code>&entity-name;</code>. Such entities are + * defined by the SGML DTD tag + * <code><!ENTITY % <i>name</i> "<i>value</i>"></code>. The parameter + * entities can be used only in SGML context. + */ + public boolean isParameter() + { + return (type & DTDConstants.PARAMETER) != 0; + } + + /** + * Returns a data as String + */ + public String getString() + { + if (sdata == null) + sdata = new String(data); + + return sdata; + } + + /** + * Get the entity type. + * @return the value of the {@link #type}. + */ + public int getType() + { + return type; + } + +} diff --git a/libjava/classpath/javax/swing/text/html/parser/Parser.java b/libjava/classpath/javax/swing/text/html/parser/Parser.java new file mode 100644 index 00000000000..5867107cd45 --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/Parser.java @@ -0,0 +1,436 @@ +/* Parser.java -- HTML parser + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import java.io.IOException; +import java.io.Reader; + +import javax.swing.text.ChangedCharSetException; +import javax.swing.text.SimpleAttributeSet; + +/* + * FOR DEVELOPERS: To avoid regression, please run the package test + * textsuite/javax.swing.text.html.parser/AllParserTests after your + * modifications. + */ + +/** + * <p>A simple error-tolerant HTML parser that uses a DTD document + * to access data on the possible tokens, arguments and syntax.</p> + * <p> The parser reads an HTML content from a Reader and calls various + * notifying methods (which should be overridden in a subclass) + * when tags or data are encountered.</p> + * <p>Some HTML elements need no opening or closing tags. The + * task of this parser is to invoke the tag handling methods also when + * the tags are not explicitly specified and must be supposed using + * information, stored in the DTD. + * For example, parsing the document + * <p><table><tr><td>a<td>b<td>c</tr> <br> + * will invoke exactly the handling methods exactly in the same order + * (and with the same parameters) as if parsing the document: <br> + * <em><html><head></head><body><table>< + * tbody></em><tr><td>a<em></td></em><td>b<em> + * </td></em><td>c<em></td></tr></em>< + * <em>/tbody></table></body></html></em></p> + * (supposed tags are given in italics). The parser also supports + * obsolete elements of HTML syntax.<p> + * </p> + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Parser + implements DTDConstants +{ + /** + * The document template description that will be used to parse the documents. + */ + protected DTD dtd; + + /** + * The value of this field determines whether or not the Parser will be + * strict in enforcing SGML compatibility. The default value is false, + * stating that the parser should do everything to parse and get at least + * some information even from the incorrectly written HTML input. + */ + protected boolean strict; + + /** + * The package level reference to the working HTML parser in this + * implementation. + */ + final gnu.javax.swing.text.html.parser.support.Parser gnu; + + /** + * Creates a new parser that uses the given DTD to access data on the + * possible tokens, arguments and syntax. There is no single - step way + * to get a default DTD; you must either refer to the implementation - + * specific packages, write your own DTD or obtain the working instance + * of parser in other way, for example, by calling + * {@link javax.swing.text.html.HTMLEditorKit#getParser() }. + * @param a_dtd A DTD to use. + */ + public Parser(DTD a_dtd) + { + dtd = a_dtd; + + final Parser j = this; + + gnu = + new gnu.javax.swing.text.html.parser.support.Parser(dtd) + { + protected final void handleComment(char[] comment) + { + j.handleComment(comment); + } + + protected final void handleEOFInComment() + { + j.handleEOFInComment(); + } + + protected final void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + j.handleEmptyTag(tag); + } + + protected final void handleStartTag(TagElement tag) + { + j.handleStartTag(tag); + } + + protected final void handleEndTag(TagElement tag) + { + j.handleEndTag(tag); + } + + protected final void handleError(int line, String message) + { + j.handleError(line, message); + } + + protected final void handleText(char[] text) + { + j.handleText(text); + } + + protected final void handleTitle(char[] title) + { + j.handleTitle(title); + } + + protected final void markFirstTime(Element element) + { + j.markFirstTime(element); + } + + protected final void startTag(TagElement tag) + throws ChangedCharSetException + { + j.startTag(tag); + } + + protected final void endTag(boolean omitted) + { + j.endTag(omitted); + } + + protected TagElement makeTag(Element element) + { + return j.makeTag(element); + } + + protected TagElement makeTag(Element element, boolean isSupposed) + { + return j.makeTag(element, isSupposed); + } + }; + } + + /** + * Parse the HTML text, calling various methods in response to the + * occurence of the corresponding HTML constructions. + * @param reader The reader to read the source HTML from. + * @throws IOException If the reader throws one. + */ + public synchronized void parse(Reader reader) + throws IOException + { + gnu.parse(reader); + } + + /** + * Parses DTD markup declaration. Currently returns without action. + * @return null. + * @throws java.io.IOException + */ + public String parseDTDMarkup() + throws IOException + { + return gnu.parseDTDMarkup(); + } + + /** + * Parse DTD document declarations. Currently only parses the document + * type declaration markup. + * @param strBuff + * @return true if this is a valid DTD markup declaration. + * @throws IOException + */ + protected boolean parseMarkupDeclarations(StringBuffer strBuff) + throws IOException + { + return gnu.parseMarkupDeclarations(strBuff); + } + + /** + * Get the attributes of the current tag. + * @return The attribute set, representing the attributes of the current tag. + */ + protected SimpleAttributeSet getAttributes() + { + return gnu.getAttributes(); + } + + /** + * Get the number of the document line being parsed. + * @return The current line. + */ + protected int getCurrentLine() + { + return gnu.hTag.where.beginLine; + } + + /** + * Get the current position in the document being parsed. + * @return The current position. + */ + protected int getCurrentPos() + { + return gnu.hTag.where.startPosition; + } + + /** + * The method is called when the HTML end (closing) tag is found or if + * the parser concludes that the one should be present in the + * current position. The method is called immediatly + * before calling the handleEndTag(). + * @param omitted True if the tag is no actually present in the document, + * but is supposed by the parser (like </html> at the end of the + * document). + */ + protected void endTag(boolean omitted) + { + } + + /** + * Invokes the error handler. The default method in this implementation + * finally delegates the call to handleError, also providing the number of the + * current line. + */ + protected void error(String msg) + { + gnu.error(msg); + } + + /** + * Invokes the error handler. The default method in this implementation + * finally delegates the call to error (msg+": '"+invalid+"'"). + */ + protected void error(String msg, String invalid) + { + gnu.error(msg, invalid); + } + + /** + * Invokes the error handler. The default method in this implementation + * finally delegates the call to error (parm1+" "+ parm2+" "+ parm3). + */ + protected void error(String parm1, String parm2, String parm3) + { + gnu.error(parm1, parm2, parm3); + } + + /** + * Invokes the error handler. The default method in this implementation + * finally delegates the call to error + * (parm1+" "+ parm2+" "+ parm3+" "+ parm4). + */ + protected void error(String parm1, String parm2, String parm3, String parm4) + { + gnu.error(parm1, parm2, parm3, parm4); + } + + /** + * In this implementation, this is never called and returns without action. + */ + protected void flushAttributes() + { + gnu.flushAttributes(); + } + + /** + * Handle HTML comment. The default method returns without action. + * @param comment The comment being handled + */ + protected void handleComment(char[] comment) + { + } + + /** + * This is additionally called in when the HTML content terminates + * without closing the HTML comment. This can only happen if the + * HTML document contains errors (for example, the closing --;gt is + * missing. The default method calls the error handler. + */ + protected void handleEOFInComment() + { + gnu.error("Unclosed comment"); + } + + /** + * Handle the tag with no content, like <br>. The method is + * called for the elements that, in accordance with the current DTD, + * has an empty content. + * @param The tag being handled. + * @throws javax.swing.text.ChangedCharSetException + */ + protected void handleEmptyTag(TagElement tag) + throws ChangedCharSetException + { + } + + /** + * The method is called when the HTML closing tag ((like </table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag being handled + */ + protected void handleEndTag(TagElement tag) + { + } + + /* Handle error that has occured in the given line. */ + protected void handleError(int line, String message) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param The tag being handled + */ + protected void handleStartTag(TagElement tag) + { + } + + /** + * Handle the text section. + * <p> For non-preformatted section, the parser replaces + * \t, \r and \n by spaces and then multiple spaces + * by a single space. Additionaly, all whitespace around + * tags is discarded. + * </p> + * <p> For pre-formatted text (inside TEXAREA and PRE), the parser preserves + * all tabs and spaces, but removes <b>one</b> bounding \r, \n or \r\n, + * if it is present. Additionally, it replaces each occurence of \r or \r\n + * by a single \n.</p> + * + * @param text A section text. + */ + protected void handleText(char[] text) + { + } + + /** + * Handle HTML <title> tag. This method is invoked when + * both title starting and closing tags are already behind. + * The passed argument contains the concatenation of all + * title text sections. + * @param The title text. + */ + protected void handleTitle(char[] title) + { + } + + /** + * Constructs the tag from the given element. In this implementation, + * this is defined, but never called. + * @param element the base element of the tag. + * @return the tag + */ + protected TagElement makeTag(Element element) + { + return makeTag(element, false); + } + + /** + * Constructs the tag from the given element. + * @param the tag base {@link javax.swing.text.html.parser.Element} + * @param isSupposed true if the tag is not actually present in the + * html input, but the parser supposes that it should to occur in + * the current location. + * @return the tag + */ + protected TagElement makeTag(Element element, boolean isSupposed) + { + return new TagElement(element, isSupposed); + } + + /** + * This is called when the tag, representing the given element, + * occurs first time in the document. + * @param element + */ + protected void markFirstTime(Element element) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. The method is called immediately before + * calling the handleStartTag. + * @param The tag + */ + protected void startTag(TagElement tag) + throws ChangedCharSetException + { + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java new file mode 100644 index 00000000000..4b54e8a486c --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java @@ -0,0 +1,210 @@ +/* ParserDelegator.java -- Delegator for ParserDocument. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.HTML_401F; +import gnu.javax.swing.text.html.parser.htmlAttributeSet; + +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; + +import javax.swing.text.BadLocationException; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.HTMLEditorKit.ParserCallback; + +/** + * This class instantiates and starts the working instance of + * html parser, being responsible for providing the default DTD. + * + * TODO Later this class must be derived from the totally abstract class + * HTMLEditorKit.Parser. HTMLEditorKit that does not yet exist. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ParserDelegator + extends javax.swing.text.html.HTMLEditorKit.Parser + implements Serializable +{ + private class gnuParser + extends gnu.javax.swing.text.html.parser.support.Parser + { + private static final long serialVersionUID = 1; + + private gnuParser(DTD d) + { + super(d); + } + + protected final void handleComment(char[] comment) + { + callBack.handleComment(comment, hTag.where.startPosition); + } + + protected final void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + callBack.handleSimpleTag(tag.getHTMLTag(), getAttributes(), + hTag.where.startPosition + ); + } + + protected final void handleEndTag(TagElement tag) + { + callBack.handleEndTag(tag.getHTMLTag(), hTag.where.startPosition); + } + + protected final void handleError(int line, String message) + { + callBack.handleError(message, hTag.where.startPosition); + } + + protected final void handleStartTag(TagElement tag) + { + htmlAttributeSet attributes = gnu.getAttributes(); + + if (tag.fictional()) + attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE); + + callBack.handleStartTag(tag.getHTMLTag(), attributes, + hTag.where.startPosition + ); + } + + protected final void handleText(char[] text) + { + callBack.handleText(text, hTag.where.startPosition); + } + + DTD getDTD() + { + // Accessing the inherited gnu.javax.swing.text.html.parser.support.Parser + // field. super. is a workaround, required to support JDK1.3's javac. + return super.dtd; + } + } + + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = -1276686502624777206L; + + private static DTD dtd = HTML_401F.getInstance(); + + /** + * The callback. + * This is package-private to avoid an accessor method. + */ + HTMLEditorKit.ParserCallback callBack; + + /** + * The reference to the working class of HTML parser that is + * actually used to parse the document. + * This is package-private to avoid an accessor method. + */ + gnuParser gnu; + + /** + * Parses the HTML document, calling methods of the provided + * callback. This method must be multithread - safe. + * @param reader The reader to read the HTML document from + * @param callback The callback that is notifyed about the presence + * of HTML elements in the document. + * @param ignoreCharSet If thrue, any charset changes during parsing + * are ignored. + * @throws java.io.IOException + */ + public void parse(Reader reader, HTMLEditorKit.ParserCallback a_callback, + boolean ignoreCharSet + ) + throws IOException + { + callBack = a_callback; + + if (gnu == null || !dtd.equals(gnu.getDTD())) + { + gnu = new gnuParser(dtd); + } + + gnu.parse(reader); + + callBack.handleEndOfLineString(gnu.getEndOfLineSequence()); + try + { + callBack.flush(); + } + catch (BadLocationException ex) + { + // Convert this into the supported type of exception. + throw new IOException(ex.getMessage()); + } + } + + /** + * Calling this method instructs that, if not specified directly, + * the documents will be parsed using the default + * DTD of the implementation. + */ + protected static void setDefaultDTD() + { + dtd = HTML_401F.getInstance(); + } + + /** + * Registers the user - written DTD under the given name, also + * making it default for the subsequent parsings. This has effect on + * all subsequent calls to the parse(...) . If you need to specify + * your DTD locally, simply {@link javax.swing.text.html.parser.Parser} + * instead. + * @param dtd The DTD that will be used to parse documents by this class. + * @param name The name of this DTD. + * @return No standard is specified on which instance of DTD must be + * returned by this method, and it is recommended to leave the returned + * value without consideration. This implementation returns the DTD + * that was previously set as the default DTD, or the implementations + * default DTD if none was set. + */ + protected static DTD createDTD(DTD a_dtd, String name) + { + DTD.putDTDHash(name, a_dtd); + + DTD dtd_prev = dtd; + dtd = a_dtd; + return dtd_prev; + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/TagElement.java b/libjava/classpath/javax/swing/text/html/parser/TagElement.java new file mode 100644 index 00000000000..4558b15eb0a --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/TagElement.java @@ -0,0 +1,142 @@ +/* TagElement.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.html.parser; + +import javax.swing.text.html.HTML; + +/** + * The SGML element, defining a single html tag. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class TagElement +{ + /** + * The Element the tag was constructed from. + */ + private final Element element; + + /** + * The coresponding HTML tag, assigned once in constructor. + */ + private final HTML.Tag tag; + + /** + * The 'fictional' flag. + */ + private final boolean fictional; + + /** + * Creates the html tag element from the defintion, stored in the + * given element. Sets the flag 'fictional' to false. + * @param an_element + */ + public TagElement(Element an_element) + { + this(an_element, false); + } + + /** + * Creates the html tag element from the defintion, stored in the + * given element, setting the flag 'fictional' to the given value. + */ + public TagElement(Element an_element, boolean is_fictional) + { + element = an_element; + fictional = is_fictional; + + HTML.Tag t = HTML.getTag(element.getName()); + + if (t != null) + tag = t; + else + tag = new HTML.UnknownTag(element.getName()); + } + + /** + * Get the element from that the tag was constructed. + */ + public Element getElement() + { + return element; + } + + /** + * Get the corresponding HTML tag. This is either one of the + * pre-defined HTML tags or the instance of the UnknownTag with the + * element name. + */ + public HTML.Tag getHTMLTag() + { + return tag; + } + + /** + * Calls isPreformatted() for the corresponding html tag and returns + * the obtained value. + */ + public boolean isPreformatted() + { + return tag.isPreformatted(); + } + + /** + * Calls breaksFlow() for the corresponding html tag and returns + * the obtained value. + */ + public boolean breaksFlow() + { + return tag.breaksFlow(); + } + + /** + * Get the value of the flag 'fictional'. + */ + public boolean fictional() + { + return fictional; + } + + /** + * Returns string representation of this object. + */ + public String toString() + { + return getElement() + (fictional ? "?" : ""); + } +} diff --git a/libjava/classpath/javax/swing/text/html/parser/package.html b/libjava/classpath/javax/swing/text/html/parser/package.html new file mode 100644 index 00000000000..5d5157fb2ed --- /dev/null +++ b/libjava/classpath/javax/swing/text/html/parser/package.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.text.html package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.text.html.parser</title></head> + +<body> +<p> Provides the DTD driven for web browsers, + web robots, web page content analysers, web editors and + other applications applications working with Hypertext + Markup Language (HTML). +</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/text/package.html b/libjava/classpath/javax/swing/text/package.html new file mode 100644 index 00000000000..50043b6c4e8 --- /dev/null +++ b/libjava/classpath/javax/swing/text/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.text package. + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.text</title></head> + +<body> +<p></p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/text/rtf/ControlWordToken.java b/libjava/classpath/javax/swing/text/rtf/ControlWordToken.java new file mode 100644 index 00000000000..7008f0fd4a9 --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/ControlWordToken.java @@ -0,0 +1,86 @@ +/* ControlWordToken.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +/** + * A special {@link Token} that represents a control word in RTF like + * '\deff0' where 'deff' is the name of the control word and '0' is an + * optional parameter. + * + * @author Roman Kennke (roman@ontographics.com) + */ +class ControlWordToken extends Token +{ + + /** + * The name of the control word. + */ + public String name; + + /** + * The optional parameter of the control word. Absence of a parameter is + * expressed through Integer.MIN_VALUE. + */ + public int param; + + /** + * Constructs a new ControlWordToken with the specified name and without + * a parameter. + * + * @param name the name of the control word + */ + public ControlWordToken(String name) + { + this(name, Integer.MIN_VALUE); + } + + + /** + * Constructs a new ControlWordToken with the specified name and parameter. + * + * @param name the name of the control word + */ + public ControlWordToken(String name, int param) + { + super(Token.CONTROL_WORD); + this.name = name; + this.param = param; + } + +} diff --git a/libjava/classpath/javax/swing/text/rtf/RTFEditorKit.java b/libjava/classpath/javax/swing/text/rtf/RTFEditorKit.java new file mode 100644 index 00000000000..b2ebe3dd18c --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/RTFEditorKit.java @@ -0,0 +1,114 @@ +/* RTFEditorKit.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.StyledEditorKit; + +/** + * Provides support for RTF data for use in + * {@link javax.swing.JEditorPane}s. + * + * @author Roman Kennke (roman@ontographics.com) + */ +public class RTFEditorKit + extends StyledEditorKit +{ + + /** + * Constructs a new RTFEditorKit. + */ + public RTFEditorKit() + { + super(); + } + + /** + * Returns the MIME content type. In the case of RTFEditorKit this is + * 'text/rtf' + * + * @return the MIME content type for RTFEditorKit + */ + public String getContentType() + { + return "text/rtf"; + } + + /** + * Reads RTF data from <code>stream</code> into <code>doc</code> at the + * specified position <code>pos</code>. + * + * @param stream the {@link InputStream} from where we read RTF data + * @param doc the {@link Document} into which we read the RTF data + * @param pos the position where to start + * + * @throws IOException if an IO error occurs + * @throws BadLocationException if the position is not valid + */ + public void read(InputStream stream, Document doc, int pos) + throws IOException, BadLocationException + { + RTFParser parser = new RTFParser(stream, doc, pos); + parser.parse(); + } + + + /** + * Reads RTF data from <code>reader</code> into <code>doc</code> at the + * specified position <code>pos</code>. + * + * @param reader the {@link Reader} from where we read RTF data + * @param doc the {@link Document} into which we read the RTF data + * @param pos the position where to start + * + * @throws IOException if an IO error occurs + * @throws BadLocationException if the position is not valid + */ + public void read(Reader reader, Document doc, int pos) + throws IOException, BadLocationException + { + RTFParser parser = new RTFParser(reader, doc, pos); + parser.parse(); + } +} diff --git a/libjava/classpath/javax/swing/text/rtf/RTFParseException.java b/libjava/classpath/javax/swing/text/rtf/RTFParseException.java new file mode 100644 index 00000000000..2a9c64f05b8 --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/RTFParseException.java @@ -0,0 +1,65 @@ +/* RTFParseException.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +/** + * Indicates a parsing error during RTF processing. + * + * @author Roman Kennke (roman@ontographics.com) + */ +class RTFParseException + extends RuntimeException +{ + /** + * Constructs a new RTFParseException without message. + */ + public RTFParseException() + { + super(); + } + + /** + * Constructs a new RTFParseException with the specified message. + */ + public RTFParseException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/javax/swing/text/rtf/RTFParser.java b/libjava/classpath/javax/swing/text/rtf/RTFParser.java new file mode 100644 index 00000000000..4f0f967c117 --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/RTFParser.java @@ -0,0 +1,195 @@ +/* RTFParser.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +/** + * Parses an RTF file into a {@link Document}. The parser utilizes + * {@link RTFScanner}. + * + * @author Roman Kennke (roman@ontographics.com) + */ +class RTFParser +{ + + /** + * Our scanner. + */ + private RTFScanner scanner; + + /** + * The document into which we parse. + */ + private Document doc; + + /** + * The current position. + */ + private int pos; + + /** + * Constructs a new RTFParser for the specified document and position, + * without initializing the scanner. This is only used internally. + * + * @param doc the {@link Document} into which we should parse + * @param pos the position to start + */ + private RTFParser(Document doc, int pos) + { + this.doc = doc; + this.pos = pos; + } + + /** + * Constructs a new RTFParser for the specified <code>stream</code>. + * + * @param stream the stream from which we parse + * @param doc the {@link Document} into which we should parse + * @param pos the position to start + */ + public RTFParser(InputStream stream, Document doc, int pos) + { + this(doc, pos); + scanner = new RTFScanner(stream); + } + + /** + * Constructs a new RTFParser for the specified <code>reader</code>. + * + * @param reader the reader from which we parse + * @param doc the {@link Document} into which we should parse + * @param pos the position to start + */ + public RTFParser(Reader reader, Document doc, int pos) + { + this(doc, pos); + scanner = new RTFScanner(reader); + } + + /** + * Returns the {@link Document} in which we parsed the RTF data. + * + * @return the {@link Document} in which we parsed the RTF data + */ + public Document getDocument() + { + return doc; + } + + /** + * Starts the parsing process. + */ + public void parse() + throws IOException, BadLocationException + { + parseFile(); + } + + /** + * The parse rules for <file>. + */ + private void parseFile() + throws IOException, BadLocationException + { + Token t1 = scanner.readToken(); + if (t1.type != Token.LCURLY) + throw new RTFParseException("expected left curly braces"); + + parseHeader(); + parseDocument(); + + Token t2 = scanner.readToken(); + if (t2.type != Token.RCURLY) + throw new RTFParseException("expected right curly braces"); + + } + + /** + * The parse rules for <header>. + * + * TODO: implement this properly + */ + private void parseHeader() + //throws IOException, BadLocationException + { + // TODO add parse rules here + } + + + /** + * The parse rules for <document>. + * + * TODO: implement this properly + */ + private void parseDocument() + throws IOException, BadLocationException + { + // !!! TODO !!! + // This simply emits every TEXT Token as text to the document + // which is plain stupid + + boolean eof = false; + + do { + Token token = scanner.readToken(); + switch (token.type) + { + case Token.TEXT: + TextToken textToken = (TextToken) token; + doc.insertString(pos, textToken.text, null); + pos += textToken.text.length(); + break; + case Token.EOF: + eof = true; + break; + default: + // FIXME + break; + } + } while (!eof); + + } + +} diff --git a/libjava/classpath/javax/swing/text/rtf/RTFScanner.java b/libjava/classpath/javax/swing/text/rtf/RTFScanner.java new file mode 100644 index 00000000000..3cdd6e8e0b9 --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/RTFScanner.java @@ -0,0 +1,268 @@ +/* RTFScanner.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +/** + * Provides a scanner that scans an {@link InputStream} for tokens of the + * RTF syntax. + * + * This scanner is based upon the RTF specification 1.6 + * available at: + * + * <a + * href="http://msdn.microsoft.com/library/en-us/dnrtfspec/html/rtfspec.asp"> + * RTF specification at MSDN</a> + * + * @author Roman Kennke (roman@ontographics.com) + */ +class RTFScanner +{ + + /** + * The reader from which we read the RTF data. + */ + private Reader in; + + /** + * This is used to constuct strings from the read in chars. + */ + private StringBuffer buffer; + + /** + * Constructs a new RTFScanner without initializing the {@link Reader}. + */ + private RTFScanner() + { + buffer = new StringBuffer(); + } + + /** + * Constructs a new RTFScanner for the given {@link InputStream}. + * The stream is wrapped into an {@link InputStreamReader} and if it's + * not yet buffered then the Reader is wrapped in a {@link BufferedReader} + * + * @param stream the {@link InputStream} to read RTF data from + */ + public RTFScanner(InputStream stream) + { + this(); + InputStreamReader reader = new InputStreamReader(stream); + in = new BufferedReader(reader); + } + + /** + * Constructs a new RTFScanner for the given {@link Reader}. + * + * If the reader is not an instance of {@link BufferedReader} then it + * is wrapped into a BufferedReader. + * + * @param reader the {@link BufferedReader} to read RTF data from + */ + public RTFScanner(Reader reader) + { + this(); + if (reader instanceof BufferedReader) + { + in = reader; + } + else + { + in = new BufferedReader(reader); + } + } + + /** + * Reads in the next {@link Token} from the stream. + * + * @return the read {@link Token} + * + * @throws IOException if the underlying stream has problems + */ + public Token readToken() + throws IOException + { + Token token = null; + + int c = in.read(); + switch(c) + { + case -1: + token = new Token(Token.EOF); + break; + + case '{': + token = new Token(Token.LCURLY); + break; + + case '}': + token = new Token(Token.RCURLY); + break; + + case '\\': + buffer.delete(0, buffer.length()); + buffer.append((char) c); + token = readControlWord(); + break; + + default: + buffer.delete(0, buffer.length()); + buffer.append((char) c); + token = readText(); + break; + } + + return token; + } + + /** + * Reads in a control word and optional parameter. + * + * @return the read in control word as {@link ControlWordToken} + * + * @throws IOException if the underlying stream has problems + */ + private Token readControlWord() + throws IOException + { + // this flag indicates if we are still reading the name or are already + // in the parameter + boolean readingName = true; + String name = null; + String param = null; + + while (true) + { + in.mark(1); + int c = in.read(); + + // check for 'a'..'z' + if (readingName && (c >= 'a') && (c <= 'z')) + { + buffer.append((char) c); + } + else if ((c >= '0') && (c <= '9')) + { + // if the last char was in the name, then finish reading the name + if (readingName) + { + name = buffer.toString(); + buffer.delete(0, buffer.length()); + readingName = false; + } + buffer.append((char) c); + } + else + { + // if we were in the name, then finish this + if (readingName) + { + name = buffer.toString(); + } + // otherwise finish the parameter + else + { + param = buffer.toString(); + } + + // clear up + buffer.delete(0, buffer.length()); + // reset input buffer to last char + in.reset(); + // break while loop + break; + } + } + + ControlWordToken token = null; + + if (param == null) + token = new ControlWordToken(name); + else + token =new ControlWordToken(name, Integer.parseInt(param)); + + return token; + + } + + /** + * Reads in a block of text. + * + * @return the token for the text + */ + private Token readText() + throws IOException + { + + boolean readingText = true; + while (readingText) + { + in.mark(1); + int c = in.read(); + switch(c) + { + case '\\': + case '{': + case '}': + case -1: + readingText = false; + in.reset(); + break; + + default: + buffer.append((char) c); + break; + } + + } + + String text = buffer.toString(); + Token token = new TextToken(text); + + buffer.delete(0, buffer.length()); + + return token; + + } +} diff --git a/libjava/classpath/javax/swing/text/rtf/TextToken.java b/libjava/classpath/javax/swing/text/rtf/TextToken.java new file mode 100644 index 00000000000..2d6d527d132 --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/TextToken.java @@ -0,0 +1,65 @@ +/* TextToken.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +/** + * A special {@link Token} that represents a piece of text in RTF. + * + * @author Roman Kennke (roman@ontographics.com) + */ +class TextToken extends Token +{ + + /** + * The text. + */ + public String text; + + /** + * Constructs a new TextToken with the specified textual data. + * + * @param text the text for this token + */ + public TextToken(String text) + { + super(Token.TEXT); + this.text = text; + } + +} diff --git a/libjava/classpath/javax/swing/text/rtf/Token.java b/libjava/classpath/javax/swing/text/rtf/Token.java new file mode 100644 index 00000000000..7d5adaaf0bb --- /dev/null +++ b/libjava/classpath/javax/swing/text/rtf/Token.java @@ -0,0 +1,91 @@ +/* Token.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.text.rtf; + +/** + * Represents a simple token that the RTFScanner can read. A simple + * only has a type (like LCURLY or RCURLY). More complex tokens may + * attach data to the token. + * + * @author Roman Kennke (roman@ontographics.com) + */ +class Token +{ + + /** + * This special type inidicates the end of the input stream. + */ + public static final int EOF = -1; + + /** + * A left curly brace '{'. + */ + public static final int LCURLY = 1; + + /** + * A right curly brace '}'. + */ + public static final int RCURLY = 2; + + /** + * A control word like '\rtf1'. Tokens with this type are represented + * through the subclass {@link ControlWordToken}. + */ + public static final int CONTROL_WORD = 3; + + /** + * A token that contains text. This is represented through the subclass + * {@link TextToken}. + */ + public static final int TEXT = 4; + + + /** The token type. */ + public int type; + + /** + * Constructs a new Token with the specified type. + * + * @param type the Token type + */ + public Token(int type) + { + this.type = type; + } +} diff --git a/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java b/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java new file mode 100644 index 00000000000..9f8e9da5984 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/AbstractLayoutCache.java @@ -0,0 +1,409 @@ +/* AbstractLayoutCache.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.awt.Rectangle; +import java.util.Enumeration; + +import javax.swing.event.TreeModelEvent; + +/** + * class AbstractLayoutCache + * + * @author Andrew Selkirk + */ +public abstract class AbstractLayoutCache + implements RowMapper +{ + /** + * class NodeDimensions + */ + public abstract static class NodeDimensions + { + /** + * Creates <code>NodeDimensions</code> object. + */ + public NodeDimensions() + { + // Do nothing here. + } + + /** + * getNodeDimensions + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + * @param value3 TODO + * @param value4 TODO + * @return Rectangle + */ + public abstract Rectangle getNodeDimensions(Object value0, int value1, + int value2, boolean value3, Rectangle value4); + } + + /** + * nodeDimensions + */ + protected NodeDimensions nodeDimensions; + + /** + * treeModel + */ + protected TreeModel treeModel; + + /** + * treeSelectionModel + */ + protected TreeSelectionModel treeSelectionModel; + + /** + * rootVisible + */ + protected boolean rootVisible; + + /** + * rowHeight + */ + protected int rowHeight; + + /** + * Constructor AbstractLayoutCache + */ + public AbstractLayoutCache() + { + // Do nothing here. + } + + /** + * setNodeDimensions + * + * @param dimensions TODO + */ + public void setNodeDimensions(NodeDimensions dimensions) + { + nodeDimensions = dimensions; + } + + /** + * getNodeDimensions + * + * @return NodeDimensions + */ + public NodeDimensions getNodeDimensions() + { + return nodeDimensions; + } + + /** + * getNodeDimensions + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + * @param value3 TODO + * @param value4 TODO + * + * @return Rectangle + */ + protected Rectangle getNodeDimensions(Object value, int row, int depth, + boolean expanded, Rectangle bounds) + { + if (bounds == null) + return new Rectangle(); + return null; + // TODO + } + + /** + * Sets the model that provides the tree data. + * + * @param the model + */ + public void setModel(TreeModel model) + { + treeModel = model; + } + + /** + * Returns the model that provides the tree data. + * + * @return the model + */ + public TreeModel getModel() + { + return treeModel; + } + + /** + * setRootVisible + * + * @param visible <code>true</code> if root should be visible, + * <code>false</code> otherwise + */ + public void setRootVisible(boolean visible) + { + rootVisible = visible; + } + + /** + * isRootVisible + * + * @return <code>true</code> if root is visible, + * <code>false</code> otherwise + */ + public boolean isRootVisible() + { + return rootVisible; + } + + /** + * setRowHeight + * + * @param height the row height + */ + public void setRowHeight(int height) + { + rowHeight = height; + } + + /** + * getRowHeight + * + * @return the row height + */ + public int getRowHeight() + { + return rowHeight; + } + + /** + * setSelectionModel + * + * @param model the model + */ + public void setSelectionModel(TreeSelectionModel model) + { + treeSelectionModel = model; + } + + /** + * getSelectionModel + * + * @return the model + */ + public TreeSelectionModel getSelectionModel() + { + return treeSelectionModel; + } + + /** + * getPreferredHeight + * + * @return int + */ + public int getPreferredHeight() + { + return 0; // TODO + } + + /** + * getPreferredWidth + * + * @param value0 TODO + * + * @return int + */ + public int getPreferredWidth(Rectangle value0) + { + return 0; // TODO + } + + /** + * isExpanded + * + * @param value0 TODO + * + * @return boolean + */ + public abstract boolean isExpanded(TreePath value0); + + /** + * getBounds + * + * @param value0 TODO + * @param value1 TODO + * + * @return Rectangle + */ + public abstract Rectangle getBounds(TreePath value0, Rectangle value1); + + /** + * getPathForRow + * + * @param row the row + * + * @return the tree path + */ + public abstract TreePath getPathForRow(int row); + + /** + * getRowForPath + * + * @param path the tree path + * + * @return the row + */ + public abstract int getRowForPath(TreePath path); + + /** + * getPathClosestTo + * + * @param value0 TODO + * @param value1 TODO + * + * @return the tree path + */ + public abstract TreePath getPathClosestTo(int value0, int value1); + + /** + * getVisiblePathsFrom + * + * @param path the tree path + * + * @return Enumeration + */ + public abstract Enumeration getVisiblePathsFrom(TreePath path); + + /** + * getVisibleChildCount + * + * @param path the tree path + * + * @return int + */ + public abstract int getVisibleChildCount(TreePath value0); + + /** + * setExpandedState + * + * @param value0 TODO + * + * @param value1 TODO + */ + public abstract void setExpandedState(TreePath value0, boolean value1); + + /** + * getExpandedState + * + * @param path the tree path + * + * @return boolean + */ + public abstract boolean getExpandedState(TreePath path); + + /** + * getRowCount + * + * @return the number of rows + */ + public abstract int getRowCount(); + + /** + * invalidateSizes + */ + public abstract void invalidateSizes(); + + /** + * invalidatePathBounds + * + * @param path the tree path + */ + public abstract void invalidatePathBounds(TreePath path); + + /** + * treeNodesChanged + * + * @param event the event to send + */ + public abstract void treeNodesChanged(TreeModelEvent event); + + /** + * treeNodesInserted + * + * @param event the event to send + */ + public abstract void treeNodesInserted(TreeModelEvent event); + + /** + * treeNodesRemoved + * + * @param event the event to send + */ + public abstract void treeNodesRemoved(TreeModelEvent event); + + /** + * treeStructureChanged + * + * @param event the event to send + */ + public abstract void treeStructureChanged(TreeModelEvent event); + + /** + * getRowsForPaths + * + * @param paths the tree paths + * + * @return an array of rows + */ + public int[] getRowsForPaths(TreePath[] paths) + { + return null; // TODO + } + + /** + * isFixedRowHeight + * + * @return boolean + */ + protected boolean isFixedRowHeight() + { + return false; // TODO + } +} diff --git a/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java b/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java new file mode 100644 index 00000000000..e709e2a0449 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/DefaultMutableTreeNode.java @@ -0,0 +1,1112 @@ +/* DefaultMutableTreeNode.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import gnu.java.util.EmptyEnumeration; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.NoSuchElementException; +import java.util.Stack; +import java.util.Vector; + + +/** + * DefaultMutableTreeNode + * + * @author Andrew Selkirk + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class DefaultMutableTreeNode + implements Cloneable, MutableTreeNode, Serializable +{ + private static final long serialVersionUID = -4298474751201349152L; + + /** + * EMPTY_ENUMERATION + */ + public static final Enumeration EMPTY_ENUMERATION = + EmptyEnumeration.getInstance(); + + /** + * parent + */ + protected MutableTreeNode parent; + + /** + * children + */ + protected Vector children = new Vector(); + + /** + * userObject + */ + protected transient Object userObject; + + /** + * allowsChildren + */ + protected boolean allowsChildren; + + /** + * Creates a <code>DefaultMutableTreeNode</code> object. + * This node allows to add child nodes. + */ + public DefaultMutableTreeNode() + { + this(null, true); + } + + /** + * Creates a <code>DefaultMutableTreeNode</code> object with the given + * user object attached to it. This node allows to add child nodes. + * + * @param userObject the user object + */ + public DefaultMutableTreeNode(Object userObject) + { + this(userObject, true); + } + + /** + * Creates a <code>DefaultMutableTreeNode</code> object with the given + * user object attached to it. + * + * @param userObject the user object + * @param allowsChildren <code>true</code> if the code allows to add child + * nodes, <code>false</code> otherwise + */ + public DefaultMutableTreeNode(Object userObject, boolean allowsChildren) + { + this.userObject = userObject; + this.allowsChildren = allowsChildren; + } + + /** + * clone + * + * @return Object + */ + public Object clone() + { + try + { + return super.clone(); + // TODO: Do we need to do more here ? + } + catch (CloneNotSupportedException e) + { + // This never happens. + return null; + } + } + + /** + * Returns a string representation of this node + * + * @return a human-readable String representing this node + */ + public String toString() + { + if (userObject == null) + return null; + + return userObject.toString(); + } + + /** + * Adds a new child node to this node. + * + * @param child the child node + * + * @throws IllegalArgumentException if <code>child</code> is null + * @throws IllegalStateException if the node does not allow children + */ + public void add(MutableTreeNode child) + { + if (child == null) + throw new IllegalArgumentException(); + + if (! allowsChildren) + throw new IllegalStateException(); + + children.add(child); + child.setParent(this); + } + + /** + * Returns the parent node of this node. + * + * @return the parent node + */ + public TreeNode getParent() + { + return parent; + } + + /** + * Removes the child with the given index from this node + * + * @param index the index + */ + public void remove(int index) + { + children.remove(index); + } + + /** + * Removes the given child from this node. + * + * @param node the child node + */ + public void remove(MutableTreeNode node) + { + children.remove(node); + } + + /** + * writeObject + * + * @param stream the output stream + * + * @exception IOException If an error occurs + */ + private void writeObject(ObjectOutputStream stream) + throws IOException + { + // TODO: Implement me. + } + + /** + * readObject + * + * @param stream the input stream + * + * @exception IOException If an error occurs + * @exception ClassNotFoundException TODO + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + // TODO: Implement me. + } + + /** + * Inserts given child node at the given index. + * + * @param node the child node + * @param index the index. + */ + public void insert(MutableTreeNode node, int index) + { + children.insertElementAt(node, index); + } + + /** + * Returns a path to this node from the root. + * + * @return an array of tree nodes + */ + public TreeNode[] getPath() + { + return getPathToRoot(this, 0); + } + + /** + * Returns an enumeration containing all children of this node. + * <code>EMPTY_ENUMERATION</code> is returned if this node has no children. + * + * @return an enumeration of tree nodes + */ + public Enumeration children() + { + if (children.size() == 0) + return EMPTY_ENUMERATION; + + return children.elements(); + } + + /** + * Set the parent node for this node. + * + * @param node the parent node + */ + public void setParent(MutableTreeNode node) + { + parent = node; + } + + /** + * Returns the child node at a given index. + * + * @param index the index + * + * @return the child node + */ + public TreeNode getChildAt(int index) + { + return (TreeNode) children.elementAt(index); + } + + /** + * Returns the number of children of this node. + * + * @return the number of children + */ + public int getChildCount() + { + return children.size(); + } + + /** + * Returns the child index for a given node. + * + * @param node this node + * + * @return the index + */ + public int getIndex(TreeNode node) + { + return children.indexOf(node); + } + + /** + * setAllowsChildren + * + * @param allowsChildren TODO + */ + public void setAllowsChildren(boolean allowsChildren) + { + this.allowsChildren = allowsChildren; + } + + /** + * getAllowsChildren + * + * @return boolean + */ + public boolean getAllowsChildren() + { + return allowsChildren; + } + + /** + * Sets the user object for this node + * + * @param userObject the user object + */ + public void setUserObject(Object userObject) + { + this.userObject = userObject; + } + + /** + * Returns the user object attached to this node. <code>null</code> is + * returned when no user object is set. + * + * @return the user object + */ + public Object getUserObject() + { + return userObject; + } + + /** + * Removes this node from its parent. + */ + public void removeFromParent() + { + parent.remove(this); + parent = null; + } + + /** + * Removes all child nodes from this node. + */ + public void removeAllChildren() + { + children.removeAllElements(); + } + + /** + * isNodeAncestor + * + * @param node TODO + * + * @return boolean + */ + public boolean isNodeAncestor(TreeNode node) + { + if (node == null) + return false; + + TreeNode current = this; + + while (current != null + && current != node) + current = current.getParent(); + + return current == node; + } + + /** + * isNodeDescendant + * + * @param node TODO + * + * @return boolean + */ + public boolean isNodeDescendant(DefaultMutableTreeNode node) + { + if (node == null) + return false; + + TreeNode current = node; + + while (current != null + && current != this) + current = current.getParent(); + + return current == this; + } + + /** + * getSharedAncestor + * + * @param node TODO + * + * @return TreeNode + */ + public TreeNode getSharedAncestor(DefaultMutableTreeNode node) + { + TreeNode current = this; + ArrayList list = new ArrayList(); + + while (current != null) + { + list.add(current); + current = current.getParent(); + } + + current = node; + + while (current != null) + { + if (list.contains(current)) + return current; + + current = current.getParent(); + } + + return null; + } + + /** + * isNodeRelated + * + * @param node TODO + * + * @return boolean + */ + public boolean isNodeRelated(DefaultMutableTreeNode node) + { + if (node == null) + return false; + + return node.getRoot() == getRoot(); + } + + /** + * getDepth + * + * @return int + */ + public int getDepth() + { + if ((! allowsChildren) + || children.size() == 0) + return 0; + + Stack stack = new Stack(); + stack.push(new Integer(0)); + TreeNode node = getChildAt(0); + int depth = 0; + int current = 1; + + while (! stack.empty()) + { + if (node.getChildCount() != 0) + { + node = node.getChildAt(0); + stack.push(new Integer(0)); + current++; + } + else + { + if (current > depth) + depth = current; + + int size; + int index; + + do + { + node = node.getParent(); + size = node.getChildCount(); + index = ((Integer) stack.pop()).intValue() + 1; + current--; + } + while (index >= size + && node != this); + + if (index < size) + { + node = node.getChildAt(index); + stack.push(new Integer(index)); + current++; + } + } + } + + return depth; + } + + /** + * getLevel + * + * @return int + */ + public int getLevel() + { + int count = -1; + TreeNode current = this; + + do + { + current = current.getParent(); + count++; + } + while (current != null); + + return count; + } + + /** + * getPathToRoot + * + * @param node TODO + * @param depth TODO + * + * @return TreeNode[] + */ + protected TreeNode[] getPathToRoot(TreeNode node, int depth) + { + if (node == null) + { + if (depth == 0) + return null; + + return new TreeNode[depth]; + } + + TreeNode[] path = getPathToRoot(node.getParent(), depth + 1); + path[path.length - depth - 1] = node; + return path; + } + + /** + * getUserObjectPath + * + * @return Object[] + */ + public Object[] getUserObjectPath() + { + TreeNode[] path = getPathToRoot(this, 0); + Object[] object = new Object[path.length]; + + for (int index = 0; index < path.length; ++index) + object[index] = ((DefaultMutableTreeNode) path[index]).getUserObject(); + + return object; + } + + /** + * Returns the root node by iterating the parents of this node. + * + * @return the root node + */ + public TreeNode getRoot() + { + TreeNode current = this; + TreeNode check = current.getParent(); + + while (check != null) + { + current = check; + check = current.getParent(); + } + + return current; + } + + /** + * Tells whether this node is the root node or not. + * + * @return <code>true</code> if this is the root node, + * <code>false</code>otherwise + */ + public boolean isRoot() + { + return parent == null; + } + + /** + * getNextNode + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getNextNode() + { + // Return first child. + if (getChildCount() != 0) + return (DefaultMutableTreeNode) getChildAt(0); + + // Return next sibling (if needed the sibling of some parent). + DefaultMutableTreeNode node = this; + DefaultMutableTreeNode sibling; + + do + { + sibling = node.getNextSibling(); + node = (DefaultMutableTreeNode) node.getParent(); + } + while (sibling == null && + node != null); + + // Return sibling. + return sibling; + } + + /** + * getPreviousNode + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getPreviousNode() + { + // Return null if no parent. + if (parent == null) + return null; + + DefaultMutableTreeNode sibling = getPreviousSibling(); + + // Return parent if no sibling. + if (sibling == null) + return (DefaultMutableTreeNode) parent; + + // Return last leaf of sibling. + if (sibling.getChildCount() != 0) + return sibling.getLastLeaf(); + + // Return sibling. + return sibling; + } + + /** + * preorderEnumeration + * + * @return Enumeration + */ + public Enumeration preorderEnumeration() + { + return new PreorderEnumeration(this); + } + + /** + * postorderEnumeration + * + * @return Enumeration + */ + public Enumeration postorderEnumeration() + { + return new PostorderEnumeration(this); + } + + /** + * breadthFirstEnumeration + * + * @return Enumeration + */ + public Enumeration breadthFirstEnumeration() + { + return new BreadthFirstEnumeration(this); + } + + /** + * depthFirstEnumeration + * + * @return Enumeration + */ + public Enumeration depthFirstEnumeration() + { + return postorderEnumeration(); + } + + /** + * pathFromAncestorEnumeration + * + * @param node TODO + * + * @return Enumeration + */ + public Enumeration pathFromAncestorEnumeration(TreeNode node) + { + if (node == null) + throw new IllegalArgumentException(); + + TreeNode parent = this; + Vector nodes = new Vector(); + nodes.add(this); + + while (parent != node && parent != null) + { + parent = parent.getParent(); + nodes.add(0, parent); + } + + if (parent != node) + throw new IllegalArgumentException(); + + return nodes.elements(); + } + + /** + * isNodeChild + * + * @param node TODO + * + * @return boolean + */ + public boolean isNodeChild(TreeNode node) + { + if (node == null) + return false; + + return node.getParent() == this; + } + + /** + * getFirstChild + * + * @return TreeNode + */ + public TreeNode getFirstChild() + { + return (TreeNode) children.firstElement(); + } + + /** + * getLastChild + * + * @return TreeNode + */ + public TreeNode getLastChild() + { + return (TreeNode) children.lastElement(); + } + + /** + * getChildAfter + * + * @param node TODO + * + * @return TreeNode + */ + public TreeNode getChildAfter(TreeNode node) + { + if (node == null + || node.getParent() != this) + throw new IllegalArgumentException(); + + int index = getIndex(node) + 1; + + if (index == getChildCount()) + return null; + + return getChildAt(index); + } + + /** + * getChildBefore + * + * @param node TODO + * + * @return TreeNode + */ + public TreeNode getChildBefore(TreeNode node) + { + if (node == null + || node.getParent() != this) + throw new IllegalArgumentException(); + + int index = getIndex(node) - 1; + + if (index < 0) + return null; + + return getChildAt(index); + } + + /** + * isNodeSibling + * + * @param node TODO + * + * @return boolean + */ + public boolean isNodeSibling(TreeNode node) + { + if (node == null) + return false; + + return (node.getParent() == getParent() + && getParent() != null); + } + + /** + * getSiblingCount + * + * @return int + */ + public int getSiblingCount() + { + if (parent == null) + return 1; + + return parent.getChildCount(); + } + + /** + * getNextSibling + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getNextSibling() + { + if (parent == null) + return null; + + int index = parent.getIndex(this) + 1; + + if (index == parent.getChildCount()) + return null; + + return (DefaultMutableTreeNode) parent.getChildAt(index); + } + + /** + * getPreviousSibling + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getPreviousSibling() + { + if (parent == null) + return null; + + int index = parent.getIndex(this) - 1; + + if (index < 0) + return null; + + return (DefaultMutableTreeNode) parent.getChildAt(index); + } + + /** + * isLeaf + * + * @return boolean + */ + public boolean isLeaf() + { + return children.size() == 0; + } + + /** + * getFirstLeaf + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getFirstLeaf() + { + TreeNode current = this; + + while (current.getChildCount() > 0) + current = current.getChildAt(0); + + return (DefaultMutableTreeNode) current; + } + + /** + * getLastLeaf + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getLastLeaf() + { + TreeNode current = this; + int size = current.getChildCount(); + + while (size > 0) + { + current = current.getChildAt(size - 1); + size = current.getChildCount(); + } + + return (DefaultMutableTreeNode) current; + } + + /** + * getNextLeaf + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getNextLeaf() + { + if (parent == null) + return null; + + // TODO: Fix implementation. + return null; + //return parent.getChildAfter(this); + } + + /** + * getPreviousLeaf + * + * @return DefaultMutableTreeNode + */ + public DefaultMutableTreeNode getPreviousLeaf() + { + if (parent == null) + return null; + + // TODO: Fix implementation. + return null; + //return parent.getChildBefore(this); + } + + /** + * getLeafCount + * + * @return int + */ + public int getLeafCount() + { + int count = 0; + Enumeration e = depthFirstEnumeration(); + + while (e.hasMoreElements()) + { + TreeNode current = (TreeNode) e.nextElement(); + + if (current.isLeaf()) + count++; + } + + return count; + } + + /** Provides an enumeration of a tree in breadth-first traversal + * order. + */ + static class BreadthFirstEnumeration implements Enumeration + { + + LinkedList queue = new LinkedList(); + + BreadthFirstEnumeration(TreeNode node) + { + queue.add(node); + } + + public boolean hasMoreElements() + { + return !queue.isEmpty(); + } + + public Object nextElement() + { + if(queue.isEmpty()) + throw new NoSuchElementException("No more elements left."); + + TreeNode node = (TreeNode) queue.removeFirst(); + + Enumeration children = node.children(); + while (children.hasMoreElements()) + queue.add(children.nextElement()); + + return node; + } + } + + /** Provides an enumeration of a tree traversing it + * preordered. + */ + static class PreorderEnumeration implements Enumeration + { + TreeNode next; + + Stack childrenEnums = new Stack(); + + PreorderEnumeration(TreeNode node) + { + next = node; + childrenEnums.push(node.children()); + } + + public boolean hasMoreElements() + { + return next != null; + } + + public Object nextElement() + { + if( next == null ) + throw new NoSuchElementException("No more elements left."); + + Object current = next; + + Enumeration children = (Enumeration) childrenEnums.peek(); + + // Retrieves the next element. + next = traverse(children); + + return current; + } + + private TreeNode traverse(Enumeration children) + { + // If more children are available step down. + if( children.hasMoreElements() ) + { + TreeNode child = (TreeNode) children.nextElement(); + childrenEnums.push(child.children()); + + return child; + } + + // If no children are left, we return to a higher level. + childrenEnums.pop(); + + // If there are no more levels left, there is no next + // element to return. + if ( childrenEnums.isEmpty() ) + return null; + else + { + return traverse((Enumeration) childrenEnums.peek()); + } + } + } + + /** Provides an enumeration of a tree traversing it + * postordered (= depth-first). + */ + static class PostorderEnumeration implements Enumeration + { + + Stack nodes = new Stack(); + Stack childrenEnums = new Stack(); + + PostorderEnumeration(TreeNode node) + { + nodes.push(node); + childrenEnums.push(node.children()); + } + + public boolean hasMoreElements() + { + return !nodes.isEmpty(); + } + + public Object nextElement() + { + if( nodes.isEmpty() ) + throw new NoSuchElementException("No more elements left!"); + + Enumeration children = (Enumeration) childrenEnums.peek(); + + return traverse(children); + } + + private Object traverse(Enumeration children) + { + if ( children.hasMoreElements() ) + { + TreeNode node = (TreeNode) children.nextElement(); + nodes.push(node); + + Enumeration newChildren = node.children(); + childrenEnums.push(newChildren); + + return traverse(newChildren); + } + else + { + childrenEnums.pop(); + + // Returns the node whose children + // have all been visited. (= postorder) + Object next = nodes.peek(); + nodes.pop(); + + return next; + } + } + + } + +} diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java new file mode 100644 index 00000000000..e509d2c18e0 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellEditor.java @@ -0,0 +1,516 @@ +/* DefaultTreeCellEditor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.EventObject; + +import javax.swing.Icon; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.border.Border; +import javax.swing.event.CellEditorListener; +import javax.swing.event.EventListenerList; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +/** + * DefaultTreeCellEditor + * @author Andrew Selkirk + */ +public class DefaultTreeCellEditor + implements ActionListener, TreeCellEditor, TreeSelectionListener +{ + /** + * EditorContainer + */ + public class EditorContainer extends Container + { + /** + * Creates an <code>EditorContainer</code> object. + */ + public EditorContainer() + { + // Do nothing here. + } + + /** + * This method only exists for API compatibility and is useless as it does + * nothing. It got probably introduced by accident. + */ + public void EditorContainer() + { + // Do nothing here. + } + + /** + * getPreferredSize + * @return Dimension + */ + public Dimension getPreferredSize() + { + return null; // TODO + } + + /** + * paint + * @param value0 TODO + */ + public void paint(Graphics value0) + { + // TODO + } + + /** + * doLayout + */ + public void doLayout() + { + // TODO + } + } + + /** + * DefaultTextField + */ + public class DefaultTextField extends JTextField + { + /** + * border + */ + protected Border border; + + /** + * Creates a <code>DefaultTextField</code> object. + * + * @param border the border to use + */ + public DefaultTextField(Border border) + { + this.border = border; + } + + /** + * getFont + * @return Font + */ + public Font getFont() + { + return null; // TODO + } + + /** + * Returns the border of the text field. + * + * @return the border + */ + public Border getBorder() + { + return border; + } + + /** + * getPreferredSize + * @return Dimension + */ + public Dimension getPreferredSize() + { + return null; // TODO + } + } + + private EventListenerList listenerList = new EventListenerList(); + + /** + * realEditor + */ + protected TreeCellEditor realEditor; + + /** + * renderer + */ + protected DefaultTreeCellRenderer renderer; + + /** + * editingContainer + */ + protected Container editingContainer; + + /** + * editingComponent + */ + protected transient Component editingComponent; + + /** + * canEdit + */ + protected boolean canEdit; + + /** + * offset + */ + protected transient int offset; + + /** + * tree + */ + protected transient JTree tree; + + /** + * lastPath + */ + protected transient TreePath lastPath; + + /** + * timer + */ + protected transient javax.swing.Timer timer; // TODO + + /** + * lastRow + */ + protected transient int lastRow; + + /** + * borderSelectionColor + */ + protected Color borderSelectionColor; + + /** + * editingIcon + */ + protected transient Icon editingIcon; + + /** + * font + */ + protected Font font; + + /** + * Constructor DefaultTreeCellEditor + * @param value0 TODO + * @param value1 TODO + */ + public DefaultTreeCellEditor(JTree value0, DefaultTreeCellRenderer value1) + { + // TODO + } + + /** + * Constructor DefaultTreeCellEditor + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public DefaultTreeCellEditor(JTree value0, DefaultTreeCellRenderer value1, + TreeCellEditor value2) + { + // TODO + } + + /** + * writeObject + * @param value0 TODO + * @exception IOException TODO + */ + private void writeObject(ObjectOutputStream value0) throws IOException + { + // TODO + } + + /** + * readObject + * @param value0 TODO + * @exception IOException TODO + * @exception ClassNotFoundException TODO + */ + private void readObject(ObjectInputStream value0) + throws IOException, ClassNotFoundException + { + // TODO + } + + /** + * setBorderSelectionColor + * @param value0 TODO + */ + public void setBorderSelectionColor(Color value0) + { + // TODO + } + + /** + * getBorderSelectionColor + * @return Color + */ + public Color getBorderSelectionColor() + { + return null; // TODO + } + + /** + * setFont + * @param value0 TODO + */ + public void setFont(Font value0) + { + // TODO + } + + /** + * getFont + * @return Font + */ + public Font getFont() + { + return null; // TODO + } + + /** + * getTreeCellEditorComponent + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + * @param value3 TODO + * @param value4 TODO + * @param value5 TODO + * @return Component + */ + public Component getTreeCellEditorComponent(JTree value0, Object value1, + boolean value2, boolean value3, + boolean value4, int value5) + { + return null; // TODO + } + + /** + * getCellEditorValue + * @return Object + */ + public Object getCellEditorValue() + { + return null; // TODO + } + + /** + * isCellEditable + * @param value0 TODO + * @return boolean + */ + public boolean isCellEditable(EventObject value0) + { + return false; // TODO + } + + /** + * shouldSelectCell + * @param value0 TODO + * @return boolean + */ + public boolean shouldSelectCell(EventObject value0) + { + return false; // TODO + } + + /** + * stopCellEditing + * @return boolean + */ + public boolean stopCellEditing() + { + return false; // TODO + } + + /** + * cancelCellEditing + */ + public void cancelCellEditing() + { + // TODO + } + + /** + * Adds a <code>CellEditorListener</code> object to this editor. + * + * @param listener the listener to add + */ + public void addCellEditorListener(CellEditorListener listener) + { + listenerList.add(CellEditorListener.class, listener); + } + + /** + * Removes a <code>CellEditorListener</code> object. + * + * @param listener the listener to remove + */ + public void removeCellEditorListener(CellEditorListener listener) + { + listenerList.remove(CellEditorListener.class, listener); + } + + /** + * Returns all added <code>CellEditorListener</code> objects to this editor. + * + * @return an array of listeners + * + * @since 1.4 + */ + public CellEditorListener[] getCellEditorListeners() + { + return (CellEditorListener[]) listenerList.getListeners(CellEditorListener.class); + } + + /** + * valueChanged + * @param value0 TODO + */ + public void valueChanged(TreeSelectionEvent value0) + { + // TODO + } + + /** + * actionPerformed + * @param value0 TODO + */ + public void actionPerformed(ActionEvent value0) + { + // TODO + } + + /** + * setTree + * @param value0 TODO + */ + protected void setTree(JTree value0) + { + // TODO + } + + /** + * shouldStartEditingTimer + * @param value0 TODO + * @return boolean + */ + protected boolean shouldStartEditingTimer(EventObject value0) + { + return false; // TODO + } + + /** + * startEditingTimer + */ + protected void startEditingTimer() + { + // TODO + } + + /** + * canEditImmediately + * @param value0 TODO + * @return boolean + */ + protected boolean canEditImmediately(EventObject value0) + { + return false; // TODO + } + + /** + * inHitRegion + * @param value0 TODO + * @param value1 TODO + * @return boolean + */ + protected boolean inHitRegion(int value0, int value1) + { + return false; // TODO + } + + /** + * determineOffset + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + * @param value3 TODO + * @param value4 TODO + * @param value5 TODO + */ + protected void determineOffset(JTree value0, Object value1, boolean value2, + boolean value3, boolean value4, int value5) + { + // TODO + } + + /** + * prepareForEditing + */ + protected void prepareForEditing() + { + // TODO + } + + /** + * createContainer + * @return Container + */ + protected Container createContainer() + { + return null; // TODO + } + + /** + * createTreeCellEditor + * @return TreeCellEditor + */ + protected TreeCellEditor createTreeCellEditor() + { + return null; // TODO + } +} diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java b/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java new file mode 100644 index 00000000000..db69c605554 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/DefaultTreeCellRenderer.java @@ -0,0 +1,591 @@ +/* DefaultTreeCellRenderer.java + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.tree; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JTree; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.plaf.UIResource; + +/** + * DefaultTreeCellRenderer + * + * @author Andrew Selkirk + */ +public class DefaultTreeCellRenderer + extends JLabel + implements TreeCellRenderer +{ + // ------------------------------------------------------------- + // Variables -------------------------------------------------- + // ------------------------------------------------------------- + + /** + * selected + */ + protected boolean selected; + + /** + * hasFocus + */ + protected boolean hasFocus; + + /** + * drawsFocusBorderAroundIcon + */ + private boolean drawsFocusBorderAroundIcon; + + /** + * closedIcon + */ + protected transient Icon closedIcon; + + /** + * leafIcon + */ + protected transient Icon leafIcon; + + /** + * openIcon + */ + protected transient Icon openIcon; + + /** + * textSelectionColor + */ + protected Color textSelectionColor; + + /** + * textNonSelectionColor + */ + protected Color textNonSelectionColor; + + /** + * backgroundSelectionColor + */ + protected Color backgroundSelectionColor; + + /** + * backgroundNonSelectionColor + */ + protected Color backgroundNonSelectionColor; + + /** + * borderSelectionColor + */ + protected Color borderSelectionColor; + + + // ------------------------------------------------------------- + // Initialization --------------------------------------------- + // ------------------------------------------------------------- + + /** + * Constructor DefaultTreeCellRenderer + */ + public DefaultTreeCellRenderer() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + setLeafIcon(getDefaultLeafIcon()); + setOpenIcon(getDefaultOpenIcon()); + setClosedIcon(getDefaultClosedIcon()); + + setTextNonSelectionColor(defaults.getColor("Tree.textForeground")); + setTextSelectionColor(defaults.getColor("Tree.selectionForeground")); + setBackgroundNonSelectionColor(defaults + .getColor("Tree.nonSelectionBackground")); + setBackgroundSelectionColor(defaults + .getColor("Tree.selectionBackground")); + setBorderSelectionColor(defaults + .getColor("Tree.selectionBorderColor")); + } + + // ------------------------------------------------------------- + // Methods ---------------------------------------------------- + // ------------------------------------------------------------- + + /** + * getDefaultOpenIcon + * + * @returns Icon + */ + public Icon getDefaultOpenIcon() + { + return UIManager.getLookAndFeelDefaults().getIcon("Tree.openIcon"); + } + + /** + * getDefaultClosedIcon + * + * @returns Icon + */ + public Icon getDefaultClosedIcon() + { + return UIManager.getLookAndFeelDefaults().getIcon("Tree.closedIcon"); + } + + /** + * getDefaultLeafIcon + * + * @returns Icon + */ + public Icon getDefaultLeafIcon() + { + return UIManager.getLookAndFeelDefaults().getIcon("Tree.leafIcon"); + } + + /** + * setOpenIcon + * + * @param value0 TODO + */ + public void setOpenIcon(Icon i) + { + openIcon = i; + } + + /** + * getOpenIcon + * + * @returns Icon + */ + public Icon getOpenIcon() + { + return openIcon; + } + + /** + * setClosedIcon + * + * @param value0 TODO + */ + public void setClosedIcon(Icon i) + { + closedIcon = i; + } + + /** + * getClosedIcon + * + * @returns Icon + */ + public Icon getClosedIcon() + { + return closedIcon; + } + + /** + * setLeafIcon + * + * @param value0 TODO + */ + public void setLeafIcon(Icon i) + { + leafIcon = i; + } + + /** + * getLeafIcon + * + * @returns Icon + */ + public Icon getLeafIcon() + { + return leafIcon; + } + + /** + * setTextSelectionColor + * + * @param value0 TODO + */ + public void setTextSelectionColor(Color c) + { + textSelectionColor = c; + } + + /** + * getTextSelectionColor + * + * @returns Color + */ + public Color getTextSelectionColor() + { + return textSelectionColor; + } + + /** + * setTextNonSelectionColor + * + * @param value0 TODO + */ + public void setTextNonSelectionColor(Color c) + { + textNonSelectionColor = c; + } + + /** + * getTextNonSelectionColor + * + * @returns Color + */ + public Color getTextNonSelectionColor() + { + return textNonSelectionColor; + } + + /** + * setBackgroundSelectionColor + * + * @param value0 TODO + */ + public void setBackgroundSelectionColor(Color c) + { + backgroundSelectionColor = c; + } + + /** + * getBackgroundSelectionColor + * + * @returns Color + */ + public Color getBackgroundSelectionColor() + { + return backgroundSelectionColor; + } + + /** + * setBackgroundNonSelectionColor + * + * @param value0 TODO + */ + public void setBackgroundNonSelectionColor(Color c) + { + backgroundNonSelectionColor = c; + } + + /** + * getBackgroundNonSelectionColor + * + * @returns Color + */ + public Color getBackgroundNonSelectionColor() + { + return backgroundNonSelectionColor; + } + + /** + * setBorderSelectionColor + * + * @param value0 TODO + */ + public void setBorderSelectionColor(Color c) + { + borderSelectionColor = c; + } + + /** + * getBorderSelectionColor + * + * @returns Color + */ + public Color getBorderSelectionColor() + { + return borderSelectionColor; + } + + /** + * setFont + * + * @param value0 TODO + */ + public void setFont(Font f) + { + if (f != null && f instanceof UIResource) + f = null; + super.setFont(f); + } + + /** + * setBackground + * + * @param value0 TODO + */ + public void setBackground(Color c) + { + if (c != null && c instanceof UIResource) + c = null; + super.setBackground(c); + } + + /** + * getTreeCellRendererComponent + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + * @param value3 TODO + * @param value4 TODO + * @param value5 TODO + * @param value6 TODO + * @returns Component + */ + public Component getTreeCellRendererComponent(JTree tree, Object val, + boolean selected, boolean expanded, boolean leaf, int row, + boolean hasFocus) + { + if (val instanceof Icon) + setIcon((Icon) val); + else + { + setText(val.toString()); + setIcon(null); + this.selected = selected; + this.hasFocus = hasFocus; + setHorizontalAlignment(LEFT); + setOpaque(true); + setVerticalAlignment(TOP); + setEnabled(true); + super.setFont(UIManager.getLookAndFeelDefaults().getFont("Tree.font")); + } + + if (selected) + { + super.setBackground(getBackgroundSelectionColor()); + setForeground(getTextSelectionColor()); + } + else + { + super.setBackground(getBackgroundNonSelectionColor()); + setForeground(getTextNonSelectionColor()); + } + + return this; + } + + /** + * getFont + * + * @return the current Font + */ + public Font getFont() + { + return super.getFont(); + } + + /** + * paint + * + * @param value0 TODO + */ + public void paint(Graphics g) + { + super.paint(g); + } + + /** + * getPreferredSize + * + * @returns Dimension + */ + public Dimension getPreferredSize() + { + return null; // TODO + } // getPreferredSize() + + /** + * validate + */ + public void validate() + { + // Overridden for performance reasons. + } // validate() + + /** + * revalidate + */ + public void revalidate() + { + // Overridden for performance reasons. + } // revalidate() + + /** + * repaint + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + * @param value3 TODO + * @param value4 TODO + */ + public void repaint(long value0, int value1, int value2, int value3, + int value4) + { + // Overridden for performance reasons. + } // repaint() + + /** + * repaint + * + * @param value0 TODO + */ + public void repaint(Rectangle value0) + { + // Overridden for performance reasons. + } // repaint() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + protected void firePropertyChange(String value0, Object value1, + Object value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, byte value1, byte value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, char value1, char value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, short value1, short value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, int value1, int value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, long value1, long value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, float value1, float value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, double value1, double value2) + { + // Overridden for performance reasons. + } // firePropertyChange() + + /** + * firePropertyChange + * + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void firePropertyChange(String value0, boolean v1, boolean v2) + { + // Overridden for performance reasons. + } // firePropertyChange() + +} // DefaultTreeCellRenderer diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeModel.java b/libjava/classpath/javax/swing/tree/DefaultTreeModel.java new file mode 100644 index 00000000000..3278ffadc77 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/DefaultTreeModel.java @@ -0,0 +1,455 @@ +/* DefaultTreeModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.EventListener; + +import javax.swing.event.EventListenerList; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.tree.DefaultMutableTreeNode; + +/** + * DefaultTreeModel + * @author Andrew Selkirk + */ +public class DefaultTreeModel + implements Serializable, TreeModel +{ + static final long serialVersionUID = -2621068368932566998L; + + /** + * root + */ + protected TreeNode root = null; + + /** + * listenerList + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * asksAllowsChildren + */ + protected boolean asksAllowsChildren; + + /** + * Constructor DefaultTreeModel + * @param value0 TODO + */ + public DefaultTreeModel(TreeNode root) + { + if (root == null) + root = new DefaultMutableTreeNode(); + setRoot(root); + } + + /** + * Constructor DefaultTreeModel + * @param value0 TODO + * @param value1 TODO + */ + public DefaultTreeModel(TreeNode root, boolean asksAllowsChildren) + { + setRoot(root); + this.asksAllowsChildren = asksAllowsChildren; + } + + /** + * writeObject + * @param value0 TODO + * @exception IOException TODO + */ + private void writeObject(ObjectOutputStream value0) throws IOException + { + // TODO + } + + /** + * readObject + * @param value0 TODO + * @exception IOException TODO + * @exception ClassNotFoundException TODO + */ + private void readObject(ObjectInputStream value0) throws IOException, + ClassNotFoundException + { + // TODO + } + + /** + * asksAllowsChildren + * @return boolean + */ + public boolean asksAllowsChildren() + { + return asksAllowsChildren; + } + + /** + * setAsksAllowsChildren + * @param value0 TODO + */ + public void setAsksAllowsChildren(boolean value) + { + asksAllowsChildren = value; // TODO + } + + /** + * setRoot + * @param value0 TODO + */ + public void setRoot(TreeNode root) + { + // Sanity Check + if (root == null) + { + throw new IllegalArgumentException("null root"); + } + // Set new root + this.root = root; + + // TODO + } + + /** + * getRoot + * @return Object + */ + public Object getRoot() + { + return root; + } + + /** + * getIndexOfChild + * @param value0 TODO + * @param value1 TODO + * @return int + */ + public int getIndexOfChild(Object parent, Object child) + { + return 0; // TODO + } + + /** + * getChild + * @param value0 TODO + * @param value1 TODO + * @return Object + */ + public Object getChild(Object node, int idx) + { + if (node instanceof TreeNode) + return ((TreeNode) node).getChildAt(idx); + else + return null; + } + + /** + * getChildCount + * @param value0 TODO + * @return int + */ + public int getChildCount(Object node) + { + if (node instanceof TreeNode) + return ((TreeNode) node).getChildCount(); + else + return 0; + } + + /** + * isLeaf + * @param value0 TODO + * @return boolean + */ + public boolean isLeaf(Object node) + { + if (node instanceof TreeNode) + return ((TreeNode) node).isLeaf(); + else + return true; + } + + /** + * reload + */ + public void reload() + { + // TODO + } + + /** + * reload + * @param value0 TODO + */ + public void reload(TreeNode value0) + { + // TODO + } + + /** + * valueForPathChanged + * @param value0 TODO + * @param value1 TODO + */ + public void valueForPathChanged(TreePath value0, Object value1) + { + // TODO + } + + /** + * insertNodeInto + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void insertNodeInto(MutableTreeNode value0, MutableTreeNode value1, + int value2) + { + // TODO + } + + /** + * removeNodeFromParent + * @param value0 TODO + */ + public void removeNodeFromParent(MutableTreeNode value0) + { + // TODO + } + + /** + * nodeChanged + * @param value0 TODO + */ + public void nodeChanged(TreeNode value0) + { + // TODO + } + + /** + * nodesWereInserted + * @param value0 TODO + * @param value1 TODO + */ + public void nodesWereInserted(TreeNode value0, int[] value1) + { + // TODO + } + + /** + * nodesWereRemoved + * @param value0 TODO + * @param value1 TODO + * @param value2 TODO + */ + public void nodesWereRemoved(TreeNode value0, int[] value1, Object[] value2) + { + // TODO + } + + /** + * nodesChanged + * @param value0 TODO + * @param value1 TODO + */ + public void nodesChanged(TreeNode value0, int[] value1) + { + // TODO + } + + /** + * nodeStructureChanged + * @param value0 TODO + */ + public void nodeStructureChanged(TreeNode value0) + { + // TODO + } + + /** + * getPathToRoot + * @param value0 TODO + * @return TreeNode[] + */ + public TreeNode[] getPathToRoot(TreeNode value0) + { + return null; // TODO + } + + /** + * getPathToRoot + * @param value0 TODO + * @param value1 TODO + * @return TreeNode[] + */ + protected TreeNode[] getPathToRoot(TreeNode value0, int value1) + { + return null; // TODO + } + + /** + * Registers a listere to the model. + * + * @param listener the listener to add + */ + public void addTreeModelListener(TreeModelListener listener) + { + listenerList.add(TreeModelListener.class, listener); + } + + /** + * Removes a listener from the model. + * + * @param listener the listener to remove + */ + public void removeTreeModelListener(TreeModelListener listener) + { + listenerList.remove(TreeModelListener.class, listener); + } + + /** + * Returns all registered <code>TreeModelListener</code> listeners. + * + * @return an array of listeners. + * + * @since 1.4 + */ + public TreeModelListener[] getTreeModelListeners() + { + return (TreeModelListener[]) listenerList + .getListeners(TreeModelListener.class); + } + + /** + * fireTreeNodesChanged + * + * @param source the node being changed + * @param path the path to the root node + * @param childIndices the indices of the changed elements + * @param children the changed elements + */ + protected void fireTreeNodesChanged(Object source, Object[] path, + int[] childIndices, Object[] children) + { + TreeModelEvent event = new TreeModelEvent(source, path, childIndices, + children); + TreeModelListener[] listeners = getTreeModelListeners(); + + for (int i = listeners.length - 1; i >= 0; --i) + listeners[i].treeNodesChanged(event); + } + + /** + * fireTreeNodesInserted + * + * @param source the node where new nodes got inserted + * @param path the path to the root node + * @param childIndices the indices of the new elements + * @param children the new elements + */ + protected void fireTreeNodesInserted(Object source, Object[] path, + int[] childIndices, Object[] children) + { + TreeModelEvent event = new TreeModelEvent(source, path, childIndices, + children); + TreeModelListener[] listeners = getTreeModelListeners(); + + for (int i = listeners.length - 1; i >= 0; --i) + listeners[i].treeNodesInserted(event); + } + + /** + * fireTreeNodesRemoved + * + * @param source the node where nodes got removed- + * @param path the path to the root node + * @param childIndices the indices of the removed elements + * @param children the removed elements + */ + protected void fireTreeNodesRemoved(Object source, Object[] path, + int[] childIndices, Object[] children) + { + TreeModelEvent event = new TreeModelEvent(source, path, childIndices, + children); + TreeModelListener[] listeners = getTreeModelListeners(); + + for (int i = listeners.length - 1; i >= 0; --i) + listeners[i].treeNodesRemoved(event); + } + + /** + * fireTreeStructureChanged + * + * @param source the node where the model has changed + * @param path the path to the root node + * @param childIndices the indices of the affected elements + * @param children the affected elements + */ + protected void fireTreeStructureChanged(Object source, Object[] path, + int[] childIndices, Object[] children) + { + TreeModelEvent event = new TreeModelEvent(source, path, childIndices, + children); + TreeModelListener[] listeners = getTreeModelListeners(); + + for (int i = listeners.length - 1; i >= 0; --i) + listeners[i].treeStructureChanged(event); + } + + /** + * Returns the registered listeners of a given type. + * + * @param listenerType the listener type to return + * + * @return an array of listeners + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } +} diff --git a/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java new file mode 100644 index 00000000000..de27dad04f9 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/DefaultTreeSelectionModel.java @@ -0,0 +1,754 @@ +/* DefaultTreeSelectionModel.java + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.tree; + +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.EventListener; +import java.util.Vector; + +import javax.swing.DefaultListSelectionModel; +import javax.swing.event.EventListenerList; +import javax.swing.event.SwingPropertyChangeSupport; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; + +/** + * DefaultTreeSelectionModel + * + * @author Andrew Selkirk + */ +public class DefaultTreeSelectionModel + implements Cloneable, Serializable, TreeSelectionModel +{ + static final long serialVersionUID = 3288129636638950196L; + + /** + * SELECTION_MODE_PROPERTY + */ + public static final String SELECTION_MODE_PROPERTY = "selectionMode"; + + /** + * Our Swing property change support. + */ + protected SwingPropertyChangeSupport changeSupport; + + /** + * The current selection. + */ + protected TreePath[] selection; + + /** + * Our TreeSelectionListeners. + */ + protected EventListenerList listenerList; + + /** + * The current RowMapper. + */ + protected transient RowMapper rowMapper; + + /** + * The current listSelectionModel. + */ + protected DefaultListSelectionModel listSelectionModel; + + /** + * The current selection mode. + */ + protected int selectionMode; + + /** + * The path that has been added last. + */ + protected TreePath leadPath; + + /** + * The index of the last added path. + */ + protected int leadIndex; + + /** + * The row of the last added path according to the RowMapper. + */ + protected int leadRow; + + /** + * Constructs a new DefaultTreeSelectionModel. + */ + public DefaultTreeSelectionModel() + { + setSelectionMode(DISCONTIGUOUS_TREE_SELECTION); + listenerList = new EventListenerList(); + } + + /** + * Creates a clone of this DefaultTreeSelectionModel with the same + * selection. + * + * @exception CloneNotSupportedException should not be thrown here + * + * @return a clone of this DefaultTreeSelectionModel + */ + public Object clone() throws CloneNotSupportedException + { + return null; // TODO + } + + /** + * Returns a string that shows this object's properties. + * + * @return a string that shows this object's properties + */ + public String toString() + { + return null; // TODO + } + + /** + * writeObject + * + * @param value0 TODO + * @exception IOException TODO + */ + private void writeObject(ObjectOutputStream value0) throws IOException + { + // TODO + } + + /** + * readObject + * + * @param value0 TODO + * @exception IOException TODO + * @exception ClassNotFoundException TODO + */ + private void readObject(ObjectInputStream value0) throws IOException, + ClassNotFoundException + { + // TODO + } + + /** + * Sets the RowMapper that should be used to map between paths and their + * rows. + * + * @param rowMapper the RowMapper to set + * + * @see RowMapper + */ + public void setRowMapper(RowMapper rowMapper) + { + // TODO + } + + /** + * Returns the RowMapper that is currently used to map between paths and + * their rows. + * + * @return the current RowMapper + * + * @see RowMapper + */ + public RowMapper getRowMapper() + { + return rowMapper; + } + + /** + * Sets the current selection mode. Possible values are + * {@link #SINGLE_TREE_SELECTION}, {@link #CONTIGUOUS_TREE_SELECTION} and + * {@link #DISCONTIGUOUS_TREE_SELECTION}. + * + * @param mode the selection mode to be set + * + * @see #getSelectionMode + * @see #SINGLE_TREE_SELECTION + * @see #CONTIGUOUS_TREE_SELECTION + * @see #DISCONTIGUOUS_TREE_SELECTION + */ + public void setSelectionMode(int mode) + { + selectionMode = mode; + } + + /** + * Returns the current selection mode. + * + * @return the current selection mode + * + * @see #setSelectionMode + * @see #SINGLE_TREE_SELECTION + * @see #CONTIGUOUS_TREE_SELECTION + * @see #DISCONTIGUOUS_TREE_SELECTION + */ + public int getSelectionMode() + { + return selectionMode; + } + + /** + * Sets this path as the only selection. + * + * If this changes the selection the registered TreeSelectionListeners are + * notified. + * + * @param path the path to set as selection + */ + public void setSelectionPath(TreePath path) + { + selection = new TreePath[] { + path }; + } + + /** + * Sets the paths as selection. This method checks for duplicates and + * removes them. + * + * If this changes the selection the registered TreeSelectionListeners are + * notified. + * + * @param paths the paths to set as selection + */ + public void setSelectionPaths(TreePath[] paths) + { + // TODO + } + + /** + * Adds a path to the list of selected paths. This method checks if the path + * is already selected and doesn't add the same path twice. + * + * If this changes the selection the registered TreeSelectionListeners are + * notified. + * + * @param path the path to add to the selection + */ + public void addSelectionPath(TreePath path) + { + if (!isPathSelected(path)) + { + if (isSelectionEmpty()) + setSelectionPath(path); + else + { + TreePath[] temp = new TreePath[selection.length + 1]; + System.arraycopy(selection, 0, temp, 0, selection.length); + temp[temp.length - 1] = path; + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + } + leadPath = path; + fireValueChanged(new TreeSelectionEvent(this, path, true, + leadPath, path)); + } + } + + /** + * Adds the paths to the list of selected paths. This method checks if the + * paths are already selected and doesn't add the same path twice. + * + * If this changes the selection the registered TreeSelectionListeners are + * notified. + * + * @param paths the paths to add to the selection + */ + public void addSelectionPaths(TreePath[] paths) + { + if (paths != null) + { + TreePath v0 = null; + for (int i = 0; i < paths.length; i++) + { + v0 = paths[i]; + if (!isPathSelected(v0)) + { + if (isSelectionEmpty()) + setSelectionPath(v0); + else + { + TreePath[] temp = new TreePath[selection.length + 1]; + System.arraycopy(selection, 0, temp, 0, + selection.length); + temp[temp.length - 1] = v0; + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + } + leadPath = paths[paths.length - 1]; + fireValueChanged(new TreeSelectionEvent(this, v0, true, + leadPath, paths[0])); + } + } + } + } + + /** + * Removes the path from the selection. + * + * If this changes the selection the registered TreeSelectionListeners are + * notified. + * + * @param path the path to remove + */ + public void removeSelectionPath(TreePath path) + { + int index = -1; + if (isPathSelected(path)) + { + for (int i = 0; i < selection.length; i++) + { + if (selection[i].equals(path)) + { + index = i; + break; + } + } + TreePath[] temp = new TreePath[selection.length - 1]; + System.arraycopy(selection, 0, temp, 0, index); + System.arraycopy(selection, index + 1, temp, index, + selection.length - index - 1); + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + + fireValueChanged(new TreeSelectionEvent(this, path, false, + leadPath, path)); + } + } + + /** + * Removes the paths from the selection. + * + * If this changes the selection the registered TreeSelectionListeners are + * notified. + * + * @param paths the paths to remove + */ + public void removeSelectionPaths(TreePath[] paths) + { + if (paths != null) + { + int index = -1; + TreePath v0 = null; + for (int i = 0; i < paths.length; i++) + { + v0 = paths[i]; + if (isPathSelected(v0)) + { + for (int x = 0; x < selection.length; x++) + { + if (selection[i].equals(v0)) + { + index = x; + break; + } + } + TreePath[] temp = new TreePath[selection.length - 1]; + System.arraycopy(selection, 0, temp, 0, index); + System.arraycopy(selection, index + 1, temp, index, + selection.length - index - 1); + selection = new TreePath[temp.length]; + System.arraycopy(temp, 0, selection, 0, temp.length); + + fireValueChanged(new TreeSelectionEvent(this, v0, false, + leadPath, paths[0])); + } + } + } + } + + /** + * Returns the first path in the selection. This is especially useful when + * the selectionMode is {@link #SINGLE_TREE_SELECTION}. + * + * @return the first path in the selection + */ + public TreePath getSelectionPath() + { + if ((selection == null) || (selection.length == 0)) + return null; + else + return selection[0]; + } + + /** + * Returns the complete selection. + * + * @return the complete selection + */ + public TreePath[] getSelectionPaths() + { + return selection; + } + + /** + * Returns the number of paths in the selection. + * + * @return the number of paths in the selection + */ + public int getSelectionCount() + { + if (selection == null) + return 0; + else + return selection.length; + } + + /** + * Checks if a given path is in the selection. + * + * @param path the path to check + * + * @return <code>true</code> if the path is in the selection, + * <code>false</code> otherwise + */ + public boolean isPathSelected(TreePath path) + { + if (selection == null) + return false; + + for (int i = 0; i < selection.length; i++) + { + if (selection[i].equals(path)) + return true; + } + return false; + } + + /** + * Checks if the selection is empty. + * + * @return <code>true</code> if the selection is empty, <code>false</code> + * otherwise + */ + public boolean isSelectionEmpty() + { + return ((selection == null) || (selection.length == 0)); + } + + /** + * Removes all paths from the selection. + */ + public void clearSelection() + { + leadPath = null; + selection = null; + } + + /** + * Adds a <code>TreeSelectionListener</code> object to this model. + * + * @param listener the listener to add + */ + public void addTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.add(TreeSelectionListener.class, listener); + } + + /** + * Removes a <code>TreeSelectionListener</code> object from this model. + * + * @param listener the listener to remove + */ + public void removeTreeSelectionListener(TreeSelectionListener listener) + { + listenerList.remove(TreeSelectionListener.class, listener); + } + + /** + * Returns all <code>TreeSelectionListener</code> added to this model. + * + * @return an array of listeners + * + * @since 1.4 + */ + public TreeSelectionListener[] getTreeSelectionListeners() + { + return (TreeSelectionListener[]) + getListeners(TreeSelectionListener.class); + } + + /** + * fireValueChanged + * + * @param event the event to fire. + */ + protected void fireValueChanged(TreeSelectionEvent event) + { + TreeSelectionListener[] listeners = getTreeSelectionListeners(); + + for (int i = 0; i < listeners.length; ++i) + listeners[i].valueChanged(event); + } + + /** + * Returns all added listeners of a special type. + * + * @param listenerType the listener type + * + * @return an array of listeners + * + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) + { + return listenerList.getListeners(listenerType); + } + + /** + * Returns the currently selected rows. + * + * @return the currently selected rows + */ + public int[] getSelectionRows() + { + if (rowMapper == null) + return null; + else + return rowMapper.getRowsForPaths(selection); + } + + /** + * Returns the smallest row index from the selection. + * + * @return the smallest row index from the selection + */ + public int getMinSelectionRow() + { + if ((rowMapper == null) || (selection == null) + || (selection.length == 0)) + return -1; + else + { + int[] rows = rowMapper.getRowsForPaths(selection); + int minRow = Integer.MAX_VALUE; + for (int index = 0; index < rows.length; index++) + minRow = Math.min(minRow, rows[index]); + return minRow; + } + } + + /** + * Returns the largest row index from the selection. + * + * @return the largest row index from the selection + */ + public int getMaxSelectionRow() + { + if ((rowMapper == null) || (selection == null) + || (selection.length == 0)) + return -1; + else + { + int[] rows = rowMapper.getRowsForPaths(selection); + int maxRow = -1; + for (int index = 0; index < rows.length; index++) + maxRow = Math.max(maxRow, rows[index]); + return maxRow; + } + } + + /** + * Checks if a particular row is selected. + * + * @param row the index of the row to check + * + * @return <code>true</code> if the row is in this selection, + * <code>false</code> otherwise + */ + public boolean isRowSelected(int row) + { + return false; // TODO + } + + /** + * Updates the mappings from TreePaths to row indices. + */ + public void resetRowSelection() + { + // TODO + } + + /** + * getLeadSelectionRow + * + * @return int + */ + public int getLeadSelectionRow() + { + if ((rowMapper == null) || (leadPath == null)) + return -1; + else + return rowMapper.getRowsForPaths(new TreePath[] { + leadPath })[0]; + } + + /** + * getLeadSelectionPath + * + * @return TreePath + */ + public TreePath getLeadSelectionPath() + { + return leadPath; + } + + /** + * Adds a <code>PropertyChangeListener</code> object to this model. + * + * @param listener the listener to add. + */ + public void addPropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.addPropertyChangeListener(listener); + } + + /** + * Removes a <code>PropertyChangeListener</code> object from this model. + * + * @param listener the listener to remove. + */ + public void removePropertyChangeListener(PropertyChangeListener listener) + { + changeSupport.removePropertyChangeListener(listener); + } + + /** + * Returns all added <code>PropertyChangeListener</code> objects. + * + * @return an array of listeners. + * + * @since 1.4 + */ + public PropertyChangeListener[] getPropertyChangeListeners() + { + return changeSupport.getPropertyChangeListeners(); + } + + /** + * Makes sure the currently selected paths are valid according to the + * current selectionMode. + * + * If the selectionMode is set to {@link #CONTIGUOUS_TREE_SELECTION} and the + * selection isn't contiguous then the selection is reset to the first set + * of contguous paths. + * + * If the selectionMode is set to {@link #SINGLE_TREE_SELECTION} and the + * selection has more than one path, the selection is reset to the contain + * only the first path. + */ + protected void insureRowContinuity() + { + // TODO + } + + /** + * Returns <code>true</code> if the paths are contiguous or we have no + * RowMapper assigned. + * + * @param paths the paths to check for continuity + * @return <code>true</code> if the paths are contiguous or we have no + * RowMapper assigned + */ + protected boolean arePathsContiguous(TreePath[] paths) + { + return false; // TODO + } + + /** + * Checks if the paths can be added. This returns <code>true</code> if: + * <ul> + * <li><code>paths</code> is <code>null</code> or empty</li> + * <li>we have no RowMapper assigned</li> + * <li>nothing is currently selected</li> + * <li>selectionMode is {@link #DISCONTIGUOUS_TREE_SELECTION}</li> + * <li>adding the paths to the selection still results in a contiguous set + * of paths</li> + * + * @param paths the paths to check + * + * @return <code>true</code> if the paths can be added with respect to the + * selectionMode + */ + protected boolean canPathsBeAdded(TreePath[] paths) + { + return false; // TODO + } + + /** + * Checks if the paths can be removed without breaking the continuity of the + * selection according to selectionMode. + * + * @param paths the paths to check + * @return <code>true</code> if the paths can be removed with respect to + * the selectionMode + */ + protected boolean canPathsBeRemoved(TreePath[] paths) + { + return false; // TODO + } + + /** + * notifyPathChange + * + * @param value0 TODO + * @param value1 TODO + */ + protected void notifyPathChange(Vector value0, TreePath value1) + { + // TODO + } + + /** + * Updates the lead index instance field. + */ + protected void updateLeadIndex() + { + // TODO + } + + /** + * Deprecated and not used. + */ + protected void insureUniqueness() + { + // TODO + } +} diff --git a/libjava/classpath/javax/swing/tree/ExpandVetoException.java b/libjava/classpath/javax/swing/tree/ExpandVetoException.java new file mode 100644 index 00000000000..1c8827c8a6c --- /dev/null +++ b/libjava/classpath/javax/swing/tree/ExpandVetoException.java @@ -0,0 +1,83 @@ +/* ExpandVetoException.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.tree; + +// Imports +import javax.swing.event.TreeExpansionEvent; + +/** + * ExpandVetoException + * @author Andrew Selkirk + */ +public class ExpandVetoException extends Exception { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + /** + * event + */ + protected TreeExpansionEvent event = null; + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor ExpandVetoException + * @param event Tree Expansion Event + */ + public ExpandVetoException(TreeExpansionEvent event) { + super(); + this.event = event; + } // ExpandVetoException() + + /** + * Constructor ExpandVetoException + * @param event Tree Expansion Event + * @param message Message + */ + public ExpandVetoException(TreeExpansionEvent event, String message) { + super(message); + this.event = event; + } // ExpandVetoException() + + +} // ExpandVetoException diff --git a/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java b/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java new file mode 100644 index 00000000000..67a21f0205a --- /dev/null +++ b/libjava/classpath/javax/swing/tree/FixedHeightLayoutCache.java @@ -0,0 +1,244 @@ +/* FixedHeightLayoutCache.java -- +Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.tree; + +import java.awt.Rectangle; +import java.util.Enumeration; + +import javax.swing.event.TreeModelEvent; + +/** + * FixedHeightLayoutCache + * + * @author Andrew Selkirk + */ +public class FixedHeightLayoutCache + extends AbstractLayoutCache +{ + + // ------------------------------------------------------------- + // Variables -------------------------------------------------- + // ------------------------------------------------------------- + + // ------------------------------------------------------------- + // Initialization --------------------------------------------- + // ------------------------------------------------------------- + + /** + * Constructor FixedHeightLayoutCache + */ + public FixedHeightLayoutCache() + { + // TODO + } // FixedHeightLayoutCache() + + // ------------------------------------------------------------- + // Methods ---------------------------------------------------- + // ------------------------------------------------------------- + + /** + * getRowCount + * + * @returns int + */ + public int getRowCount() + { + return 0; // TODO + } // getRowCount() + + /** + * invalidatePathBounds + * + * @param value0 TODO + */ + public void invalidatePathBounds(TreePath value0) + { + // TODO + } // invalidatePathBounds() + + /** + * invalidateSizes + */ + public void invalidateSizes() + { + // TODO + } // invalidateSizes() + + /** + * isExpanded + * + * @param value0 TODO + * @returns boolean + */ + public boolean isExpanded(TreePath value0) + { + return false; // TODO + } // isExpanded() + + /** + * getBounds + * + * @param value0 TODO + * @param value1 TODO + * @returns Rectangle + */ + public Rectangle getBounds(TreePath value0, Rectangle value1) + { + return null; // TODO + } // getBounds() + + /** + * getPathForRow + * + * @param value0 TODO + * @returns TreePath + */ + public TreePath getPathForRow(int row) + { + //TODO + return null; + } // getPathForRow() + + /** + * getRowForPath + * + * @param value0 TODO + * @returns int + */ + public int getRowForPath(TreePath value0) + { + return 0; + } // getRowForPath() + + /** + * getPathClosestTo + * + * @param value0 TODO + * @param value1 TODO + * @returns TreePath + */ + public TreePath getPathClosestTo(int value0, int value1) + { + return null; // TODO + } // getPathClosestTo() + + /** + * getVisibleChildCount + * + * @param value0 TODO + * @returns int + */ + public int getVisibleChildCount(TreePath value0) + { + return 0; // TODO + } // getVisibleChildCount() + + /** + * getVisiblePathsFrom + * + * @param value0 TODO + * @returns Enumeration + */ + public Enumeration getVisiblePathsFrom(TreePath value0) + { + return null; // TODO + } // getVisiblePathsFrom() + + /** + * setExpandedState + * + * @param value0 TODO + * @param value1 TODO + */ + public void setExpandedState(TreePath value0, boolean value1) + { + // TODO + } // setExpandedState() + + /** + * getExpandedState + * + * @param value0 TODO + * @returns boolean + */ + public boolean getExpandedState(TreePath value0) + { + return false; // TODO + } // getExpandedState() + + /** + * treeNodesChanged + * + * @param value0 TODO + */ + public void treeNodesChanged(TreeModelEvent value0) + { + // TODO + } // treeNodesChanged() + + /** + * treeNodesInserted + * + * @param value0 TODO + */ + public void treeNodesInserted(TreeModelEvent value0) + { + // TODO + } // treeNodesInserted() + + /** + * treeNodesRemoved + * + * @param value0 TODO + */ + public void treeNodesRemoved(TreeModelEvent value0) + { + // TODO + } // treeNodesRemoved() + + /** + * treeStructureChanged + * + * @param value0 TODO + */ + public void treeStructureChanged(TreeModelEvent value0) + { + // TODO + } // treeStructureChanged() + +} // FixedHeightLayoutCache diff --git a/libjava/classpath/javax/swing/tree/MutableTreeNode.java b/libjava/classpath/javax/swing/tree/MutableTreeNode.java new file mode 100644 index 00000000000..9f0ff4ded81 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/MutableTreeNode.java @@ -0,0 +1,104 @@ +/* MutableTreeNode.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.tree; + +/** + * MutableTreeNode public interface + + * @author Andrew Selkirk + */ +public interface MutableTreeNode extends TreeNode +{ + /** + * Inserts a node as child at a given index. + * + * @param child the note to insert + * @param index the index + * + * @see #remove(int) + * @see #remove(MutableTreeNode) + * @see #setParent(MutableTreeNode) + */ + void insert(MutableTreeNode child, int index); + + /** + * Removes the child node a given index. + * + * @param index the index + * + * @see #insert(MutableTreeNode,int) + * @see #remove(MutableTreeNode) + * @see #removeFromParent() + */ + void remove(int index); + + /** + * Removes a given child node. + * + * @param node the node to remove + * + * @see #insert(MutableTreeNode,int) + * @see #remove(int) + * @see #removeFromParent() + */ + void remove(MutableTreeNode node); + + /** + * Sets a user object, the data represented by the node. + * + * @param object the data + */ + void setUserObject(Object object); + + /** + * Removes this node from its parent. + * + * @see #remove(int) + * @see #remove(MutableTreeNode) + */ + void removeFromParent(); + + /** + * Sets the parent of the node. + * + * @param parent the parent + * + * @see #insert(MutableTreeNode,int) + */ + void setParent(MutableTreeNode parent); +} diff --git a/libjava/classpath/javax/swing/tree/RowMapper.java b/libjava/classpath/javax/swing/tree/RowMapper.java new file mode 100644 index 00000000000..690efb77e32 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/RowMapper.java @@ -0,0 +1,54 @@ +/* RowMapper.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.tree; + +/** + * RowMapper public interface + * @author Andrew Selkirk + */ +public interface RowMapper { + + /** + * getRowsForPaths + * @param path TreePath + * @return TODO + */ + int[] getRowsForPaths(TreePath[] path); + + +} // RowMapper diff --git a/libjava/classpath/javax/swing/tree/TreeCellEditor.java b/libjava/classpath/javax/swing/tree/TreeCellEditor.java new file mode 100644 index 00000000000..691cbc16386 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/TreeCellEditor.java @@ -0,0 +1,65 @@ +/* TreeCellEditor.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.awt.Component; + +import javax.swing.CellEditor; +import javax.swing.JTree; + +/** + * TreeCellEditor public interface + * @author Andrew Selkirk + */ +public interface TreeCellEditor extends CellEditor +{ + /** + * getTreeCellEditorComponent + * @param tree TODO + * @param value TODO + * @param isSelected TODO + * @param expanded TODO + * @param leaf TODO + * @param row TODO + * @return TODO + */ + Component getTreeCellEditorComponent(JTree tree, Object value, + boolean isSelected, boolean expanded, + boolean leaf, int row); +} diff --git a/libjava/classpath/javax/swing/tree/TreeCellRenderer.java b/libjava/classpath/javax/swing/tree/TreeCellRenderer.java new file mode 100644 index 00000000000..ebbe3fa9133 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/TreeCellRenderer.java @@ -0,0 +1,67 @@ +/* TreeCellRenderer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.awt.Component; + +import javax.swing.JTree; + +/** + * TreeCellRenderer public interface + * @author Andrew Selkirk + */ +public interface TreeCellRenderer { + + /** + * getTreeCellRendererComponent + * @param tree TODO + * @param value TODO + * @param selected TODO + * @param expanded TODO + * @param leaf TODO + * @param row TODO + * @param us TODO + * @returns TODO + */ + Component getTreeCellRendererComponent(JTree tree, + Object value, boolean selected, boolean expanded, + boolean leaf, int row, boolean hasFocus); + + +} // TreeCellRenderer diff --git a/libjava/classpath/javax/swing/tree/TreeModel.java b/libjava/classpath/javax/swing/tree/TreeModel.java new file mode 100644 index 00000000000..759aaac588c --- /dev/null +++ b/libjava/classpath/javax/swing/tree/TreeModel.java @@ -0,0 +1,109 @@ +/* TreeModel.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import javax.swing.event.TreeModelListener; + +/** + * TreeModel public interface + * @author Andrew Selkirk + */ +public interface TreeModel { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getRoot + * @returns Object + */ + Object getRoot(); + + /** + * getChild + * @param parent TODO + * @param index TODO + * @returns Object + */ + Object getChild(Object parent, int index); + + /** + * getChildCount + * @param parent TODO + * @returns int + */ + int getChildCount(Object parent); + + /** + * isLeaf + * @param node TODO + * @returns boolean + */ + boolean isLeaf(Object node); + + /** + * valueForPathChanged + * @param path TODO + * @param newvalue TODO + */ + void valueForPathChanged(TreePath path, Object newvalue); + + /** + * getIndexOfChild + * @param parent TODO + * @param ild TODO + * @returns int + */ + int getIndexOfChild(Object parent, Object child); + + /** + * addTreeModelListener + * @param listener TODO + */ + void addTreeModelListener(TreeModelListener listener); + + /** + * removeTreeModelListener + * @param listener TODO + */ + void removeTreeModelListener(TreeModelListener listener); + + +} // TreeModel diff --git a/libjava/classpath/javax/swing/tree/TreeNode.java b/libjava/classpath/javax/swing/tree/TreeNode.java new file mode 100644 index 00000000000..fb8f880f286 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/TreeNode.java @@ -0,0 +1,99 @@ +/* TreeNode.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.util.Enumeration; + +/** + * TreeNode public interface + * @author Andrew Selkirk + */ +public interface TreeNode { + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * getParent + * @returns TreeNode + */ + TreeNode getParent(); + + /** + * getIndex + * @param node TODO + * @returns int + */ + int getIndex(TreeNode node); + + /** + * getChildAt + * @param index TODO + * @returns TreeNode + */ + TreeNode getChildAt(int index); + + /** + * getChildCount + * @returns int + */ + int getChildCount(); + + /** + * getAllowsChildren + * @returns boolean + */ + boolean getAllowsChildren(); + + /** + * isLeaf + * @returns boolean + */ + boolean isLeaf(); + + /** + * children + * @returns Enumeration + */ + Enumeration children(); + + +} // TreeNode + diff --git a/libjava/classpath/javax/swing/tree/TreePath.java b/libjava/classpath/javax/swing/tree/TreePath.java new file mode 100644 index 00000000000..37ec632c95f --- /dev/null +++ b/libjava/classpath/javax/swing/tree/TreePath.java @@ -0,0 +1,299 @@ +/* TreePath.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.io.Serializable; +import java.util.Arrays; + +/** + * A <code>TreePath</code> represents a sequence of tree elements that form + * a path starting from the root of a tree. A tree element can be represented + * by any {@link Object}. + * + * @author Andrew Selkirk + */ +public class TreePath implements Serializable +{ + static final long serialVersionUID = 4380036194768077479L; + + /** + * path + */ + private Object[] path = null; + + + /** + * Creates a path from the list of objects representing tree elements. The + * incoming array is copied so that subsequent changes do not affect this + * tree path. + * + * @param path the elements in the path (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>path</code> is <code>null</code>. + */ + public TreePath(Object[] path) + { + if (path == null) + throw new IllegalArgumentException("Null 'path' not permitted."); + this.path = new Object[path.length]; + System.arraycopy(path, 0, this.path, 0, path.length); + } + + /** + * Creates a new path from a single element. + * + * @param element the element (<code>null</code> not permitted). + * + * @throws IllegalArgumentException if <code>element</code> is + * <code>null</code>. + */ + public TreePath(Object element) + { + path = new Object[1]; + path[0] = element; + } + + /** + * Creates a new tree path by adding the specified <code>element</code> to + * the <code>path</code>. + * + * @param path a tree path. + * @param element a path element. + */ + protected TreePath(TreePath path, Object element) + { + if (element == null) + throw new NullPointerException("Null 'element' argument."); + Object[] treepath = path.getPath(); + + // Create Tree Path + this.path = new Object[treepath.length + 1]; + System.arraycopy(treepath, 0, this.path, 0, treepath.length); + this.path[treepath.length] = element; + } + + /** + * Creates a new tree path using the first <code>length</code> elements + * from the given array. + * + * @param path the path elements. + * @param length the path length. + */ + protected TreePath(Object[] path, int length) + { + // Create Path + this.path = new Object[length]; + System.arraycopy(path, 0, this.path, 0, length); + } + + /** + * Default constructor. + */ + protected TreePath() + { + path = new Object[0]; + } + + + /** + * Returns a hashcode for the path. + * + * @return A hashcode. + */ + public int hashCode() + { + return getLastPathComponent().hashCode(); + } + + /** + * Tests this path for equality with an arbitrary object. An object is + * considered equal to this path if and only if: + * <ul> + * <li>the object is not <code>null</code>;</li> + * <li>the object is an instanceof {@link TreePath};</li> + * <li>the object contains the same elements in the same order as this + * {@link TreePath};</li> + * </ul> + * + * @param object the object (<code>null</code> permitted). + * + * @returns <code>true</code> if <code>obj</code> is equal to this tree path, + * and <code>false</code> otherwise. + */ + public boolean equals(Object object) + { + Object[] treepath; + int index; + + if (object instanceof TreePath) + { + treepath = ((TreePath) object).getPath(); + if (treepath.length != path.length) + return false; + for (index = 0; index < path.length; index++) + { + if (!treepath[index].equals(path[index])) + return false; + } + + // Tree Path's are equals + return true; + } + + // Unequal + return false; + } + + /** + * Returns a string representation of this path. + * + * @return A string representation of this path. + */ + public String toString() + { + if (path.length == 1) + return String.valueOf(path[0]); + else + return Arrays.asList(path).toString(); + } + + /** + * Returns an array containing the path elements. + * + * @returns An array containing the path elements. + */ + public Object[] getPath() + { + return (Object[]) path.clone(); + } + + /** + * Returns the last object in the path. + * + * @return The last object in the path. + */ + public Object getLastPathComponent() + { + return path[path.length - 1]; + } + + /** + * Returns the number of elements in the path. + * + * @returns The number of elements in the path. + */ + public int getPathCount() + { + return path.length; + } + + /** + * Returns the element at the specified position in the path. + * + * @param position the element position (<code>0 < N - 1</code>, where + * <code>N</code> is the number of elements in the path). + * + * @return The element at the specified position. + * + * @throws IllegalArgumentException if <code>position</code> is outside the + * valid range. + */ + public Object getPathComponent(int position) + { + if (position < 0 || position >= getPathCount()) + throw new IllegalArgumentException("Invalid position: " + position); + return path[position]; + } + + /** + * Returns <code>true</code> if <code>path</code> is a descendant of this + * path, and <code>false</code> otherwise. If <code>path</code> is + * <code>null</code>, this method returns <code>false</code>. + * + * @param path the path to check (<code>null</code> permitted). + * + * @returns <code>true</code> if <code>path</code> is a descendant of this + * path, and <code>false</code> otherwise + */ + public boolean isDescendant(TreePath path) + { + if (path == null) + return false; + int count = getPathCount(); + if (path.getPathCount() < count) + return false; + for (int i = 0; i < count; i++) + { + if (!this.path[i].equals(path.getPathComponent(i))) + return false; + } + return true; + } + + /** + * Creates a new path that is equivalent to this path plus the specified + * element. + * + * @param element the element. + * + * @returns A tree path. + */ + public TreePath pathByAddingChild(Object element) + { + return new TreePath(this, element); + } + + /** + * Returns the parent path, which is a path containing all the same elements + * as this path, except for the last one. If this path contains only one + * element, the method returns <code>null</code>. + * + * @returns The parent path, or <code>null</code> if this path has only one + * element. + */ + public TreePath getParentPath() + { + // If this path has only one element, then we return null. That + // is what the JDK does. + if (path.length <= 1) + return null; + + return new TreePath(this.getPath(), path.length - 1); + } +} diff --git a/libjava/classpath/javax/swing/tree/TreeSelectionModel.java b/libjava/classpath/javax/swing/tree/TreeSelectionModel.java new file mode 100644 index 00000000000..4072ccc64c5 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/TreeSelectionModel.java @@ -0,0 +1,84 @@ +/* TreeSelectionModel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.beans.PropertyChangeListener; + +import javax.swing.event.TreeSelectionListener; + +/** + * TreeSelectionModel public interface + * @author Andrew Selkirk + */ +public interface TreeSelectionModel { + + int SINGLE_TREE_SELECTION = 1; + int CONTIGUOUS_TREE_SELECTION = 2; + int DISCONTIGUOUS_TREE_SELECTION = 4; + + void setSelectionMode(int mode); + int getSelectionMode(); + void setSelectionPath(TreePath path); + void setSelectionPaths(TreePath[] paths); + void addSelectionPath(TreePath path); + void addSelectionPaths(TreePath[] paths); + void removeSelectionPath(TreePath path); + void removeSelectionPaths(TreePath[] paths); + TreePath getSelectionPath(); + TreePath[] getSelectionPaths(); + int getSelectionCount(); + boolean isPathSelected(TreePath path); + boolean isSelectionEmpty(); + void clearSelection(); + void setRowMapper(RowMapper newMapper); + RowMapper getRowMapper(); + int[] getSelectionRows(); + int getMinSelectionRow(); + int getMaxSelectionRow(); + boolean isRowSelected(int row); + void resetRowSelection(); + int getLeadSelectionRow(); + TreePath getLeadSelectionPath(); + void addPropertyChangeListener(PropertyChangeListener listener); + void removePropertyChangeListener(PropertyChangeListener listener); + void addTreeSelectionListener(TreeSelectionListener x); + void removeTreeSelectionListener(TreeSelectionListener x); + + +} // TreeSelectionModel diff --git a/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java b/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java new file mode 100644 index 00000000000..2c9136c5103 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/VariableHeightLayoutCache.java @@ -0,0 +1,253 @@ +/* VariableHeightLayoutCache.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.tree; + +import java.awt.Rectangle; +import java.util.Enumeration; + +import javax.swing.event.TreeModelEvent; + +/** + * VariableHeightLayoutCache + * @author Andrew Selkirk + */ +public class VariableHeightLayoutCache extends AbstractLayoutCache { + + //------------------------------------------------------------- + // Variables -------------------------------------------------- + //------------------------------------------------------------- + + + //------------------------------------------------------------- + // Initialization --------------------------------------------- + //------------------------------------------------------------- + + /** + * Constructor VariableHeightLayoutCache + */ + public VariableHeightLayoutCache() { + // TODO + } // VariableHeightLayoutCache() + + + //------------------------------------------------------------- + // Methods ---------------------------------------------------- + //------------------------------------------------------------- + + /** + * setModel + * @param value0 TODO + */ + public void setModel(TreeModel value0) { + // TODO + } // setModel() + + /** + * setRootVisible + * @param value0 TODO + */ + public void setRootVisible(boolean value0) { + // TODO + } // setRootVisible() + + /** + * setNodeDimensions + * @param value0 TODO + */ + public void setNodeDimensions(NodeDimensions value0) { + // TODO + } // setNodeDimensions() + + /** + * setExpandedState + * @param value0 TODO + * @param value1 TODO + */ + public void setExpandedState(TreePath value0, boolean value1) { + // TODO + } // setExpandedState() + + /** + * getExpandedState + * @param value0 TODO + * @returns boolean + */ + public boolean getExpandedState(TreePath value0) { + return false; // TODO + } // getExpandedState() + + /** + * getBounds + * @param value0 TODO + * @param value1 TODO + * @returns Rectangle + */ + public Rectangle getBounds(TreePath value0, Rectangle value1) { + return null; // TODO + } // getBounds() + + /** + * getPathForRow + * @param value0 TODO + * @returns TreePath + */ + public TreePath getPathForRow(int value0) { + return null; // TODO + } // getPathForRow() + + /** + * getRowForPath + * @param value0 TODO + * @returns int + */ + public int getRowForPath(TreePath value0) { + return 0; // TODO + } // getRowForPath() + + /** + * getRowCount + * @returns int + */ + public int getRowCount() { + return 0; // TODO + } // getRowCount() + + /** + * invalidatePathBounds + * @param value0 TODO + */ + public void invalidatePathBounds(TreePath value0) { + // TODO + } // invalidatePathBounds() + + /** + * getPreferredHeight + * @returns int + */ + public int getPreferredHeight() { + return 0; // TODO + } // getPreferredHeight() + + /** + * getPreferredWidth + * @param value0 TODO + * @returns int + */ + public int getPreferredWidth(Rectangle value0) { + return 0; // TODO + } // getPreferredWidth() + + /** + * getPathClosestTo + * @param value0 TODO + * @param value1 TODO + * @returns TreePath + */ + public TreePath getPathClosestTo(int value0, int value1) { + return null; // TODO + } // getPathClosestTo() + + /** + * getVisiblePathsFrom + * @param value0 TODO + * @returns Enumeration + */ + public Enumeration getVisiblePathsFrom(TreePath value0) { + return null; // TODO + } // getVisiblePathsFrom() + + /** + * getVisibleChildCount + * @param value0 TODO + * @returns int + */ + public int getVisibleChildCount(TreePath value0) { + return 0; // TODO + } // getVisibleChildCount() + + /** + * invalidateSizes + */ + public void invalidateSizes() { + // TODO + } // invalidateSizes() + + /** + * isExpanded + * @param value0 TODO + * @returns boolean + */ + public boolean isExpanded(TreePath value0) { + return false; // TODO + } // isExpanded() + + /** + * treeNodesChanged + * @param value0 TODO + */ + public void treeNodesChanged(TreeModelEvent value0) { + // TODO + } // treeNodesChanged() + + /** + * treeNodesInserted + * @param value0 TODO + */ + public void treeNodesInserted(TreeModelEvent value0) { + // TODO + } // treeNodesInserted() + + /** + * treeNodesRemoved + * @param value0 TODO + */ + public void treeNodesRemoved(TreeModelEvent value0) { + // TODO + } // treeNodesRemoved() + + /** + * treeStructureChanged + * @param value0 TODO + */ + public void treeStructureChanged(TreeModelEvent value0) { + // TODO + } // treeStructureChanged() + + +} // VariableHeightLayoutCache diff --git a/libjava/classpath/javax/swing/tree/package.html b/libjava/classpath/javax/swing/tree/package.html new file mode 100644 index 00000000000..22538e4bad3 --- /dev/null +++ b/libjava/classpath/javax/swing/tree/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.tree package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.tree</title></head> + +<body> +<p>Interfaces and classes that support the {@link javax.swing.JTree} +component.</p> + +</body> +</html> diff --git a/libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java b/libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java new file mode 100644 index 00000000000..34c41aea274 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/AbstractUndoableEdit.java @@ -0,0 +1,323 @@ +/* AbstractUndoableEdit.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.undo; + +import java.io.Serializable; + +import javax.swing.UIManager; + +/** + * A default implementation of <code>UndoableEdit</code> that can be + * used as a base for implementing editing operations. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class AbstractUndoableEdit + implements UndoableEdit, Serializable +{ + /** + * The serialization ID. Verified using the <code>serialver</code> + * tool of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5, and Sun JDK + * 1.4.1_01 on GNU/Linux. + */ + static final long serialVersionUID = 580150227676302096L; + + + /** + * The constant string “Undo”, which was returned by + * {@link #getUndoPresentationName()} on early versions of the + * platform. However, this field has become obsolete with version + * 1.3.1. That method now retrieves a localized string from the + * {@link javax.swing.UIManager}, using the key + * <code>“AbstractUndoableEdit.undoText”</code>. + */ + protected static final String UndoName = "Undo"; + + + /** + * The constant string “Redo”, which was returned by + * {@link #getRedoPresentationName()} on early versions of the + * platform. However, this field has become obsolete with version + * 1.3.1. That method now retrieves a localized string from the + * {@link javax.swing.UIManager}, using the key + * <code>“AbstractUndoableEdit.redoText”</code>. + */ + protected static final String RedoName = "Redo"; + + + /** + * Indicates whether this editing action has been executed. A value + * of <code>true</code> means that the action was performed, or that + * a redo operation was successful. A value of <code>false</code> + * means that the action has not yet performed, or that an undo + * operation was successful. + */ + private boolean hasBeenDone; + + + /** + * Indicates whether this editing action is still alive. The value + * is set to <code>true</code> by the constructor, and to + * <code>false</code> by the {@link #die()} method. + */ + private boolean alive; + + + /** + * Constructs a new <code>AbstractUndoableEdit</code>. The initial + * state is that the editing action is alive, and + * <code>hasBeenDone</code> is <code>true</code>. + */ + public AbstractUndoableEdit() + { + // The API specification is not clear, but Mauve test code has + // determined that hasBeenDone is initially set to true. + alive = hasBeenDone = true; + } + + + /** + * Undoes this editing action. + * + * @throws CannotUndoException if {@link #canUndo()} returns + * <code>false</code>, for example because this action has already + * been undone. + * + * @see #canUndo() + * @see #redo() + */ + public void undo() + throws CannotUndoException + { + if (!canUndo()) + throw new CannotUndoException(); + hasBeenDone = false; + } + + + /** + * Determines whether it would be possible to undo this editing + * action. + * + * @return <code>true</code> to indicate that this action can be + * undone, <code>false</code> otherwise. + * + * @see #undo() + * @see #canRedo() + */ + public boolean canUndo() + { + return alive && hasBeenDone; + } + + + /** + * Redoes this editing action. + * + * @throws CannotRedoException if {@link #canRedo()} returns + * <code>false</code>, for example because this action has not + * yet been undone. + * + * @see #canRedo() + * @see #undo() + */ + public void redo() + throws CannotRedoException + { + if (!canRedo()) + throw new CannotRedoException(); + hasBeenDone = true; + } + + + /** + * Determines whether it would be possible to redo this editing + * action. + * + * @return <code>true</code> to indicate that this action can be + * redone, <code>false</code> otherwise. + * + * @see #redo() + * @see #canUndo() + */ + public boolean canRedo() + { + return alive && !hasBeenDone; + } + + + /** + * Informs this edit action that it will no longer be used. Some + * actions might use this information to release resources, for + * example open files. Called by {@link UndoManager} before this + * action is removed from the edit queue. + */ + public void die() + { + alive = false; + } + + + /** + * Incorporates another editing action into this one, thus forming a + * combined action. + * + * <p>The default implementation always returns <code>false</code>, + * indicating that the editing action could not be incorporated. + * + * @param edit the editing action to be incorporated. + */ + public boolean addEdit(UndoableEdit edit) + { + return false; + } + + + /** + * Incorporates another editing action into this one, thus forming a + * combined action that replaces the argument action. + * + * <p>The default implementation always returns <code>false</code>, + * indicating that the argument action should not be replaced. + * + * @param edit the editing action to be replaced. + */ + public boolean replaceEdit(UndoableEdit edit) + { + return false; + } + + + /** + * Determines whether this editing action is significant enough for + * being seperately undoable by the user. A typical significant + * action would be the resizing of an object. However, changing the + * selection in a text document would usually not be considered + * significant. + * + * <p>The default implementation returns <code>true</code>. + * + * @return <code>true</code> to indicate that the action is + * significant enough for being separately undoable, or + * <code>false</code> otherwise. + */ + public boolean isSignificant() + { + return true; + } + + + /** + * Returns a human-readable, localized name that describes this + * editing action and can be displayed to the user. + * + * <p>The default implementation returns an empty string. + */ + public String getPresentationName() + { + return ""; + } + + + /** + * Calculates a localized name for presenting the undo action to the + * user. + * + * <p>The default implementation returns the concatenation of the + * string “Undo” and the action name, which is + * determined by calling {@link #getPresentationName()}. + * + * <p>The string “Undo” is retrieved from the {@link + * javax.swing.UIManager}, using the key + * <code>“AbstractUndoableEdit.undoText”</code>. This + * allows the text to be localized. + */ + public String getUndoPresentationName() + { + String msg, pres; + + msg = UIManager.getString("AbstractUndoableEdit.undoText"); + if (msg == null) + msg = UndoName; + + pres = getPresentationName(); + if ((pres == null) || (pres.length() == 0)) + return msg; + else + return msg + ' ' + pres; + } + + + /** + * Calculates a localized name for presenting the redo action to the + * user. + * + * <p>The default implementation returns the concatenation of the + * string “Redo” and the action name, which is + * determined by calling {@link #getPresentationName()}. + * + * <p>The string “Redo” is retrieved from the {@link + * javax.swing.UIManager}, using the key + * <code>“AbstractUndoableEdit.redoText”</code>. This + * allows the text to be localized. + */ + public String getRedoPresentationName() + { + String msg, pres; + + msg = UIManager.getString("AbstractUndoableEdit.redoText"); + if (msg == null) + msg = RedoName; + + pres = getPresentationName(); + if ((pres == null) || (pres.length() == 0)) + return msg; + else + return msg + ' ' + pres; + } + + + public String toString() + { + return super.toString() + + " hasBeenDone: " + hasBeenDone + + " alive: " + alive; + } +} diff --git a/libjava/classpath/javax/swing/undo/CannotRedoException.java b/libjava/classpath/javax/swing/undo/CannotRedoException.java new file mode 100644 index 00000000000..7d70a38c2c8 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/CannotRedoException.java @@ -0,0 +1,56 @@ +/* CannotRedoException.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.undo; + +/** + * An exception which indicates that an editing action cannot be + * redone. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class CannotRedoException + extends RuntimeException +{ + /** + * Constructs a new instance of a <code>CannotRedoException</code>. + */ + public CannotRedoException() + { + } +} diff --git a/libjava/classpath/javax/swing/undo/CannotUndoException.java b/libjava/classpath/javax/swing/undo/CannotUndoException.java new file mode 100644 index 00000000000..9fc0ec3bd3a --- /dev/null +++ b/libjava/classpath/javax/swing/undo/CannotUndoException.java @@ -0,0 +1,57 @@ +/* CannotUndoException.java + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.undo; + + +/** + * An exception which indicates that an editing action cannot be + * undone. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class CannotUndoException + extends RuntimeException +{ + /** + * Constructs a new instance of a <code>CannotUndoException</code>. + */ + public CannotUndoException() + { + } +} diff --git a/libjava/classpath/javax/swing/undo/CompoundEdit.java b/libjava/classpath/javax/swing/undo/CompoundEdit.java new file mode 100644 index 00000000000..e1cfbb619b3 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/CompoundEdit.java @@ -0,0 +1,400 @@ +/* CompoundEdit.java -- Combines multiple UndoableEdits. + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.undo; + +import java.util.Vector; + +/** + * An editing action that consists of multiple + * <code>UndoableEdits</code>. + * + * <p>The use of a <code>CompoundEdit</code> is divided in two separate + * phases.</p> + * + * <ol> + * <li>In the first phase, the <code>CompoundEdit</code> is + * initialized. After a new instance of <code>CompoundEdit</code> has + * been created, {@link #addEdit(UndoableEdit)} is called for each + * element of the compound. To terminate the initialization phase, + * call {@link #end()}.</li> + * <li>In the second phase, the the <code>CompoundEdit</code> can be + * used, typically by invoking {@link #undo()} and + * {@link #redo()}.</li> + * </ol> + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class CompoundEdit + extends AbstractUndoableEdit +{ + /** + * The identifier of this class in object serialization. Determined + * using the serialver tool of Sun J2SE 1.4.1_01. + */ + private static final long serialVersionUID = -6512679249930119683L; + + + /** + * The <code>UndoableEdit</code>s being combined into a compound + * editing action. + */ + protected Vector edits; + + + /** + * Indicates whether the creation of this CompoundEdit is still in + * progress. Initially, the value of this flag is + * <code>true</code>. The {@link #end()} method changes the flag to + * <code>false</code>. + */ + private boolean inProgress; + + + /** + * Constructs a new CompoundEdit. + */ + public CompoundEdit() + { + edits = new Vector(); + inProgress = true; + } + + + /** + * Undoes all edits that are part of of this + * <code>CompoundEdit</code>. The compound elements will receive the + * <code>undo</code> message in the reverse order of addition. + * + * @throws CannotUndoException if {@link #canUndo()} returns + * <code>false</code>. This can happen if {@link #end()} has not + * been called on this <code>CompoundEdit</code>, or if this edit + * has already been undone. + * + * @see #canUndo() + * @see #redo() + */ + public void undo() + throws CannotUndoException + { + // AbstractUndoableEdit.undo() will throw a CannotUndoException if + // canUndo returns false. + super.undo(); + + for (int i = edits.size() - 1; i >= 0; i--) + ((UndoableEdit) edits.elementAt(i)).undo(); + } + + + /** + * Redoes all edits that are part of of this + * <code>CompoundEdit</code>. The compound elements will receive the + * <code>undo</code> message in the same order as they were added. + * + * @throws CannotRedoException if {@link #canRedo()} returns + * <code>false</code>. This can happen if {@link #end()} has not + * been called on this <code>CompoundEdit</code>, or if this edit + * has already been redone. + * + * @see #canRedo() + * @see #undo() + */ + public void redo() + throws CannotRedoException + { + // AbstractUndoableEdit.redo() will throw a CannotRedoException if + // canRedo returns false. + super.redo(); + + for (int i = 0; i < edits.size(); i++) + ((UndoableEdit) edits.elementAt(i)).redo(); + } + + + /** + * Returns the the <code>UndoableEdit</code> that was last added to + * this compound. + */ + protected UndoableEdit lastEdit() + { + if (edits.size() == 0) + return null; + else + return (UndoableEdit) edits.elementAt(edits.size() - 1); + } + + + /** + * Informs this edit action, and all compound edits, that they will + * no longer be used. Some actions might use this information to + * release resources such as open files. Called by {@link + * UndoManager} before this action is removed from the edit queue. + * + * <p>The compound elements will receive the + * <code>die</code> message in the reverse order of addition. + */ + public void die() + { + for (int i = edits.size() - 1; i >= 0; i--) + ((UndoableEdit) edits.elementAt(i)).die(); + + super.die(); + } + + + /** + * Incorporates another editing action into this one, thus forming a + * combined edit. + * + * <p>If this edit’s {@link #end()} method has been called + * before, <code>false</code> is returned immediately. Otherwise, + * the {@linkplain #lastEdit() last added edit} is given the + * opportunity to {@linkplain UndoableEdit#addEdit(UndoableEdit) + * incorporate} <code>edit</code>. If this fails, <code>edit</code> + * is given the opportunity to {@linkplain + * UndoableEdit#replaceEdit(UndoableEdit) replace} the last added + * edit. If this fails as well, <code>edit</code> gets added as a + * new compound to {@link #edits}. + * + * @param edit the editing action being added. + * + * @return <code>true</code> if <code>edit</code> could somehow be + * incorporated; <code>false</code> if <code>edit</code> has not + * been incorporated because {@link #end()} was called before. + */ + public boolean addEdit(UndoableEdit edit) + { + UndoableEdit last; + + // If end has been called before, do nothing. + if (!inProgress) + return false; + + last = lastEdit(); + + // If edit is the very first edit, just add it to the list. + if (last == null) + { + edits.add(edit); + return true; + } + + // Try to incorporate edit into last. + if (last.addEdit(edit)) + return true; + + // Try to replace last by edit. + if (edit.replaceEdit(last)) + { + edits.set(edits.size() - 1, edit); + return true; + } + + // If everything else has failed, add edit to the list of compound + // edits. + edits.add(edit); + return true; + } + + + /** + * Informs this <code>CompoundEdit</code> that its construction + * phase has been completed. After this method has been called, + * {@link #undo()} and {@link #redo()} may be called, {@link + * #isInProgress()} will return <code>false</code>, and all attempts + * to {@linkplain #addEdit(UndoableEdit) add further edits} will + * fail. + */ + public void end() + { + inProgress = false; + } + + + /** + * Determines whether it would be possible to undo this editing + * action. The result will be <code>true</code> if {@link #end()} + * has been called on this <code>CompoundEdit</code>, {@link #die()} + * has not yet been called, and the edit has not been undone + * already. + * + * @return <code>true</code> to indicate that this action can be + * undone; <code>false</code> otherwise. + * + * @see #undo() + * @see #canRedo() + */ + public boolean canUndo() + { + return !inProgress && super.canUndo(); + } + + + /** + * Determines whether it would be possible to redo this editing + * action. The result will be <code>true</code> if {@link #end()} + * has been called on this <code>CompoundEdit</code>, {@link #die()} + * has not yet been called, and the edit has not been redone + * already. + * + * @return <code>true</code> to indicate that this action can be + * redone; <code>false</code> otherwise. + * + * @see #redo() + * @see #canUndo() + */ + public boolean canRedo() + { + return !inProgress && super.canRedo(); + } + + + /** + * Determines whether the initial construction phase of this + * <code>CompoundEdit</code> is still in progress. During this + * phase, edits {@linkplain #addEdit(UndoableEdit) may be + * added}. After initialization has been terminated by calling + * {@link #end()}, {@link #undo()} and {@link #redo()} can be used. + * + * @return <code>true</code> if the initialization phase is still in + * progress; <code>false</code> if {@link #end()} has been called. + * + * @see #end() + */ + public boolean isInProgress() + { + return inProgress; + } + + + /** + * Determines whether this editing action is significant enough for + * being seperately undoable by the user. A typical significant + * action would be the resizing of an object. However, changing the + * selection in a text document would usually not be considered + * significant. + * + * <p>A <code>CompoundEdit</code> is significant if any of its + * elements are significant. + */ + public boolean isSignificant() + { + for (int i = edits.size() - 1; i >= 0; i--) + if (((UndoableEdit) edits.elementAt(i)).isSignificant()) + return true; + + return false; + } + + + /** + * Returns a human-readable, localized name that describes this + * editing action and can be displayed to the user. + * + * <p>The implementation delegates the call to the {@linkplain + * #lastEdit() last added edit action}. If no edit has been added + * yet, the inherited implementation will be invoked, which always + * returns an empty string. + */ + public String getPresentationName() + { + UndoableEdit last; + + last = lastEdit(); + if (last == null) + return super.getPresentationName(); + else + return last.getPresentationName(); + } + + + /** + * Calculates a localized message text for presenting the undo + * action to the user. + * + * <p>The implementation delegates the call to the {@linkplain + * #lastEdit() last added edit action}. If no edit has been added + * yet, the {@linkplain + * AbstractUndoableEdit#getUndoPresentationName() inherited + * implementation} will be invoked. + */ + public String getUndoPresentationName() + { + UndoableEdit last; + + last = lastEdit(); + if (last == null) + return super.getUndoPresentationName(); + else + return last.getUndoPresentationName(); + } + + + /** + * Calculates a localized message text for presenting the redo + * action to the user. + * + * <p>The implementation delegates the call to the {@linkplain + * #lastEdit() last added edit action}. If no edit has been added + * yet, the {@linkplain + * AbstractUndoableEdit#getRedoPresentationName() inherited + * implementation} will be invoked. + */ + public String getRedoPresentationName() + { + UndoableEdit last; + + last = lastEdit(); + if (last == null) + return super.getRedoPresentationName(); + else + return last.getRedoPresentationName(); + } + + + /** + * Calculates a string that may be useful for debugging. + */ + public String toString() + { + return super.toString() + + " inProgress: " + inProgress + + " edits: " + edits; + } +} diff --git a/libjava/classpath/javax/swing/undo/StateEdit.java b/libjava/classpath/javax/swing/undo/StateEdit.java new file mode 100644 index 00000000000..80e4e33ec29 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/StateEdit.java @@ -0,0 +1,263 @@ +/* StateEdit.java -- UndoableEdit for StateEditable implementations. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.undo; + +import java.util.Hashtable; +import java.util.Iterator; + +/** + * A helper class, making it easy to support undo and redo. + * + * <p>The following example shows how to use this class.</p> + * + * <pre> + * Foo foo; // class Foo implements {@link StateEditable} + * StateEdit edit; + * + * edit = new StateEdit(foo, "Name Change"); + * foo.setName("Jane Doe"); + * edit.end(); + * undoManager.addEdit(edit); + * </pre> + * + * <p>If <code>Foo</code>’s implementation of {@link + * StateEditable} considers the name as part of the editable state, + * the user can now choose “Undo Name Change” or + * “Redo Name Change” from the respective menu. No + * further undo support is needed from the application.</p> + * + * <p>The following explains what happens in the example.</p> + * + * <ol> + * <li>When a <code>StateEdit</code> is created, the associated + * {@link StateEditable} gets asked to store its state into a hash + * table, {@link #preState}.</li> + * <li>The application will now perform some changes to the edited + * object. This typically happens by invoking methods on the edited + * object.</li> + * <li>The editing phase is terminated by invoking the {@link #end()} + * method of the <code>StateEdit</code>. The <code>end()</code> method + * does two things. + * + * <ul> + * <li>The edited object receives a second request for storing + * its state. This time, it will use a different hash table, {@link + * #postState}.</li> + * <li>To increase efficiency, the <code>StateEdit</code> now removes + * any entries from {@link #preState} and {@link #postState} that have + * the same key, and whose values are equal. Equality is determined + * by invoking the <code>equals</code> method inherited from + * {@link java.lang.Object}.</li> + * </ul></li> + * <li>When the user later chooses to undo the <code>StateEdit</code>, + * the edited object is asked to {@linkplain StateEditable#restoreState + * restore its state} from the {@link #preState} table. Similarly, + * when the user chooses to <i>redo</i> the <code>StateEdit</code>, + * the edited object gets asked to restore its state from the {@link + * #postState}.</li> + * </ol> + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class StateEdit + extends AbstractUndoableEdit +{ + /** + * The ID of the Java source file in Sun’s Revision Control + * System (RCS). This certainly should not be part of the API + * specification. But in order to be API-compatible with + * Sun’s reference implementation, GNU Classpath also has to + * provide this field. However, we do not try to match its value. + */ + protected static final String RCSID = ""; + + + /** + * The object which is being edited by this <code>StateEdit</code>. + */ + protected StateEditable object; + + + /** + * The state of <code>object</code> at the time of constructing + * this <code>StateEdit</code>. + */ + protected Hashtable preState; + + + /** + * The state of <code>object</code> at the time when {@link #end()} + * was called. + */ + protected Hashtable postState; + + + /** + * A human-readable name for this edit action. + */ + protected String undoRedoName; + + + /** + * Constructs a <code>StateEdit</code>, specifying the object whose + * state is being edited. + * + * @param obj the object whose state is being edited by this + * <code>StateEdit</code>. + */ + public StateEdit(StateEditable obj) + { + init(obj, null); + } + + + /** + * Constructs a <code>StateEdit</code>, specifying the object whose + * state is being edited. + * + * @param obj the object whose state is being edited by this + * <code>StateEdit</code>. + * + * @param name the human-readable name of the editing action. + */ + public StateEdit(StateEditable obj, String name) + { + init(obj, name); + } + + + /** + * Initializes this <code>StateEdit</code>. The edited object will + * be asked to store its current state into {@link #preState}. + * + * @param obj the object being edited. + * + * @param name the human-readable name of the editing action. + */ + protected void init(StateEditable obj, String name) + { + object = obj; + undoRedoName = name; + preState = new Hashtable(); + postState = new Hashtable(); + obj.storeState(preState); + } + + + /** + * Informs this <code>StateEdit</code> that all edits are finished. + * The edited object will be asked to store its state into {@link + * #postState}, and any redundant entries will get removed from + * {@link #preState} and {@link #postState}. + */ + public void end() + { + object.storeState(postState); + removeRedundantState(); + } + + + /** + * Undoes this edit operation. The edited object will be asked to + * {@linkplain StateEditable#restoreState restore its state} from + * {@link #preState}. + * + * @throws CannotUndoException if {@link #canUndo()} returns + * <code>false</code>, for example because this action has already + * been undone. + */ + public void undo() + { + super.undo(); + object.restoreState(preState); + } + + + /** + * Redoes this edit operation. The edited object will be asked to + * {@linkplain StateEditable#restoreState restore its state} from + * {@link #postState}. + * + * @throws CannotRedoException if {@link #canRedo()} returns + * <code>false</code>, for example because this action has not yet + * been undone. + */ + public void redo() + { + super.redo(); + object.restoreState(postState); + } + + + /** + * Returns a human-readable, localized name that describes this + * editing action and can be displayed to the user. + * + * @return the name, or <code>null</code> if no presentation + * name is available. + */ + public String getPresentationName() + { + return undoRedoName; + } + + + /** + * Removes all redundant entries from the pre- and post-edit state + * hash tables. An entry is considered redundant if it is present + * both before and after the edit, and if the two values are equal. + */ + protected void removeRedundantState() + { + Iterator i = preState.keySet().iterator(); + while (i.hasNext()) + { + Object key = i.next(); + if (postState.containsKey(key)) + { + if (preState.get(key).equals(postState.get(key))) + { + i.remove(); + postState.remove(key); + } + } + } + } +} diff --git a/libjava/classpath/javax/swing/undo/StateEditable.java b/libjava/classpath/javax/swing/undo/StateEditable.java new file mode 100644 index 00000000000..9a7fb09545d --- /dev/null +++ b/libjava/classpath/javax/swing/undo/StateEditable.java @@ -0,0 +1,112 @@ +/* StateEditable.java -- Interface for collaborating with StateEdit. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.undo; + +import java.util.Hashtable; + + +/** + * The interface for objects whose state can be undone or redone by a + * {@link StateEdit} action. + * + * <p>The following example shows how to write a class that implements + * this interface. + * + * <pre> class Foo + * implements StateEditable + * { + * private String name; + * + * public void setName(String n) { name = n; } + * + * public void restoreState(Hashtable h) + * { + * if (h.containsKey("name")) + * setName((String) h.get("name")); + * } + * + * public void storeState(Hashtable s) + * { + * s.put("name", name); + * } + * }</pre> + * + * @see StateEdit + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public interface StateEditable +{ + /** + * The ID of the Java source file in Sun’s Revision Control + * System (RCS). This certainly should not be part of the API + * specification. But in order to be API-compatible with + * Sun’s reference implementation, GNU Classpath also has to + * provide this field. However, we do not try to match its value. + */ + String RCSID = ""; + + + /** + * Performs an edit action, taking any editable state information + * from the specified hash table. + * + * <p><b>Note to implementors of this interface:</b> To increase + * efficiency, the <code>StateEdit</code> class {@linkplan + * StateEdit#removeRedundantState() removes redundant state + * information}. Therefore, implementations of this interface must be + * prepared for the case where certain keys were stored into the + * table by {@link #storeState}, but are not present anymore + * when the <code>restoreState</code> method gets called. + * + * @param state a hash table containing the relevant state + * information. + */ + void restoreState(Hashtable state); + + + /** + * Stores any editable state information into the specified hash + * table. + * + * @param state a hash table for storing relevant state + * information. + */ + void storeState(Hashtable state); +} diff --git a/libjava/classpath/javax/swing/undo/UndoManager.java b/libjava/classpath/javax/swing/undo/UndoManager.java new file mode 100644 index 00000000000..565b5ca8884 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/UndoManager.java @@ -0,0 +1,625 @@ +/* AbstractTableModel.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.undo; + +import javax.swing.UIManager; +import javax.swing.event.UndoableEditEvent; +import javax.swing.event.UndoableEditListener; + + +/** + * A manager for providing an application’s undo/redo + * functionality. + * + * <p>Tyipcally, an application will create only one single instance + * of UndoManager. When the user performs an undoable action, for + * instance changing the color of an object from green to blue, the + * application registers an {@link UndoableEdit} object with the + * <code>UndoManager</code>. To implement the “undo” and + * “redo” menu commands, the application invokes the + * UndoManager’s {@link #undo} and {@link #redo} methods. The + * human-readable text of these menu commands is provided by {@link + * #getUndoPresentationName} and {@link #getRedoPresentationName}, + * respectively. To determine whether the menu item should be + * selectable or greyed out, use {@link #canUndo} and {@link + * #canRedo}. + * + * <p>The UndoManager will only keep a specified number of editing + * actions, the <em>limit</em>. The value of this parameter can be + * retrieved by calling {@link #getLimit} and set with {@link + * #setLimit}. If more UndoableEdits are added to the UndoManager, + * the oldest actions will be discarded. + * + * <p>Some applications do not provide separate menu commands for + * “undo” and “redo.” Instead, they + * have just a single command whose text switches between the two. + * Such applications would use an UndoManager with a <code>limit</code> + * of 1. The text of this combined menu item is available via + * {@link #getUndoOrRedoPresentationName}, and it is implemented + * by calling {@link #undoOrRedo}. + * + * <p><b>Thread Safety:</b> In constrast to the other classes of the + * <code>javax.swing.undo</code> package, the public methods of an + * <code>UndoManager</code> are safe to call from concurrent threads. + * The caller does not need to perform external synchronization, and + * {@link javax.swing.event.UndoableEditEvent} sources do not need to + * broadcast their events from inside the Swing worker thread. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class UndoManager + extends CompoundEdit + implements UndoableEditListener +{ + /** + * The unique ID for serializing instances of this class. Determined + * using the <code>serialver</code> tool of Sun JDK 1.4.1_01 on + * GNU/Linux. + */ + static final long serialVersionUID = -2077529998244066750L; + + + /** + * An index into the inherited {@link #edits} Vector that indicates + * at which position newly added editing actions would get inserted. + * + * <p>Normally, the value of <code>indexOfNextAdd</code> equals + * the number of UndoableEdits stored by this UndoManager, i.e. + * <code>edits.size()</code>. For each call to {@link #undo}, + * <code>indexOfNextAdd</code> is decremented by one. For each + * call to {@link #redo}, it is incremented again. + */ + int indexOfNextAdd; + + + /** + * The maximum number of UndoableEdits stored by this UndoManager. + */ + int limit; + + + /** + * Constructs an UndoManager. + * + * <p>The <code>limit</code> of the freshly constructed UndoManager + * is 100. + */ + public UndoManager() + { + limit = 100; + } + + + /** + * Returns a string representation for this UndoManager. This may be + * useful for debugging purposes. For the text of menu items, please + * refer to {@link #getUndoPresentationName}, {@link + * #getRedoPresentationName}, and {@link + * #getUndoOrRedoPresentationName}. + */ + public String toString() + { + return super.toString() + + " limit: " + limit + + " indexOfNextAdd: " + indexOfNextAdd; + } + + + /** + * Puts this UndoManager into a state where it acts as a normal + * {@link CompoundEdit}. It is unlikely that an application would + * want to do this. + */ + public synchronized void end() + { + super.end(); + trimEdits(indexOfNextAdd, edits.size() - 1); + } + + + /** + * Returns how many edits this UndoManager can maximally hold. + * + * @see #setLimit + */ + public synchronized int getLimit() + { + return limit; + } + + + /** + * Changes the maximal number of edits that this UndoManager can + * process. If there are currently more edits than the new limit + * allows, they will receive a {@link UndoableEdit#die() die} + * message in reverse order of addition. + * + * @param limit the new limit. + * + * @throws IllegalStateException if {@link #end()} has already been + * called on this UndoManager. + */ + public synchronized void setLimit(int limit) + { + if (!isInProgress()) + throw new IllegalStateException(); + + this.limit = limit; + trimForLimit(); + } + + + /** + * Discards all editing actions that are currently registered with + * this UndoManager. Each {@link UndoableEdit} will receive a {@link + * UndoableEdit#die() die message}. + */ + public synchronized void discardAllEdits() + { + int size; + + size = edits.size(); + for (int i = size - 1; i >= 0; i--) + ((UndoableEdit) edits.get(i)).die(); + indexOfNextAdd = 0; + edits.clear(); + } + + + /** + * Called by various internal methods in order to enforce + * the <code>limit</code> value. + */ + protected void trimForLimit() + { + int high, s; + + s = edits.size(); + + /* The Sun J2SE1.4.1_01 implementation can be observed to do + * nothing (instead of throwing an exception) with a negative or + * zero limit. It may be debatable whether this is the best + * behavior, but we replicate it for sake of compatibility. + */ + if (limit <= 0 || s <= limit) + return; + + high = Math.min(indexOfNextAdd + limit/2 - 1, s - 1); + trimEdits(high + 1, s - 1); + trimEdits(0, high - limit); + } + + + /** + * Discards a range of edits. All edits in the range <code>[from + * .. to]</code> will receive a {@linkplain UndoableEdit#die() die + * message} before being removed from the edits array. If + * <code>from</code> is greater than <code>to</code>, nothing + * happens. + * + * @param from the lower bound of the range of edits to be + * discarded. + * + * @param to the upper bound of the range of edits to be discarded. + */ + protected void trimEdits(int from, int to) + { + if (from > to) + return; + + for (int i = to; i >= from; i--) + ((UndoableEdit) edits.get(i)).die(); + + // Remove the range [from .. to] from edits. If from == to, which + // is likely to be a very common case, we can do better than + // creating a sub-list and clearing it. + if (to == from) + edits.remove(from); + else + edits.subList(from, to + 1).clear(); + + if (indexOfNextAdd > to) + indexOfNextAdd = indexOfNextAdd - to + from - 1; + else if (indexOfNextAdd >= from) + indexOfNextAdd = from; + } + + + /** + * Determines which significant edit would be undone if {@link + * #undo()} was called. + * + * @returns the significant edit that would be undone, or + * <code>null</code> if no significant edit would be affected by + * calling {@link #undo()}. + */ + protected UndoableEdit editToBeUndone() + { + UndoableEdit result; + + for (int i = indexOfNextAdd - 1; i >= 0; i--) + { + result = (UndoableEdit) edits.get(i); + if (result.isSignificant()) + return result; + } + + return null; + } + + + /** + * Determines which significant edit would be redone if {@link + * #redo()} was called. + * + * @returns the significant edit that would be redone, or + * <code>null</code> if no significant edit would be affected by + * calling {@link #redo()}. + */ + protected UndoableEdit editToBeRedone() + { + UndoableEdit result; + + for (int i = indexOfNextAdd; i < edits.size(); i++) + { + result = (UndoableEdit) edits.get(i); + if (result.isSignificant()) + return result; + } + + return null; + } + + + /** + * Undoes all editing actions in reverse order of addition, + * up to the specified action, + * + * @param edit the last editing action to be undone. + */ + protected void undoTo(UndoableEdit edit) + throws CannotUndoException + { + UndoableEdit cur; + + if (!edits.contains(edit)) + throw new CannotUndoException(); + + while (true) + { + indexOfNextAdd -= 1; + cur = (UndoableEdit) edits.get(indexOfNextAdd); + cur.undo(); + if (cur == edit) + return; + } + } + + + /** + * Redoes all editing actions in the same order as they were + * added to this UndoManager, up to the specified action. + * + * @param edit the last editing action to be redone. + */ + protected void redoTo(UndoableEdit edit) + throws CannotRedoException + { + UndoableEdit cur; + + if (!edits.contains(edit)) + throw new CannotRedoException(); + + while (true) + { + cur = (UndoableEdit) edits.get(indexOfNextAdd); + indexOfNextAdd += 1; + cur.redo(); + if (cur == edit) + return; + } + } + + + /** + * Undoes or redoes the last action. If the last action has already + * been undone, it will be re-done, and vice versa. + * + * <p>This is useful for applications that do not present a separate + * undo and redo facility, but just have a single menu item for + * undoing and redoing the very last action. Such applications will + * use an <code>UndoManager</code> whose <code>limit</code> is 1. + */ + public synchronized void undoOrRedo() + throws CannotRedoException, CannotUndoException + { + if (indexOfNextAdd == edits.size()) + undo(); + else + redo(); + } + + + /** + * Determines whether it would be possible to either undo or redo + * this editing action. + * + * <p>This is useful for applications that do not present a separate + * undo and redo facility, but just have a single menu item for + * undoing and redoing the very last action. Such applications will + * use an <code>UndoManager</code> whose <code>limit</code> is 1. + * + * @return <code>true</code> to indicate that this action can be + * undone or redone; <code>false</code> if neither is possible at + * the current time. + */ + public synchronized boolean canUndoOrRedo() + { + return indexOfNextAdd == edits.size() ? canUndo() : canRedo(); + } + + + /** + * Undoes one significant edit action. If insignificant actions have + * been posted after the last signficant action, the insignificant + * ones will be undone first. + * + * <p>However, if {@link #end()} has been called on this + * UndoManager, it will behave like a normal {@link + * CompoundEdit}. In this case, all actions will be undone in + * reverse order of addition. Typical applications will never call + * {@link #end()} on their <code>UndoManager</code>. + * + * @throws CannotUndoException if no action can be undone. + * + * @see #canUndo() + * @see #redo() + * @see #undoOrRedo() + */ + public synchronized void undo() + throws CannotUndoException + { + if (!isInProgress()) + { + super.undo(); + return; + } + + UndoableEdit edit = editToBeUndone(); + if (edit == null) + throw new CannotUndoException(); + + undoTo(edit); + } + + + /** + * Determines whether it would be possible to undo this editing + * action. + * + * @return <code>true</code> to indicate that this action can be + * undone; <code>false</code> otherwise. + * + * @see #undo() + * @see #canRedo() + * @see #canUndoOrRedo() + */ + public synchronized boolean canUndo() + { + UndoableEdit edit; + + if (!isInProgress()) + return super.canUndo(); + + edit = editToBeUndone(); + return edit != null && edit.canUndo(); + } + + + + /** + * Redoes one significant edit action. If insignificant actions have + * been posted in between, the insignificant ones will be redone + * first. + * + * <p>However, if {@link #end()} has been called on this + * UndoManager, it will behave like a normal {@link + * CompoundEdit}. In this case, <em>all</em> actions will be redone + * in order of addition. Typical applications will never call {@link + * #end()} on their <code>UndoManager</code>. + * + * @throws CannotRedoException if no action can be redone. + * + * @see #canRedo() + * @see #redo() + * @see #undoOrRedo() + */ + public synchronized void redo() + throws CannotRedoException + { + if (!isInProgress()) + { + super.redo(); + return; + } + + UndoableEdit edit = editToBeRedone(); + if (edit == null) + throw new CannotRedoException(); + + redoTo(edit); + } + + + /** + * Determines whether it would be possible to redo this editing + * action. + * + * @return <code>true</code> to indicate that this action can be + * redone; <code>false</code> otherwise. + * + * @see #redo() + * @see #canUndo() + * @see #canUndoOrRedo() + */ + public synchronized boolean canRedo() + { + UndoableEdit edit; + + if (!isInProgress()) + return super.canRedo(); + + edit = editToBeRedone(); + return edit != null && edit.canRedo(); + } + + + /** + * Registers an undoable editing action with this UndoManager. If + * the capacity <code>limit</code> is reached, the oldest action + * will be discarded (and receives a {@linkplain UndoableEdit#die() + * die message}. Equally, any actions that were undone (but not re-done) + * will be discarded, too. + * + * @param edit the editing action that is added to this UndoManager. + * + * @return <code>true</code> if <code>edit</code> could be + * incorporated; <code>false</code> if <code>edit</code> has not + * been incorporated because {@link #end()} has already been called + * on this <code>UndoManager</code>. + */ + public synchronized boolean addEdit(UndoableEdit edit) + { + boolean result; + + // Discard any edits starting at indexOfNextAdd. + trimEdits(indexOfNextAdd, edits.size() - 1); + + result = super.addEdit(edit); + indexOfNextAdd = edits.size(); + trimForLimit(); + return result; + } + + + /** + * Calculates a localized text for presenting the undo or redo + * action to the user, for example in the form of a menu command. + * + * <p>This is useful for applications that do not present a separate + * undo and redo facility, but just have a single menu item for + * undoing and redoing the very last action. Such applications will + * use an <code>UndoManager</code> whose <code>limit</code> is 1. + * + * @return the redo presentation name if the last action has already + * been undone, or the undo presentation name otherwise. + * + * @see #getUndoPresentationName() + * @see #getRedoPresentationName() + */ + public synchronized String getUndoOrRedoPresentationName() + { + if (indexOfNextAdd == edits.size()) + return getUndoPresentationName(); + else + return getRedoPresentationName(); + } + + + /** + * Calculates a localized text for presenting the undo action + * to the user, for example in the form of a menu command. + */ + public synchronized String getUndoPresentationName() + { + UndoableEdit edit; + + if (!isInProgress()) + return super.getUndoPresentationName(); + + edit = editToBeUndone(); + if (edit == null) + return UIManager.getString("AbstractUndoableEdit.undoText"); + else + return edit.getUndoPresentationName(); + } + + + /** + * Calculates a localized text for presenting the redo action + * to the user, for example in the form of a menu command. + */ + public synchronized String getRedoPresentationName() + { + UndoableEdit edit; + + if (!isInProgress()) + return super.getRedoPresentationName(); + + edit = editToBeRedone(); + if (edit == null) + return UIManager.getString("AbstractUndoableEdit.redoText"); + else + return edit.getRedoPresentationName(); + } + + + /** + * Registers the edit action of an {@link UndoableEditEvent} + * with this UndoManager. + * + * <p><b>Thread Safety:</b> This method may safely be invoked from + * concurrent threads. The caller does not need to perform external + * synchronization. This means that {@link + * javax.swing.event.UndoableEditEvent} sources do not need to broadcast + * their events from inside the Swing worker thread. + * + * @param event the event whose <code>edit</code> will be + * passed to {@link #addEdit}. + * + * @see UndoableEditEvent#getEdit() + * @see #addEdit + */ + public void undoableEditHappened(UndoableEditEvent event) + { + // Note that this method does not need to be synchronized, + // because addEdit will obtain and release the mutex. + addEdit(event.getEdit()); + } +} diff --git a/libjava/classpath/javax/swing/undo/UndoableEdit.java b/libjava/classpath/javax/swing/undo/UndoableEdit.java new file mode 100644 index 00000000000..982d7f2a729 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/UndoableEdit.java @@ -0,0 +1,114 @@ +/* AbstractTableModel.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.undo; + +/** + * UndoableEdit public interface + * @author Andrew Selkirk + */ +public interface UndoableEdit { + + /** + * anEdit + * @param anEdit TODO + * @returns TODO + */ + boolean addEdit(UndoableEdit anEdit); + + /** + * canRedo + * @returns TODO + */ + boolean canRedo(); + + /** + * canRedo + * @returns TODO + */ + boolean canUndo(); + + /** + * die + */ + void die(); + + /** + * getPresentationName + * @returns TODO + */ + String getPresentationName(); + + /** + * getRedoPresentationName + * @returns TODO + */ + String getRedoPresentationName(); + + /** + * getUndoPresentationName + * @returns TODO + */ + String getUndoPresentationName(); + + /** + * isSignificant + * @returns TODO + */ + boolean isSignificant(); + + /** + * redo + * @throws CannotRedoException TODO + */ + void redo() throws CannotRedoException; + + /** + * replaceEdit + * @param anEdit TODO + * @returns TODO + */ + boolean replaceEdit(UndoableEdit anEdit); + + /** + * undo + * @throws CannotUndoException TODO + */ + void undo() throws CannotUndoException; + + +} // UndoableEdit diff --git a/libjava/classpath/javax/swing/undo/UndoableEditSupport.java b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java new file mode 100644 index 00000000000..918e7352313 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/UndoableEditSupport.java @@ -0,0 +1,271 @@ +/* UndoableEditSupport.java -- + Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package javax.swing.undo; + +import java.util.Iterator; +import java.util.Vector; + +import javax.swing.event.UndoableEditEvent; +import javax.swing.event.UndoableEditListener; + +/** + * A helper class for supporting {@link + * javax.swing.event.UndoableEditListener}. + * + * @author Andrew Selkirk (aselkirk@sympatico.ca) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class UndoableEditSupport +{ + /** + * The number of times that {@link #beginUpdate()} has been called + * without a matching call to {@link #endUpdate()}. + */ + protected int updateLevel; + + + /** + * compoundEdit + */ + protected CompoundEdit compoundEdit; + + + /** + * The currently registered listeners. + */ + protected Vector listeners = new Vector(); + + + /** + * The source of the broadcast UndoableEditEvents. + */ + protected Object realSource; + + + /** + * Constructs a new helper for broadcasting UndoableEditEvents. The + * events will indicate the newly constructed + * <code>UndoableEditSupport</code> instance as their source. + * + * @see #UndoableEditSupport(java.lang.Object) + */ + public UndoableEditSupport() + { + realSource = this; + } + + + /** + * Constructs a new helper for broadcasting UndoableEditEvents. + * + * @param realSource the source of the UndoableEditEvents that will + * be broadcast by this helper. If <code>realSource</code> is + * <code>null</code>, the events will indicate the newly constructed + * <code>UndoableEditSupport</code> instance as their source. + */ + public UndoableEditSupport(Object realSource) + { + if (realSource == null) + realSource = this; + this.realSource = realSource; + } + + + /** + * Returns a string representation of this object that may be useful + * for debugging. + */ + public String toString() + { + // Note that often, this.realSource == this. Therefore, dumping + // realSource without additional checks may lead to infinite + // recursion. See Classpath bug #7119. + return super.toString() + " updateLevel: " + updateLevel + + " listeners: " + listeners + " compoundEdit: " + compoundEdit; + } + + + /** + * Registers a listener. + * + * @param val the listener to be added. + */ + public synchronized void addUndoableEditListener(UndoableEditListener val) + { + listeners.add(val); + } + + + /** + * Unregisters a listener. + * @param val the listener to be removed. + */ + public synchronized void removeUndoableEditListener(UndoableEditListener val) + { + listeners.removeElement(val); + } + + + /** + * Returns an array containing the currently registered listeners. + */ + public synchronized UndoableEditListener[] getUndoableEditListeners() + { + UndoableEditListener[] result = new UndoableEditListener[listeners.size()]; + return (UndoableEditListener[]) listeners.toArray(result); + } + + + /** + * Notifies all registered listeners that an {@link + * UndoableEditEvent} has occured. + * + * <p><b>Lack of Thread Safety:</b> It is <em>not</em> safe to call + * this method from concurrent threads, unless the call is protected + * by a synchronization on this <code>UndoableEditSupport</code> + * instance. + * + * @param edit the edit action to be posted. + */ + protected void _postEdit(UndoableEdit edit) + { + UndoableEditEvent event; + Iterator iter; + + // Do nothing if we have no listeners. + if (listeners.isEmpty()) + return; + + event = new UndoableEditEvent(realSource, edit); + + // We clone the vector because this allows listeners to register + // or unregister listeners in their undoableEditHappened method. + // Otherwise, this would throw exceptions (in the case of + // Iterator, a java.util.ConcurrentModificationException; in the + // case of a direct loop over the Vector elements, some + // index-out-of-bounds exception). + iter = ((Vector) listeners.clone()).iterator(); + while (iter.hasNext()) + ((UndoableEditListener) iter.next()).undoableEditHappened(event); + } + + + /** + * If {@link #beginUpdate} has been called (so that the current + * update level is greater than zero), adds the specified edit + * to {@link #compoundEdit}. Otherwise, notify listeners of the + * edit by calling {@link #_postEdit(UndoableEdit)}. + * + * <p><b>Thread Safety:</b> It is safe to call this method from any + * thread without external synchronization. + * + * @param edit the edit action to be posted. + */ + public synchronized void postEdit(UndoableEdit edit) + { + if (compoundEdit != null) + compoundEdit.addEdit(edit); + else + _postEdit(edit); + } + + + /** + * Returns the current update level. + */ + public int getUpdateLevel() + { + return updateLevel; + } + + + /** + * Starts a (possibly nested) update session. If the current update + * level is zero, {@link #compoundEdit} is set to the result of the + * {@link #createCompoundEdit} method. In any case, the update level + * is increased by one. + * + * <p><b>Thread Safety:</b> It is safe to call this method from any + * thread without external synchronization. + */ + public synchronized void beginUpdate() + { + if (compoundEdit == null) + compoundEdit = createCompoundEdit(); + ++updateLevel; + } + + + /** + * Creates a new instance of {@link CompoundEdit}. Called by {@link + * #beginUpdate}. If a subclass wants {@link #beginUpdate} to work + * on a specific {@link #compoundEdit}, it should override this + * method. + * + * @returns a newly created instance of {@link CompoundEdit}. + */ + protected CompoundEdit createCompoundEdit() + { + return new CompoundEdit(); + } + + + /** + * Ends an update session. If the terminated session was the + * outermost session, {@link #compoundEdit} will receive an + * <code>end</code> message, and {@link #_postEdit} gets called in + * order to notify any listeners. Finally, the + * <code>compoundEdit</code> is discarded. + * + * <p><b>Thread Safety:</b> It is safe to call this method from any + * thread without external synchronization. + */ + public synchronized void endUpdate() + { + if (updateLevel == 0) + throw new IllegalStateException(); + + if (--updateLevel > 0) + return; + + compoundEdit.end(); + _postEdit(compoundEdit); + compoundEdit = null; + } +} diff --git a/libjava/classpath/javax/swing/undo/package.html b/libjava/classpath/javax/swing/undo/package.html new file mode 100644 index 00000000000..125bd4446a6 --- /dev/null +++ b/libjava/classpath/javax/swing/undo/package.html @@ -0,0 +1,46 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.undo package. + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - javax.swing.undo</title></head> + +<body> +<p>Provides a mechanism to support undo/redo operations.</p> + +</body> +</html> |