feat(jdk8): move files to new folder to avoid resources compiled.

This commit is contained in:
2025-09-07 15:25:52 +08:00
parent 3f0047bf6f
commit 8c35cfb1c0
17415 changed files with 217 additions and 213 deletions

View File

@@ -0,0 +1,367 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.Hashtable;
import java.util.Enumeration;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.AccessController;
import javax.swing.event.SwingPropertyChangeSupport;
import sun.security.action.GetPropertyAction;
/**
* This class provides default implementations for the JFC <code>Action</code>
* interface. Standard behaviors like the get and set methods for
* <code>Action</code> object properties (icon, text, and enabled) are defined
* here. The developer need only subclass this abstract class and
* define the <code>actionPerformed</code> method.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Georges Saab
* @see Action
*/
public abstract class AbstractAction implements Action, Cloneable, Serializable
{
/**
* Whether or not actions should reconfigure all properties on null.
*/
private static Boolean RECONFIGURE_ON_NULL;
/**
* Specifies whether action is enabled; the default is true.
*/
protected boolean enabled = true;
/**
* Contains the array of key bindings.
*/
private transient ArrayTable arrayTable;
/**
* Whether or not to reconfigure all action properties from the
* specified event.
*/
static boolean shouldReconfigure(PropertyChangeEvent e) {
if (e.getPropertyName() == null) {
synchronized(AbstractAction.class) {
if (RECONFIGURE_ON_NULL == null) {
RECONFIGURE_ON_NULL = Boolean.valueOf(
AccessController.doPrivileged(new GetPropertyAction(
"swing.actions.reconfigureOnNull", "false")));
}
return RECONFIGURE_ON_NULL;
}
}
return false;
}
/**
* Sets the enabled state of a component from an Action.
*
* @param c the Component to set the enabled state on
* @param a the Action to set the enabled state from, may be null
*/
static void setEnabledFromAction(JComponent c, Action a) {
c.setEnabled((a != null) ? a.isEnabled() : true);
}
/**
* Sets the tooltip text of a component from an Action.
*
* @param c the Component to set the tooltip text on
* @param a the Action to set the tooltip text from, may be null
*/
static void setToolTipTextFromAction(JComponent c, Action a) {
c.setToolTipText(a != null ?
(String)a.getValue(Action.SHORT_DESCRIPTION) : null);
}
static boolean hasSelectedKey(Action a) {
return (a != null && a.getValue(Action.SELECTED_KEY) != null);
}
static boolean isSelected(Action a) {
return Boolean.TRUE.equals(a.getValue(Action.SELECTED_KEY));
}
/**
* Creates an {@code Action}.
*/
public AbstractAction() {
}
/**
* Creates an {@code Action} with the specified name.
*
* @param name the name ({@code Action.NAME}) for the action; a
* value of {@code null} is ignored
*/
public AbstractAction(String name) {
putValue(Action.NAME, name);
}
/**
* Creates an {@code Action} with the specified name and small icon.
*
* @param name the name ({@code Action.NAME}) for the action; a
* value of {@code null} is ignored
* @param icon the small icon ({@code Action.SMALL_ICON}) for the action; a
* value of {@code null} is ignored
*/
public AbstractAction(String name, Icon icon) {
this(name);
putValue(Action.SMALL_ICON, icon);
}
/**
* Gets the <code>Object</code> associated with the specified key.
*
* @param key a string containing the specified <code>key</code>
* @return the binding <code>Object</code> stored with this key; if there
* are no keys, it will return <code>null</code>
* @see Action#getValue
*/
public Object getValue(String key) {
if (key == "enabled") {
return enabled;
}
if (arrayTable == null) {
return null;
}
return arrayTable.get(key);
}
/**
* Sets the <code>Value</code> associated with the specified key.
*
* @param key the <code>String</code> that identifies the stored object
* @param newValue the <code>Object</code> to store using this key
* @see Action#putValue
*/
public void putValue(String key, Object newValue) {
Object oldValue = null;
if (key == "enabled") {
// Treat putValue("enabled") the same way as a call to setEnabled.
// If we don't do this it means the two may get out of sync, and a
// bogus property change notification would be sent.
//
// To avoid dependencies between putValue & setEnabled this
// directly changes enabled. If we instead called setEnabled
// to change enabled, it would be possible for stack
// overflow in the case where a developer implemented setEnabled
// in terms of putValue.
if (newValue == null || !(newValue instanceof Boolean)) {
newValue = false;
}
oldValue = enabled;
enabled = (Boolean)newValue;
} else {
if (arrayTable == null) {
arrayTable = new ArrayTable();
}
if (arrayTable.containsKey(key))
oldValue = arrayTable.get(key);
// Remove the entry for key if newValue is null
// else put in the newValue for key.
if (newValue == null) {
arrayTable.remove(key);
} else {
arrayTable.put(key,newValue);
}
}
firePropertyChange(key, oldValue, newValue);
}
/**
* Returns true if the action is enabled.
*
* @return true if the action is enabled, false otherwise
* @see Action#isEnabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Sets whether the {@code Action} is enabled. The default is {@code true}.
*
* @param newValue {@code true} to enable the action, {@code false} to
* disable it
* @see Action#setEnabled
*/
public void setEnabled(boolean newValue) {
boolean oldValue = this.enabled;
if (oldValue != newValue) {
this.enabled = newValue;
firePropertyChange("enabled",
Boolean.valueOf(oldValue), Boolean.valueOf(newValue));
}
}
/**
* Returns an array of <code>Object</code>s which are keys for
* which values have been set for this <code>AbstractAction</code>,
* or <code>null</code> if no keys have values set.
* @return an array of key objects, or <code>null</code> if no
* keys have values set
* @since 1.3
*/
public Object[] getKeys() {
if (arrayTable == null) {
return null;
}
Object[] keys = new Object[arrayTable.size()];
arrayTable.getKeys(keys);
return keys;
}
/**
* If any <code>PropertyChangeListeners</code> have been registered, the
* <code>changeSupport</code> field describes them.
*/
protected SwingPropertyChangeSupport changeSupport;
/**
* Supports reporting bound property changes. This method can be called
* when a bound property has changed and it will send the appropriate
* <code>PropertyChangeEvent</code> to any registered
* <code>PropertyChangeListeners</code>.
*/
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
if (changeSupport == null ||
(oldValue != null && newValue != null && oldValue.equals(newValue))) {
return;
}
changeSupport.firePropertyChange(propertyName, oldValue, newValue);
}
/**
* Adds a <code>PropertyChangeListener</code> to the listener list.
* The listener is registered for all properties.
* <p>
* A <code>PropertyChangeEvent</code> will get fired in response to setting
* a bound property, e.g. <code>setFont</code>, <code>setBackground</code>,
* or <code>setForeground</code>.
* Note that if the current component is inheriting its foreground,
* background, or font from its container, then no event will be
* fired in response to a change in the inherited property.
*
* @param listener The <code>PropertyChangeListener</code> to be added
*
* @see Action#addPropertyChangeListener
*/
public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
if (changeSupport == null) {
changeSupport = new SwingPropertyChangeSupport(this);
}
changeSupport.addPropertyChangeListener(listener);
}
/**
* Removes a <code>PropertyChangeListener</code> from the listener list.
* This removes a <code>PropertyChangeListener</code> that was registered
* for all properties.
*
* @param listener the <code>PropertyChangeListener</code> to be removed
*
* @see Action#removePropertyChangeListener
*/
public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
if (changeSupport == null) {
return;
}
changeSupport.removePropertyChangeListener(listener);
}
/**
* Returns an array of all the <code>PropertyChangeListener</code>s added
* to this AbstractAction with addPropertyChangeListener().
*
* @return all of the <code>PropertyChangeListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
if (changeSupport == null) {
return new PropertyChangeListener[0];
}
return changeSupport.getPropertyChangeListeners();
}
/**
* Clones the abstract action. This gives the clone
* its own copy of the key/value list,
* which is not handled for you by <code>Object.clone()</code>.
**/
protected Object clone() throws CloneNotSupportedException {
AbstractAction newAction = (AbstractAction)super.clone();
synchronized(this) {
if (arrayTable != null) {
newAction.arrayTable = (ArrayTable)arrayTable.clone();
}
}
return newAction;
}
private void writeObject(ObjectOutputStream s) throws IOException {
// Store the default fields
s.defaultWriteObject();
// And the keys
ArrayTable.writeArrayTable(s, arrayTable);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException,
IOException {
s.defaultReadObject();
for (int counter = s.readInt() - 1; counter >= 0; counter--) {
putValue((String)s.readObject(), s.readObject());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.event.*;
import java.util.EventObject;
import java.io.Serializable;
/**
*
* A base class for <code>CellEditors</code>, providing default
* implementations for the methods in the <code>CellEditor</code>
* interface except <code>getCellEditorValue()</code>.
* Like the other abstract implementations in Swing, also manages a list
* of listeners.
*
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Philip Milne
* @since 1.3
*/
public abstract class AbstractCellEditor implements CellEditor, Serializable {
protected EventListenerList listenerList = new EventListenerList();
transient protected ChangeEvent changeEvent = null;
// Force this to be implemented.
// public Object getCellEditorValue()
/**
* Returns true.
* @param e an event object
* @return true
*/
public boolean isCellEditable(EventObject e) {
return true;
}
/**
* Returns true.
* @param anEvent an event object
* @return true
*/
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
/**
* Calls <code>fireEditingStopped</code> and returns true.
* @return true
*/
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
/**
* Calls <code>fireEditingCanceled</code>.
*/
public void cancelCellEditing() {
fireEditingCanceled();
}
/**
* Adds a <code>CellEditorListener</code> to the listener list.
* @param l the new listener to be added
*/
public void addCellEditorListener(CellEditorListener l) {
listenerList.add(CellEditorListener.class, l);
}
/**
* Removes a <code>CellEditorListener</code> from the listener list.
* @param l the listener to be removed
*/
public void removeCellEditorListener(CellEditorListener l) {
listenerList.remove(CellEditorListener.class, l);
}
/**
* Returns an array of all the <code>CellEditorListener</code>s added
* to this AbstractCellEditor with addCellEditorListener().
*
* @return all of the <code>CellEditorListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public CellEditorListener[] getCellEditorListeners() {
return listenerList.getListeners(CellEditorListener.class);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. The event instance
* is created lazily.
*
* @see EventListenerList
*/
protected void fireEditingStopped() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((CellEditorListener)listeners[i+1]).editingStopped(changeEvent);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. The event instance
* is created lazily.
*
* @see EventListenerList
*/
protected void fireEditingCanceled() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==CellEditorListener.class) {
// Lazily create the event:
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((CellEditorListener)listeners[i+1]).editingCanceled(changeEvent);
}
}
}
}

View File

@@ -0,0 +1,222 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.event.*;
import java.io.Serializable;
import java.util.EventListener;
/**
* The abstract definition for the data model that provides
* a <code>List</code> with its contents.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @param <E> the type of the elements of this model
*
* @author Hans Muller
*/
public abstract class AbstractListModel<E> implements ListModel<E>, Serializable
{
protected EventListenerList listenerList = new EventListenerList();
/**
* Adds a listener to the list that's notified each time a change
* to the data model occurs.
*
* @param l the <code>ListDataListener</code> to be added
*/
public void addListDataListener(ListDataListener l) {
listenerList.add(ListDataListener.class, l);
}
/**
* Removes a listener from the list that's notified each time a
* change to the data model occurs.
*
* @param l the <code>ListDataListener</code> to be removed
*/
public void removeListDataListener(ListDataListener l) {
listenerList.remove(ListDataListener.class, l);
}
/**
* Returns an array of all the list data listeners
* registered on this <code>AbstractListModel</code>.
*
* @return all of this model's <code>ListDataListener</code>s,
* or an empty array if no list data listeners
* are currently registered
*
* @see #addListDataListener
* @see #removeListDataListener
*
* @since 1.4
*/
public ListDataListener[] getListDataListeners() {
return listenerList.getListeners(ListDataListener.class);
}
/**
* <code>AbstractListModel</code> subclasses must call this method
* <b>after</b>
* one or more elements of the list change. The changed elements
* are specified by the closed interval index0, index1 -- the endpoints
* are included. Note that
* index0 need not be less than or equal to index1.
*
* @param source the <code>ListModel</code> that changed, typically "this"
* @param index0 one end of the new interval
* @param index1 the other end of the new interval
* @see EventListenerList
* @see DefaultListModel
*/
protected void fireContentsChanged(Object source, int index0, int index1)
{
Object[] listeners = listenerList.getListenerList();
ListDataEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ListDataListener.class) {
if (e == null) {
e = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, index0, index1);
}
((ListDataListener)listeners[i+1]).contentsChanged(e);
}
}
}
/**
* <code>AbstractListModel</code> subclasses must call this method
* <b>after</b>
* one or more elements are added to the model. The new elements
* are specified by a closed interval index0, index1 -- the enpoints
* are included. Note that
* index0 need not be less than or equal to index1.
*
* @param source the <code>ListModel</code> that changed, typically "this"
* @param index0 one end of the new interval
* @param index1 the other end of the new interval
* @see EventListenerList
* @see DefaultListModel
*/
protected void fireIntervalAdded(Object source, int index0, int index1)
{
Object[] listeners = listenerList.getListenerList();
ListDataEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ListDataListener.class) {
if (e == null) {
e = new ListDataEvent(source, ListDataEvent.INTERVAL_ADDED, index0, index1);
}
((ListDataListener)listeners[i+1]).intervalAdded(e);
}
}
}
/**
* <code>AbstractListModel</code> subclasses must call this method
* <b>after</b> one or more elements are removed from the model.
* <code>index0</code> and <code>index1</code> are the end points
* of the interval that's been removed. Note that <code>index0</code>
* need not be less than or equal to <code>index1</code>.
*
* @param source the <code>ListModel</code> that changed, typically "this"
* @param index0 one end of the removed interval,
* including <code>index0</code>
* @param index1 the other end of the removed interval,
* including <code>index1</code>
* @see EventListenerList
* @see DefaultListModel
*/
protected void fireIntervalRemoved(Object source, int index0, int index1)
{
Object[] listeners = listenerList.getListenerList();
ListDataEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ListDataListener.class) {
if (e == null) {
e = new ListDataEvent(source, ListDataEvent.INTERVAL_REMOVED, index0, index1);
}
((ListDataListener)listeners[i+1]).intervalRemoved(e);
}
}
}
/**
* Returns an array of all the objects currently registered as
* <code><em>Foo</em>Listener</code>s
* upon this model.
* <code><em>Foo</em>Listener</code>s
* are registered using the <code>add<em>Foo</em>Listener</code> method.
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
* For example, you can query a list model
* <code>m</code>
* for its list data listeners
* with the following code:
*
* <pre>ListDataListener[] ldls = (ListDataListener[])(m.getListeners(ListDataListener.class));</pre>
*
* If no such listeners exist,
* this method returns an empty array.
*
* @param listenerType the type of listeners requested;
* this parameter should specify an interface
* that descends from <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s
* on this model,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code> doesn't
* specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getListDataListeners
*
* @since 1.3
*/
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
return listenerList.getListeners(listenerType);
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.*;
import javax.swing.event.*;
import java.io.Serializable;
/**
* This class provides the ChangeListener part of the
* SpinnerModel interface that should be suitable for most concrete SpinnerModel
* implementations. Subclasses must provide an implementation of the
* <code>setValue</code>, <code>getValue</code>, <code>getNextValue</code> and
* <code>getPreviousValue</code> methods.
*
* @see JSpinner
* @see SpinnerModel
* @see SpinnerListModel
* @see SpinnerNumberModel
* @see SpinnerDateModel
*
* @author Hans Muller
* @since 1.4
*/
public abstract class AbstractSpinnerModel implements SpinnerModel, Serializable
{
/**
* Only one ChangeEvent is needed per model instance since the
* event's only (read-only) state is the source property. The source
* of events generated here is always "this".
*/
private transient ChangeEvent changeEvent = null;
/**
* The list of ChangeListeners for this model. Subclasses may
* store their own listeners here.
*/
protected EventListenerList listenerList = new EventListenerList();
/**
* Adds a ChangeListener to the model's listener list. The
* ChangeListeners must be notified when the models value changes.
*
* @param l the ChangeListener to add
* @see #removeChangeListener
* @see SpinnerModel#addChangeListener
*/
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
/**
* Removes a ChangeListener from the model's listener list.
*
* @param l the ChangeListener to remove
* @see #addChangeListener
* @see SpinnerModel#removeChangeListener
*/
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
/**
* Returns an array of all the <code>ChangeListener</code>s added
* to this AbstractSpinnerModel with addChangeListener().
*
* @return all of the <code>ChangeListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public ChangeListener[] getChangeListeners() {
return listenerList.getListeners(ChangeListener.class);
}
/**
* Run each ChangeListeners stateChanged() method.
*
* @see #setValue
* @see EventListenerList
*/
protected void fireStateChanged()
{
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -=2 ) {
if (listeners[i] == ChangeListener.class) {
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
}
}
}
/**
* Return an array of all the listeners of the given type that
* were added to this model. For example to find all of the
* ChangeListeners added to this model:
* <pre>
* myAbstractSpinnerModel.getListeners(ChangeListener.class);
* </pre>
*
* @param listenerType the type of listeners to return, e.g. ChangeListener.class
* @return all of the objects receiving <em>listenerType</em> notifications
* from this model
*/
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
return listenerList.getListeners(listenerType);
}
}

View File

@@ -0,0 +1,390 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
/**
* The <code>Action</code> interface provides a useful extension to the
* <code>ActionListener</code>
* interface in cases where the same functionality may be accessed by
* several controls.
* <p>
* In addition to the <code>actionPerformed</code> method defined by the
* <code>ActionListener</code> interface, this interface allows the
* application to define, in a single place:
* <ul>
* <li>One or more text strings that describe the function. These strings
* can be used, for example, to display the flyover text for a button
* or to set the text in a menu item.
* <li>One or more icons that depict the function. These icons can be used
* for the images in a menu control, or for composite entries in a more
* sophisticated user interface.
* <li>The enabled/disabled state of the functionality. Instead of having
* to separately disable the menu item and the toolbar button, the
* application can disable the function that implements this interface.
* All components which are registered as listeners for the state change
* then know to disable event generation for that item and to modify the
* display accordingly.
* </ul>
* <p>
* This interface can be added to an existing class or used to create an
* adapter (typically, by subclassing <code>AbstractAction</code>).
* The <code>Action</code> object
* can then be added to multiple <code>Action</code>-aware containers
* and connected to <code>Action</code>-capable
* components. The GUI controls can then be activated or
* deactivated all at once by invoking the <code>Action</code> object's
* <code>setEnabled</code> method.
* <p>
* Note that <code>Action</code> implementations tend to be more expensive
* in terms of storage than a typical <code>ActionListener</code>,
* which does not offer the benefits of centralized control of
* functionality and broadcast of property changes. For this reason,
* you should take care to only use <code>Action</code>s where their benefits
* are desired, and use simple <code>ActionListener</code>s elsewhere.
* <br>
*
* <h3><a name="buttonActions"></a>Swing Components Supporting <code>Action</code></h3>
* <p>
* Many of Swing's components have an <code>Action</code> property. When
* an <code>Action</code> is set on a component, the following things
* happen:
* <ul>
* <li>The <code>Action</code> is added as an <code>ActionListener</code> to
* the component.
* <li>The component configures some of its properties to match the
* <code>Action</code>.
* <li>The component installs a <code>PropertyChangeListener</code> on the
* <code>Action</code> so that the component can change its properties
* to reflect changes in the <code>Action</code>'s properties.
* </ul>
* <p>
* The following table describes the properties used by
* <code>Swing</code> components that support <code>Actions</code>.
* In the table, <em>button</em> refers to any
* <code>AbstractButton</code> subclass, which includes not only
* <code>JButton</code> but also classes such as
* <code>JMenuItem</code>. Unless otherwise stated, a
* <code>null</code> property value in an <code>Action</code> (or a
* <code>Action</code> that is <code>null</code>) results in the
* button's corresponding property being set to <code>null</code>.
*
* <table border="1" cellpadding="1" cellspacing="0"
* summary="Supported Action properties">
* <tr valign="top" align="left">
* <th style="background-color:#CCCCFF" align="left">Component Property
* <th style="background-color:#CCCCFF" align="left">Components
* <th style="background-color:#CCCCFF" align="left">Action Key
* <th style="background-color:#CCCCFF" align="left">Notes
* <tr valign="top" align="left">
* <td><b><code>enabled</code></b>
* <td>All
* <td>The <code>isEnabled</code> method
* <td>&nbsp;
* <tr valign="top" align="left">
* <td><b><code>toolTipText</code></b>
* <td>All
* <td><code>SHORT_DESCRIPTION</code>
* <td>&nbsp;
* <tr valign="top" align="left">
* <td><b><code>actionCommand</code></b>
* <td>All
* <td><code>ACTION_COMMAND_KEY</code>
* <td>&nbsp;
* <tr valign="top" align="left">
* <td><b><code>mnemonic</code></b>
* <td>All buttons
* <td><code>MNEMONIC_KEY</code>
* <td>A <code>null</code> value or <code>Action</code> results in the
* button's <code>mnemonic</code> property being set to
* <code>'\0'</code>.
* <tr valign="top" align="left">
* <td><b><code>text</code></b>
* <td>All buttons
* <td><code>NAME</code>
* <td>If you do not want the text of the button to mirror that
* of the <code>Action</code>, set the property
* <code>hideActionText</code> to <code>true</code>. If
* <code>hideActionText</code> is <code>true</code>, setting the
* <code>Action</code> changes the text of the button to
* <code>null</code> and any changes to <code>NAME</code>
* are ignored. <code>hideActionText</code> is useful for
* tool bar buttons that typically only show an <code>Icon</code>.
* <code>JToolBar.add(Action)</code> sets the property to
* <code>true</code> if the <code>Action</code> has a
* non-<code>null</code> value for <code>LARGE_ICON_KEY</code> or
* <code>SMALL_ICON</code>.
* <tr valign="top" align="left">
* <td><b><code>displayedMnemonicIndex</code></b>
* <td>All buttons
* <td><code>DISPLAYED_MNEMONIC_INDEX_KEY</code>
* <td>If the value of <code>DISPLAYED_MNEMONIC_INDEX_KEY</code> is
* beyond the bounds of the text, it is ignored. When
* <code>setAction</code> is called, if the value from the
* <code>Action</code> is <code>null</code>, the displayed
* mnemonic index is not updated. In any subsequent changes to
* <code>DISPLAYED_MNEMONIC_INDEX_KEY</code>, <code>null</code>
* is treated as -1.
* <tr valign="top" align="left">
* <td><b><code>icon</code></b>
* <td>All buttons except of <code>JCheckBox</code>,
* <code>JToggleButton</code> and <code>JRadioButton</code>.
* <td>either <code>LARGE_ICON_KEY</code> or
* <code>SMALL_ICON</code>
* <td>The <code>JMenuItem</code> subclasses only use
* <code>SMALL_ICON</code>. All other buttons will use
* <code>LARGE_ICON_KEY</code>; if the value is <code>null</code> they
* use <code>SMALL_ICON</code>.
* <tr valign="top" align="left">
* <td><b><code>accelerator</code></b>
* <td>All <code>JMenuItem</code> subclasses, with the exception of
* <code>JMenu</code>.
* <td><code>ACCELERATOR_KEY</code>
* <td>&nbsp;
* <tr valign="top" align="left">
* <td><b><code>selected</code></b>
* <td><code>JToggleButton</code>, <code>JCheckBox</code>,
* <code>JRadioButton</code>, <code>JCheckBoxMenuItem</code> and
* <code>JRadioButtonMenuItem</code>
* <td><code>SELECTED_KEY</code>
* <td>Components that honor this property only use
* the value if it is {@code non-null}. For example, if
* you set an {@code Action} that has a {@code null}
* value for {@code SELECTED_KEY} on a {@code JToggleButton}, the
* {@code JToggleButton} will not update it's selected state in
* any way. Similarly, any time the {@code JToggleButton}'s
* selected state changes it will only set the value back on
* the {@code Action} if the {@code Action} has a {@code non-null}
* value for {@code SELECTED_KEY}.
* <br>
* Components that honor this property keep their selected state
* in sync with this property. When the same {@code Action} is used
* with multiple components, all the components keep their selected
* state in sync with this property. Mutually exclusive
* buttons, such as {@code JToggleButton}s in a {@code ButtonGroup},
* force only one of the buttons to be selected. As such, do not
* use the same {@code Action} that defines a value for the
* {@code SELECTED_KEY} property with multiple mutually
* exclusive buttons.
* </table>
* <p>
* <code>JPopupMenu</code>, <code>JToolBar</code> and <code>JMenu</code>
* all provide convenience methods for creating a component and setting the
* <code>Action</code> on the corresponding component. Refer to each of
* these classes for more information.
* <p>
* <code>Action</code> uses <code>PropertyChangeListener</code> to
* inform listeners the <code>Action</code> has changed. The beans
* specification indicates that a <code>null</code> property name can
* be used to indicate multiple values have changed. By default Swing
* components that take an <code>Action</code> do not handle such a
* change. To indicate that Swing should treat <code>null</code>
* according to the beans specification set the system property
* <code>swing.actions.reconfigureOnNull</code> to the <code>String</code>
* value <code>true</code>.
*
* @author Georges Saab
* @see AbstractAction
*/
public interface Action extends ActionListener {
/**
* Useful constants that can be used as the storage-retrieval key
* when setting or getting one of this object's properties (text
* or icon).
*/
/**
* Not currently used.
*/
public static final String DEFAULT = "Default";
/**
* The key used for storing the <code>String</code> name
* for the action, used for a menu or button.
*/
public static final String NAME = "Name";
/**
* The key used for storing a short <code>String</code>
* description for the action, used for tooltip text.
*/
public static final String SHORT_DESCRIPTION = "ShortDescription";
/**
* The key used for storing a longer <code>String</code>
* description for the action, could be used for context-sensitive help.
*/
public static final String LONG_DESCRIPTION = "LongDescription";
/**
* The key used for storing a small <code>Icon</code>, such
* as <code>ImageIcon</code>. This is typically used with
* menus such as <code>JMenuItem</code>.
* <p>
* If the same <code>Action</code> is used with menus and buttons you'll
* typically specify both a <code>SMALL_ICON</code> and a
* <code>LARGE_ICON_KEY</code>. The menu will use the
* <code>SMALL_ICON</code> and the button will use the
* <code>LARGE_ICON_KEY</code>.
*/
public static final String SMALL_ICON = "SmallIcon";
/**
* The key used to determine the command <code>String</code> for the
* <code>ActionEvent</code> that will be created when an
* <code>Action</code> is going to be notified as the result of
* residing in a <code>Keymap</code> associated with a
* <code>JComponent</code>.
*/
public static final String ACTION_COMMAND_KEY = "ActionCommandKey";
/**
* The key used for storing a <code>KeyStroke</code> to be used as the
* accelerator for the action.
*
* @since 1.3
*/
public static final String ACCELERATOR_KEY="AcceleratorKey";
/**
* The key used for storing an <code>Integer</code> that corresponds to
* one of the <code>KeyEvent</code> key codes. The value is
* commonly used to specify a mnemonic. For example:
* <code>myAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A)</code>
* sets the mnemonic of <code>myAction</code> to 'a', while
* <code>myAction.putValue(Action.MNEMONIC_KEY, KeyEvent.getExtendedKeyCodeForChar('\u0444'))</code>
* sets the mnemonic of <code>myAction</code> to Cyrillic letter "Ef".
*
* @since 1.3
*/
public static final String MNEMONIC_KEY="MnemonicKey";
/**
* The key used for storing a <code>Boolean</code> that corresponds
* to the selected state. This is typically used only for components
* that have a meaningful selection state. For example,
* <code>JRadioButton</code> and <code>JCheckBox</code> make use of
* this but instances of <code>JMenu</code> don't.
* <p>
* This property differs from the others in that it is both read
* by the component and set by the component. For example,
* if an <code>Action</code> is attached to a <code>JCheckBox</code>
* the selected state of the <code>JCheckBox</code> will be set from
* that of the <code>Action</code>. If the user clicks on the
* <code>JCheckBox</code> the selected state of the <code>JCheckBox</code>
* <b>and</b> the <code>Action</code> will <b>both</b> be updated.
* <p>
* Note: the value of this field is prefixed with 'Swing' to
* avoid possible collisions with existing <code>Actions</code>.
*
* @since 1.6
*/
public static final String SELECTED_KEY = "SwingSelectedKey";
/**
* The key used for storing an <code>Integer</code> that corresponds
* to the index in the text (identified by the <code>NAME</code>
* property) that the decoration for a mnemonic should be rendered at. If
* the value of this property is greater than or equal to the length of
* the text, it will treated as -1.
* <p>
* Note: the value of this field is prefixed with 'Swing' to
* avoid possible collisions with existing <code>Actions</code>.
*
* @see AbstractButton#setDisplayedMnemonicIndex
* @since 1.6
*/
public static final String DISPLAYED_MNEMONIC_INDEX_KEY =
"SwingDisplayedMnemonicIndexKey";
/**
* The key used for storing an <code>Icon</code>. This is typically
* used by buttons, such as <code>JButton</code> and
* <code>JToggleButton</code>.
* <p>
* If the same <code>Action</code> is used with menus and buttons you'll
* typically specify both a <code>SMALL_ICON</code> and a
* <code>LARGE_ICON_KEY</code>. The menu will use the
* <code>SMALL_ICON</code> and the button the <code>LARGE_ICON_KEY</code>.
* <p>
* Note: the value of this field is prefixed with 'Swing' to
* avoid possible collisions with existing <code>Actions</code>.
*
* @since 1.6
*/
public static final String LARGE_ICON_KEY = "SwingLargeIconKey";
/**
* Gets one of this object's properties
* using the associated key.
* @see #putValue
*/
public Object getValue(String key);
/**
* Sets one of this object's properties
* using the associated key. If the value has
* changed, a <code>PropertyChangeEvent</code> is sent
* to listeners.
*
* @param key a <code>String</code> containing the key
* @param value an <code>Object</code> value
*/
public void putValue(String key, Object value);
/**
* Sets the enabled state of the <code>Action</code>. When enabled,
* any component associated with this object is active and
* able to fire this object's <code>actionPerformed</code> method.
* If the value has changed, a <code>PropertyChangeEvent</code> is sent
* to listeners.
*
* @param b true to enable this <code>Action</code>, false to disable it
*/
public void setEnabled(boolean b);
/**
* Returns the enabled state of the <code>Action</code>. When enabled,
* any component associated with this object is active and
* able to fire this object's <code>actionPerformed</code> method.
*
* @return true if this <code>Action</code> is enabled
*/
public boolean isEnabled();
/**
* Adds a <code>PropertyChange</code> listener. Containers and attached
* components use these methods to register interest in this
* <code>Action</code> object. When its enabled state or other property
* changes, the registered listeners are informed of the change.
*
* @param listener a <code>PropertyChangeListener</code> object
*/
public void addPropertyChangeListener(PropertyChangeListener listener);
/**
* Removes a <code>PropertyChange</code> listener.
*
* @param listener a <code>PropertyChangeListener</code> object
* @see #addPropertyChangeListener
*/
public void removePropertyChangeListener(PropertyChangeListener listener);
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Set;
/**
* <code>ActionMap</code> provides mappings from
* <code>Object</code>s
* (called <em>keys</em> or <em><code>Action</code> names</em>)
* to <code>Action</code>s.
* An <code>ActionMap</code> is usually used with an <code>InputMap</code>
* to locate a particular action
* when a key is pressed. As with <code>InputMap</code>,
* an <code>ActionMap</code> can have a parent
* that is searched for keys not defined in the <code>ActionMap</code>.
* <p>As with <code>InputMap</code> if you create a cycle, eg:
* <pre>
* ActionMap am = new ActionMap();
* ActionMap bm = new ActionMap():
* am.setParent(bm);
* bm.setParent(am);
* </pre>
* some of the methods will cause a StackOverflowError to be thrown.
*
* @see InputMap
*
* @author Scott Violet
* @since 1.3
*/
@SuppressWarnings("serial")
public class ActionMap implements Serializable {
/** Handles the mapping between Action name and Action. */
private transient ArrayTable arrayTable;
/** Parent that handles any bindings we don't contain. */
private ActionMap parent;
/**
* Creates an <code>ActionMap</code> with no parent and no mappings.
*/
public ActionMap() {
}
/**
* Sets this <code>ActionMap</code>'s parent.
*
* @param map the <code>ActionMap</code> that is the parent of this one
*/
public void setParent(ActionMap map) {
this.parent = map;
}
/**
* Returns this <code>ActionMap</code>'s parent.
*
* @return the <code>ActionMap</code> that is the parent of this one,
* or null if this <code>ActionMap</code> has no parent
*/
public ActionMap getParent() {
return parent;
}
/**
* Adds a binding for <code>key</code> to <code>action</code>.
* If <code>action</code> is null, this removes the current binding
* for <code>key</code>.
* <p>In most instances, <code>key</code> will be
* <code>action.getValue(NAME)</code>.
*/
public void put(Object key, Action action) {
if (key == null) {
return;
}
if (action == null) {
remove(key);
}
else {
if (arrayTable == null) {
arrayTable = new ArrayTable();
}
arrayTable.put(key, action);
}
}
/**
* Returns the binding for <code>key</code>, messaging the
* parent <code>ActionMap</code> if the binding is not locally defined.
*/
public Action get(Object key) {
Action value = (arrayTable == null) ? null :
(Action)arrayTable.get(key);
if (value == null) {
ActionMap parent = getParent();
if (parent != null) {
return parent.get(key);
}
}
return value;
}
/**
* Removes the binding for <code>key</code> from this <code>ActionMap</code>.
*/
public void remove(Object key) {
if (arrayTable != null) {
arrayTable.remove(key);
}
}
/**
* Removes all the mappings from this <code>ActionMap</code>.
*/
public void clear() {
if (arrayTable != null) {
arrayTable.clear();
}
}
/**
* Returns the <code>Action</code> names that are bound in this <code>ActionMap</code>.
*/
public Object[] keys() {
if (arrayTable == null) {
return null;
}
return arrayTable.getKeys(null);
}
/**
* Returns the number of bindings in this {@code ActionMap}.
*
* @return the number of bindings in this {@code ActionMap}
*/
public int size() {
if (arrayTable == null) {
return 0;
}
return arrayTable.size();
}
/**
* Returns an array of the keys defined in this <code>ActionMap</code> and
* its parent. This method differs from <code>keys()</code> in that
* this method includes the keys defined in the parent.
*/
public Object[] allKeys() {
int count = size();
ActionMap parent = getParent();
if (count == 0) {
if (parent != null) {
return parent.allKeys();
}
return keys();
}
if (parent == null) {
return keys();
}
Object[] keys = keys();
Object[] pKeys = parent.allKeys();
if (pKeys == null) {
return keys;
}
if (keys == null) {
// Should only happen if size() != keys.length, which should only
// happen if mutated from multiple threads (or a bogus subclass).
return pKeys;
}
HashMap<Object, Object> keyMap = new HashMap<Object, Object>();
int counter;
for (counter = keys.length - 1; counter >= 0; counter--) {
keyMap.put(keys[counter], keys[counter]);
}
for (counter = pKeys.length - 1; counter >= 0; counter--) {
keyMap.put(pKeys[counter], pKeys[counter]);
}
return keyMap.keySet().toArray();
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
ArrayTable.writeArrayTable(s, arrayTable);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException,
IOException {
s.defaultReadObject();
for (int counter = s.readInt() - 1; counter >= 0; counter--) {
put(s.readObject(), (Action)s.readObject());
}
}
}

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
/**
* A package-private PropertyChangeListener which listens for
* property changes on an Action and updates the properties
* of an ActionEvent source.
* <p>
* Subclasses must override the actionPropertyChanged method,
* which is invoked from the propertyChange method as long as
* the target is still valid.
* </p>
* <p>
* WARNING WARNING WARNING WARNING WARNING WARNING:<br>
* Do NOT create an annonymous inner class that extends this! If you do
* a strong reference will be held to the containing class, which in most
* cases defeats the purpose of this class.
*
* @param T the type of JComponent the underlying Action is attached to
*
* @author Georges Saab
* @see AbstractButton
*/
abstract class ActionPropertyChangeListener<T extends JComponent>
implements PropertyChangeListener, Serializable {
private static ReferenceQueue<JComponent> queue;
// WeakReference's aren't serializable.
private transient OwnedWeakReference<T> target;
// The Component's that reference an Action do so through a strong
// reference, so that there is no need to check for serialized.
private Action action;
private static ReferenceQueue<JComponent> getQueue() {
synchronized(ActionPropertyChangeListener.class) {
if (queue == null) {
queue = new ReferenceQueue<JComponent>();
}
}
return queue;
}
public ActionPropertyChangeListener(T c, Action a) {
super();
setTarget(c);
this.action = a;
}
/**
* PropertyChangeListener method. If the target has been gc'ed this
* will remove the <code>PropertyChangeListener</code> from the Action,
* otherwise this will invoke actionPropertyChanged.
*/
public final void propertyChange(PropertyChangeEvent e) {
T target = getTarget();
if (target == null) {
getAction().removePropertyChangeListener(this);
} else {
actionPropertyChanged(target, getAction(), e);
}
}
/**
* Invoked when a property changes on the Action and the target
* still exists.
*/
protected abstract void actionPropertyChanged(T target, Action action,
PropertyChangeEvent e);
private void setTarget(T c) {
ReferenceQueue<JComponent> queue = getQueue();
// Check to see whether any old buttons have
// been enqueued for GC. If so, look up their
// PCL instance and remove it from its Action.
OwnedWeakReference<?> r;
while ((r = (OwnedWeakReference)queue.poll()) != null) {
ActionPropertyChangeListener<?> oldPCL = r.getOwner();
Action oldAction = oldPCL.getAction();
if (oldAction!=null) {
oldAction.removePropertyChangeListener(oldPCL);
}
}
this.target = new OwnedWeakReference<T>(c, queue, this);
}
public T getTarget() {
if (target == null) {
// Will only happen if serialized and real target was null
return null;
}
return this.target.get();
}
public Action getAction() {
return action;
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeObject(getTarget());
}
@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
T target = (T)s.readObject();
if (target != null) {
setTarget(target);
}
}
private static class OwnedWeakReference<U extends JComponent> extends
WeakReference<U> {
private ActionPropertyChangeListener<?> owner;
OwnedWeakReference(U target, ReferenceQueue<? super U> queue,
ActionPropertyChangeListener<?> owner) {
super(target, queue);
this.owner = owner;
}
public ActionPropertyChangeListener<?> getOwner() {
return owner;
}
}
}

View File

@@ -0,0 +1,240 @@
/*
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.event.*;
import java.awt.event.*;
import java.awt.Component;
import java.awt.Container;
import java.awt.Window;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.io.Serializable;
/**
* @author Dave Moore
*/
@SuppressWarnings("serial")
class AncestorNotifier implements ComponentListener, PropertyChangeListener, Serializable
{
transient Component firstInvisibleAncestor;
EventListenerList listenerList = new EventListenerList();
JComponent root;
AncestorNotifier(JComponent root) {
this.root = root;
addListeners(root, true);
}
void addAncestorListener(AncestorListener l) {
listenerList.add(AncestorListener.class, l);
}
void removeAncestorListener(AncestorListener l) {
listenerList.remove(AncestorListener.class, l);
}
AncestorListener[] getAncestorListeners() {
return listenerList.getListeners(AncestorListener.class);
}
/**
* Notify all listeners that have registered interest for
* notification on this event type. The event instance
* is lazily created using the parameters passed into
* the fire method.
* @see EventListenerList
*/
protected void fireAncestorAdded(JComponent source, int id, Container ancestor, Container ancestorParent) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==AncestorListener.class) {
// Lazily create the event:
AncestorEvent ancestorEvent =
new AncestorEvent(source, id, ancestor, ancestorParent);
((AncestorListener)listeners[i+1]).ancestorAdded(ancestorEvent);
}
}
}
/**
* Notify all listeners that have registered interest for
* notification on this event type. The event instance
* is lazily created using the parameters passed into
* the fire method.
* @see EventListenerList
*/
protected void fireAncestorRemoved(JComponent source, int id, Container ancestor, Container ancestorParent) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==AncestorListener.class) {
// Lazily create the event:
AncestorEvent ancestorEvent =
new AncestorEvent(source, id, ancestor, ancestorParent);
((AncestorListener)listeners[i+1]).ancestorRemoved(ancestorEvent);
}
}
}
/**
* Notify all listeners that have registered interest for
* notification on this event type. The event instance
* is lazily created using the parameters passed into
* the fire method.
* @see EventListenerList
*/
protected void fireAncestorMoved(JComponent source, int id, Container ancestor, Container ancestorParent) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==AncestorListener.class) {
// Lazily create the event:
AncestorEvent ancestorEvent =
new AncestorEvent(source, id, ancestor, ancestorParent);
((AncestorListener)listeners[i+1]).ancestorMoved(ancestorEvent);
}
}
}
void removeAllListeners() {
removeListeners(root);
}
void addListeners(Component ancestor, boolean addToFirst) {
Component a;
firstInvisibleAncestor = null;
for (a = ancestor;
firstInvisibleAncestor == null;
a = a.getParent()) {
if (addToFirst || a != ancestor) {
a.addComponentListener(this);
if (a instanceof JComponent) {
JComponent jAncestor = (JComponent)a;
jAncestor.addPropertyChangeListener(this);
}
}
if (!a.isVisible() || a.getParent() == null || a instanceof Window) {
firstInvisibleAncestor = a;
}
}
if (firstInvisibleAncestor instanceof Window &&
firstInvisibleAncestor.isVisible()) {
firstInvisibleAncestor = null;
}
}
void removeListeners(Component ancestor) {
Component a;
for (a = ancestor; a != null; a = a.getParent()) {
a.removeComponentListener(this);
if (a instanceof JComponent) {
JComponent jAncestor = (JComponent)a;
jAncestor.removePropertyChangeListener(this);
}
if (a == firstInvisibleAncestor || a instanceof Window) {
break;
}
}
}
public void componentResized(ComponentEvent e) {}
public void componentMoved(ComponentEvent e) {
Component source = e.getComponent();
fireAncestorMoved(root, AncestorEvent.ANCESTOR_MOVED,
(Container)source, source.getParent());
}
public void componentShown(ComponentEvent e) {
Component ancestor = e.getComponent();
if (ancestor == firstInvisibleAncestor) {
addListeners(ancestor, false);
if (firstInvisibleAncestor == null) {
fireAncestorAdded(root, AncestorEvent.ANCESTOR_ADDED,
(Container)ancestor, ancestor.getParent());
}
}
}
public void componentHidden(ComponentEvent e) {
Component ancestor = e.getComponent();
boolean needsNotify = firstInvisibleAncestor == null;
if ( !(ancestor instanceof Window) ) {
removeListeners(ancestor.getParent());
}
firstInvisibleAncestor = ancestor;
if (needsNotify) {
fireAncestorRemoved(root, AncestorEvent.ANCESTOR_REMOVED,
(Container)ancestor, ancestor.getParent());
}
}
public void propertyChange(PropertyChangeEvent evt) {
String s = evt.getPropertyName();
if (s!=null && (s.equals("parent") || s.equals("ancestor"))) {
JComponent component = (JComponent)evt.getSource();
if (evt.getNewValue() != null) {
if (component == firstInvisibleAncestor) {
addListeners(component, false);
if (firstInvisibleAncestor == null) {
fireAncestorAdded(root, AncestorEvent.ANCESTOR_ADDED,
component, component.getParent());
}
}
} else {
boolean needsNotify = firstInvisibleAncestor == null;
Container oldParent = (Container)evt.getOldValue();
removeListeners(oldParent);
firstInvisibleAncestor = component;
if (needsNotify) {
fireAncestorRemoved(root, AncestorEvent.ANCESTOR_REMOVED,
component, oldParent);
}
}
}
}
}

View File

@@ -0,0 +1,342 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Hashtable;
/*
* Private storage mechanism for Action key-value pairs.
* In most cases this will be an array of alternating
* key-value pairs. As it grows larger it is scaled
* up to a Hashtable.
* <p>
* This does no synchronization, if you need thread safety synchronize on
* another object before calling this.
*
* @author Georges Saab
* @author Scott Violet
*/
class ArrayTable implements Cloneable {
// Our field for storage
private Object table = null;
private static final int ARRAY_BOUNDARY = 8;
/**
* Writes the passed in ArrayTable to the passed in ObjectOutputStream.
* The data is saved as an integer indicating how many key/value
* pairs are being archived, followed by the the key/value pairs. If
* <code>table</code> is null, 0 will be written to <code>s</code>.
* <p>
* This is a convenience method that ActionMap/InputMap and
* AbstractAction use to avoid having the same code in each class.
*/
static void writeArrayTable(ObjectOutputStream s, ArrayTable table) throws IOException {
Object keys[];
if (table == null || (keys = table.getKeys(null)) == null) {
s.writeInt(0);
}
else {
// Determine how many keys have Serializable values, when
// done all non-null values in keys identify the Serializable
// values.
int validCount = 0;
for (int counter = 0; counter < keys.length; counter++) {
Object key = keys[counter];
/* include in Serialization when both keys and values are Serializable */
if ( (key instanceof Serializable
&& table.get(key) instanceof Serializable)
||
/* include these only so that we get the appropriate exception below */
(key instanceof ClientPropertyKey
&& ((ClientPropertyKey)key).getReportValueNotSerializable())) {
validCount++;
} else {
keys[counter] = null;
}
}
// Write ou the Serializable key/value pairs.
s.writeInt(validCount);
if (validCount > 0) {
for (Object key : keys) {
if (key != null) {
s.writeObject(key);
s.writeObject(table.get(key));
if (--validCount == 0) {
break;
}
}
}
}
}
}
/*
* Put the key-value pair into storage
*/
public void put(Object key, Object value){
if (table==null) {
table = new Object[] {key, value};
} else {
int size = size();
if (size < ARRAY_BOUNDARY) { // We are an array
if (containsKey(key)) {
Object[] tmp = (Object[])table;
for (int i = 0; i<tmp.length-1; i+=2) {
if (tmp[i].equals(key)) {
tmp[i+1]=value;
break;
}
}
} else {
Object[] array = (Object[])table;
int i = array.length;
Object[] tmp = new Object[i+2];
System.arraycopy(array, 0, tmp, 0, i);
tmp[i] = key;
tmp[i+1] = value;
table = tmp;
}
} else { // We are a hashtable
if ((size==ARRAY_BOUNDARY) && isArray()) {
grow();
}
((Hashtable<Object,Object>)table).put(key, value);
}
}
}
/*
* Gets the value for key
*/
public Object get(Object key) {
Object value = null;
if (table !=null) {
if (isArray()) {
Object[] array = (Object[])table;
for (int i = 0; i<array.length-1; i+=2) {
if (array[i].equals(key)) {
value = array[i+1];
break;
}
}
} else {
value = ((Hashtable)table).get(key);
}
}
return value;
}
/*
* Returns the number of pairs in storage
*/
public int size() {
int size;
if (table==null)
return 0;
if (isArray()) {
size = ((Object[])table).length/2;
} else {
size = ((Hashtable)table).size();
}
return size;
}
/*
* Returns true if we have a value for the key
*/
public boolean containsKey(Object key) {
boolean contains = false;
if (table !=null) {
if (isArray()) {
Object[] array = (Object[])table;
for (int i = 0; i<array.length-1; i+=2) {
if (array[i].equals(key)) {
contains = true;
break;
}
}
} else {
contains = ((Hashtable)table).containsKey(key);
}
}
return contains;
}
/*
* Removes the key and its value
* Returns the value for the pair removed
*/
public Object remove(Object key){
Object value = null;
if (key==null) {
return null;
}
if (table !=null) {
if (isArray()){
// Is key on the list?
int index = -1;
Object[] array = (Object[])table;
for (int i = array.length-2; i>=0; i-=2) {
if (array[i].equals(key)) {
index = i;
value = array[i+1];
break;
}
}
// If so, remove it
if (index != -1) {
Object[] tmp = new Object[array.length-2];
// Copy the list up to index
System.arraycopy(array, 0, tmp, 0, index);
// Copy from two past the index, up to
// the end of tmp (which is two elements
// shorter than the old list)
if (index < tmp.length)
System.arraycopy(array, index+2, tmp, index,
tmp.length - index);
// set the listener array to the new array or null
table = (tmp.length == 0) ? null : tmp;
}
} else {
value = ((Hashtable)table).remove(key);
}
if (size()==ARRAY_BOUNDARY - 1 && !isArray()) {
shrink();
}
}
return value;
}
/**
* Removes all the mappings.
*/
public void clear() {
table = null;
}
/*
* Returns a clone of the <code>ArrayTable</code>.
*/
public Object clone() {
ArrayTable newArrayTable = new ArrayTable();
if (isArray()) {
Object[] array = (Object[])table;
for (int i = 0 ;i < array.length-1 ; i+=2) {
newArrayTable.put(array[i], array[i+1]);
}
} else {
Hashtable<?,?> tmp = (Hashtable)table;
Enumeration<?> keys = tmp.keys();
while (keys.hasMoreElements()) {
Object o = keys.nextElement();
newArrayTable.put(o,tmp.get(o));
}
}
return newArrayTable;
}
/**
* Returns the keys of the table, or <code>null</code> if there
* are currently no bindings.
* @param keys array of keys
* @return an array of bindings
*/
public Object[] getKeys(Object[] keys) {
if (table == null) {
return null;
}
if (isArray()) {
Object[] array = (Object[])table;
if (keys == null) {
keys = new Object[array.length / 2];
}
for (int i = 0, index = 0 ;i < array.length-1 ; i+=2,
index++) {
keys[index] = array[i];
}
} else {
Hashtable<?,?> tmp = (Hashtable)table;
Enumeration<?> enum_ = tmp.keys();
int counter = tmp.size();
if (keys == null) {
keys = new Object[counter];
}
while (counter > 0) {
keys[--counter] = enum_.nextElement();
}
}
return keys;
}
/*
* Returns true if the current storage mechanism is
* an array of alternating key-value pairs.
*/
private boolean isArray(){
return (table instanceof Object[]);
}
/*
* Grows the storage from an array to a hashtable.
*/
private void grow() {
Object[] array = (Object[])table;
Hashtable<Object, Object> tmp = new Hashtable<Object, Object>(array.length/2);
for (int i = 0; i<array.length; i+=2) {
tmp.put(array[i], array[i+1]);
}
table = tmp;
}
/*
* Shrinks the storage from a hashtable to an array.
*/
private void shrink() {
Hashtable<?,?> tmp = (Hashtable)table;
Object[] array = new Object[tmp.size()*2];
Enumeration<?> keys = tmp.keys();
int j = 0;
while (keys.hasMoreElements()) {
Object o = keys.nextElement();
array[j] = o;
array[j+1] = tmp.get(o);
j+=2;
}
table = array;
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import sun.awt.AWTAccessor;
import sun.awt.AWTAccessor.MouseEventAccessor;
/**
* Autoscroller is responsible for generating synthetic mouse dragged
* events. It is the responsibility of the Component (or its MouseListeners)
* that receive the events to do the actual scrolling in response to the
* mouse dragged events.
*
* @author Dave Moore
* @author Scott Violet
*/
class Autoscroller implements ActionListener {
/**
* Global Autoscroller.
*/
private static Autoscroller sharedInstance = new Autoscroller();
// As there can only ever be one autoscroller active these fields are
// static. The Timer is recreated as necessary to target the appropriate
// Autoscroller instance.
private static MouseEvent event;
private static Timer timer;
private static JComponent component;
//
// The public API, all methods are cover methods for an instance method
//
/**
* Stops autoscroll events from happening on the specified component.
*/
public static void stop(JComponent c) {
sharedInstance._stop(c);
}
/**
* Stops autoscroll events from happening on the specified component.
*/
public static boolean isRunning(JComponent c) {
return sharedInstance._isRunning(c);
}
/**
* Invoked when a mouse dragged event occurs, will start the autoscroller
* if necessary.
*/
public static void processMouseDragged(MouseEvent e) {
sharedInstance._processMouseDragged(e);
}
Autoscroller() {
}
/**
* Starts the timer targeting the passed in component.
*/
private void start(JComponent c, MouseEvent e) {
Point screenLocation = c.getLocationOnScreen();
if (component != c) {
_stop(component);
}
component = c;
event = new MouseEvent(component, e.getID(), e.getWhen(),
e.getModifiers(), e.getX() + screenLocation.x,
e.getY() + screenLocation.y,
e.getXOnScreen(),
e.getYOnScreen(),
e.getClickCount(), e.isPopupTrigger(),
MouseEvent.NOBUTTON);
MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
meAccessor.setCausedByTouchEvent(event,
meAccessor.isCausedByTouchEvent(e));
if (timer == null) {
timer = new Timer(100, this);
}
if (!timer.isRunning()) {
timer.start();
}
}
//
// Methods mirror the public static API
//
/**
* Stops scrolling for the passed in widget.
*/
private void _stop(JComponent c) {
if (component == c) {
if (timer != null) {
timer.stop();
}
timer = null;
event = null;
component = null;
}
}
/**
* Returns true if autoscrolling is currently running for the specified
* widget.
*/
private boolean _isRunning(JComponent c) {
return (c == component && timer != null && timer.isRunning());
}
/**
* MouseListener method, invokes start/stop as necessary.
*/
private void _processMouseDragged(MouseEvent e) {
JComponent component = (JComponent)e.getComponent();
boolean stop = true;
if (component.isShowing()) {
Rectangle visibleRect = component.getVisibleRect();
stop = visibleRect.contains(e.getX(), e.getY());
}
if (stop) {
_stop(component);
} else {
start(component, e);
}
}
//
// ActionListener
//
/**
* ActionListener method. Invoked when the Timer fires. This will scroll
* if necessary.
*/
public void actionPerformed(ActionEvent x) {
JComponent component = Autoscroller.component;
if (component == null || !component.isShowing() || (event == null)) {
_stop(component);
return;
}
Point screenLocation = component.getLocationOnScreen();
MouseEvent e = new MouseEvent(component, event.getID(),
event.getWhen(), event.getModifiers(),
event.getX() - screenLocation.x,
event.getY() - screenLocation.y,
event.getXOnScreen(),
event.getYOnScreen(),
event.getClickCount(),
event.isPopupTrigger(),
MouseEvent.NOBUTTON);
MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
meAccessor.setCausedByTouchEvent(e,
meAccessor.isCausedByTouchEvent(event));
component.superProcessMouseMotionEvent(e);
}
}

View File

@@ -0,0 +1,762 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Paint;
import javax.swing.border.*;
/**
* Factory class for vending standard <code>Border</code> objects. Wherever
* possible, this factory will hand out references to shared
* <code>Border</code> instances.
* For further information and examples see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/border.htmll">How
to Use Borders</a>,
* a section in <em>The Java Tutorial</em>.
*
* @author David Kloba
*/
public class BorderFactory
{
/** Don't let anyone instantiate this class */
private BorderFactory() {
}
//// LineBorder ///////////////////////////////////////////////////////////////
/**
* Creates a line border withe the specified color.
*
* @param color a <code>Color</code> to use for the line
* @return the <code>Border</code> object
*/
public static Border createLineBorder(Color color) {
return new LineBorder(color, 1);
}
/**
* Creates a line border with the specified color
* and width. The width applies to all four sides of the
* border. To specify widths individually for the top,
* bottom, left, and right, use
* {@link #createMatteBorder(int,int,int,int,Color)}.
*
* @param color a <code>Color</code> to use for the line
* @param thickness an integer specifying the width in pixels
* @return the <code>Border</code> object
*/
public static Border createLineBorder(Color color, int thickness) {
return new LineBorder(color, thickness);
}
/**
* Creates a line border with the specified color, thickness, and corner shape.
*
* @param color the color of the border
* @param thickness the thickness of the border
* @param rounded whether or not border corners should be round
* @return the {@code Border} object
*
* @see LineBorder#LineBorder(Color, int, boolean)
* @since 1.7
*/
public static Border createLineBorder(Color color, int thickness, boolean rounded) {
return new LineBorder(color, thickness, rounded);
}
//// BevelBorder /////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static final Border sharedRaisedBevel = new BevelBorder(BevelBorder.RAISED);
static final Border sharedLoweredBevel = new BevelBorder(BevelBorder.LOWERED);
/**
* Creates 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 <code>Border</code> object
*/
public static Border createRaisedBevelBorder() {
return createSharedBevel(BevelBorder.RAISED);
}
/**
* Creates 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 <code>Border</code> object
*/
public static Border createLoweredBevelBorder() {
return createSharedBevel(BevelBorder.LOWERED);
}
/**
* Creates 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 integer specifying either
* <code>BevelBorder.LOWERED</code> or
* <code>BevelBorder.RAISED</code>
* @return the <code>Border</code> object
*/
public static Border createBevelBorder(int type) {
return createSharedBevel(type);
}
/**
* Creates 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 shadow color.
*
* @param type an integer specifying either
* <code>BevelBorder.LOWERED</code> or
* <code>BevelBorder.RAISED</code>
* @param highlight a <code>Color</code> object for highlights
* @param shadow a <code>Color</code> object for shadows
* @return the <code>Border</code> object
*/
public static Border createBevelBorder(int type, Color highlight, Color shadow) {
return new BevelBorder(type, highlight, shadow);
}
/**
* Creates a beveled border of the specified type, using
* the specified colors for the inner and outer highlight
* and shadow areas.
*
* @param type an integer specifying either
* <code>BevelBorder.LOWERED</code> or
* <code>BevelBorder.RAISED</code>
* @param highlightOuter a <code>Color</code> object for the
* outer edge of the highlight area
* @param highlightInner a <code>Color</code> object for the
* inner edge of the highlight area
* @param shadowOuter a <code>Color</code> object for the
* outer edge of the shadow area
* @param shadowInner a <code>Color</code> object for the
* inner edge of the shadow area
* @return the <code>Border</code> object
*/
public static Border createBevelBorder(int type,
Color highlightOuter, Color highlightInner,
Color shadowOuter, Color shadowInner) {
return new BevelBorder(type, highlightOuter, highlightInner,
shadowOuter, shadowInner);
}
static Border createSharedBevel(int type) {
if(type == BevelBorder.RAISED) {
return sharedRaisedBevel;
} else if(type == BevelBorder.LOWERED) {
return sharedLoweredBevel;
}
return null;
}
//// SoftBevelBorder ///////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
private static Border sharedSoftRaisedBevel;
private static Border sharedSoftLoweredBevel;
/**
* Creates a beveled border with a raised edge and softened corners,
* 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 {@code Border} object
*
* @since 1.7
*/
public static Border createRaisedSoftBevelBorder() {
if (sharedSoftRaisedBevel == null) {
sharedSoftRaisedBevel = new SoftBevelBorder(BevelBorder.RAISED);
}
return sharedSoftRaisedBevel;
}
/**
* Creates a beveled border with a lowered edge and softened corners,
* 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 {@code Border} object
*
* @since 1.7
*/
public static Border createLoweredSoftBevelBorder() {
if (sharedSoftLoweredBevel == null) {
sharedSoftLoweredBevel = new SoftBevelBorder(BevelBorder.LOWERED);
}
return sharedSoftLoweredBevel;
}
/**
* Creates a beveled border of the specified type with softened corners,
* using brighter shades of the component's current background color
* for highlighting, and darker shading for shadows.
* The type is either {@link BevelBorder#RAISED} or {@link BevelBorder#LOWERED}.
*
* @param type a type of a bevel
* @return the {@code Border} object or {@code null}
* if the specified type is not valid
*
* @see BevelBorder#BevelBorder(int)
* @since 1.7
*/
public static Border createSoftBevelBorder(int type) {
if (type == BevelBorder.RAISED) {
return createRaisedSoftBevelBorder();
}
if (type == BevelBorder.LOWERED) {
return createLoweredSoftBevelBorder();
}
return null;
}
/**
* Creates a beveled border of the specified type with softened corners,
* using the specified highlighting and shadowing.
* The type is either {@link BevelBorder#RAISED} or {@link BevelBorder#LOWERED}.
* The outer edge of the highlight area uses
* a brighter shade of the {@code highlight} color.
* The inner edge of the shadow area uses
* a brighter shade of the {@code shadow} color.
*
* @param type a type of a bevel
* @param highlight a basic color of the highlight area
* @param shadow a basic color of the shadow area
* @return the {@code Border} object
*
* @see BevelBorder#BevelBorder(int, Color, Color)
* @since 1.7
*/
public static Border createSoftBevelBorder(int type, Color highlight, Color shadow) {
return new SoftBevelBorder(type, highlight, shadow);
}
/**
* Creates a beveled border of the specified type with softened corners,
* using the specified colors for the inner and outer edges
* of the highlight and the shadow areas.
* The type is either {@link BevelBorder#RAISED} or {@link BevelBorder#LOWERED}.
* Note: The shadow inner and outer colors are switched
* for a lowered bevel border.
*
* @param type a type of a bevel
* @param highlightOuter a color of the outer edge of the highlight area
* @param highlightInner a color of the inner edge of the highlight area
* @param shadowOuter a color of the outer edge of the shadow area
* @param shadowInner a color of the inner edge of the shadow area
* @return the {@code Border} object
*
* @see BevelBorder#BevelBorder(int, Color, Color, Color, Color)
* @since 1.7
*/
public static Border createSoftBevelBorder(int type, Color highlightOuter, Color highlightInner, Color shadowOuter, Color shadowInner) {
return new SoftBevelBorder(type, highlightOuter, highlightInner, shadowOuter, shadowInner);
}
//// EtchedBorder ///////////////////////////////////////////////////////////
static final Border sharedEtchedBorder = new EtchedBorder();
private static Border sharedRaisedEtchedBorder;
/**
* Creates a border with an "etched" look using
* the component's current background color for
* highlighting and shading.
*
* @return the <code>Border</code> object
*/
public static Border createEtchedBorder() {
return sharedEtchedBorder;
}
/**
* Creates a border with an "etched" look using
* the specified highlighting and shading colors.
*
* @param highlight a <code>Color</code> object for the border highlights
* @param shadow a <code>Color</code> object for the border shadows
* @return the <code>Border</code> object
*/
public static Border createEtchedBorder(Color highlight, Color shadow) {
return new EtchedBorder(highlight, shadow);
}
/**
* Creates a border with an "etched" look using
* the component's current background color for
* highlighting and shading.
*
* @param type one of <code>EtchedBorder.RAISED</code>, or
* <code>EtchedBorder.LOWERED</code>
* @return the <code>Border</code> object
* @exception IllegalArgumentException if type is not either
* <code>EtchedBorder.RAISED</code> or
* <code>EtchedBorder.LOWERED</code>
* @since 1.3
*/
public static Border createEtchedBorder(int type) {
switch (type) {
case EtchedBorder.RAISED:
if (sharedRaisedEtchedBorder == null) {
sharedRaisedEtchedBorder = new EtchedBorder
(EtchedBorder.RAISED);
}
return sharedRaisedEtchedBorder;
case EtchedBorder.LOWERED:
return sharedEtchedBorder;
default:
throw new IllegalArgumentException("type must be one of EtchedBorder.RAISED or EtchedBorder.LOWERED");
}
}
/**
* Creates a border with an "etched" look using
* the specified highlighting and shading colors.
*
* @param type one of <code>EtchedBorder.RAISED</code>, or
* <code>EtchedBorder.LOWERED</code>
* @param highlight a <code>Color</code> object for the border highlights
* @param shadow a <code>Color</code> object for the border shadows
* @return the <code>Border</code> object
* @since 1.3
*/
public static Border createEtchedBorder(int type, Color highlight,
Color shadow) {
return new EtchedBorder(type, highlight, shadow);
}
//// TitledBorder ////////////////////////////////////////////////////////////
/**
* Creates a new titled border with the specified title,
* the default border type (determined by the current look and feel),
* the default text position (determined by the current look and feel),
* the default justification (leading), and the default
* font and text color (determined by the current look and feel).
*
* @param title a <code>String</code> containing the text of the title
* @return the <code>TitledBorder</code> object
*/
public static TitledBorder createTitledBorder(String title) {
return new TitledBorder(title);
}
/**
* Creates a new titled border with an empty title,
* the specified border object,
* the default text position (determined by the current look and feel),
* the default justification (leading), and the default
* font and text color (determined by the current look and feel).
*
* @param border the <code>Border</code> object to add the title to; if
* <code>null</code> the <code>Border</code> is determined
* by the current look and feel.
* @return the <code>TitledBorder</code> object
*/
public static TitledBorder createTitledBorder(Border border) {
return new TitledBorder(border);
}
/**
* Adds a title to an existing border,
* with default positioning (determined by the current look and feel),
* default justification (leading) and the default
* font and text color (determined by the current look and feel).
*
* @param border the <code>Border</code> object to add the title to
* @param title a <code>String</code> containing the text of the title
* @return the <code>TitledBorder</code> object
*/
public static TitledBorder createTitledBorder(Border border,
String title) {
return new TitledBorder(border, title);
}
/**
* Adds a title to an existing border, with the specified
* positioning and using the default
* font and text color (determined by the current look and feel).
*
* @param border the <code>Border</code> object to add the title to
* @param title a <code>String</code> containing the text of the title
* @param titleJustification an integer specifying the justification
* of the title -- one of the following:
*<ul>
*<li><code>TitledBorder.LEFT</code>
*<li><code>TitledBorder.CENTER</code>
*<li><code>TitledBorder.RIGHT</code>
*<li><code>TitledBorder.LEADING</code>
*<li><code>TitledBorder.TRAILING</code>
*<li><code>TitledBorder.DEFAULT_JUSTIFICATION</code> (leading)
*</ul>
* @param titlePosition an integer specifying the vertical position of
* the text in relation to the border -- one of the following:
*<ul>
*<li><code> TitledBorder.ABOVE_TOP</code>
*<li><code>TitledBorder.TOP</code> (sitting on the top line)
*<li><code>TitledBorder.BELOW_TOP</code>
*<li><code>TitledBorder.ABOVE_BOTTOM</code>
*<li><code>TitledBorder.BOTTOM</code> (sitting on the bottom line)
*<li><code>TitledBorder.BELOW_BOTTOM</code>
*<li><code>TitledBorder.DEFAULT_POSITION</code> (the title position
* is determined by the current look and feel)
*</ul>
* @return the <code>TitledBorder</code> object
*/
public static TitledBorder createTitledBorder(Border border,
String title,
int titleJustification,
int titlePosition) {
return new TitledBorder(border, title, titleJustification,
titlePosition);
}
/**
* Adds a title to an existing border, with the specified
* positioning and font, and using the default text color
* (determined by the current look and feel).
*
* @param border the <code>Border</code> object to add the title to
* @param title a <code>String</code> containing the text of the title
* @param titleJustification an integer specifying the justification
* of the title -- one of the following:
*<ul>
*<li><code>TitledBorder.LEFT</code>
*<li><code>TitledBorder.CENTER</code>
*<li><code>TitledBorder.RIGHT</code>
*<li><code>TitledBorder.LEADING</code>
*<li><code>TitledBorder.TRAILING</code>
*<li><code>TitledBorder.DEFAULT_JUSTIFICATION</code> (leading)
*</ul>
* @param titlePosition an integer specifying the vertical position of
* the text in relation to the border -- one of the following:
*<ul>
*<li><code> TitledBorder.ABOVE_TOP</code>
*<li><code>TitledBorder.TOP</code> (sitting on the top line)
*<li><code>TitledBorder.BELOW_TOP</code>
*<li><code>TitledBorder.ABOVE_BOTTOM</code>
*<li><code>TitledBorder.BOTTOM</code> (sitting on the bottom line)
*<li><code>TitledBorder.BELOW_BOTTOM</code>
*<li><code>TitledBorder.DEFAULT_POSITION</code> (the title position
* is determined by the current look and feel)
*</ul>
* @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);
}
/**
* Adds a title to an existing border, with the specified
* positioning, font and color.
*
* @param border the <code>Border</code> object to add the title to
* @param title a <code>String</code> containing the text of the title
* @param titleJustification an integer specifying the justification
* of the title -- one of the following:
*<ul>
*<li><code>TitledBorder.LEFT</code>
*<li><code>TitledBorder.CENTER</code>
*<li><code>TitledBorder.RIGHT</code>
*<li><code>TitledBorder.LEADING</code>
*<li><code>TitledBorder.TRAILING</code>
*<li><code>TitledBorder.DEFAULT_JUSTIFICATION</code> (leading)
*</ul>
* @param titlePosition an integer specifying the vertical position of
* the text in relation to the border -- one of the following:
*<ul>
*<li><code> TitledBorder.ABOVE_TOP</code>
*<li><code>TitledBorder.TOP</code> (sitting on the top line)
*<li><code>TitledBorder.BELOW_TOP</code>
*<li><code>TitledBorder.ABOVE_BOTTOM</code>
*<li><code>TitledBorder.BOTTOM</code> (sitting on the bottom line)
*<li><code>TitledBorder.BELOW_BOTTOM</code>
*<li><code>TitledBorder.DEFAULT_POSITION</code> (the title position
* is determined by the current look and feel)
*</ul>
* @param titleFont a <code>Font</code> object specifying the title font
* @param titleColor a <code>Color</code> object specifying the title color
* @return the <code>TitledBorder</code> 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);
}
//// EmptyBorder ///////////////////////////////////////////////////////////
final static Border emptyBorder = new EmptyBorder(0, 0, 0, 0);
/**
* Creates an empty border that takes up no space. (The width
* of the top, bottom, left, and right sides are all zero.)
*
* @return the <code>Border</code> object
*/
public static Border createEmptyBorder() {
return emptyBorder;
}
/**
* Creates an empty border that takes up space but which does
* no drawing, specifying the width of the top, left, bottom, and
* right sides.
*
* @param top an integer specifying the width of the top,
* in pixels
* @param left an integer specifying the width of the left side,
* in pixels
* @param bottom an integer specifying the width of the bottom,
* in pixels
* @param right an integer specifying the width of the right side,
* in pixels
* @return the <code>Border</code> object
*/
public static Border createEmptyBorder(int top, int left,
int bottom, int right) {
return new EmptyBorder(top, left, bottom, right);
}
//// CompoundBorder ////////////////////////////////////////////////////////
/**
* Creates a compound border with a <code>null</code> inside edge and a
* <code>null</code> outside edge.
*
* @return the <code>CompoundBorder</code> object
*/
public static CompoundBorder createCompoundBorder() {
return new CompoundBorder();
}
/**
* Creates a compound border specifying the border objects to use
* for the outside and inside edges.
*
* @param outsideBorder a <code>Border</code> object for the outer
* edge of the compound border
* @param insideBorder a <code>Border</code> object for the inner
* edge of the compound border
* @return the <code>CompoundBorder</code> object
*/
public static CompoundBorder createCompoundBorder(Border outsideBorder,
Border insideBorder) {
return new CompoundBorder(outsideBorder, insideBorder);
}
//// MatteBorder ////////////////////////////////////////////////////////
/**
* Creates 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 integer specifying the width of the top,
* in pixels
* @param left an integer specifying the width of the left side,
* in pixels
* @param bottom an integer specifying the width of the right side,
* in pixels
* @param right an integer specifying the width of the bottom,
* in pixels
* @param color a <code>Color</code> to use for the border
* @return the <code>MatteBorder</code> object
*/
public static MatteBorder createMatteBorder(int top, int left, int bottom, int right,
Color color) {
return new MatteBorder(top, left, bottom, right, color);
}
/**
* Creates 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.
* <p>
* Note:<br>
* If the icon doesn't load, the border area is painted gray.
*
* @param top an integer specifying the width of the top,
* in pixels
* @param left an integer specifying the width of the left side,
* in pixels
* @param bottom an integer specifying the width of the right side,
* in pixels
* @param right an integer specifying the width of the bottom,
* in pixels
* @param tileIcon the <code>Icon</code> object used for the border tiles
* @return the <code>MatteBorder</code> object
*/
public static MatteBorder createMatteBorder(int top, int left, int bottom, int right,
Icon tileIcon) {
return new MatteBorder(top, left, bottom, right, tileIcon);
}
//// StrokeBorder //////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
* Creates a border of the specified {@code stroke}.
* The component's foreground color will be used to render the border.
*
* @param stroke the {@link BasicStroke} object used to stroke a shape
* @return the {@code Border} object
*
* @throws NullPointerException if the specified {@code stroke} is {@code null}
*
* @since 1.7
*/
public static Border createStrokeBorder(BasicStroke stroke) {
return new StrokeBorder(stroke);
}
/**
* Creates a border of the specified {@code stroke} and {@code paint}.
* If the specified {@code paint} is {@code null},
* the component's foreground color will be used to render the border.
*
* @param stroke the {@link BasicStroke} object used to stroke a shape
* @param paint the {@link Paint} object used to generate a color
* @return the {@code Border} object
*
* @throws NullPointerException if the specified {@code stroke} is {@code null}
*
* @since 1.7
*/
public static Border createStrokeBorder(BasicStroke stroke, Paint paint) {
return new StrokeBorder(stroke, paint);
}
//// DashedBorder //////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
private static Border sharedDashedBorder;
/**
* Creates a dashed border of the specified {@code paint}.
* If the specified {@code paint} is {@code null},
* the component's foreground color will be used to render the border.
* The width of a dash line is equal to {@code 1}.
* The relative length of a dash line and
* the relative spacing between dash lines are equal to {@code 1}.
* A dash line is not rounded.
*
* @param paint the {@link Paint} object used to generate a color
* @return the {@code Border} object
*
* @since 1.7
*/
public static Border createDashedBorder(Paint paint) {
return createDashedBorder(paint, 1.0f, 1.0f, 1.0f, false);
}
/**
* Creates a dashed border of the specified {@code paint},
* relative {@code length}, and relative {@code spacing}.
* If the specified {@code paint} is {@code null},
* the component's foreground color will be used to render the border.
* The width of a dash line is equal to {@code 1}.
* A dash line is not rounded.
*
* @param paint the {@link Paint} object used to generate a color
* @param length the relative length of a dash line
* @param spacing the relative spacing between dash lines
* @return the {@code Border} object
*
* @throws IllegalArgumentException if the specified {@code length} is less than {@code 1}, or
* if the specified {@code spacing} is less than {@code 0}
* @since 1.7
*/
public static Border createDashedBorder(Paint paint, float length, float spacing) {
return createDashedBorder(paint, 1.0f, length, spacing, false);
}
/**
* Creates a dashed border of the specified {@code paint}, {@code thickness},
* line shape, relative {@code length}, and relative {@code spacing}.
* If the specified {@code paint} is {@code null},
* the component's foreground color will be used to render the border.
*
* @param paint the {@link Paint} object used to generate a color
* @param thickness the width of a dash line
* @param length the relative length of a dash line
* @param spacing the relative spacing between dash lines
* @param rounded whether or not line ends should be round
* @return the {@code Border} object
*
* @throws IllegalArgumentException if the specified {@code thickness} is less than {@code 1}, or
* if the specified {@code length} is less than {@code 1}, or
* if the specified {@code spacing} is less than {@code 0}
* @since 1.7
*/
public static Border createDashedBorder(Paint paint, float thickness, float length, float spacing, boolean rounded) {
boolean shared = !rounded && (paint == null) && (thickness == 1.0f) && (length == 1.0f) && (spacing == 1.0f);
if (shared && (sharedDashedBorder != null)) {
return sharedDashedBorder;
}
if (thickness < 1.0f) {
throw new IllegalArgumentException("thickness is less than 1");
}
if (length < 1.0f) {
throw new IllegalArgumentException("length is less than 1");
}
if (spacing < 0.0f) {
throw new IllegalArgumentException("spacing is less than 0");
}
int cap = rounded ? BasicStroke.CAP_ROUND : BasicStroke.CAP_SQUARE;
int join = rounded ? BasicStroke.JOIN_ROUND : BasicStroke.JOIN_MITER;
float[] array = { thickness * (length - 1.0f), thickness * (spacing + 1.0f) };
Border border = createStrokeBorder(new BasicStroke(thickness, cap, join, thickness * 2.0f, array, 0.0f), paint);
if (shared) {
sharedDashedBorder = border;
}
return border;
}
}

View File

@@ -0,0 +1,268 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.event.*;
/**
* Defines the data model used by components like <code>Slider</code>s
* and <code>ProgressBar</code>s.
* Defines four interrelated integer properties: minimum, maximum, extent
* and value. These four integers define two nested ranges like this:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* The outer range is <code>minimum,maximum</code> and the inner
* range is <code>value,value+extent</code>. The inner range
* must lie within the outer one, i.e. <code>value</code> must be
* less than or equal to <code>maximum</code> and <code>value+extent</code>
* must greater than or equal to <code>minimum</code>, and <code>maximum</code>
* must be greater than or equal to <code>minimum</code>.
* There are a few features of this model that one might find a little
* surprising. These quirks exist for the convenience of the
* Swing BoundedRangeModel clients, such as <code>Slider</code> and
* <code>ScrollBar</code>.
* <ul>
* <li>
* The minimum and maximum set methods "correct" the other
* three properties to accommodate their new value argument. For
* example setting the model's minimum may change its maximum, value,
* and extent properties (in that order), to maintain the constraints
* specified above.
*
* <li>
* The value and extent set methods "correct" their argument to
* fit within the limits defined by the other three properties.
* For example if <code>value == maximum</code>, <code>setExtent(10)</code>
* would change the extent (back) to zero.
*
* <li>
* The four BoundedRangeModel values are defined as Java Beans properties
* however Swing ChangeEvents are used to notify clients of changes rather
* than PropertyChangeEvents. This was done to keep the overhead of monitoring
* a BoundedRangeModel low. Changes are often reported at MouseDragged rates.
* </ul>
*
* <p>
*
* For an example of specifying custom bounded range models used by sliders,
* see <a
href="http://www.oracle.com/technetwork/java/architecture-142923.html#separable">Separable model architecture</a>
* in <em>A Swing Architecture Overview.</em>
*
* @author Hans Muller
* @see DefaultBoundedRangeModel
*/
public interface BoundedRangeModel
{
/**
* Returns the minimum acceptable value.
*
* @return the value of the minimum property
* @see #setMinimum
*/
int getMinimum();
/**
* Sets the model's minimum to <I>newMinimum</I>. The
* other three properties may be changed as well, to ensure
* that:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* <p>
* Notifies any listeners if the model changes.
*
* @param newMinimum the model's new minimum
* @see #getMinimum
* @see #addChangeListener
*/
void setMinimum(int newMinimum);
/**
* Returns the model's maximum. Note that the upper
* limit on the model's value is (maximum - extent).
*
* @return the value of the maximum property.
* @see #setMaximum
* @see #setExtent
*/
int getMaximum();
/**
* Sets the model's maximum to <I>newMaximum</I>. The other
* three properties may be changed as well, to ensure that
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* <p>
* Notifies any listeners if the model changes.
*
* @param newMaximum the model's new maximum
* @see #getMaximum
* @see #addChangeListener
*/
void setMaximum(int newMaximum);
/**
* Returns the model's current value. Note that the upper
* limit on the model's value is <code>maximum - extent</code>
* and the lower limit is <code>minimum</code>.
*
* @return the model's value
* @see #setValue
*/
int getValue();
/**
* Sets the model's current value to <code>newValue</code> if <code>newValue</code>
* satisfies the model's constraints. Those constraints are:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* Otherwise, if <code>newValue</code> is less than <code>minimum</code>
* it's set to <code>minimum</code>, if its greater than
* <code>maximum</code> then it's set to <code>maximum</code>, and
* if it's greater than <code>value+extent</code> then it's set to
* <code>value+extent</code>.
* <p>
* When a BoundedRange model is used with a scrollbar the value
* specifies the origin of the scrollbar knob (aka the "thumb" or
* "elevator"). The value usually represents the origin of the
* visible part of the object being scrolled.
* <p>
* Notifies any listeners if the model changes.
*
* @param newValue the model's new value
* @see #getValue
*/
void setValue(int newValue);
/**
* This attribute indicates that any upcoming changes to the value
* of the model should be considered a single event. This attribute
* will be set to true at the start of a series of changes to the value,
* and will be set to false when the value has finished changing. Normally
* this allows a listener to only take action when the final value change in
* committed, instead of having to do updates for all intermediate values.
* <p>
* Sliders and scrollbars use this property when a drag is underway.
*
* @param b true if the upcoming changes to the value property are part of a series
*/
void setValueIsAdjusting(boolean b);
/**
* Returns true if the current changes to the value property are part
* of a series of changes.
*
* @return the valueIsAdjustingProperty.
* @see #setValueIsAdjusting
*/
boolean getValueIsAdjusting();
/**
* Returns the model's extent, the length of the inner range that
* begins at the model's value.
*
* @return the value of the model's extent property
* @see #setExtent
* @see #setValue
*/
int getExtent();
/**
* Sets the model's extent. The <I>newExtent</I> is forced to
* be greater than or equal to zero and less than or equal to
* maximum - value.
* <p>
* When a BoundedRange model is used with a scrollbar the extent
* defines the length of the scrollbar knob (aka the "thumb" or
* "elevator"). The extent usually represents how much of the
* object being scrolled is visible. When used with a slider,
* the extent determines how much the value can "jump", for
* example when the user presses PgUp or PgDn.
* <p>
* Notifies any listeners if the model changes.
*
* @param newExtent the model's new extent
* @see #getExtent
* @see #setValue
*/
void setExtent(int newExtent);
/**
* This method sets all of the model's data with a single method call.
* The method results in a single change event being generated. This is
* convenient when you need to adjust all the model data simultaneously and
* do not want individual change events to occur.
*
* @param value an int giving the current value
* @param extent an int giving the amount by which the value can "jump"
* @param min an int giving the minimum value
* @param max an int giving the maximum value
* @param adjusting a boolean, true if a series of changes are in
* progress
*
* @see #setValue
* @see #setExtent
* @see #setMinimum
* @see #setMaximum
* @see #setValueIsAdjusting
*/
void setRangeProperties(int value, int extent, int min, int max, boolean adjusting);
/**
* Adds a ChangeListener to the model's listener list.
*
* @param x the ChangeListener to add
* @see #removeChangeListener
*/
void addChangeListener(ChangeListener x);
/**
* Removes a ChangeListener from the model's listener list.
*
* @param x the ChangeListener to remove
* @see #addChangeListener
*/
void removeChangeListener(ChangeListener x);
}

View File

@@ -0,0 +1,441 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.ConstructorProperties;
import java.util.Locale;
import java.io.Serializable;
import javax.accessibility.*;
/**
* A lightweight container
* that uses a BoxLayout object as its layout manager.
* Box provides several class methods
* that are useful for containers using BoxLayout --
* even non-Box containers.
*
* <p>
* The <code>Box</code> class can create several kinds
* of invisible components
* that affect layout:
* glue, struts, and rigid areas.
* If all the components your <code>Box</code> contains
* have a fixed size,
* you might want to use a glue component
* (returned by <code>createGlue</code>)
* to control the components' positions.
* If you need a fixed amount of space between two components,
* try using a strut
* (<code>createHorizontalStrut</code> or <code>createVerticalStrut</code>).
* If you need an invisible component
* that always takes up the same amount of space,
* get it by invoking <code>createRigidArea</code>.
* <p>
* If you are implementing a <code>BoxLayout</code> you
* can find further information and examples in
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/layout/box.html">How to Use BoxLayout</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see BoxLayout
*
* @author Timothy Prinzing
*/
@SuppressWarnings("serial")
public class Box extends JComponent implements Accessible {
/**
* Creates a <code>Box</code> that displays its components
* along the the specified axis.
*
* @param axis can be {@link BoxLayout#X_AXIS},
* {@link BoxLayout#Y_AXIS},
* {@link BoxLayout#LINE_AXIS} or
* {@link BoxLayout#PAGE_AXIS}.
* @throws AWTError if the <code>axis</code> is invalid
* @see #createHorizontalBox
* @see #createVerticalBox
*/
public Box(int axis) {
super();
super.setLayout(new BoxLayout(this, axis));
}
/**
* Creates a <code>Box</code> that displays its components
* from left to right. If you want a <code>Box</code> that
* respects the component orientation you should create the
* <code>Box</code> using the constructor and pass in
* <code>BoxLayout.LINE_AXIS</code>, eg:
* <pre>
* Box lineBox = new Box(BoxLayout.LINE_AXIS);
* </pre>
*
* @return the box
*/
public static Box createHorizontalBox() {
return new Box(BoxLayout.X_AXIS);
}
/**
* Creates a <code>Box</code> that displays its components
* from top to bottom. If you want a <code>Box</code> that
* respects the component orientation you should create the
* <code>Box</code> using the constructor and pass in
* <code>BoxLayout.PAGE_AXIS</code>, eg:
* <pre>
* Box lineBox = new Box(BoxLayout.PAGE_AXIS);
* </pre>
*
* @return the box
*/
public static Box createVerticalBox() {
return new Box(BoxLayout.Y_AXIS);
}
/**
* Creates an invisible component that's always the specified size.
* <!-- WHEN WOULD YOU USE THIS AS OPPOSED TO A STRUT? -->
*
* @param d the dimensions of the invisible component
* @return the component
* @see #createGlue
* @see #createHorizontalStrut
* @see #createVerticalStrut
*/
public static Component createRigidArea(Dimension d) {
return new Filler(d, d, d);
}
/**
* Creates an invisible, fixed-width component.
* In a horizontal box,
* you typically use this method
* to force a certain amount of space between two components.
* In a vertical box,
* you might use this method
* to force the box to be at least the specified width.
* The invisible component has no height
* unless excess space is available,
* in which case it takes its share of available space,
* just like any other component that has no maximum height.
*
* @param width the width of the invisible component, in pixels &gt;= 0
* @return the component
* @see #createVerticalStrut
* @see #createGlue
* @see #createRigidArea
*/
public static Component createHorizontalStrut(int width) {
return new Filler(new Dimension(width,0), new Dimension(width,0),
new Dimension(width, Short.MAX_VALUE));
}
/**
* Creates an invisible, fixed-height component.
* In a vertical box,
* you typically use this method
* to force a certain amount of space between two components.
* In a horizontal box,
* you might use this method
* to force the box to be at least the specified height.
* The invisible component has no width
* unless excess space is available,
* in which case it takes its share of available space,
* just like any other component that has no maximum width.
*
* @param height the height of the invisible component, in pixels &gt;= 0
* @return the component
* @see #createHorizontalStrut
* @see #createGlue
* @see #createRigidArea
*/
public static Component createVerticalStrut(int height) {
return new Filler(new Dimension(0,height), new Dimension(0,height),
new Dimension(Short.MAX_VALUE, height));
}
/**
* Creates an invisible "glue" component
* that can be useful in a Box
* whose visible components have a maximum width
* (for a horizontal box)
* or height (for a vertical box).
* You can think of the glue component
* as being a gooey substance
* that expands as much as necessary
* to fill the space between its neighboring components.
*
* <p>
*
* For example, suppose you have
* a horizontal box that contains two fixed-size components.
* If the box gets extra space,
* the fixed-size components won't become larger,
* so where does the extra space go?
* Without glue,
* the extra space goes to the right of the second component.
* If you put glue between the fixed-size components,
* then the extra space goes there.
* If you put glue before the first fixed-size component,
* the extra space goes there,
* and the fixed-size components are shoved against the right
* edge of the box.
* If you put glue before the first fixed-size component
* and after the second fixed-size component,
* the fixed-size components are centered in the box.
*
* <p>
*
* To use glue,
* call <code>Box.createGlue</code>
* and add the returned component to a container.
* The glue component has no minimum or preferred size,
* so it takes no space unless excess space is available.
* If excess space is available,
* then the glue component takes its share of available
* horizontal or vertical space,
* just like any other component that has no maximum width or height.
*
* @return the component
*/
public static Component createGlue() {
return new Filler(new Dimension(0,0), new Dimension(0,0),
new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
}
/**
* Creates a horizontal glue component.
*
* @return the component
*/
public static Component createHorizontalGlue() {
return new Filler(new Dimension(0,0), new Dimension(0,0),
new Dimension(Short.MAX_VALUE, 0));
}
/**
* Creates a vertical glue component.
*
* @return the component
*/
public static Component createVerticalGlue() {
return new Filler(new Dimension(0,0), new Dimension(0,0),
new Dimension(0, Short.MAX_VALUE));
}
/**
* Throws an AWTError, since a Box can use only a BoxLayout.
*
* @param l the layout manager to use
*/
public void setLayout(LayoutManager l) {
throw new AWTError("Illegal request");
}
/**
* Paints this <code>Box</code>. If this <code>Box</code> has a UI this
* method invokes super's implementation, otherwise if this
* <code>Box</code> is opaque the <code>Graphics</code> is filled
* using the background.
*
* @param g the <code>Graphics</code> to paint to
* @throws NullPointerException if <code>g</code> is null
* @since 1.6
*/
protected void paintComponent(Graphics g) {
if (ui != null) {
// On the off chance some one created a UI, honor it
super.paintComponent(g);
} else if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
/**
* An implementation of a lightweight component that participates in
* layout but has no view.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
public static class Filler extends JComponent implements Accessible {
/**
* Constructor to create shape with the given size ranges.
*
* @param min Minimum size
* @param pref Preferred size
* @param max Maximum size
*/
@ConstructorProperties({"minimumSize", "preferredSize", "maximumSize"})
public Filler(Dimension min, Dimension pref, Dimension max) {
setMinimumSize(min);
setPreferredSize(pref);
setMaximumSize(max);
}
/**
* Change the size requests for this shape. An invalidate() is
* propagated upward as a result so that layout will eventually
* happen with using the new sizes.
*
* @param min Value to return for getMinimumSize
* @param pref Value to return for getPreferredSize
* @param max Value to return for getMaximumSize
*/
public void changeShape(Dimension min, Dimension pref, Dimension max) {
setMinimumSize(min);
setPreferredSize(pref);
setMaximumSize(max);
revalidate();
}
// ---- Component methods ------------------------------------------
/**
* Paints this <code>Filler</code>. If this
* <code>Filler</code> has a UI this method invokes super's
* implementation, otherwise if this <code>Filler</code> is
* opaque the <code>Graphics</code> is filled using the
* background.
*
* @param g the <code>Graphics</code> to paint to
* @throws NullPointerException if <code>g</code> is null
* @since 1.6
*/
protected void paintComponent(Graphics g) {
if (ui != null) {
// On the off chance some one created a UI, honor it
super.paintComponent(g);
} else if (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
}
/////////////////
// Accessibility support for Box$Filler
////////////////
/**
* Gets the AccessibleContext associated with this Box.Filler.
* For box fillers, the AccessibleContext takes the form of an
* AccessibleBoxFiller.
* A new AccessibleAWTBoxFiller instance is created if necessary.
*
* @return an AccessibleBoxFiller that serves as the
* AccessibleContext of this Box.Filler.
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleBoxFiller();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>Box.Filler</code> class.
*/
@SuppressWarnings("serial")
protected class AccessibleBoxFiller extends AccessibleAWTComponent {
// AccessibleContext methods
//
/**
* Gets the role of this object.
*
* @return an instance of AccessibleRole describing the role of
* the object (AccessibleRole.FILLER)
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.FILLER;
}
}
}
/////////////////
// Accessibility support for Box
////////////////
/**
* Gets the AccessibleContext associated with this Box.
* For boxes, the AccessibleContext takes the form of an
* AccessibleBox.
* A new AccessibleAWTBox instance is created if necessary.
*
* @return an AccessibleBox that serves as the
* AccessibleContext of this Box
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleBox();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>Box</code> class.
*/
@SuppressWarnings("serial")
protected class AccessibleBox extends AccessibleAWTContainer {
// AccessibleContext methods
//
/**
* Gets the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object (AccessibleRole.FILLER)
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.FILLER;
}
} // inner class AccessibleBox
}

View File

@@ -0,0 +1,539 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.beans.ConstructorProperties;
import java.io.Serializable;
import java.io.PrintStream;
/**
* A layout manager that allows multiple components to be laid out either
* vertically or horizontally. The components will not wrap so, for
* example, a vertical arrangement of components will stay vertically
* arranged when the frame is resized.
* <TABLE STYLE="FLOAT:RIGHT" BORDER="0" SUMMARY="layout">
* <TR>
* <TD ALIGN="CENTER">
* <P STYLE="TEXT-ALIGN:CENTER"><IMG SRC="doc-files/BoxLayout-1.gif"
* alt="The following text describes this graphic."
* WIDTH="191" HEIGHT="201" STYLE="FLOAT:BOTTOM; BORDER:0">
* </TD>
* </TR>
* </TABLE>
* <p>
* Nesting multiple panels with different combinations of horizontal and
* vertical gives an effect similar to GridBagLayout, without the
* complexity. The diagram shows two panels arranged horizontally, each
* of which contains 3 components arranged vertically.
*
* <p> The BoxLayout manager is constructed with an axis parameter that
* specifies the type of layout that will be done. There are four choices:
*
* <blockquote><b><tt>X_AXIS</tt></b> - Components are laid out horizontally
* from left to right.</blockquote>
*
* <blockquote><b><tt>Y_AXIS</tt></b> - Components are laid out vertically
* from top to bottom.</blockquote>
*
* <blockquote><b><tt>LINE_AXIS</tt></b> - Components are laid out the way
* words are laid out in a line, based on the container's
* <tt>ComponentOrientation</tt> property. If the container's
* <tt>ComponentOrientation</tt> is horizontal then components are laid out
* horizontally, otherwise they are laid out vertically. For horizontal
* orientations, if the container's <tt>ComponentOrientation</tt> is left to
* right then components are laid out left to right, otherwise they are laid
* out right to left. For vertical orientations components are always laid out
* from top to bottom.</blockquote>
*
* <blockquote><b><tt>PAGE_AXIS</tt></b> - Components are laid out the way
* text lines are laid out on a page, based on the container's
* <tt>ComponentOrientation</tt> property. If the container's
* <tt>ComponentOrientation</tt> is horizontal then components are laid out
* vertically, otherwise they are laid out horizontally. For horizontal
* orientations, if the container's <tt>ComponentOrientation</tt> is left to
* right then components are laid out left to right, otherwise they are laid
* out right to left.&nbsp; For vertical orientations components are always
* laid out from top to bottom.</blockquote>
* <p>
* For all directions, components are arranged in the same order as they were
* added to the container.
* <p>
* BoxLayout attempts to arrange components
* at their preferred widths (for horizontal layout)
* or heights (for vertical layout).
* For a horizontal layout,
* if not all the components are the same height,
* BoxLayout attempts to make all the components
* as high as the highest component.
* If that's not possible for a particular component,
* then BoxLayout aligns that component vertically,
* according to the component's Y alignment.
* By default, a component has a Y alignment of 0.5,
* which means that the vertical center of the component
* should have the same Y coordinate as
* the vertical centers of other components with 0.5 Y alignment.
* <p>
* Similarly, for a vertical layout,
* BoxLayout attempts to make all components in the column
* as wide as the widest component.
* If that fails, it aligns them horizontally
* according to their X alignments. For <code>PAGE_AXIS</code> layout,
* horizontal alignment is done based on the leading edge of the component.
* In other words, an X alignment value of 0.0 means the left edge of a
* component if the container's <code>ComponentOrientation</code> is left to
* right and it means the right edge of the component otherwise.
* <p>
* Instead of using BoxLayout directly, many programs use the Box class.
* The Box class is a lightweight container that uses a BoxLayout.
* It also provides handy methods to help you use BoxLayout well.
* Adding components to multiple nested boxes is a powerful way to get
* the arrangement you want.
* <p>
* For further information and examples see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/layout/box.html">How to Use BoxLayout</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see Box
* @see java.awt.ComponentOrientation
* @see JComponent#getAlignmentX
* @see JComponent#getAlignmentY
*
* @author Timothy Prinzing
*/
@SuppressWarnings("serial")
public class BoxLayout implements LayoutManager2, Serializable {
/**
* Specifies that components should be laid out left to right.
*/
public static final int X_AXIS = 0;
/**
* Specifies that components should be laid out top to bottom.
*/
public static final int Y_AXIS = 1;
/**
* Specifies that components should be laid out in the direction of
* a line of text as determined by the target container's
* <code>ComponentOrientation</code> property.
*/
public static final int LINE_AXIS = 2;
/**
* Specifies that components should be laid out in the direction that
* lines flow across a page as determined by the target container's
* <code>ComponentOrientation</code> property.
*/
public static final int PAGE_AXIS = 3;
/**
* Creates a layout manager that will lay out components along the
* given axis.
*
* @param target the container that needs to be laid out
* @param axis the axis to lay out components along. Can be one of:
* <code>BoxLayout.X_AXIS</code>,
* <code>BoxLayout.Y_AXIS</code>,
* <code>BoxLayout.LINE_AXIS</code> or
* <code>BoxLayout.PAGE_AXIS</code>
*
* @exception AWTError if the value of <code>axis</code> is invalid
*/
@ConstructorProperties({"target", "axis"})
public BoxLayout(Container target, int axis) {
if (axis != X_AXIS && axis != Y_AXIS &&
axis != LINE_AXIS && axis != PAGE_AXIS) {
throw new AWTError("Invalid axis");
}
this.axis = axis;
this.target = target;
}
/**
* Constructs a BoxLayout that
* produces debugging messages.
*
* @param target the container that needs to be laid out
* @param axis the axis to lay out components along. Can be one of:
* <code>BoxLayout.X_AXIS</code>,
* <code>BoxLayout.Y_AXIS</code>,
* <code>BoxLayout.LINE_AXIS</code> or
* <code>BoxLayout.PAGE_AXIS</code>
*
* @param dbg the stream to which debugging messages should be sent,
* null if none
*/
BoxLayout(Container target, int axis, PrintStream dbg) {
this(target, axis);
this.dbg = dbg;
}
/**
* Returns the container that uses this layout manager.
*
* @return the container that uses this layout manager
*
* @since 1.6
*/
public final Container getTarget() {
return this.target;
}
/**
* Returns the axis that was used to lay out components.
* Returns one of:
* <code>BoxLayout.X_AXIS</code>,
* <code>BoxLayout.Y_AXIS</code>,
* <code>BoxLayout.LINE_AXIS</code> or
* <code>BoxLayout.PAGE_AXIS</code>
*
* @return the axis that was used to lay out components
*
* @since 1.6
*/
public final int getAxis() {
return this.axis;
}
/**
* Indicates that a child has changed its layout related information,
* and thus any cached calculations should be flushed.
* <p>
* This method is called by AWT when the invalidate method is called
* on the Container. Since the invalidate method may be called
* asynchronously to the event thread, this method may be called
* asynchronously.
*
* @param target the affected container
*
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
*/
public synchronized void invalidateLayout(Container target) {
checkContainer(target);
xChildren = null;
yChildren = null;
xTotal = null;
yTotal = null;
}
/**
* Not used by this class.
*
* @param name the name of the component
* @param comp the component
*/
public void addLayoutComponent(String name, Component comp) {
invalidateLayout(comp.getParent());
}
/**
* Not used by this class.
*
* @param comp the component
*/
public void removeLayoutComponent(Component comp) {
invalidateLayout(comp.getParent());
}
/**
* Not used by this class.
*
* @param comp the component
* @param constraints constraints
*/
public void addLayoutComponent(Component comp, Object constraints) {
invalidateLayout(comp.getParent());
}
/**
* Returns the preferred dimensions for this layout, given the components
* in the specified target container.
*
* @param target the container that needs to be laid out
* @return the dimensions &gt;= 0 &amp;&amp; &lt;= Integer.MAX_VALUE
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
* @see Container
* @see #minimumLayoutSize
* @see #maximumLayoutSize
*/
public Dimension preferredLayoutSize(Container target) {
Dimension size;
synchronized(this) {
checkContainer(target);
checkRequests();
size = new Dimension(xTotal.preferred, yTotal.preferred);
}
Insets insets = target.getInsets();
size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
return size;
}
/**
* Returns the minimum dimensions needed to lay out the components
* contained in the specified target container.
*
* @param target the container that needs to be laid out
* @return the dimensions &gt;= 0 &amp;&amp; &lt;= Integer.MAX_VALUE
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
* @see #preferredLayoutSize
* @see #maximumLayoutSize
*/
public Dimension minimumLayoutSize(Container target) {
Dimension size;
synchronized(this) {
checkContainer(target);
checkRequests();
size = new Dimension(xTotal.minimum, yTotal.minimum);
}
Insets insets = target.getInsets();
size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
return size;
}
/**
* Returns the maximum dimensions the target container can use
* to lay out the components it contains.
*
* @param target the container that needs to be laid out
* @return the dimensions &gt;= 0 &amp;&amp; &lt;= Integer.MAX_VALUE
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
* @see #preferredLayoutSize
* @see #minimumLayoutSize
*/
public Dimension maximumLayoutSize(Container target) {
Dimension size;
synchronized(this) {
checkContainer(target);
checkRequests();
size = new Dimension(xTotal.maximum, yTotal.maximum);
}
Insets insets = target.getInsets();
size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
return size;
}
/**
* Returns the alignment along the X axis for the container.
* If the box is horizontal, the default
* alignment will be returned. Otherwise, the alignment needed
* to place the children along the X axis will be returned.
*
* @param target the container
* @return the alignment &gt;= 0.0f &amp;&amp; &lt;= 1.0f
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
*/
public synchronized float getLayoutAlignmentX(Container target) {
checkContainer(target);
checkRequests();
return xTotal.alignment;
}
/**
* Returns the alignment along the Y axis for the container.
* If the box is vertical, the default
* alignment will be returned. Otherwise, the alignment needed
* to place the children along the Y axis will be returned.
*
* @param target the container
* @return the alignment &gt;= 0.0f &amp;&amp; &lt;= 1.0f
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
*/
public synchronized float getLayoutAlignmentY(Container target) {
checkContainer(target);
checkRequests();
return yTotal.alignment;
}
/**
* Called by the AWT <!-- XXX CHECK! --> when the specified container
* needs to be laid out.
*
* @param target the container to lay out
*
* @exception AWTError if the target isn't the container specified to the
* BoxLayout constructor
*/
public void layoutContainer(Container target) {
checkContainer(target);
int nChildren = target.getComponentCount();
int[] xOffsets = new int[nChildren];
int[] xSpans = new int[nChildren];
int[] yOffsets = new int[nChildren];
int[] ySpans = new int[nChildren];
Dimension alloc = target.getSize();
Insets in = target.getInsets();
alloc.width -= in.left + in.right;
alloc.height -= in.top + in.bottom;
// Resolve axis to an absolute value (either X_AXIS or Y_AXIS)
ComponentOrientation o = target.getComponentOrientation();
int absoluteAxis = resolveAxis( axis, o );
boolean ltr = (absoluteAxis != axis) ? o.isLeftToRight() : true;
// determine the child placements
synchronized(this) {
checkRequests();
if (absoluteAxis == X_AXIS) {
SizeRequirements.calculateTiledPositions(alloc.width, xTotal,
xChildren, xOffsets,
xSpans, ltr);
SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
yChildren, yOffsets,
ySpans);
} else {
SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
xChildren, xOffsets,
xSpans, ltr);
SizeRequirements.calculateTiledPositions(alloc.height, yTotal,
yChildren, yOffsets,
ySpans);
}
}
// flush changes to the container
for (int i = 0; i < nChildren; i++) {
Component c = target.getComponent(i);
c.setBounds((int) Math.min((long) in.left + (long) xOffsets[i], Integer.MAX_VALUE),
(int) Math.min((long) in.top + (long) yOffsets[i], Integer.MAX_VALUE),
xSpans[i], ySpans[i]);
}
if (dbg != null) {
for (int i = 0; i < nChildren; i++) {
Component c = target.getComponent(i);
dbg.println(c.toString());
dbg.println("X: " + xChildren[i]);
dbg.println("Y: " + yChildren[i]);
}
}
}
void checkContainer(Container target) {
if (this.target != target) {
throw new AWTError("BoxLayout can't be shared");
}
}
void checkRequests() {
if (xChildren == null || yChildren == null) {
// The requests have been invalidated... recalculate
// the request information.
int n = target.getComponentCount();
xChildren = new SizeRequirements[n];
yChildren = new SizeRequirements[n];
for (int i = 0; i < n; i++) {
Component c = target.getComponent(i);
if (!c.isVisible()) {
xChildren[i] = new SizeRequirements(0,0,0, c.getAlignmentX());
yChildren[i] = new SizeRequirements(0,0,0, c.getAlignmentY());
continue;
}
Dimension min = c.getMinimumSize();
Dimension typ = c.getPreferredSize();
Dimension max = c.getMaximumSize();
xChildren[i] = new SizeRequirements(min.width, typ.width,
max.width,
c.getAlignmentX());
yChildren[i] = new SizeRequirements(min.height, typ.height,
max.height,
c.getAlignmentY());
}
// Resolve axis to an absolute value (either X_AXIS or Y_AXIS)
int absoluteAxis = resolveAxis(axis,target.getComponentOrientation());
if (absoluteAxis == X_AXIS) {
xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
} else {
xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
}
}
}
/**
* Given one of the 4 axis values, resolve it to an absolute axis.
* The relative axis values, PAGE_AXIS and LINE_AXIS are converted
* to their absolute couterpart given the target's ComponentOrientation
* value. The absolute axes, X_AXIS and Y_AXIS are returned unmodified.
*
* @param axis the axis to resolve
* @param o the ComponentOrientation to resolve against
* @return the resolved axis
*/
private int resolveAxis( int axis, ComponentOrientation o ) {
int absoluteAxis;
if( axis == LINE_AXIS ) {
absoluteAxis = o.isHorizontal() ? X_AXIS : Y_AXIS;
} else if( axis == PAGE_AXIS ) {
absoluteAxis = o.isHorizontal() ? Y_AXIS : X_AXIS;
} else {
absoluteAxis = axis;
}
return absoluteAxis;
}
private int axis;
private Container target;
private transient SizeRequirements[] xChildren;
private transient SizeRequirements[] yChildren;
private transient SizeRequirements xTotal;
private transient SizeRequirements yTotal;
private transient PrintStream dbg;
}

View File

@@ -0,0 +1,952 @@
/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.lang.reflect.*;
import java.lang.ref.WeakReference;
import java.util.*;
import com.sun.java.swing.SwingUtilities3;
import sun.awt.SubRegionShowable;
import sun.java2d.SunGraphics2D;
import sun.java2d.pipe.hw.ExtendedBufferCapabilities;
import sun.awt.SunToolkit;
import sun.util.logging.PlatformLogger;
/**
* A PaintManager implementation that uses a BufferStrategy for
* rendering.
*
* @author Scott Violet
*/
class BufferStrategyPaintManager extends RepaintManager.PaintManager {
//
// All drawing is done to a BufferStrategy. At the end of painting
// (endPaint) the region that was painted is flushed to the screen
// (using BufferStrategy.show).
//
// PaintManager.show is overriden to show directly from the
// BufferStrategy (when using blit), if successful true is
// returned and a paint event will not be generated. To avoid
// showing from the buffer while painting a locking scheme is
// implemented. When beginPaint is invoked the field painting is
// set to true. If painting is true and show is invoked we
// immediately return false. This is done to avoid blocking the
// toolkit thread while painting happens. In a similar way when
// show is invoked the field showing is set to true, beginPaint
// will then block until showing is true. This scheme ensures we
// only ever have one thread using the BufferStrategy and it also
// ensures the toolkit thread remains as responsive as possible.
//
// If we're using a flip strategy the contents of the backbuffer may
// have changed and so show only attempts to show from the backbuffer
// if we get a blit strategy.
//
//
// Methods used to create BufferStrategy for Applets.
//
private static Method COMPONENT_CREATE_BUFFER_STRATEGY_METHOD;
private static Method COMPONENT_GET_BUFFER_STRATEGY_METHOD;
private static final PlatformLogger LOGGER = PlatformLogger.getLogger(
"javax.swing.BufferStrategyPaintManager");
/**
* List of BufferInfos. We don't use a Map primarily because
* there are typically only a handful of top level components making
* a Map overkill.
*/
private ArrayList<BufferInfo> bufferInfos;
/**
* Indicates <code>beginPaint</code> has been invoked. This is
* set to true for the life of beginPaint/endPaint pair.
*/
private boolean painting;
/**
* Indicates we're in the process of showing. All painting, on the EDT,
* is blocked while this is true.
*/
private boolean showing;
//
// Region that we need to flush. When beginPaint is called these are
// reset and any subsequent calls to paint/copyArea then update these
// fields accordingly. When endPaint is called we then try and show
// the accumulated region.
// These fields are in the coordinate system of the root.
//
private int accumulatedX;
private int accumulatedY;
private int accumulatedMaxX;
private int accumulatedMaxY;
//
// The following fields are set by prepare
//
/**
* Farthest JComponent ancestor for the current paint/copyArea.
*/
private JComponent rootJ;
/**
* Location of component being painted relative to root.
*/
private int xOffset;
/**
* Location of component being painted relative to root.
*/
private int yOffset;
/**
* Graphics from the BufferStrategy.
*/
private Graphics bsg;
/**
* BufferStrategy currently being used.
*/
private BufferStrategy bufferStrategy;
/**
* BufferInfo corresponding to root.
*/
private BufferInfo bufferInfo;
/**
* Set to true if the bufferInfo needs to be disposed when current
* paint loop is done.
*/
private boolean disposeBufferOnEnd;
private static Method getGetBufferStrategyMethod() {
if (COMPONENT_GET_BUFFER_STRATEGY_METHOD == null) {
getMethods();
}
return COMPONENT_GET_BUFFER_STRATEGY_METHOD;
}
private static Method getCreateBufferStrategyMethod() {
if (COMPONENT_CREATE_BUFFER_STRATEGY_METHOD == null) {
getMethods();
}
return COMPONENT_CREATE_BUFFER_STRATEGY_METHOD;
}
private static void getMethods() {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Object>() {
public Object run() {
try {
COMPONENT_CREATE_BUFFER_STRATEGY_METHOD = Component.class.
getDeclaredMethod("createBufferStrategy",
new Class[] { int.class,
BufferCapabilities.class });
COMPONENT_CREATE_BUFFER_STRATEGY_METHOD.
setAccessible(true);
COMPONENT_GET_BUFFER_STRATEGY_METHOD = Component.class.
getDeclaredMethod("getBufferStrategy");
COMPONENT_GET_BUFFER_STRATEGY_METHOD.setAccessible(true);
} catch (SecurityException e) {
assert false;
} catch (NoSuchMethodException nsme) {
assert false;
}
return null;
}
});
}
BufferStrategyPaintManager() {
bufferInfos = new ArrayList<BufferInfo>(1);
}
//
// PaintManager methods
//
/**
* Cleans up any created BufferStrategies.
*/
protected void dispose() {
// dipose can be invoked at any random time. To avoid
// threading dependancies we do the actual diposing via an
// invokeLater.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
java.util.List<BufferInfo> bufferInfos;
synchronized(BufferStrategyPaintManager.this) {
while (showing) {
try {
BufferStrategyPaintManager.this.wait();
} catch (InterruptedException ie) {
}
}
bufferInfos = BufferStrategyPaintManager.this.bufferInfos;
BufferStrategyPaintManager.this.bufferInfos = null;
}
dispose(bufferInfos);
}
});
}
private void dispose(java.util.List<BufferInfo> bufferInfos) {
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("BufferStrategyPaintManager disposed",
new RuntimeException());
}
if (bufferInfos != null) {
for (BufferInfo bufferInfo : bufferInfos) {
bufferInfo.dispose();
}
}
}
/**
* Shows the specified region of the back buffer. This will return
* true if successful, false otherwise. This is invoked on the
* toolkit thread in response to an expose event.
*/
public boolean show(Container c, int x, int y, int w, int h) {
synchronized(this) {
if (painting) {
// Don't show from backbuffer while in the process of
// painting.
return false;
}
showing = true;
}
try {
BufferInfo info = getBufferInfo(c);
BufferStrategy bufferStrategy;
if (info != null && info.isInSync() &&
(bufferStrategy = info.getBufferStrategy(false)) != null) {
SubRegionShowable bsSubRegion =
(SubRegionShowable)bufferStrategy;
boolean paintAllOnExpose = info.getPaintAllOnExpose();
info.setPaintAllOnExpose(false);
if (bsSubRegion.showIfNotLost(x, y, (x + w), (y + h))) {
return !paintAllOnExpose;
}
// Mark the buffer as needing to be repainted. We don't
// immediately do a repaint as this method will return false
// indicating a PaintEvent should be generated which will
// trigger a complete repaint.
bufferInfo.setContentsLostDuringExpose(true);
}
}
finally {
synchronized(this) {
showing = false;
notifyAll();
}
}
return false;
}
public boolean paint(JComponent paintingComponent,
JComponent bufferComponent, Graphics g,
int x, int y, int w, int h) {
Container root = fetchRoot(paintingComponent);
if (prepare(paintingComponent, root, true, x, y, w, h)) {
if ((g instanceof SunGraphics2D) &&
((SunGraphics2D)g).getDestination() == root) {
// BufferStrategy may have already constrained the Graphics. To
// account for that we revert the constrain, then apply a
// constrain for Swing on top of that.
int cx = ((SunGraphics2D)bsg).constrainX;
int cy = ((SunGraphics2D)bsg).constrainY;
if (cx != 0 || cy != 0) {
bsg.translate(-cx, -cy);
}
((SunGraphics2D)bsg).constrain(xOffset + cx, yOffset + cy,
x + w, y + h);
bsg.setClip(x, y, w, h);
paintingComponent.paintToOffscreen(bsg, x, y, w, h,
x + w, y + h);
accumulate(xOffset + x, yOffset + y, w, h);
return true;
} else {
// Assume they are going to eventually render to the screen.
// This disables showing from backbuffer until a complete
// repaint occurs.
bufferInfo.setInSync(false);
// Fall through to old rendering.
}
}
// Invalid root, do what Swing has always done.
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("prepare failed");
}
return super.paint(paintingComponent, bufferComponent, g, x, y, w, h);
}
public void copyArea(JComponent c, Graphics g, int x, int y, int w, int h,
int deltaX, int deltaY, boolean clip) {
// Note: this method is only called internally and we know that
// g is from a heavyweight Component, so no check is necessary as
// it is in paint() above.
//
// If the buffer isn't in sync there is no point in doing a copyArea,
// it has garbage.
Container root = fetchRoot(c);
if (prepare(c, root, false, 0, 0, 0, 0) && bufferInfo.isInSync()) {
if (clip) {
Rectangle cBounds = c.getVisibleRect();
int relX = xOffset + x;
int relY = yOffset + y;
bsg.clipRect(xOffset + cBounds.x,
yOffset + cBounds.y,
cBounds.width, cBounds.height);
bsg.copyArea(relX, relY, w, h, deltaX, deltaY);
}
else {
bsg.copyArea(xOffset + x, yOffset + y, w, h, deltaX,
deltaY);
}
accumulate(x + xOffset + deltaX, y + yOffset + deltaY, w, h);
} else {
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("copyArea: prepare failed or not in sync");
}
// Prepare failed, or not in sync. By calling super.copyArea
// we'll copy on screen. We need to flush any pending paint to
// the screen otherwise we'll do a copyArea on the wrong thing.
if (!flushAccumulatedRegion()) {
// Flush failed, copyArea will be copying garbage,
// force repaint of all.
rootJ.repaint();
} else {
super.copyArea(c, g, x, y, w, h, deltaX, deltaY, clip);
}
}
}
public void beginPaint() {
synchronized(this) {
painting = true;
// Make sure another thread isn't attempting to show from
// the back buffer.
while(showing) {
try {
wait();
} catch (InterruptedException ie) {
}
}
}
if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {
LOGGER.finest("beginPaint");
}
// Reset the area that needs to be painted.
resetAccumulated();
}
public void endPaint() {
if (LOGGER.isLoggable(PlatformLogger.Level.FINEST)) {
LOGGER.finest("endPaint: region " + accumulatedX + " " +
accumulatedY + " " + accumulatedMaxX + " " +
accumulatedMaxY);
}
if (painting) {
if (!flushAccumulatedRegion()) {
if (!isRepaintingRoot()) {
repaintRoot(rootJ);
}
else {
// Contents lost twice in a row, punt.
resetDoubleBufferPerWindow();
// In case we've left junk on the screen, force a repaint.
rootJ.repaint();
}
}
}
BufferInfo toDispose = null;
synchronized(this) {
painting = false;
if (disposeBufferOnEnd) {
disposeBufferOnEnd = false;
toDispose = bufferInfo;
bufferInfos.remove(toDispose);
}
}
if (toDispose != null) {
toDispose.dispose();
}
}
/**
* Renders the BufferStrategy to the screen.
*
* @return true if successful, false otherwise.
*/
private boolean flushAccumulatedRegion() {
boolean success = true;
if (accumulatedX != Integer.MAX_VALUE) {
SubRegionShowable bsSubRegion = (SubRegionShowable)bufferStrategy;
boolean contentsLost = bufferStrategy.contentsLost();
if (!contentsLost) {
bsSubRegion.show(accumulatedX, accumulatedY,
accumulatedMaxX, accumulatedMaxY);
contentsLost = bufferStrategy.contentsLost();
}
if (contentsLost) {
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("endPaint: contents lost");
}
// Shown region was bogus, mark buffer as out of sync.
bufferInfo.setInSync(false);
success = false;
}
}
resetAccumulated();
return success;
}
private void resetAccumulated() {
accumulatedX = Integer.MAX_VALUE;
accumulatedY = Integer.MAX_VALUE;
accumulatedMaxX = 0;
accumulatedMaxY = 0;
}
/**
* Invoked when the double buffering or useTrueDoubleBuffering
* changes for a JRootPane. If the rootpane is not double
* buffered, or true double buffering changes we throw out any
* cache we may have.
*/
public void doubleBufferingChanged(final JRootPane rootPane) {
if ((!rootPane.isDoubleBuffered() ||
!rootPane.getUseTrueDoubleBuffering()) &&
rootPane.getParent() != null) {
if (!SwingUtilities.isEventDispatchThread()) {
Runnable updater = new Runnable() {
public void run() {
doubleBufferingChanged0(rootPane);
}
};
SwingUtilities.invokeLater(updater);
}
else {
doubleBufferingChanged0(rootPane);
}
}
}
/**
* Does the work for doubleBufferingChanged.
*/
private void doubleBufferingChanged0(JRootPane rootPane) {
// This will only happen on the EDT.
BufferInfo info;
synchronized(this) {
// Make sure another thread isn't attempting to show from
// the back buffer.
while(showing) {
try {
wait();
} catch (InterruptedException ie) {
}
}
info = getBufferInfo(rootPane.getParent());
if (painting && bufferInfo == info) {
// We're in the process of painting and the user grabbed
// the Graphics. If we dispose now, endPaint will attempt
// to show a bogus BufferStrategy. Set a flag so that
// endPaint knows it needs to dispose this buffer.
disposeBufferOnEnd = true;
info = null;
} else if (info != null) {
bufferInfos.remove(info);
}
}
if (info != null) {
info.dispose();
}
}
/**
* Calculates information common to paint/copyArea.
*
* @return true if should use buffering per window in painting.
*/
private boolean prepare(JComponent c, Container root, boolean isPaint, int x, int y,
int w, int h) {
if (bsg != null) {
bsg.dispose();
bsg = null;
}
bufferStrategy = null;
if (root != null) {
boolean contentsLost = false;
BufferInfo bufferInfo = getBufferInfo(root);
if (bufferInfo == null) {
contentsLost = true;
bufferInfo = new BufferInfo(root);
bufferInfos.add(bufferInfo);
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("prepare: new BufferInfo: " + root);
}
}
this.bufferInfo = bufferInfo;
if (!bufferInfo.hasBufferStrategyChanged()) {
bufferStrategy = bufferInfo.getBufferStrategy(true);
if (bufferStrategy != null) {
bsg = bufferStrategy.getDrawGraphics();
if (bufferStrategy.contentsRestored()) {
contentsLost = true;
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("prepare: contents restored in prepare");
}
}
}
else {
// Couldn't create BufferStrategy, fallback to normal
// painting.
return false;
}
if (bufferInfo.getContentsLostDuringExpose()) {
contentsLost = true;
bufferInfo.setContentsLostDuringExpose(false);
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("prepare: contents lost on expose");
}
}
if (isPaint && c == rootJ && x == 0 && y == 0 &&
c.getWidth() == w && c.getHeight() == h) {
bufferInfo.setInSync(true);
}
else if (contentsLost) {
// We either recreated the BufferStrategy, or the contents
// of the buffer strategy were restored. We need to
// repaint the root pane so that the back buffer is in sync
// again.
bufferInfo.setInSync(false);
if (!isRepaintingRoot()) {
repaintRoot(rootJ);
}
else {
// Contents lost twice in a row, punt
resetDoubleBufferPerWindow();
}
}
return (bufferInfos != null);
}
}
return false;
}
private Container fetchRoot(JComponent c) {
boolean encounteredHW = false;
rootJ = c;
Container root = c;
xOffset = yOffset = 0;
while (root != null &&
(!(root instanceof Window) &&
!SunToolkit.isInstanceOf(root, "java.applet.Applet"))) {
xOffset += root.getX();
yOffset += root.getY();
root = root.getParent();
if (root != null) {
if (root instanceof JComponent) {
rootJ = (JComponent)root;
}
else if (!root.isLightweight()) {
if (!encounteredHW) {
encounteredHW = true;
}
else {
// We've encountered two hws now and may have
// a containment hierarchy with lightweights containing
// heavyweights containing other lightweights.
// Heavyweights poke holes in lightweight
// rendering so that if we call show on the BS
// (which is associated with the Window) you will
// not see the contents over any child
// heavyweights. If we didn't do this when we
// went to show the descendants of the nested hw
// you would see nothing, so, we bail out here.
return null;
}
}
}
}
if ((root instanceof RootPaneContainer) &&
(rootJ instanceof JRootPane)) {
// We're in a Swing heavyeight (JFrame/JWindow...), use double
// buffering if double buffering enabled on the JRootPane and
// the JRootPane wants true double buffering.
if (rootJ.isDoubleBuffered() &&
((JRootPane)rootJ).getUseTrueDoubleBuffering()) {
// Whether or not a component is double buffered is a
// bit tricky with Swing. This gives a good approximation
// of the various ways to turn on double buffering for
// components.
return root;
}
}
// Don't do true double buffering.
return null;
}
/**
* Turns off double buffering per window.
*/
private void resetDoubleBufferPerWindow() {
if (bufferInfos != null) {
dispose(bufferInfos);
bufferInfos = null;
repaintManager.setPaintManager(null);
}
}
/**
* Returns the BufferInfo for the specified root or null if one
* hasn't been created yet.
*/
private BufferInfo getBufferInfo(Container root) {
for (int counter = bufferInfos.size() - 1; counter >= 0; counter--) {
BufferInfo bufferInfo = bufferInfos.get(counter);
Container biRoot = bufferInfo.getRoot();
if (biRoot == null) {
// Window gc'ed
bufferInfos.remove(counter);
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("BufferInfo pruned, root null");
}
}
else if (biRoot == root) {
return bufferInfo;
}
}
return null;
}
private void accumulate(int x, int y, int w, int h) {
accumulatedX = Math.min(x, accumulatedX);
accumulatedY = Math.min(y, accumulatedY);
accumulatedMaxX = Math.max(accumulatedMaxX, x + w);
accumulatedMaxY = Math.max(accumulatedMaxY, y + h);
}
/**
* BufferInfo is used to track the BufferStrategy being used for
* a particular Component. In addition to tracking the BufferStrategy
* it will install a WindowListener and ComponentListener. When the
* component is hidden/iconified the buffer is marked as needing to be
* completely repainted.
*/
private class BufferInfo extends ComponentAdapter implements
WindowListener {
// NOTE: This class does NOT hold a direct reference to the root, if it
// did there would be a cycle between the BufferPerWindowPaintManager
// and the Window so that it could never be GC'ed
//
// Reference to BufferStrategy is referenced via WeakReference for
// same reason.
private WeakReference<BufferStrategy> weakBS;
private WeakReference<Container> root;
// Indicates whether or not the backbuffer and display are in sync.
// This is set to true when a full repaint on the rootpane is done.
private boolean inSync;
// Indicates the contents were lost during and expose event.
private boolean contentsLostDuringExpose;
// Indicates we need to generate a paint event on expose.
private boolean paintAllOnExpose;
public BufferInfo(Container root) {
this.root = new WeakReference<Container>(root);
root.addComponentListener(this);
if (root instanceof Window) {
((Window)root).addWindowListener(this);
}
}
public void setPaintAllOnExpose(boolean paintAllOnExpose) {
this.paintAllOnExpose = paintAllOnExpose;
}
public boolean getPaintAllOnExpose() {
return paintAllOnExpose;
}
public void setContentsLostDuringExpose(boolean value) {
contentsLostDuringExpose = value;
}
public boolean getContentsLostDuringExpose() {
return contentsLostDuringExpose;
}
public void setInSync(boolean inSync) {
this.inSync = inSync;
}
/**
* Whether or not the contents of the buffer strategy
* is in sync with the window. This is set to true when the root
* pane paints all, and false when contents are lost/restored.
*/
public boolean isInSync() {
return inSync;
}
/**
* Returns the Root (Window or Applet) that this BufferInfo references.
*/
public Container getRoot() {
return (root == null) ? null : root.get();
}
/**
* Returns the BufferStartegy. This will return null if
* the BufferStartegy hasn't been created and <code>create</code> is
* false, or if there is a problem in creating the
* <code>BufferStartegy</code>.
*
* @param create If true, and the BufferStartegy is currently null,
* one will be created.
*/
public BufferStrategy getBufferStrategy(boolean create) {
BufferStrategy bs = (weakBS == null) ? null : weakBS.get();
if (bs == null && create) {
bs = createBufferStrategy();
if (bs != null) {
weakBS = new WeakReference<BufferStrategy>(bs);
}
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("getBufferStrategy: created bs: " + bs);
}
}
return bs;
}
/**
* Returns true if the buffer strategy of the component differs
* from current buffer strategy.
*/
public boolean hasBufferStrategyChanged() {
Container root = getRoot();
if (root != null) {
BufferStrategy ourBS = null;
BufferStrategy componentBS = null;
ourBS = getBufferStrategy(false);
if (root instanceof Window) {
componentBS = ((Window)root).getBufferStrategy();
}
else {
try {
componentBS = (BufferStrategy)
getGetBufferStrategyMethod().invoke(root);
} catch (InvocationTargetException ite) {
assert false;
} catch (IllegalArgumentException iae) {
assert false;
} catch (IllegalAccessException iae2) {
assert false;
}
}
if (componentBS != ourBS) {
// Component has a different BS, dispose ours.
if (ourBS != null) {
ourBS.dispose();
}
weakBS = null;
return true;
}
}
return false;
}
/**
* Creates the BufferStrategy. If the appropriate system property
* has been set we'll try for flip first and then we'll try for
* blit.
*/
private BufferStrategy createBufferStrategy() {
Container root = getRoot();
if (root == null) {
return null;
}
BufferStrategy bs = null;
if (SwingUtilities3.isVsyncRequested(root)) {
bs = createBufferStrategy(root, true);
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("createBufferStrategy: using vsynced strategy");
}
}
if (bs == null) {
bs = createBufferStrategy(root, false);
}
if (!(bs instanceof SubRegionShowable)) {
// We do this for two reasons:
// 1. So that we know we can cast to SubRegionShowable and
// invoke show with the minimal region to update
// 2. To avoid the possibility of invoking client code
// on the toolkit thread.
bs = null;
}
return bs;
}
// Creates and returns a buffer strategy. If
// there is a problem creating the buffer strategy this will
// eat the exception and return null.
private BufferStrategy createBufferStrategy(Container root,
boolean isVsynced) {
BufferCapabilities caps;
if (isVsynced) {
caps = new ExtendedBufferCapabilities(
new ImageCapabilities(true), new ImageCapabilities(true),
BufferCapabilities.FlipContents.COPIED,
ExtendedBufferCapabilities.VSyncType.VSYNC_ON);
} else {
caps = new BufferCapabilities(
new ImageCapabilities(true), new ImageCapabilities(true),
null);
}
BufferStrategy bs = null;
if (SunToolkit.isInstanceOf(root, "java.applet.Applet")) {
try {
getCreateBufferStrategyMethod().invoke(root, 2, caps);
bs = (BufferStrategy)getGetBufferStrategyMethod().
invoke(root);
} catch (InvocationTargetException ite) {
// Type is not supported
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("createBufferStratety failed",
ite);
}
} catch (IllegalArgumentException iae) {
assert false;
} catch (IllegalAccessException iae2) {
assert false;
}
}
else {
try {
((Window)root).createBufferStrategy(2, caps);
bs = ((Window)root).getBufferStrategy();
} catch (AWTException e) {
// Type not supported
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("createBufferStratety failed",
e);
}
}
}
return bs;
}
/**
* Cleans up and removes any references.
*/
public void dispose() {
Container root = getRoot();
if (LOGGER.isLoggable(PlatformLogger.Level.FINER)) {
LOGGER.finer("disposed BufferInfo for: " + root);
}
if (root != null) {
root.removeComponentListener(this);
if (root instanceof Window) {
((Window)root).removeWindowListener(this);
}
BufferStrategy bs = getBufferStrategy(false);
if (bs != null) {
bs.dispose();
}
}
this.root = null;
weakBS = null;
}
// We mark the buffer as needing to be painted on a hide/iconify
// because the developer may have conditionalized painting based on
// visibility.
// Ideally we would also move to having the BufferStrategy being
// a SoftReference in Component here, but that requires changes to
// Component and the like.
public void componentHidden(ComponentEvent e) {
Container root = getRoot();
if (root != null && root.isVisible()) {
// This case will only happen if a developer calls
// hide immediately followed by show. In this case
// the event is delivered after show and the window
// will still be visible. If a developer altered the
// contents of the window between the hide/show
// invocations we won't recognize we need to paint and
// the contents would be bogus. Calling repaint here
// fixs everything up.
root.repaint();
}
else {
setPaintAllOnExpose(true);
}
}
public void windowIconified(WindowEvent e) {
setPaintAllOnExpose(true);
}
// On a dispose we chuck everything.
public void windowClosed(WindowEvent e) {
// Make sure we're not showing.
synchronized(BufferStrategyPaintManager.this) {
while (showing) {
try {
BufferStrategyPaintManager.this.wait();
} catch (InterruptedException ie) {
}
}
bufferInfos.remove(this);
}
dispose();
}
public void windowOpened(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowActivated(WindowEvent e) {
}
public void windowDeactivated(WindowEvent e) {
}
}
}

View File

@@ -0,0 +1,191 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.event.*;
import java.util.Vector;
import java.util.Enumeration;
import java.io.Serializable;
/**
* This class is used to create a multiple-exclusion scope for
* a set of buttons. Creating a set of buttons with the
* same <code>ButtonGroup</code> object means that
* turning "on" one of those buttons
* turns off all other buttons in the group.
* <p>
* A <code>ButtonGroup</code> can be used with
* any set of objects that inherit from <code>AbstractButton</code>.
* Typically a button group contains instances of
* <code>JRadioButton</code>,
* <code>JRadioButtonMenuItem</code>,
* or <code>JToggleButton</code>.
* It wouldn't make sense to put an instance of
* <code>JButton</code> or <code>JMenuItem</code>
* in a button group
* because <code>JButton</code> and <code>JMenuItem</code>
* don't implement the selected state.
* <p>
* Initially, all buttons in the group are unselected.
* <p>
* For examples and further information on using button groups see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/button.html#radiobutton">How to Use Radio Buttons</a>,
* a section in <em>The Java Tutorial</em>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Jeff Dinkins
*/
@SuppressWarnings("serial")
public class ButtonGroup implements Serializable {
// the list of buttons participating in this group
protected Vector<AbstractButton> buttons = new Vector<AbstractButton>();
/**
* The current selection.
*/
ButtonModel selection = null;
/**
* Creates a new <code>ButtonGroup</code>.
*/
public ButtonGroup() {}
/**
* Adds the button to the group.
* @param b the button to be added
*/
public void add(AbstractButton b) {
if(b == null) {
return;
}
buttons.addElement(b);
if (b.isSelected()) {
if (selection == null) {
selection = b.getModel();
} else {
b.setSelected(false);
}
}
b.getModel().setGroup(this);
}
/**
* Removes the button from the group.
* @param b the button to be removed
*/
public void remove(AbstractButton b) {
if(b == null) {
return;
}
buttons.removeElement(b);
if(b.getModel() == selection) {
selection = null;
}
b.getModel().setGroup(null);
}
/**
* Clears the selection such that none of the buttons
* in the <code>ButtonGroup</code> are selected.
*
* @since 1.6
*/
public void clearSelection() {
if (selection != null) {
ButtonModel oldSelection = selection;
selection = null;
oldSelection.setSelected(false);
}
}
/**
* Returns all the buttons that are participating in
* this group.
* @return an <code>Enumeration</code> of the buttons in this group
*/
public Enumeration<AbstractButton> getElements() {
return buttons.elements();
}
/**
* Returns the model of the selected button.
* @return the selected button model
*/
public ButtonModel getSelection() {
return selection;
}
/**
* Sets the selected value for the <code>ButtonModel</code>.
* Only one button in the group may be selected at a time.
* @param m the <code>ButtonModel</code>
* @param b <code>true</code> if this button is to be
* selected, otherwise <code>false</code>
*/
public void setSelected(ButtonModel m, boolean b) {
if (b && m != null && m != selection) {
ButtonModel oldSelection = selection;
selection = m;
if (oldSelection != null) {
oldSelection.setSelected(false);
}
m.setSelected(true);
}
}
/**
* Returns whether a <code>ButtonModel</code> is selected.
* @return <code>true</code> if the button is selected,
* otherwise returns <code>false</code>
*/
public boolean isSelected(ButtonModel m) {
return (m == selection);
}
/**
* Returns the number of buttons in the group.
* @return the button count
* @since 1.3
*/
public int getButtonCount() {
if (buttons == null) {
return 0;
} else {
return buttons.size();
}
}
}

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.event.*;
import java.awt.*;
import javax.swing.event.*;
/**
* State model for buttons.
* <p>
* This model is used for regular buttons, as well as check boxes
* and radio buttons, which are special kinds of buttons. In practice,
* a button's UI takes the responsibility of calling methods on its
* model to manage the state, as detailed below:
* <p>
* In simple terms, pressing and releasing the mouse over a regular
* button triggers the button and causes and <code>ActionEvent</code>
* to be fired. The same behavior can be produced via a keyboard key
* defined by the look and feel of the button (typically the SPACE BAR).
* Pressing and releasing this key while the button has
* focus will give the same results. For check boxes and radio buttons, the
* mouse or keyboard equivalent sequence just described causes the button
* to become selected.
* <p>
* In details, the state model for buttons works as follows
* when used with the mouse:
* <br>
* Pressing the mouse on top of a button makes the model both
* armed and pressed. As long as the mouse remains down,
* the model remains pressed, even if the mouse moves
* outside the button. On the contrary, the model is only
* armed while the mouse remains pressed within the bounds of
* the button (it can move in or out of the button, but the model
* is only armed during the portion of time spent within the button).
* A button is triggered, and an <code>ActionEvent</code> is fired,
* when the mouse is released while the model is armed
* - meaning when it is released over top of the button after the mouse
* has previously been pressed on that button (and not already released).
* Upon mouse release, the model becomes unarmed and unpressed.
* <p>
* In details, the state model for buttons works as follows
* when used with the keyboard:
* <br>
* Pressing the look and feel defined keyboard key while the button
* has focus makes the model both armed and pressed. As long as this key
* remains down, the model remains in this state. Releasing the key sets
* the model to unarmed and unpressed, triggers the button, and causes an
* <code>ActionEvent</code> to be fired.
*
* @author Jeff Dinkins
*/
public interface ButtonModel extends ItemSelectable {
/**
* Indicates partial commitment towards triggering the
* button.
*
* @return <code>true</code> if the button is armed,
* and ready to be triggered
* @see #setArmed
*/
boolean isArmed();
/**
* Indicates if the button has been selected. Only needed for
* certain types of buttons - such as radio buttons and check boxes.
*
* @return <code>true</code> if the button is selected
*/
boolean isSelected();
/**
* Indicates if the button can be selected or triggered by
* an input device, such as a mouse pointer.
*
* @return <code>true</code> if the button is enabled
*/
boolean isEnabled();
/**
* Indicates if the button is pressed.
*
* @return <code>true</code> if the button is pressed
*/
boolean isPressed();
/**
* Indicates that the mouse is over the button.
*
* @return <code>true</code> if the mouse is over the button
*/
boolean isRollover();
/**
* Marks the button as armed or unarmed.
*
* @param b whether or not the button should be armed
*/
public void setArmed(boolean b);
/**
* Selects or deselects the button.
*
* @param b <code>true</code> selects the button,
* <code>false</code> deselects the button
*/
public void setSelected(boolean b);
/**
* Enables or disables the button.
*
* @param b whether or not the button should be enabled
* @see #isEnabled
*/
public void setEnabled(boolean b);
/**
* Sets the button to pressed or unpressed.
*
* @param b whether or not the button should be pressed
* @see #isPressed
*/
public void setPressed(boolean b);
/**
* Sets or clears the button's rollover state
*
* @param b whether or not the button is in the rollover state
* @see #isRollover
*/
public void setRollover(boolean b);
/**
* Sets the keyboard mnemonic (shortcut key or
* accelerator key) for the button.
*
* @param key an int specifying the accelerator key
*/
public void setMnemonic(int key);
/**
* Gets the keyboard mnemonic for the button.
*
* @return an int specifying the accelerator key
* @see #setMnemonic
*/
public int getMnemonic();
/**
* Sets the action command string that gets sent as part of the
* <code>ActionEvent</code> when the button is triggered.
*
* @param s the <code>String</code> that identifies the generated event
* @see #getActionCommand
* @see java.awt.event.ActionEvent#getActionCommand
*/
public void setActionCommand(String s);
/**
* Returns the action command string for the button.
*
* @return the <code>String</code> that identifies the generated event
* @see #setActionCommand
*/
public String getActionCommand();
/**
* Identifies the group the button belongs to --
* needed for radio buttons, which are mutually
* exclusive within their group.
*
* @param group the <code>ButtonGroup</code> the button belongs to
*/
public void setGroup(ButtonGroup group);
/**
* Adds an <code>ActionListener</code> to the model.
*
* @param l the listener to add
*/
void addActionListener(ActionListener l);
/**
* Removes an <code>ActionListener</code> from the model.
*
* @param l the listener to remove
*/
void removeActionListener(ActionListener l);
/**
* Adds an <code>ItemListener</code> to the model.
*
* @param l the listener to add
*/
void addItemListener(ItemListener l);
/**
* Removes an <code>ItemListener</code> from the model.
*
* @param l the listener to remove
*/
void removeItemListener(ItemListener l);
/**
* Adds a <code>ChangeListener</code> to the model.
*
* @param l the listener to add
*/
void addChangeListener(ChangeListener l);
/**
* Removes a <code>ChangeListener</code> from the model.
*
* @param l the listener to remove
*/
void removeChangeListener(ChangeListener l);
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.EventObject;
import javax.swing.event.*;
/**
* This interface defines the methods any general editor should be able
* to implement. <p>
*
* Having this interface enables complex components (the client of the
* editor) such as <code>JTree</code> and
* <code>JTable</code> to allow any generic editor to
* edit values in a table cell, or tree cell, etc. Without this generic
* editor interface, <code>JTable</code> would have to know about specific editors,
* such as <code>JTextField</code>, <code>JCheckBox</code>, <code>JComboBox</code>,
* etc. In addition, without this interface, clients of editors such as
* <code>JTable</code> would not be able
* to work with any editors developed in the future by the user
* or a 3rd party ISV. <p>
*
* To use this interface, a developer creating a new editor can have the
* new component implement the interface. Or the developer can
* choose a wrapper based approach and provide a companion object which
* implements the <code>CellEditor</code> interface (See
* <code>DefaultCellEditor</code> for example). The wrapper approach
* is particularly useful if the user want to use a 3rd party ISV
* editor with <code>JTable</code>, but the ISV didn't implement the
* <code>CellEditor</code> interface. The user can simply create an object
* that contains an instance of the 3rd party editor object and "translate"
* the <code>CellEditor</code> API into the 3rd party editor's API.
*
* @see javax.swing.event.CellEditorListener
*
* @author Alan Chung
*/
public interface CellEditor {
/**
* Returns the value contained in the editor.
* @return the value contained in the editor
*/
public Object getCellEditorValue();
/**
* Asks the editor if it can start editing using <code>anEvent</code>.
* <code>anEvent</code> is in the invoking component coordinate system.
* The editor can not assume the Component returned by
* <code>getCellEditorComponent</code> is installed. This method
* is intended for the use of client to avoid the cost of setting up
* and installing the editor component if editing is not possible.
* If editing can be started this method returns true.
*
* @param anEvent the event the editor should use to consider
* whether to begin editing or not
* @return true if editing can be started
* @see #shouldSelectCell
*/
public boolean isCellEditable(EventObject anEvent);
/**
* Returns true if the editing cell should be selected, false otherwise.
* Typically, the return value is true, because is most cases the editing
* cell should be selected. However, it is useful to return false to
* keep the selection from changing for some types of edits.
* eg. A table that contains a column of check boxes, the user might
* want to be able to change those checkboxes without altering the
* selection. (See Netscape Communicator for just such an example)
* Of course, it is up to the client of the editor to use the return
* value, but it doesn't need to if it doesn't want to.
*
* @param anEvent the event the editor should use to start
* editing
* @return true if the editor would like the editing cell to be selected;
* otherwise returns false
* @see #isCellEditable
*/
public boolean shouldSelectCell(EventObject anEvent);
/**
* Tells the editor to stop editing and accept any partially edited
* value as the value of the editor. The editor returns false if
* editing was not stopped; this is useful for editors that validate
* and can not accept invalid entries.
*
* @return true if editing was stopped; false otherwise
*/
public boolean stopCellEditing();
/**
* Tells the editor to cancel editing and not accept any partially
* edited value.
*/
public void cancelCellEditing();
/**
* Adds a listener to the list that's notified when the editor
* stops, or cancels editing.
*
* @param l the CellEditorListener
*/
public void addCellEditorListener(CellEditorListener l);
/**
* Removes a listener from the list that's notified
*
* @param l the CellEditorListener
*/
public void removeCellEditorListener(CellEditorListener l);
}

View File

@@ -0,0 +1,227 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.beans.PropertyChangeListener;
import java.util.Locale;
import java.util.Vector;
import javax.accessibility.*;
/**
* This class is inserted in between cell renderers and the components that
* use them. It just exists to thwart the repaint() and invalidate() methods
* which would otherwise propagate up the tree when the renderer was configured.
* It's used by the implementations of JTable, JTree, and JList. For example,
* here's how CellRendererPane is used in the code the paints each row
* in a JList:
* <pre>
* cellRendererPane = new CellRendererPane();
* ...
* Component rendererComponent = renderer.getListCellRendererComponent();
* renderer.configureListCellRenderer(dataModel.getElementAt(row), row);
* cellRendererPane.paintComponent(g, rendererComponent, this, x, y, w, h);
* </pre>
* <p>
* A renderer component must override isShowing() and unconditionally return
* true to work correctly because the Swing paint does nothing for components
* with isShowing false.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Hans Muller
*/
public class CellRendererPane extends Container implements Accessible
{
/**
* Construct a CellRendererPane object.
*/
public CellRendererPane() {
super();
setLayout(null);
setVisible(false);
}
/**
* Overridden to avoid propagating a invalidate up the tree when the
* cell renderer child is configured.
*/
public void invalidate() { }
/**
* Shouldn't be called.
*/
public void paint(Graphics g) { }
/**
* Shouldn't be called.
*/
public void update(Graphics g) { }
/**
* If the specified component is already a child of this then we don't
* bother doing anything - stacking order doesn't matter for cell
* renderer components (CellRendererPane doesn't paint anyway).
*/
protected void addImpl(Component x, Object constraints, int index) {
if (x.getParent() == this) {
return;
}
else {
super.addImpl(x, constraints, index);
}
}
/**
* Paint a cell renderer component c on graphics object g. Before the component
* is drawn it's reparented to this (if that's necessary), it's bounds
* are set to w,h and the graphics object is (effectively) translated to x,y.
* If it's a JComponent, double buffering is temporarily turned off. After
* the component is painted it's bounds are reset to -w, -h, 0, 0 so that, if
* it's the last renderer component painted, it will not start consuming input.
* The Container p is the component we're actually drawing on, typically it's
* equal to this.getParent(). If shouldValidate is true the component c will be
* validated before painted.
*/
public void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h, boolean shouldValidate) {
if (c == null) {
if (p != null) {
Color oldColor = g.getColor();
g.setColor(p.getBackground());
g.fillRect(x, y, w, h);
g.setColor(oldColor);
}
return;
}
if (c.getParent() != this) {
this.add(c);
}
c.setBounds(x, y, w, h);
if(shouldValidate) {
c.validate();
}
boolean wasDoubleBuffered = false;
if ((c instanceof JComponent) && ((JComponent)c).isDoubleBuffered()) {
wasDoubleBuffered = true;
((JComponent)c).setDoubleBuffered(false);
}
Graphics cg = g.create(x, y, w, h);
try {
c.paint(cg);
}
finally {
cg.dispose();
}
if (wasDoubleBuffered && (c instanceof JComponent)) {
((JComponent)c).setDoubleBuffered(true);
}
c.setBounds(-w, -h, 0, 0);
}
/**
* Calls this.paintComponent(g, c, p, x, y, w, h, false).
*/
public void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
paintComponent(g, c, p, x, y, w, h, false);
}
/**
* Calls this.paintComponent() with the rectangles x,y,width,height fields.
*/
public void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
paintComponent(g, c, p, r.x, r.y, r.width, r.height);
}
private void writeObject(ObjectOutputStream s) throws IOException {
removeAll();
s.defaultWriteObject();
}
/////////////////
// Accessibility support
////////////////
protected AccessibleContext accessibleContext = null;
/**
* Gets the AccessibleContext associated with this CellRendererPane.
* For CellRendererPanes, the AccessibleContext takes the form of an
* AccessibleCellRendererPane.
* A new AccessibleCellRendererPane instance is created if necessary.
*
* @return an AccessibleCellRendererPane that serves as the
* AccessibleContext of this CellRendererPane
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleCellRendererPane();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>CellRendererPane</code> class.
*/
protected class AccessibleCellRendererPane extends AccessibleAWTContainer {
// AccessibleContext methods
//
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PANEL;
}
} // inner class AccessibleCellRendererPane
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import sun.awt.AWTAccessor;
/**
* An enumeration for keys used as client properties within the Swing
* implementation.
* <p>
* This enum holds only a small subset of the keys currently used within Swing,
* but we may move more of them here in the future.
* <p>
* Adding an item to, and using, this class instead of {@code String} for
* client properties protects against conflicts with developer-set client
* properties. Using this class also avoids a problem with {@code StringBuilder}
* and {@code StringBuffer} keys, whereby the keys are not recognized upon
* deserialization.
* <p>
* When a client property value associated with one of these keys does not
* implement {@code Serializable}, the result during serialization depends
* on how the key is defined here. Historically, client properties with values
* not implementing {@code Serializable} have simply been dropped and left out
* of the serialized representation. To define keys with such behavior in this
* enum, provide a value of {@code false} for the {@code reportValueNotSerializable}
* property. When migrating existing properties to this enum, one may wish to
* consider using this by default, to preserve backward compatibility.
* <p>
* To instead have a {@code NotSerializableException} thrown when a
* {@code non-Serializable} property is encountered, provide the value of
* {@code true} for the {@code reportValueNotSerializable} property. This
* is useful when the property represents something that the developer
* needs to know about when it cannot be serialized.
*
* @author Shannon Hickey
*/
enum ClientPropertyKey {
/**
* Key used by JComponent for storing InputVerifier.
*/
JComponent_INPUT_VERIFIER(true),
/**
* Key used by JComponent for storing TransferHandler.
*/
JComponent_TRANSFER_HANDLER(true),
/**
* Key used by JComponent for storing AncestorNotifier.
*/
JComponent_ANCESTOR_NOTIFIER(true),
/**
* Key used by PopupFactory to force heavy weight popups for a
* component.
*/
PopupFactory_FORCE_HEAVYWEIGHT_POPUP(true);
/**
* Whether or not a {@code NotSerializableException} should be thrown
* during serialization, when the value associated with this key does
* not implement {@code Serializable}.
*/
private final boolean reportValueNotSerializable;
static {
AWTAccessor.setClientPropertyKeyAccessor(
new AWTAccessor.ClientPropertyKeyAccessor() {
public Object getJComponent_TRANSFER_HANDLER() {
return JComponent_TRANSFER_HANDLER;
}
});
}
/**
* Constructs a key with the {@code reportValueNotSerializable} property
* set to {@code false}.
*/
private ClientPropertyKey() {
this(false);
}
/**
* Constructs a key with the {@code reportValueNotSerializable} property
* set to the given value.
*/
private ClientPropertyKey(boolean reportValueNotSerializable) {
this.reportValueNotSerializable = reportValueNotSerializable;
}
/**
* Returns whether or not a {@code NotSerializableException} should be thrown
* during serialization, when the value associated with this key does
* not implement {@code Serializable}.
*/
public boolean getReportValueNotSerializable() {
return reportValueNotSerializable;
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
/**
* The editor component used for JComboBox components.
*
* @author Arnaud Weber
*/
public interface ComboBoxEditor {
/** Return the component that should be added to the tree hierarchy for
* this editor
*/
public Component getEditorComponent();
/** Set the item that should be edited. Cancel any editing if necessary **/
public void setItem(Object anObject);
/** Return the edited item **/
public Object getItem();
/** Ask the editor to start editing and to select everything **/
public void selectAll();
/** Add an ActionListener. An action event is generated when the edited item changes **/
public void addActionListener(ActionListener l);
/** Remove an ActionListener **/
public void removeActionListener(ActionListener l);
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
/**
* A data model for a combo box. This interface extends <code>ListDataModel</code>
* and adds the concept of a <i>selected item</i>. The selected item is generally
* the item which is visible in the combo box display area.
* <p>
* The selected item may not necessarily be managed by the underlying
* <code>ListModel</code>. This disjoint behavior allows for the temporary
* storage and retrieval of a selected item in the model.
*
* @param <E> the type of the elements of this model
*
* @author Arnaud Weber
*/
public interface ComboBoxModel<E> extends ListModel<E> {
/**
* Set the selected item. The implementation of this method should notify
* all registered <code>ListDataListener</code>s that the contents
* have changed.
*
* @param anItem the list object to select or <code>null</code>
* to clear the selection
*/
void setSelectedItem(Object anItem);
/**
* Returns the selected item
* @return The selected item or <code>null</code> if there is no selection
*/
Object getSelectedItem();
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
/**
* A <code>ComponentInputMap</code> is an <code>InputMap</code>
* associated with a particular <code>JComponent</code>.
* The component is automatically notified whenever
* the <code>ComponentInputMap</code> changes.
* <code>ComponentInputMap</code>s are used for
* <code>WHEN_IN_FOCUSED_WINDOW</code> bindings.
*
* @author Scott Violet
* @since 1.3
*/
@SuppressWarnings("serial")
public class ComponentInputMap extends InputMap {
/** Component binding is created for. */
private JComponent component;
/**
* Creates a <code>ComponentInputMap</code> associated with the
* specified component.
*
* @param component a non-null <code>JComponent</code>
* @throws IllegalArgumentException if <code>component</code> is null
*/
public ComponentInputMap(JComponent component) {
this.component = component;
if (component == null) {
throw new IllegalArgumentException("ComponentInputMaps must be associated with a non-null JComponent");
}
}
/**
* Sets the parent, which must be a <code>ComponentInputMap</code>
* associated with the same component as this
* <code>ComponentInputMap</code>.
*
* @param map a <code>ComponentInputMap</code>
*
* @throws IllegalArgumentException if <code>map</code>
* is not a <code>ComponentInputMap</code>
* or is not associated with the same component
*/
public void setParent(InputMap map) {
if (getParent() == map) {
return;
}
if (map != null && (!(map instanceof ComponentInputMap) ||
((ComponentInputMap)map).getComponent() != getComponent())) {
throw new IllegalArgumentException("ComponentInputMaps must have a parent ComponentInputMap associated with the same component");
}
super.setParent(map);
getComponent().componentInputMapChanged(this);
}
/**
* Returns the component the <code>InputMap</code> was created for.
*/
public JComponent getComponent() {
return component;
}
/**
* Adds a binding for <code>keyStroke</code> to <code>actionMapKey</code>.
* If <code>actionMapKey</code> is null, this removes the current binding
* for <code>keyStroke</code>.
*/
public void put(KeyStroke keyStroke, Object actionMapKey) {
super.put(keyStroke, actionMapKey);
if (getComponent() != null) {
getComponent().componentInputMapChanged(this);
}
}
/**
* Removes the binding for <code>key</code> from this object.
*/
public void remove(KeyStroke key) {
super.remove(key);
if (getComponent() != null) {
getComponent().componentInputMapChanged(this);
}
}
/**
* Removes all the mappings from this object.
*/
public void clear() {
int oldSize = size();
super.clear();
if (oldSize > 0 && getComponent() != null) {
getComponent().componentInputMapChanged(this);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.image.*;
/** Color filter for DebugGraphics, used for images only.
*
* @author Dave Karlton
*/
class DebugGraphicsFilter extends RGBImageFilter {
Color color;
DebugGraphicsFilter(Color c) {
canFilterIndexColorModel = true;
color = c;
}
public int filterRGB(int x, int y, int rgb) {
return color.getRGB() | (rgb & 0xFF000000);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.util.*;
/** Class used by DebugGraphics for maintaining information about how
* to render graphics calls.
*
* @author Dave Karlton
*/
class DebugGraphicsInfo {
Color flashColor = Color.red;
int flashTime = 100;
int flashCount = 2;
Hashtable<JComponent, Integer> componentToDebug;
JFrame debugFrame = null;
java.io.PrintStream stream = System.out;
void setDebugOptions(JComponent component, int debug) {
if (debug == 0) {
return;
}
if (componentToDebug == null) {
componentToDebug = new Hashtable<JComponent, Integer>();
}
if (debug > 0) {
componentToDebug.put(component, Integer.valueOf(debug));
} else {
componentToDebug.remove(component);
}
}
int getDebugOptions(JComponent component) {
if (componentToDebug == null) {
return 0;
} else {
Integer integer = componentToDebug.get(component);
return integer == null ? 0 : integer.intValue();
}
}
void log(String string) {
stream.println(string);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.image.*;
/** ImageObserver for DebugGraphics, used for images only.
*
* @author Dave Karlton
*/
class DebugGraphicsObserver implements ImageObserver {
int lastInfo;
synchronized boolean allBitsPresent() {
return (lastInfo & ImageObserver.ALLBITS) != 0;
}
synchronized boolean imageHasProblem() {
return ((lastInfo & ImageObserver.ERROR) != 0 ||
(lastInfo & ImageObserver.ABORT) != 0);
}
public synchronized boolean imageUpdate(Image img, int infoflags,
int x, int y,
int width, int height) {
lastInfo = infoflags;
return true;
}
}

View File

@@ -0,0 +1,423 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.event.*;
import java.io.Serializable;
import java.util.EventListener;
/**
* A generic implementation of BoundedRangeModel.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author David Kloba
* @author Hans Muller
* @see BoundedRangeModel
*/
public class DefaultBoundedRangeModel implements BoundedRangeModel, Serializable
{
/**
* Only one <code>ChangeEvent</code> is needed per model instance since the
* event's only (read-only) state is the source property. The source
* of events generated here is always "this".
*/
protected transient ChangeEvent changeEvent = null;
/** The listeners waiting for model changes. */
protected EventListenerList listenerList = new EventListenerList();
private int value = 0;
private int extent = 0;
private int min = 0;
private int max = 100;
private boolean isAdjusting = false;
/**
* Initializes all of the properties with default values.
* Those values are:
* <ul>
* <li><code>value</code> = 0
* <li><code>extent</code> = 0
* <li><code>minimum</code> = 0
* <li><code>maximum</code> = 100
* <li><code>adjusting</code> = false
* </ul>
*/
public DefaultBoundedRangeModel() {
}
/**
* Initializes value, extent, minimum and maximum. Adjusting is false.
* Throws an <code>IllegalArgumentException</code> if the following
* constraints aren't satisfied:
* <pre>
* min &lt;= value &lt;= value+extent &lt;= max
* </pre>
*/
public DefaultBoundedRangeModel(int value, int extent, int min, int max)
{
if ((max >= min) &&
(value >= min) &&
((value + extent) >= value) &&
((value + extent) <= max)) {
this.value = value;
this.extent = extent;
this.min = min;
this.max = max;
}
else {
throw new IllegalArgumentException("invalid range properties");
}
}
/**
* Returns the model's current value.
* @return the model's current value
* @see #setValue
* @see BoundedRangeModel#getValue
*/
public int getValue() {
return value;
}
/**
* Returns the model's extent.
* @return the model's extent
* @see #setExtent
* @see BoundedRangeModel#getExtent
*/
public int getExtent() {
return extent;
}
/**
* Returns the model's minimum.
* @return the model's minimum
* @see #setMinimum
* @see BoundedRangeModel#getMinimum
*/
public int getMinimum() {
return min;
}
/**
* Returns the model's maximum.
* @return the model's maximum
* @see #setMaximum
* @see BoundedRangeModel#getMaximum
*/
public int getMaximum() {
return max;
}
/**
* Sets the current value of the model. For a slider, that
* determines where the knob appears. Ensures that the new
* value, <I>n</I> falls within the model's constraints:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
*
* @see BoundedRangeModel#setValue
*/
public void setValue(int n) {
n = Math.min(n, Integer.MAX_VALUE - extent);
int newValue = Math.max(n, min);
if (newValue + extent > max) {
newValue = max - extent;
}
setRangeProperties(newValue, extent, min, max, isAdjusting);
}
/**
* Sets the extent to <I>n</I> after ensuring that <I>n</I>
* is greater than or equal to zero and falls within the model's
* constraints:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* @see BoundedRangeModel#setExtent
*/
public void setExtent(int n) {
int newExtent = Math.max(0, n);
if(value + newExtent > max) {
newExtent = max - value;
}
setRangeProperties(value, newExtent, min, max, isAdjusting);
}
/**
* Sets the minimum to <I>n</I> after ensuring that <I>n</I>
* that the other three properties obey the model's constraints:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* @see #getMinimum
* @see BoundedRangeModel#setMinimum
*/
public void setMinimum(int n) {
int newMax = Math.max(n, max);
int newValue = Math.max(n, value);
int newExtent = Math.min(newMax - newValue, extent);
setRangeProperties(newValue, newExtent, n, newMax, isAdjusting);
}
/**
* Sets the maximum to <I>n</I> after ensuring that <I>n</I>
* that the other three properties obey the model's constraints:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* @see BoundedRangeModel#setMaximum
*/
public void setMaximum(int n) {
int newMin = Math.min(n, min);
int newExtent = Math.min(n - newMin, extent);
int newValue = Math.min(n - newExtent, value);
setRangeProperties(newValue, newExtent, newMin, n, isAdjusting);
}
/**
* Sets the <code>valueIsAdjusting</code> property.
*
* @see #getValueIsAdjusting
* @see #setValue
* @see BoundedRangeModel#setValueIsAdjusting
*/
public void setValueIsAdjusting(boolean b) {
setRangeProperties(value, extent, min, max, b);
}
/**
* Returns true if the value is in the process of changing
* as a result of actions being taken by the user.
*
* @return the value of the <code>valueIsAdjusting</code> property
* @see #setValue
* @see BoundedRangeModel#getValueIsAdjusting
*/
public boolean getValueIsAdjusting() {
return isAdjusting;
}
/**
* Sets all of the <code>BoundedRangeModel</code> properties after forcing
* the arguments to obey the usual constraints:
* <pre>
* minimum &lt;= value &lt;= value+extent &lt;= maximum
* </pre>
* <p>
* At most, one <code>ChangeEvent</code> is generated.
*
* @see BoundedRangeModel#setRangeProperties
* @see #setValue
* @see #setExtent
* @see #setMinimum
* @see #setMaximum
* @see #setValueIsAdjusting
*/
public void setRangeProperties(int newValue, int newExtent, int newMin, int newMax, boolean adjusting)
{
if (newMin > newMax) {
newMin = newMax;
}
if (newValue > newMax) {
newMax = newValue;
}
if (newValue < newMin) {
newMin = newValue;
}
/* Convert the addends to long so that extent can be
* Integer.MAX_VALUE without rolling over the sum.
* A JCK test covers this, see bug 4097718.
*/
if (((long)newExtent + (long)newValue) > newMax) {
newExtent = newMax - newValue;
}
if (newExtent < 0) {
newExtent = 0;
}
boolean isChange =
(newValue != value) ||
(newExtent != extent) ||
(newMin != min) ||
(newMax != max) ||
(adjusting != isAdjusting);
if (isChange) {
value = newValue;
extent = newExtent;
min = newMin;
max = newMax;
isAdjusting = adjusting;
fireStateChanged();
}
}
/**
* Adds a <code>ChangeListener</code>. The change listeners are run each
* time any one of the Bounded Range model properties changes.
*
* @param l the ChangeListener to add
* @see #removeChangeListener
* @see BoundedRangeModel#addChangeListener
*/
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
/**
* Removes a <code>ChangeListener</code>.
*
* @param l the <code>ChangeListener</code> to remove
* @see #addChangeListener
* @see BoundedRangeModel#removeChangeListener
*/
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
/**
* Returns an array of all the change listeners
* registered on this <code>DefaultBoundedRangeModel</code>.
*
* @return all of this model's <code>ChangeListener</code>s
* or an empty
* array if no change listeners are currently registered
*
* @see #addChangeListener
* @see #removeChangeListener
*
* @since 1.4
*/
public ChangeListener[] getChangeListeners() {
return listenerList.getListeners(ChangeListener.class);
}
/**
* Runs each <code>ChangeListener</code>'s <code>stateChanged</code> method.
*
* @see #setRangeProperties
* @see EventListenerList
*/
protected void fireStateChanged()
{
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i -=2 ) {
if (listeners[i] == ChangeListener.class) {
if (changeEvent == null) {
changeEvent = new ChangeEvent(this);
}
((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
}
}
}
/**
* Returns a string that displays all of the
* <code>BoundedRangeModel</code> properties.
*/
public String toString() {
String modelString =
"value=" + getValue() + ", " +
"extent=" + getExtent() + ", " +
"min=" + getMinimum() + ", " +
"max=" + getMaximum() + ", " +
"adj=" + getValueIsAdjusting();
return getClass().getName() + "[" + modelString + "]";
}
/**
* Returns an array of all the objects currently registered as
* <code><em>Foo</em>Listener</code>s
* upon this model.
* <code><em>Foo</em>Listener</code>s
* are registered using the <code>add<em>Foo</em>Listener</code> method.
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
* For example, you can query a <code>DefaultBoundedRangeModel</code>
* instance <code>m</code>
* for its change listeners
* with the following code:
*
* <pre>ChangeListener[] cls = (ChangeListener[])(m.getListeners(ChangeListener.class));</pre>
*
* If no such listeners exist,
* this method returns an empty array.
*
* @param listenerType the type of listeners requested;
* this parameter should specify an interface
* that descends from <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s
* on this model,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code> doesn't
* specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getChangeListeners
*
* @since 1.3
*/
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
return listenerList.getListeners(listenerType);
}
}

View File

@@ -0,0 +1,533 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.Serializable;
import java.util.EventListener;
import javax.swing.event.*;
/**
* The default implementation of a <code>Button</code> component's data model.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Jeff Dinkins
*/
public class DefaultButtonModel implements ButtonModel, Serializable {
/** The bitmask used to store the state of the button. */
protected int stateMask = 0;
/** The action command string fired by the button. */
protected String actionCommand = null;
/** The button group that the button belongs to. */
protected ButtonGroup group = null;
/** The button's mnemonic. */
protected int mnemonic = 0;
/**
* Only one <code>ChangeEvent</code> is needed per button model
* instance since the event's only state is the source property.
* The source of events generated is always "this".
*/
protected transient ChangeEvent changeEvent = null;
/** Stores the listeners on this model. */
protected EventListenerList listenerList = new EventListenerList();
// controls the usage of the MenuItem.disabledAreNavigable UIDefaults
// property in the setArmed() method
private boolean menuItem = false;
/**
* Constructs a <code>DefaultButtonModel</code>.
*
*/
public DefaultButtonModel() {
stateMask = 0;
setEnabled(true);
}
/**
* Identifies the "armed" bit in the bitmask, which
* indicates partial commitment towards choosing/triggering
* the button.
*/
public final static int ARMED = 1 << 0;
/**
* Identifies the "selected" bit in the bitmask, which
* indicates that the button has been selected. Only needed for
* certain types of buttons - such as radio button or check box.
*/
public final static int SELECTED = 1 << 1;
/**
* Identifies the "pressed" bit in the bitmask, which
* indicates that the button is pressed.
*/
public final static int PRESSED = 1 << 2;
/**
* Identifies the "enabled" bit in the bitmask, which
* indicates that the button can be selected by
* an input device (such as a mouse pointer).
*/
public final static int ENABLED = 1 << 3;
/**
* Identifies the "rollover" bit in the bitmask, which
* indicates that the mouse is over the button.
*/
public final static int ROLLOVER = 1 << 4;
/**
* {@inheritDoc}
*/
public void setActionCommand(String actionCommand) {
this.actionCommand = actionCommand;
}
/**
* {@inheritDoc}
*/
public String getActionCommand() {
return actionCommand;
}
/**
* {@inheritDoc}
*/
public boolean isArmed() {
return (stateMask & ARMED) != 0;
}
/**
* {@inheritDoc}
*/
public boolean isSelected() {
return (stateMask & SELECTED) != 0;
}
/**
* {@inheritDoc}
*/
public boolean isEnabled() {
return (stateMask & ENABLED) != 0;
}
/**
* {@inheritDoc}
*/
public boolean isPressed() {
return (stateMask & PRESSED) != 0;
}
/**
* {@inheritDoc}
*/
public boolean isRollover() {
return (stateMask & ROLLOVER) != 0;
}
/**
* {@inheritDoc}
*/
public void setArmed(boolean b) {
if(isMenuItem() &&
UIManager.getBoolean("MenuItem.disabledAreNavigable")) {
if ((isArmed() == b)) {
return;
}
} else {
if ((isArmed() == b) || !isEnabled()) {
return;
}
}
if (b) {
stateMask |= ARMED;
} else {
stateMask &= ~ARMED;
}
fireStateChanged();
}
/**
* {@inheritDoc}
*/
public void setEnabled(boolean b) {
if(isEnabled() == b) {
return;
}
if (b) {
stateMask |= ENABLED;
} else {
stateMask &= ~ENABLED;
// unarm and unpress, just in case
stateMask &= ~ARMED;
stateMask &= ~PRESSED;
}
fireStateChanged();
}
/**
* {@inheritDoc}
*/
public void setSelected(boolean b) {
if (this.isSelected() == b) {
return;
}
if (b) {
stateMask |= SELECTED;
} else {
stateMask &= ~SELECTED;
}
fireItemStateChanged(
new ItemEvent(this,
ItemEvent.ITEM_STATE_CHANGED,
this,
b ? ItemEvent.SELECTED : ItemEvent.DESELECTED));
fireStateChanged();
}
/**
* {@inheritDoc}
*/
public void setPressed(boolean b) {
if((isPressed() == b) || !isEnabled()) {
return;
}
if (b) {
stateMask |= PRESSED;
} else {
stateMask &= ~PRESSED;
}
if(!isPressed() && isArmed()) {
int modifiers = 0;
AWTEvent currentEvent = EventQueue.getCurrentEvent();
if (currentEvent instanceof InputEvent) {
modifiers = ((InputEvent)currentEvent).getModifiers();
} else if (currentEvent instanceof ActionEvent) {
modifiers = ((ActionEvent)currentEvent).getModifiers();
}
fireActionPerformed(
new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
getActionCommand(),
EventQueue.getMostRecentEventTime(),
modifiers));
}
fireStateChanged();
}
/**
* {@inheritDoc}
*/
public void setRollover(boolean b) {
if((isRollover() == b) || !isEnabled()) {
return;
}
if (b) {
stateMask |= ROLLOVER;
} else {
stateMask &= ~ROLLOVER;
}
fireStateChanged();
}
/**
* {@inheritDoc}
*/
public void setMnemonic(int key) {
mnemonic = key;
fireStateChanged();
}
/**
* {@inheritDoc}
*/
public int getMnemonic() {
return mnemonic;
}
/**
* {@inheritDoc}
*/
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
/**
* {@inheritDoc}
*/
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
/**
* Returns an array of all the change listeners
* registered on this <code>DefaultButtonModel</code>.
*
* @return all of this model's <code>ChangeListener</code>s
* or an empty
* array if no change listeners are currently registered
*
* @see #addChangeListener
* @see #removeChangeListener
*
* @since 1.4
*/
public ChangeListener[] getChangeListeners() {
return listenerList.getListeners(ChangeListener.class);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. The event instance
* is created lazily.
*
* @see EventListenerList
*/
protected void fireStateChanged() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ChangeListener.class) {
// Lazily create the event:
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
}
}
}
/**
* {@inheritDoc}
*/
public void addActionListener(ActionListener l) {
listenerList.add(ActionListener.class, l);
}
/**
* {@inheritDoc}
*/
public void removeActionListener(ActionListener l) {
listenerList.remove(ActionListener.class, l);
}
/**
* Returns an array of all the action listeners
* registered on this <code>DefaultButtonModel</code>.
*
* @return all of this model's <code>ActionListener</code>s
* or an empty
* array if no action listeners are currently registered
*
* @see #addActionListener
* @see #removeActionListener
*
* @since 1.4
*/
public ActionListener[] getActionListeners() {
return listenerList.getListeners(ActionListener.class);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param e the <code>ActionEvent</code> to deliver to listeners
* @see EventListenerList
*/
protected void fireActionPerformed(ActionEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ActionListener.class) {
// Lazily create the event:
// if (changeEvent == null)
// changeEvent = new ChangeEvent(this);
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
/**
* {@inheritDoc}
*/
public void addItemListener(ItemListener l) {
listenerList.add(ItemListener.class, l);
}
/**
* {@inheritDoc}
*/
public void removeItemListener(ItemListener l) {
listenerList.remove(ItemListener.class, l);
}
/**
* Returns an array of all the item listeners
* registered on this <code>DefaultButtonModel</code>.
*
* @return all of this model's <code>ItemListener</code>s
* or an empty
* array if no item listeners are currently registered
*
* @see #addItemListener
* @see #removeItemListener
*
* @since 1.4
*/
public ItemListener[] getItemListeners() {
return listenerList.getListeners(ItemListener.class);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param e the <code>ItemEvent</code> to deliver to listeners
* @see EventListenerList
*/
protected void fireItemStateChanged(ItemEvent e) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ItemListener.class) {
// Lazily create the event:
// if (changeEvent == null)
// changeEvent = new ChangeEvent(this);
((ItemListener)listeners[i+1]).itemStateChanged(e);
}
}
}
/**
* Returns an array of all the objects currently registered as
* <code><em>Foo</em>Listener</code>s
* upon this model.
* <code><em>Foo</em>Listener</code>s
* are registered using the <code>add<em>Foo</em>Listener</code> method.
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
* For example, you can query a <code>DefaultButtonModel</code>
* instance <code>m</code>
* for its action listeners
* with the following code:
*
* <pre>ActionListener[] als = (ActionListener[])(m.getListeners(ActionListener.class));</pre>
*
* If no such listeners exist,
* this method returns an empty array.
*
* @param listenerType the type of listeners requested;
* this parameter should specify an interface
* that descends from <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s
* on this model,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code> doesn't
* specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getActionListeners
* @see #getChangeListeners
* @see #getItemListeners
*
* @since 1.3
*/
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
return listenerList.getListeners(listenerType);
}
/** Overridden to return <code>null</code>. */
public Object[] getSelectedObjects() {
return null;
}
/**
* {@inheritDoc}
*/
public void setGroup(ButtonGroup group) {
this.group = group;
}
/**
* Returns the group that the button belongs to.
* Normally used with radio buttons, which are mutually
* exclusive within their group.
*
* @return the <code>ButtonGroup</code> that the button belongs to
*
* @since 1.3
*/
public ButtonGroup getGroup() {
return group;
}
boolean isMenuItem() {
return menuItem;
}
void setMenuItem(boolean menuItem) {
this.menuItem = menuItem;
}
}

View File

@@ -0,0 +1,398 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Component;
import java.awt.event.*;
import java.beans.ConstructorProperties;
import java.lang.Boolean;
import javax.swing.table.*;
import javax.swing.event.*;
import java.util.EventObject;
import javax.swing.tree.*;
import java.io.Serializable;
/**
* The default editor for table and tree cells.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Alan Chung
* @author Philip Milne
*/
public class DefaultCellEditor extends AbstractCellEditor
implements TableCellEditor, TreeCellEditor {
//
// Instance Variables
//
/** The Swing component being edited. */
protected JComponent editorComponent;
/**
* The delegate class which handles all methods sent from the
* <code>CellEditor</code>.
*/
protected EditorDelegate delegate;
/**
* An integer specifying the number of clicks needed to start editing.
* Even if <code>clickCountToStart</code> is defined as zero, it
* will not initiate until a click occurs.
*/
protected int clickCountToStart = 1;
//
// Constructors
//
/**
* Constructs a <code>DefaultCellEditor</code> that uses a text field.
*
* @param textField a <code>JTextField</code> object
*/
@ConstructorProperties({"component"})
public DefaultCellEditor(final JTextField textField) {
editorComponent = textField;
this.clickCountToStart = 2;
delegate = new EditorDelegate() {
public void setValue(Object value) {
textField.setText((value != null) ? value.toString() : "");
}
public Object getCellEditorValue() {
return textField.getText();
}
};
textField.addActionListener(delegate);
}
/**
* Constructs a <code>DefaultCellEditor</code> object that uses a check box.
*
* @param checkBox a <code>JCheckBox</code> object
*/
public DefaultCellEditor(final JCheckBox checkBox) {
editorComponent = checkBox;
delegate = new EditorDelegate() {
public void setValue(Object value) {
boolean selected = false;
if (value instanceof Boolean) {
selected = ((Boolean)value).booleanValue();
}
else if (value instanceof String) {
selected = value.equals("true");
}
checkBox.setSelected(selected);
}
public Object getCellEditorValue() {
return Boolean.valueOf(checkBox.isSelected());
}
};
checkBox.addActionListener(delegate);
checkBox.setRequestFocusEnabled(false);
}
/**
* Constructs a <code>DefaultCellEditor</code> object that uses a
* combo box.
*
* @param comboBox a <code>JComboBox</code> object
*/
public DefaultCellEditor(final JComboBox comboBox) {
editorComponent = comboBox;
comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
delegate = new EditorDelegate() {
public void setValue(Object value) {
comboBox.setSelectedItem(value);
}
public Object getCellEditorValue() {
return comboBox.getSelectedItem();
}
public boolean shouldSelectCell(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
MouseEvent e = (MouseEvent)anEvent;
return e.getID() != MouseEvent.MOUSE_DRAGGED;
}
return true;
}
public boolean stopCellEditing() {
if (comboBox.isEditable()) {
// Commit edited value.
comboBox.actionPerformed(new ActionEvent(
DefaultCellEditor.this, 0, ""));
}
return super.stopCellEditing();
}
};
comboBox.addActionListener(delegate);
}
/**
* Returns a reference to the editor component.
*
* @return the editor <code>Component</code>
*/
public Component getComponent() {
return editorComponent;
}
//
// Modifying
//
/**
* Specifies the number of clicks needed to start editing.
*
* @param count an int specifying the number of clicks needed to start editing
* @see #getClickCountToStart
*/
public void setClickCountToStart(int count) {
clickCountToStart = count;
}
/**
* Returns the number of clicks needed to start editing.
* @return the number of clicks needed to start editing
*/
public int getClickCountToStart() {
return clickCountToStart;
}
//
// Override the implementations of the superclass, forwarding all methods
// from the CellEditor interface to our delegate.
//
/**
* Forwards the message from the <code>CellEditor</code> to
* the <code>delegate</code>.
* @see EditorDelegate#getCellEditorValue
*/
public Object getCellEditorValue() {
return delegate.getCellEditorValue();
}
/**
* Forwards the message from the <code>CellEditor</code> to
* the <code>delegate</code>.
* @see EditorDelegate#isCellEditable(EventObject)
*/
public boolean isCellEditable(EventObject anEvent) {
return delegate.isCellEditable(anEvent);
}
/**
* Forwards the message from the <code>CellEditor</code> to
* the <code>delegate</code>.
* @see EditorDelegate#shouldSelectCell(EventObject)
*/
public boolean shouldSelectCell(EventObject anEvent) {
return delegate.shouldSelectCell(anEvent);
}
/**
* Forwards the message from the <code>CellEditor</code> to
* the <code>delegate</code>.
* @see EditorDelegate#stopCellEditing
*/
public boolean stopCellEditing() {
return delegate.stopCellEditing();
}
/**
* Forwards the message from the <code>CellEditor</code> to
* the <code>delegate</code>.
* @see EditorDelegate#cancelCellEditing
*/
public void cancelCellEditing() {
delegate.cancelCellEditing();
}
//
// Implementing the TreeCellEditor Interface
//
/** Implements the <code>TreeCellEditor</code> interface. */
public Component getTreeCellEditorComponent(JTree tree, Object value,
boolean isSelected,
boolean expanded,
boolean leaf, int row) {
String stringValue = tree.convertValueToText(value, isSelected,
expanded, leaf, row, false);
delegate.setValue(stringValue);
return editorComponent;
}
//
// Implementing the CellEditor Interface
//
/** Implements the <code>TableCellEditor</code> interface. */
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected,
int row, int column) {
delegate.setValue(value);
if (editorComponent instanceof JCheckBox) {
//in order to avoid a "flashing" effect when clicking a checkbox
//in a table, it is important for the editor to have as a border
//the same border that the renderer has, and have as the background
//the same color as the renderer has. This is primarily only
//needed for JCheckBox since this editor doesn't fill all the
//visual space of the table cell, unlike a text field.
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component c = renderer.getTableCellRendererComponent(table, value,
isSelected, true, row, column);
if (c != null) {
editorComponent.setOpaque(true);
editorComponent.setBackground(c.getBackground());
if (c instanceof JComponent) {
editorComponent.setBorder(((JComponent)c).getBorder());
}
} else {
editorComponent.setOpaque(false);
}
}
return editorComponent;
}
//
// Protected EditorDelegate class
//
/**
* The protected <code>EditorDelegate</code> class.
*/
protected class EditorDelegate implements ActionListener, ItemListener, Serializable {
/** The value of this cell. */
protected Object value;
/**
* Returns the value of this cell.
* @return the value of this cell
*/
public Object getCellEditorValue() {
return value;
}
/**
* Sets the value of this cell.
* @param value the new value of this cell
*/
public void setValue(Object value) {
this.value = value;
}
/**
* Returns true if <code>anEvent</code> is <b>not</b> a
* <code>MouseEvent</code>. Otherwise, it returns true
* if the necessary number of clicks have occurred, and
* returns false otherwise.
*
* @param anEvent the event
* @return true if cell is ready for editing, false otherwise
* @see #setClickCountToStart
* @see #shouldSelectCell
*/
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
/**
* Returns true to indicate that the editing cell may
* be selected.
*
* @param anEvent the event
* @return true
* @see #isCellEditable
*/
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
/**
* Returns true to indicate that editing has begun.
*
* @param anEvent the event
*/
public boolean startCellEditing(EventObject anEvent) {
return true;
}
/**
* Stops editing and
* returns true to indicate that editing has stopped.
* This method calls <code>fireEditingStopped</code>.
*
* @return true
*/
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
/**
* Cancels editing. This method calls <code>fireEditingCanceled</code>.
*/
public void cancelCellEditing() {
fireEditingCanceled();
}
/**
* When an action is performed, editing is ended.
* @param e the action event
* @see #stopCellEditing
*/
public void actionPerformed(ActionEvent e) {
DefaultCellEditor.this.stopCellEditing();
}
/**
* When an item's state changes, editing is ended.
* @param e the action event
* @see #stopCellEditing
*/
public void itemStateChanged(ItemEvent e) {
DefaultCellEditor.this.stopCellEditing();
}
}
} // End of class JCellEditor

View File

@@ -0,0 +1,179 @@
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.*;
import java.io.Serializable;
/**
* The default model for combo boxes.
*
* @param <E> the type of the elements of this model
*
* @author Arnaud Weber
* @author Tom Santos
*/
public class DefaultComboBoxModel<E> extends AbstractListModel<E> implements MutableComboBoxModel<E>, Serializable {
Vector<E> objects;
Object selectedObject;
/**
* Constructs an empty DefaultComboBoxModel object.
*/
public DefaultComboBoxModel() {
objects = new Vector<E>();
}
/**
* Constructs a DefaultComboBoxModel object initialized with
* an array of objects.
*
* @param items an array of Object objects
*/
public DefaultComboBoxModel(final E items[]) {
objects = new Vector<E>(items.length);
int i,c;
for ( i=0,c=items.length;i<c;i++ )
objects.addElement(items[i]);
if ( getSize() > 0 ) {
selectedObject = getElementAt( 0 );
}
}
/**
* Constructs a DefaultComboBoxModel object initialized with
* a vector.
*
* @param v a Vector object ...
*/
public DefaultComboBoxModel(Vector<E> v) {
objects = v;
if ( getSize() > 0 ) {
selectedObject = getElementAt( 0 );
}
}
// implements javax.swing.ComboBoxModel
/**
* Set the value of the selected item. The selected item may be null.
*
* @param anObject The combo box value or null for no selection.
*/
public void setSelectedItem(Object anObject) {
if ((selectedObject != null && !selectedObject.equals( anObject )) ||
selectedObject == null && anObject != null) {
selectedObject = anObject;
fireContentsChanged(this, -1, -1);
}
}
// implements javax.swing.ComboBoxModel
public Object getSelectedItem() {
return selectedObject;
}
// implements javax.swing.ListModel
public int getSize() {
return objects.size();
}
// implements javax.swing.ListModel
public E getElementAt(int index) {
if ( index >= 0 && index < objects.size() )
return objects.elementAt(index);
else
return null;
}
/**
* Returns the index-position of the specified object in the list.
*
* @param anObject
* @return an int representing the index position, where 0 is
* the first position
*/
public int getIndexOf(Object anObject) {
return objects.indexOf(anObject);
}
// implements javax.swing.MutableComboBoxModel
public void addElement(E anObject) {
objects.addElement(anObject);
fireIntervalAdded(this,objects.size()-1, objects.size()-1);
if ( objects.size() == 1 && selectedObject == null && anObject != null ) {
setSelectedItem( anObject );
}
}
// implements javax.swing.MutableComboBoxModel
public void insertElementAt(E anObject,int index) {
objects.insertElementAt(anObject,index);
fireIntervalAdded(this, index, index);
}
// implements javax.swing.MutableComboBoxModel
public void removeElementAt(int index) {
if ( getElementAt( index ) == selectedObject ) {
if ( index == 0 ) {
setSelectedItem( getSize() == 1 ? null : getElementAt( index + 1 ) );
}
else {
setSelectedItem( getElementAt( index - 1 ) );
}
}
objects.removeElementAt(index);
fireIntervalRemoved(this, index, index);
}
// implements javax.swing.MutableComboBoxModel
public void removeElement(Object anObject) {
int index = objects.indexOf(anObject);
if ( index != -1 ) {
removeElementAt(index);
}
}
/**
* Empties the list.
*/
public void removeAllElements() {
if ( objects.size() > 0 ) {
int firstIndex = 0;
int lastIndex = objects.size() - 1;
objects.removeAllElements();
selectedObject = null;
fireIntervalRemoved(this, firstIndex, lastIndex);
} else {
selectedObject = null;
}
}
}

View File

@@ -0,0 +1,815 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import com.sun.awt.AWTUtilities;
import sun.awt.AWTAccessor;
import sun.awt.SunToolkit;
import java.awt.*;
import java.beans.PropertyVetoException;
/** This is an implementation of the <code>DesktopManager</code>.
* It currently implements the basic behaviors for managing
* <code>JInternalFrame</code>s in an arbitrary parent.
* <code>JInternalFrame</code>s that are not children of a
* <code>JDesktop</code> will use this component
* to handle their desktop-like actions.
* <p>This class provides a policy for the various JInternalFrame methods,
* it is not meant to be called directly rather the various JInternalFrame
* methods will call into the DesktopManager.</p>
* @see JDesktopPane
* @see JInternalFrame
* @author David Kloba
* @author Steve Wilson
*/
public class DefaultDesktopManager implements DesktopManager, java.io.Serializable {
final static String HAS_BEEN_ICONIFIED_PROPERTY = "wasIconOnce";
final static int DEFAULT_DRAG_MODE = 0;
final static int OUTLINE_DRAG_MODE = 1;
final static int FASTER_DRAG_MODE = 2;
int dragMode = DEFAULT_DRAG_MODE;
private transient Rectangle currentBounds = null;
private transient Graphics desktopGraphics = null;
private transient Rectangle desktopBounds = null;
private transient Rectangle[] floatingItems = {};
/**
* Set to true when the user actually drags a frame vs clicks on it
* to start the drag operation. This is only used when dragging with
* FASTER_DRAG_MODE.
*/
private transient boolean didDrag;
/** Normally this method will not be called. If it is, it
* try to determine the appropriate parent from the desktopIcon of the frame.
* Will remove the desktopIcon from its parent if it successfully adds the frame.
*/
public void openFrame(JInternalFrame f) {
if(f.getDesktopIcon().getParent() != null) {
f.getDesktopIcon().getParent().add(f);
removeIconFor(f);
}
}
/**
* Removes the frame, and, if necessary, the
* <code>desktopIcon</code>, from its parent.
* @param f the <code>JInternalFrame</code> to be removed
*/
public void closeFrame(JInternalFrame f) {
JDesktopPane d = f.getDesktopPane();
if (d == null) {
return;
}
boolean findNext = f.isSelected();
Container c = f.getParent();
JInternalFrame nextFrame = null;
if (findNext) {
nextFrame = d.getNextFrame(f);
try { f.setSelected(false); } catch (PropertyVetoException e2) { }
}
if(c != null) {
c.remove(f); // Removes the focus.
c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
}
removeIconFor(f);
if(f.getNormalBounds() != null)
f.setNormalBounds(null);
if(wasIcon(f))
setWasIcon(f, null);
if (nextFrame != null) {
try { nextFrame.setSelected(true); }
catch (PropertyVetoException e2) { }
} else if (findNext && d.getComponentCount() == 0) {
// It was selected and was the last component on the desktop.
d.requestFocus();
}
}
/**
* Resizes the frame to fill its parents bounds.
* @param f the frame to be resized
*/
public void maximizeFrame(JInternalFrame f) {
if (f.isIcon()) {
try {
// In turn calls deiconifyFrame in the desktop manager.
// That method will handle the maximization of the frame.
f.setIcon(false);
} catch (PropertyVetoException e2) {
}
} else {
f.setNormalBounds(f.getBounds());
Rectangle desktopBounds = f.getParent().getBounds();
setBoundsForFrame(f, 0, 0,
desktopBounds.width, desktopBounds.height);
}
// Set the maximized frame as selected.
try {
f.setSelected(true);
} catch (PropertyVetoException e2) {
}
}
/**
* Restores the frame back to its size and position prior
* to a <code>maximizeFrame</code> call.
* @param f the <code>JInternalFrame</code> to be restored
*/
public void minimizeFrame(JInternalFrame f) {
// If the frame was an icon restore it back to an icon.
if (f.isIcon()) {
iconifyFrame(f);
return;
}
if ((f.getNormalBounds()) != null) {
Rectangle r = f.getNormalBounds();
f.setNormalBounds(null);
try { f.setSelected(true); } catch (PropertyVetoException e2) { }
setBoundsForFrame(f, r.x, r.y, r.width, r.height);
}
}
/**
* Removes the frame from its parent and adds its
* <code>desktopIcon</code> to the parent.
* @param f the <code>JInternalFrame</code> to be iconified
*/
public void iconifyFrame(JInternalFrame f) {
JInternalFrame.JDesktopIcon desktopIcon;
Container c = f.getParent();
JDesktopPane d = f.getDesktopPane();
boolean findNext = f.isSelected();
desktopIcon = f.getDesktopIcon();
if(!wasIcon(f)) {
Rectangle r = getBoundsForIconOf(f);
desktopIcon.setBounds(r.x, r.y, r.width, r.height);
// we must validate the hierarchy to not break the hw/lw mixing
desktopIcon.revalidate();
setWasIcon(f, Boolean.TRUE);
}
if (c == null || d == null) {
return;
}
if (c instanceof JLayeredPane) {
JLayeredPane lp = (JLayeredPane)c;
int layer = lp.getLayer(f);
lp.putLayer(desktopIcon, layer);
}
// If we are maximized we already have the normal bounds recorded
// don't try to re-record them, otherwise we incorrectly set the
// normal bounds to maximized state.
if (!f.isMaximum()) {
f.setNormalBounds(f.getBounds());
}
d.setComponentOrderCheckingEnabled(false);
c.remove(f);
c.add(desktopIcon);
d.setComponentOrderCheckingEnabled(true);
c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
if (findNext) {
if (d.selectFrame(true) == null) {
// The icon is the last frame.
f.restoreSubcomponentFocus();
}
}
}
/**
* Removes the desktopIcon from its parent and adds its frame
* to the parent.
* @param f the <code>JInternalFrame</code> to be de-iconified
*/
public void deiconifyFrame(JInternalFrame f) {
JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon();
Container c = desktopIcon.getParent();
JDesktopPane d = f.getDesktopPane();
if (c != null && d != null) {
c.add(f);
// If the frame is to be restored to a maximized state make
// sure it still fills the whole desktop.
if (f.isMaximum()) {
Rectangle desktopBounds = c.getBounds();
if (f.getWidth() != desktopBounds.width ||
f.getHeight() != desktopBounds.height) {
setBoundsForFrame(f, 0, 0,
desktopBounds.width, desktopBounds.height);
}
}
removeIconFor(f);
if (f.isSelected()) {
f.moveToFront();
f.restoreSubcomponentFocus();
}
else {
try {
f.setSelected(true);
} catch (PropertyVetoException e2) {}
}
}
}
/** This will activate <b>f</b> moving it to the front. It will
* set the current active frame's (if any)
* <code>IS_SELECTED_PROPERTY</code> to <code>false</code>.
* There can be only one active frame across all Layers.
* @param f the <code>JInternalFrame</code> to be activated
*/
public void activateFrame(JInternalFrame f) {
Container p = f.getParent();
Component[] c;
JDesktopPane d = f.getDesktopPane();
JInternalFrame currentlyActiveFrame =
(d == null) ? null : d.getSelectedFrame();
// fix for bug: 4162443
if(p == null) {
// If the frame is not in parent, its icon maybe, check it
p = f.getDesktopIcon().getParent();
if(p == null)
return;
}
// we only need to keep track of the currentActive InternalFrame, if any
if (currentlyActiveFrame == null){
if (d != null) { d.setSelectedFrame(f);}
} else if (currentlyActiveFrame != f) {
// if not the same frame as the current active
// we deactivate the current
if (currentlyActiveFrame.isSelected()) {
try {
currentlyActiveFrame.setSelected(false);
}
catch(PropertyVetoException e2) {}
}
if (d != null) { d.setSelectedFrame(f);}
}
f.moveToFront();
}
// implements javax.swing.DesktopManager
public void deactivateFrame(JInternalFrame f) {
JDesktopPane d = f.getDesktopPane();
JInternalFrame currentlyActiveFrame =
(d == null) ? null : d.getSelectedFrame();
if (currentlyActiveFrame == f)
d.setSelectedFrame(null);
}
// implements javax.swing.DesktopManager
public void beginDraggingFrame(JComponent f) {
setupDragMode(f);
if (dragMode == FASTER_DRAG_MODE) {
Component desktop = f.getParent();
floatingItems = findFloatingItems(f);
currentBounds = f.getBounds();
if (desktop instanceof JComponent) {
desktopBounds = ((JComponent)desktop).getVisibleRect();
}
else {
desktopBounds = desktop.getBounds();
desktopBounds.x = desktopBounds.y = 0;
}
desktopGraphics = JComponent.safelyGetGraphics(desktop);
((JInternalFrame)f).isDragging = true;
didDrag = false;
}
}
private void setupDragMode(JComponent f) {
JDesktopPane p = getDesktopPane(f);
Container parent = f.getParent();
dragMode = DEFAULT_DRAG_MODE;
if (p != null) {
String mode = (String)p.getClientProperty("JDesktopPane.dragMode");
Window window = SwingUtilities.getWindowAncestor(f);
if (window != null && !AWTUtilities.isWindowOpaque(window)) {
dragMode = DEFAULT_DRAG_MODE;
} else if (mode != null && mode.equals("outline")) {
dragMode = OUTLINE_DRAG_MODE;
} else if (mode != null && mode.equals("faster")
&& f instanceof JInternalFrame
&& ((JInternalFrame)f).isOpaque() &&
(parent == null || parent.isOpaque())) {
dragMode = FASTER_DRAG_MODE;
} else {
if (p.getDragMode() == JDesktopPane.OUTLINE_DRAG_MODE ) {
dragMode = OUTLINE_DRAG_MODE;
} else if ( p.getDragMode() == JDesktopPane.LIVE_DRAG_MODE
&& f instanceof JInternalFrame
&& ((JInternalFrame)f).isOpaque()) {
dragMode = FASTER_DRAG_MODE;
} else {
dragMode = DEFAULT_DRAG_MODE;
}
}
}
}
private transient Point currentLoc = null;
/**
* Moves the visible location of the frame being dragged
* to the location specified. The means by which this occurs can vary depending
* on the dragging algorithm being used. The actual logical location of the frame
* might not change until <code>endDraggingFrame</code> is called.
*/
public void dragFrame(JComponent f, int newX, int newY) {
if (dragMode == OUTLINE_DRAG_MODE) {
JDesktopPane desktopPane = getDesktopPane(f);
if (desktopPane != null){
Graphics g = JComponent.safelyGetGraphics(desktopPane);
g.setXORMode(Color.white);
if (currentLoc != null) {
g.drawRect(currentLoc.x, currentLoc.y,
f.getWidth()-1, f.getHeight()-1);
}
g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1);
/* Work around for 6635462: XOR mode may cause a SurfaceLost on first use.
* Swing doesn't expect that its XOR drawRect did
* not complete, so believes that on re-entering at
* the next update location, that there is an XOR rect
* to draw out at "currentLoc". But in fact
* its now got a new clean surface without that rect,
* so drawing it "out" in fact draws it on, leaving garbage.
* So only update/set currentLoc if the draw completed.
*/
sun.java2d.SurfaceData sData =
((sun.java2d.SunGraphics2D)g).getSurfaceData();
if (!sData.isSurfaceLost()) {
currentLoc = new Point (newX, newY);
}
;
g.dispose();
}
} else if (dragMode == FASTER_DRAG_MODE) {
dragFrameFaster(f, newX, newY);
} else {
setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
}
}
// implements javax.swing.DesktopManager
public void endDraggingFrame(JComponent f) {
if ( dragMode == OUTLINE_DRAG_MODE && currentLoc != null) {
setBoundsForFrame(f, currentLoc.x, currentLoc.y, f.getWidth(), f.getHeight() );
currentLoc = null;
} else if (dragMode == FASTER_DRAG_MODE) {
currentBounds = null;
if (desktopGraphics != null) {
desktopGraphics.dispose();
desktopGraphics = null;
}
desktopBounds = null;
((JInternalFrame)f).isDragging = false;
}
}
// implements javax.swing.DesktopManager
public void beginResizingFrame(JComponent f, int direction) {
setupDragMode(f);
}
/**
* Calls <code>setBoundsForFrame</code> with the new values.
* @param f the component to be resized
* @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 f, int newX, int newY, int newWidth, int newHeight) {
if ( dragMode == DEFAULT_DRAG_MODE || dragMode == FASTER_DRAG_MODE ) {
setBoundsForFrame(f, newX, newY, newWidth, newHeight);
} else {
JDesktopPane desktopPane = getDesktopPane(f);
if (desktopPane != null){
Graphics g = JComponent.safelyGetGraphics(desktopPane);
g.setXORMode(Color.white);
if (currentBounds != null) {
g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1);
}
g.drawRect( newX, newY, newWidth-1, newHeight-1);
// Work around for 6635462, see comment in dragFrame()
sun.java2d.SurfaceData sData =
((sun.java2d.SunGraphics2D)g).getSurfaceData();
if (!sData.isSurfaceLost()) {
currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
}
g.setPaintMode();
g.dispose();
}
}
}
// implements javax.swing.DesktopManager
public void endResizingFrame(JComponent f) {
if ( dragMode == OUTLINE_DRAG_MODE && currentBounds != null) {
setBoundsForFrame(f, currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height );
currentBounds = null;
}
}
/** This moves the <code>JComponent</code> and repaints the damaged areas. */
public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
f.setBounds(newX, newY, newWidth, newHeight);
// we must validate the hierarchy to not break the hw/lw mixing
f.revalidate();
}
/** Convenience method to remove the desktopIcon of <b>f</b> is necessary. */
protected void removeIconFor(JInternalFrame f) {
JInternalFrame.JDesktopIcon di = f.getDesktopIcon();
Container c = di.getParent();
if(c != null) {
c.remove(di);
c.repaint(di.getX(), di.getY(), di.getWidth(), di.getHeight());
}
}
/** The iconifyFrame() code calls this to determine the proper bounds
* for the desktopIcon.
*/
protected Rectangle getBoundsForIconOf(JInternalFrame f) {
//
// Get the icon for this internal frame and its preferred size
//
JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();
Dimension prefSize = icon.getPreferredSize();
//
// Get the parent bounds and child components.
//
Container c = f.getParent();
if (c == null) {
c = f.getDesktopIcon().getParent();
}
if (c == null) {
/* the frame has not yet been added to the parent; how about (0,0) ?*/
return new Rectangle(0, 0, prefSize.width, prefSize.height);
}
Rectangle parentBounds = c.getBounds();
Component [] components = c.getComponents();
//
// Iterate through valid default icon locations and return the
// first one that does not intersect any other icons.
//
Rectangle availableRectangle = null;
JInternalFrame.JDesktopIcon currentIcon = null;
int x = 0;
int y = parentBounds.height - prefSize.height;
int w = prefSize.width;
int h = prefSize.height;
boolean found = false;
while (!found) {
availableRectangle = new Rectangle(x,y,w,h);
found = true;
for ( int i=0; i<components.length; i++ ) {
//
// Get the icon for this component
//
if ( components[i] instanceof JInternalFrame ) {
currentIcon = ((JInternalFrame)components[i]).getDesktopIcon();
}
else if ( components[i] instanceof JInternalFrame.JDesktopIcon ){
currentIcon = (JInternalFrame.JDesktopIcon)components[i];
} else
/* found a child that's neither an internal frame nor
an icon. I don't believe this should happen, but at
present it does and causes a null pointer exception.
Even when that gets fixed, this code protects against
the npe. hania */
continue;
//
// If this icon intersects the current location, get next location.
//
if ( !currentIcon.equals(icon) ) {
if ( availableRectangle.intersects(currentIcon.getBounds()) ) {
found = false;
break;
}
}
}
if (currentIcon == null)
/* didn't find any useful children above. This probably shouldn't
happen, but this check protects against an npe if it ever does
(and it's happening now) */
return availableRectangle;
x += currentIcon.getBounds().width;
if ( x + w > parentBounds.width ) {
x = 0;
y -= h;
}
}
return(availableRectangle);
}
/**
* Stores the bounds of the component just before a maximize call.
* @param f the component about to be resized
* @param r the normal bounds to be saved away
*/
protected void setPreviousBounds(JInternalFrame f, Rectangle r) {
f.setNormalBounds(r);
}
/**
* Gets the normal bounds of the component prior to the component
* being maximized.
* @param f the <code>JInternalFrame</code> of interest
* @return the normal bounds of the component
*/
protected Rectangle getPreviousBounds(JInternalFrame f) {
return f.getNormalBounds();
}
/**
* Sets that the component has been iconized and the bounds of the
* <code>desktopIcon</code> are valid.
*/
protected void setWasIcon(JInternalFrame f, Boolean value) {
if (value != null) {
f.putClientProperty(HAS_BEEN_ICONIFIED_PROPERTY, value);
}
}
/**
* Returns <code>true</code> if the component has been iconized
* and the bounds of the <code>desktopIcon</code> are valid,
* otherwise returns <code>false</code>.
*
* @param f the <code>JInternalFrame</code> of interest
* @return <code>true</code> if the component has been iconized;
* otherwise returns <code>false</code>
*/
protected boolean wasIcon(JInternalFrame f) {
return (f.getClientProperty(HAS_BEEN_ICONIFIED_PROPERTY) == Boolean.TRUE);
}
JDesktopPane getDesktopPane( JComponent frame ) {
JDesktopPane pane = null;
Component c = frame.getParent();
// Find the JDesktopPane
while ( pane == null ) {
if ( c instanceof JDesktopPane ) {
pane = (JDesktopPane)c;
}
else if ( c == null ) {
break;
}
else {
c = c.getParent();
}
}
return pane;
}
// =========== stuff for faster frame dragging ===================
private void dragFrameFaster(JComponent f, int newX, int newY) {
Rectangle previousBounds = new Rectangle(currentBounds.x,
currentBounds.y,
currentBounds.width,
currentBounds.height);
// move the frame
currentBounds.x = newX;
currentBounds.y = newY;
if (didDrag) {
// Only initiate cleanup if we have actually done a drag.
emergencyCleanup(f);
}
else {
didDrag = true;
// We reset the danger field as until now we haven't actually
// moved the internal frame so we don't need to initiate repaint.
((JInternalFrame)f).danger = false;
}
boolean floaterCollision = isFloaterCollision(previousBounds, currentBounds);
JComponent parent = (JComponent)f.getParent();
Rectangle visBounds = previousBounds.intersection(desktopBounds);
RepaintManager currentManager = RepaintManager.currentManager(f);
currentManager.beginPaint();
try {
if(!floaterCollision) {
currentManager.copyArea(parent, desktopGraphics, visBounds.x,
visBounds.y,
visBounds.width,
visBounds.height,
newX - previousBounds.x,
newY - previousBounds.y,
true);
}
f.setBounds(currentBounds);
if (!floaterCollision) {
Rectangle r = currentBounds;
currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);
}
if(floaterCollision) {
// since we couldn't blit we just redraw as fast as possible
// the isDragging mucking is to avoid activating emergency
// cleanup
((JInternalFrame)f).isDragging = false;
parent.paintImmediately(currentBounds);
((JInternalFrame)f).isDragging = true;
}
// fake out the repaint manager. We'll take care of everything
currentManager.markCompletelyClean(parent);
currentManager.markCompletelyClean(f);
// compute the minimal newly exposed area
// if the rects intersect then we use computeDifference. Otherwise
// we'll repaint the entire previous bounds
Rectangle[] dirtyRects = null;
if ( previousBounds.intersects(currentBounds) ) {
dirtyRects = SwingUtilities.computeDifference(previousBounds,
currentBounds);
} else {
dirtyRects = new Rectangle[1];
dirtyRects[0] = previousBounds;
};
// Fix the damage
for (int i = 0; i < dirtyRects.length; i++) {
parent.paintImmediately(dirtyRects[i]);
Rectangle r = dirtyRects[i];
currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);
}
// new areas of blit were exposed
if ( !(visBounds.equals(previousBounds)) ) {
dirtyRects = SwingUtilities.computeDifference(previousBounds,
desktopBounds);
for (int i = 0; i < dirtyRects.length; i++) {
dirtyRects[i].x += newX - previousBounds.x;
dirtyRects[i].y += newY - previousBounds.y;
((JInternalFrame)f).isDragging = false;
parent.paintImmediately(dirtyRects[i]);
((JInternalFrame)f).isDragging = true;
Rectangle r = dirtyRects[i];
currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);
}
}
} finally {
currentManager.endPaint();
}
// update window if it's non-opaque
Window topLevel = SwingUtilities.getWindowAncestor(f);
Toolkit tk = Toolkit.getDefaultToolkit();
if (!topLevel.isOpaque() &&
(tk instanceof SunToolkit) &&
((SunToolkit)tk).needUpdateWindow())
{
AWTAccessor.getWindowAccessor().updateWindow(topLevel);
}
}
private boolean isFloaterCollision(Rectangle moveFrom, Rectangle moveTo) {
if (floatingItems.length == 0) {
// System.out.println("no floaters");
return false;
}
for (int i = 0; i < floatingItems.length; i++) {
boolean intersectsFrom = moveFrom.intersects(floatingItems[i]);
if (intersectsFrom) {
return true;
}
boolean intersectsTo = moveTo.intersects(floatingItems[i]);
if (intersectsTo) {
return true;
}
}
return false;
}
private Rectangle[] findFloatingItems(JComponent f) {
Container desktop = f.getParent();
Component[] children = desktop.getComponents();
int i = 0;
for (i = 0; i < children.length; i++) {
if (children[i] == f) {
break;
}
}
// System.out.println(i);
Rectangle[] floaters = new Rectangle[i];
for (i = 0; i < floaters.length; i++) {
floaters[i] = children[i].getBounds();
}
return floaters;
}
/**
* This method is here to clean up problems associated
* with a race condition which can occur when the full contents
* of a copyArea's source argument is not available onscreen.
* This uses brute force to clean up in case of possible damage
*/
private void emergencyCleanup(final JComponent f) {
if ( ((JInternalFrame)f).danger ) {
SwingUtilities.invokeLater( new Runnable(){
public void run(){
((JInternalFrame)f).isDragging = false;
f.paintImmediately(0,0,
f.getWidth(),
f.getHeight());
//finalFrame.repaint();
((JInternalFrame)f).isDragging = true;
// System.out.println("repair complete");
}});
((JInternalFrame)f).danger = false;
}
}
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.util.Comparator;
/**
* This class has been obsoleted by the 1.4 focus APIs. While client code may
* still use this class, developers are strongly encouraged to use
* <code>java.awt.KeyboardFocusManager</code> and
* <code>java.awt.DefaultKeyboardFocusManager</code> instead.
* <p>
* Please see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
* How to Use the Focus Subsystem</a>,
* a section in <em>The Java Tutorial</em>, and the
* <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
* for more information.
*
* @author Arnaud Weber
* @author David Mendenhall
*/
public class DefaultFocusManager extends FocusManager {
final FocusTraversalPolicy gluePolicy =
new LegacyGlueFocusTraversalPolicy(this);
private final FocusTraversalPolicy layoutPolicy =
new LegacyLayoutFocusTraversalPolicy(this);
private final LayoutComparator comparator =
new LayoutComparator();
public DefaultFocusManager() {
setDefaultFocusTraversalPolicy(gluePolicy);
}
public Component getComponentAfter(Container aContainer,
Component aComponent)
{
Container root = (aContainer.isFocusCycleRoot())
? aContainer
: aContainer.getFocusCycleRootAncestor();
// Support for mixed 1.4/pre-1.4 focus APIs. If a particular root's
// traversal policy is non-legacy, then honor it.
if (root != null) {
FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
if (policy != gluePolicy) {
return policy.getComponentAfter(root, aComponent);
}
comparator.setComponentOrientation(root.getComponentOrientation());
return layoutPolicy.getComponentAfter(root, aComponent);
}
return null;
}
public Component getComponentBefore(Container aContainer,
Component aComponent)
{
Container root = (aContainer.isFocusCycleRoot())
? aContainer
: aContainer.getFocusCycleRootAncestor();
// Support for mixed 1.4/pre-1.4 focus APIs. If a particular root's
// traversal policy is non-legacy, then honor it.
if (root != null) {
FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
if (policy != gluePolicy) {
return policy.getComponentBefore(root, aComponent);
}
comparator.setComponentOrientation(root.getComponentOrientation());
return layoutPolicy.getComponentBefore(root, aComponent);
}
return null;
}
public Component getFirstComponent(Container aContainer) {
Container root = (aContainer.isFocusCycleRoot())
? aContainer
: aContainer.getFocusCycleRootAncestor();
// Support for mixed 1.4/pre-1.4 focus APIs. If a particular root's
// traversal policy is non-legacy, then honor it.
if (root != null) {
FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
if (policy != gluePolicy) {
return policy.getFirstComponent(root);
}
comparator.setComponentOrientation(root.getComponentOrientation());
return layoutPolicy.getFirstComponent(root);
}
return null;
}
public Component getLastComponent(Container aContainer) {
Container root = (aContainer.isFocusCycleRoot())
? aContainer
: aContainer.getFocusCycleRootAncestor();
// Support for mixed 1.4/pre-1.4 focus APIs. If a particular root's
// traversal policy is non-legacy, then honor it.
if (root != null) {
FocusTraversalPolicy policy = root.getFocusTraversalPolicy();
if (policy != gluePolicy) {
return policy.getLastComponent(root);
}
comparator.setComponentOrientation(root.getComponentOrientation());
return layoutPolicy.getLastComponent(root);
}
return null;
}
public boolean compareTabOrder(Component a, Component b) {
return (comparator.compare(a, b) < 0);
}
}
final class LegacyLayoutFocusTraversalPolicy
extends LayoutFocusTraversalPolicy
{
LegacyLayoutFocusTraversalPolicy(DefaultFocusManager defaultFocusManager) {
super(new CompareTabOrderComparator(defaultFocusManager));
}
}
final class CompareTabOrderComparator implements Comparator<Component> {
private final DefaultFocusManager defaultFocusManager;
CompareTabOrderComparator(DefaultFocusManager defaultFocusManager) {
this.defaultFocusManager = defaultFocusManager;
}
public int compare(Component o1, Component o2) {
if (o1 == o2) {
return 0;
}
return (defaultFocusManager.compareTabOrder(o1, o2)) ? -1 : 1;
}
}

View File

@@ -0,0 +1,348 @@
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.awt.Component;
import java.awt.Color;
import java.awt.Rectangle;
import java.io.Serializable;
import sun.swing.DefaultLookup;
/**
* Renders an item in a list.
* <p>
* <strong><a name="override">Implementation Note:</a></strong>
* This class overrides
* <code>invalidate</code>,
* <code>validate</code>,
* <code>revalidate</code>,
* <code>repaint</code>,
* <code>isOpaque</code>,
* and
* <code>firePropertyChange</code>
* solely to improve performance.
* If not overridden, these frequently called methods would execute code paths
* that are unnecessary for the default list cell renderer.
* If you write your own renderer,
* take care to weigh the benefits and
* drawbacks of overriding these methods.
*
* <p>
*
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Philip Milne
* @author Hans Muller
*/
public class DefaultListCellRenderer extends JLabel
implements ListCellRenderer<Object>, Serializable
{
/**
* An empty <code>Border</code>. This field might not be used. To change the
* <code>Border</code> used by this renderer override the
* <code>getListCellRendererComponent</code> method and set the border
* of the returned component directly.
*/
private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1, 1, 1);
protected static Border noFocusBorder = DEFAULT_NO_FOCUS_BORDER;
/**
* Constructs a default renderer object for an item
* in a list.
*/
public DefaultListCellRenderer() {
super();
setOpaque(true);
setBorder(getNoFocusBorder());
setName("List.cellRenderer");
}
private Border getNoFocusBorder() {
Border border = DefaultLookup.getBorder(this, ui, "List.cellNoFocusBorder");
if (System.getSecurityManager() != null) {
if (border != null) return border;
return SAFE_NO_FOCUS_BORDER;
} else {
if (border != null &&
(noFocusBorder == null ||
noFocusBorder == DEFAULT_NO_FOCUS_BORDER)) {
return border;
}
return noFocusBorder;
}
}
public Component getListCellRendererComponent(
JList<?> list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus)
{
setComponentOrientation(list.getComponentOrientation());
Color bg = null;
Color fg = null;
JList.DropLocation dropLocation = list.getDropLocation();
if (dropLocation != null
&& !dropLocation.isInsert()
&& dropLocation.getIndex() == index) {
bg = DefaultLookup.getColor(this, ui, "List.dropCellBackground");
fg = DefaultLookup.getColor(this, ui, "List.dropCellForeground");
isSelected = true;
}
if (isSelected) {
setBackground(bg == null ? list.getSelectionBackground() : bg);
setForeground(fg == null ? list.getSelectionForeground() : fg);
}
else {
setBackground(list.getBackground());
setForeground(list.getForeground());
}
if (value instanceof Icon) {
setIcon((Icon)value);
setText("");
}
else {
setIcon(null);
setText((value == null) ? "" : value.toString());
}
setEnabled(list.isEnabled());
setFont(list.getFont());
Border border = null;
if (cellHasFocus) {
if (isSelected) {
border = DefaultLookup.getBorder(this, ui, "List.focusSelectedCellHighlightBorder");
}
if (border == null) {
border = DefaultLookup.getBorder(this, ui, "List.focusCellHighlightBorder");
}
} else {
border = getNoFocusBorder();
}
setBorder(border);
return this;
}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*
* @since 1.5
* @return <code>true</code> if the background is completely opaque
* and differs from the JList's background;
* <code>false</code> otherwise
*/
@Override
public boolean isOpaque() {
Color back = getBackground();
Component p = getParent();
if (p != null) {
p = p.getParent();
}
// p should now be the JList.
boolean colorMatch = (back != null) && (p != null) &&
back.equals(p.getBackground()) &&
p.isOpaque();
return !colorMatch && super.isOpaque();
}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void validate() {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*
* @since 1.5
*/
@Override
public void invalidate() {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*
* @since 1.5
*/
@Override
public void repaint() {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void revalidate() {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void repaint(long tm, int x, int y, int width, int height) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void repaint(Rectangle r) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
// Strings get interned...
if (propertyName == "text"
|| ((propertyName == "font" || propertyName == "foreground")
&& oldValue != newValue
&& getClientProperty(javax.swing.plaf.basic.BasicHTML.propertyKey) != null)) {
super.firePropertyChange(propertyName, oldValue, newValue);
}
}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, char oldValue, char newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, short oldValue, short newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, int oldValue, int newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, long oldValue, long newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, float oldValue, float newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, double oldValue, double newValue) {}
/**
* Overridden for performance reasons.
* See the <a href="#override">Implementation Note</a>
* for more information.
*/
@Override
public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {}
/**
* A subclass of DefaultListCellRenderer that implements UIResource.
* DefaultListCellRenderer doesn't implement UIResource
* directly so that applications can safely override the
* cellRenderer property with DefaultListCellRenderer subclasses.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
public static class UIResource extends DefaultListCellRenderer
implements javax.swing.plaf.UIResource
{
}
}

View File

@@ -0,0 +1,546 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.Vector;
import java.util.Enumeration;
import javax.swing.event.*;
/**
* This class loosely implements the <code>java.util.Vector</code>
* API, in that it implements the 1.1.x version of
* <code>java.util.Vector</code>, has no collection class support,
* and notifies the <code>ListDataListener</code>s when changes occur.
* Presently it delegates to a <code>Vector</code>,
* in a future release it will be a real Collection implementation.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @param <E> the type of the elements of this model
*
* @author Hans Muller
*/
public class DefaultListModel<E> extends AbstractListModel<E>
{
private Vector<E> delegate = new Vector<E>();
/**
* Returns the number of components in this list.
* <p>
* This method is identical to <code>size</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* This method exists in conjunction with <code>setSize</code> so that
* <code>size</code> is identifiable as a JavaBean property.
*
* @return the number of components in this list
* @see #size()
*/
public int getSize() {
return delegate.size();
}
/**
* Returns the component at the specified index.
* <blockquote>
* <b>Note:</b> Although this method is not deprecated, the preferred
* method to use is <code>get(int)</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote>
* @param index an index into this list
* @return the component at the specified index
* @exception ArrayIndexOutOfBoundsException if the <code>index</code>
* is negative or greater than the current size of this
* list
* @see #get(int)
*/
public E getElementAt(int index) {
return delegate.elementAt(index);
}
/**
* Copies the components of this list into the specified array.
* The array must be big enough to hold all the objects in this list,
* else an <code>IndexOutOfBoundsException</code> is thrown.
*
* @param anArray the array into which the components get copied
* @see Vector#copyInto(Object[])
*/
public void copyInto(Object anArray[]) {
delegate.copyInto(anArray);
}
/**
* Trims the capacity of this list to be the list's current size.
*
* @see Vector#trimToSize()
*/
public void trimToSize() {
delegate.trimToSize();
}
/**
* Increases the capacity of this list, if necessary, to ensure
* that it can hold at least the number of components specified by
* the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
* @see Vector#ensureCapacity(int)
*/
public void ensureCapacity(int minCapacity) {
delegate.ensureCapacity(minCapacity);
}
/**
* Sets the size of this list.
*
* @param newSize the new size of this list
* @see Vector#setSize(int)
*/
public void setSize(int newSize) {
int oldSize = delegate.size();
delegate.setSize(newSize);
if (oldSize > newSize) {
fireIntervalRemoved(this, newSize, oldSize-1);
}
else if (oldSize < newSize) {
fireIntervalAdded(this, oldSize, newSize-1);
}
}
/**
* Returns the current capacity of this list.
*
* @return the current capacity
* @see Vector#capacity()
*/
public int capacity() {
return delegate.capacity();
}
/**
* Returns the number of components in this list.
*
* @return the number of components in this list
* @see Vector#size()
*/
public int size() {
return delegate.size();
}
/**
* Tests whether this list has any components.
*
* @return <code>true</code> if and only if this list has
* no components, that is, its size is zero;
* <code>false</code> otherwise
* @see Vector#isEmpty()
*/
public boolean isEmpty() {
return delegate.isEmpty();
}
/**
* Returns an enumeration of the components of this list.
*
* @return an enumeration of the components of this list
* @see Vector#elements()
*/
public Enumeration<E> elements() {
return delegate.elements();
}
/**
* Tests whether the specified object is a component in this list.
*
* @param elem an object
* @return <code>true</code> if the specified object
* is the same as a component in this list
* @see Vector#contains(Object)
*/
public boolean contains(Object elem) {
return delegate.contains(elem);
}
/**
* Searches for the first occurrence of <code>elem</code>.
*
* @param elem an object
* @return the index of the first occurrence of the argument in this
* list; returns <code>-1</code> if the object is not found
* @see Vector#indexOf(Object)
*/
public int indexOf(Object elem) {
return delegate.indexOf(elem);
}
/**
* Searches for the first occurrence of <code>elem</code>, beginning
* the search at <code>index</code>.
*
* @param elem an desired component
* @param index the index from which to begin searching
* @return the index where the first occurrence of <code>elem</code>
* is found after <code>index</code>; returns <code>-1</code>
* if the <code>elem</code> is not found in the list
* @see Vector#indexOf(Object,int)
*/
public int indexOf(Object elem, int index) {
return delegate.indexOf(elem, index);
}
/**
* Returns the index of the last occurrence of <code>elem</code>.
*
* @param elem the desired component
* @return the index of the last occurrence of <code>elem</code>
* in the list; returns <code>-1</code> if the object is not found
* @see Vector#lastIndexOf(Object)
*/
public int lastIndexOf(Object elem) {
return delegate.lastIndexOf(elem);
}
/**
* Searches backwards for <code>elem</code>, starting from the
* specified index, and returns an index to it.
*
* @param elem the desired component
* @param index the index to start searching from
* @return the index of the last occurrence of the <code>elem</code>
* in this list at position less than <code>index</code>;
* returns <code>-1</code> if the object is not found
* @see Vector#lastIndexOf(Object,int)
*/
public int lastIndexOf(Object elem, int index) {
return delegate.lastIndexOf(elem, index);
}
/**
* Returns the component at the specified index.
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
* is negative or not less than the size of the list.
* <blockquote>
* <b>Note:</b> Although this method is not deprecated, the preferred
* method to use is <code>get(int)</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote>
*
* @param index an index into this list
* @return the component at the specified index
* @see #get(int)
* @see Vector#elementAt(int)
*/
public E elementAt(int index) {
return delegate.elementAt(index);
}
/**
* Returns the first component of this list.
* Throws a <code>NoSuchElementException</code> if this
* vector has no components.
* @return the first component of this list
* @see Vector#firstElement()
*/
public E firstElement() {
return delegate.firstElement();
}
/**
* Returns the last component of the list.
* Throws a <code>NoSuchElementException</code> if this vector
* has no components.
*
* @return the last component of the list
* @see Vector#lastElement()
*/
public E lastElement() {
return delegate.lastElement();
}
/**
* Sets the component at the specified <code>index</code> of this
* list to be the specified element. The previous component at that
* position is discarded.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
* is invalid.
* <blockquote>
* <b>Note:</b> Although this method is not deprecated, the preferred
* method to use is <code>set(int,Object)</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote>
*
* @param element what the component is to be set to
* @param index the specified index
* @see #set(int,Object)
* @see Vector#setElementAt(Object,int)
*/
public void setElementAt(E element, int index) {
delegate.setElementAt(element, index);
fireContentsChanged(this, index, index);
}
/**
* Deletes the component at the specified index.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
* is invalid.
* <blockquote>
* <b>Note:</b> Although this method is not deprecated, the preferred
* method to use is <code>remove(int)</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote>
*
* @param index the index of the object to remove
* @see #remove(int)
* @see Vector#removeElementAt(int)
*/
public void removeElementAt(int index) {
delegate.removeElementAt(index);
fireIntervalRemoved(this, index, index);
}
/**
* Inserts the specified element as a component in this list at the
* specified <code>index</code>.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the index
* is invalid.
* <blockquote>
* <b>Note:</b> Although this method is not deprecated, the preferred
* method to use is <code>add(int,Object)</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote>
*
* @param element the component to insert
* @param index where to insert the new component
* @exception ArrayIndexOutOfBoundsException if the index was invalid
* @see #add(int,Object)
* @see Vector#insertElementAt(Object,int)
*/
public void insertElementAt(E element, int index) {
delegate.insertElementAt(element, index);
fireIntervalAdded(this, index, index);
}
/**
* Adds the specified component to the end of this list.
*
* @param element the component to be added
* @see Vector#addElement(Object)
*/
public void addElement(E element) {
int index = delegate.size();
delegate.addElement(element);
fireIntervalAdded(this, index, index);
}
/**
* Removes the first (lowest-indexed) occurrence of the argument
* from this list.
*
* @param obj the component to be removed
* @return <code>true</code> if the argument was a component of this
* list; <code>false</code> otherwise
* @see Vector#removeElement(Object)
*/
public boolean removeElement(Object obj) {
int index = indexOf(obj);
boolean rv = delegate.removeElement(obj);
if (index >= 0) {
fireIntervalRemoved(this, index, index);
}
return rv;
}
/**
* Removes all components from this list and sets its size to zero.
* <blockquote>
* <b>Note:</b> Although this method is not deprecated, the preferred
* method to use is <code>clear</code>, which implements the
* <code>List</code> interface defined in the 1.2 Collections framework.
* </blockquote>
*
* @see #clear()
* @see Vector#removeAllElements()
*/
public void removeAllElements() {
int index1 = delegate.size()-1;
delegate.removeAllElements();
if (index1 >= 0) {
fireIntervalRemoved(this, 0, index1);
}
}
/**
* Returns a string that displays and identifies this
* object's properties.
*
* @return a String representation of this object
*/
public String toString() {
return delegate.toString();
}
/* The remaining methods are included for compatibility with the
* Java 2 platform Vector class.
*/
/**
* Returns an array containing all of the elements in this list in the
* correct order.
*
* @return an array containing the elements of the list
* @see Vector#toArray()
*/
public Object[] toArray() {
Object[] rv = new Object[delegate.size()];
delegate.copyInto(rv);
return rv;
}
/**
* Returns the element at the specified position in this list.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code>
* if the index is out of range
* (<code>index &lt; 0 || index &gt;= size()</code>).
*
* @param index index of element to return
*/
public E get(int index) {
return delegate.elementAt(index);
}
/**
* Replaces the element at the specified position in this list with the
* specified element.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code>
* if the index is out of range
* (<code>index &lt; 0 || index &gt;= size()</code>).
*
* @param index index of element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
*/
public E set(int index, E element) {
E rv = delegate.elementAt(index);
delegate.setElementAt(element, index);
fireContentsChanged(this, index, index);
return rv;
}
/**
* Inserts the specified element at the specified position in this list.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code> if the
* index is out of range
* (<code>index &lt; 0 || index &gt; size()</code>).
*
* @param index index at which the specified element is to be inserted
* @param element element to be inserted
*/
public void add(int index, E element) {
delegate.insertElementAt(element, index);
fireIntervalAdded(this, index, index);
}
/**
* Removes the element at the specified position in this list.
* Returns the element that was removed from the list.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code>
* if the index is out of range
* (<code>index &lt; 0 || index &gt;= size()</code>).
*
* @param index the index of the element to removed
* @return the element previously at the specified position
*/
public E remove(int index) {
E rv = delegate.elementAt(index);
delegate.removeElementAt(index);
fireIntervalRemoved(this, index, index);
return rv;
}
/**
* Removes all of the elements from this list. The list will
* be empty after this call returns (unless it throws an exception).
*/
public void clear() {
int index1 = delegate.size()-1;
delegate.removeAllElements();
if (index1 >= 0) {
fireIntervalRemoved(this, 0, index1);
}
}
/**
* Deletes the components at the specified range of indexes.
* The removal is inclusive, so specifying a range of (1,5)
* removes the component at index 1 and the component at index 5,
* as well as all components in between.
* <p>
* Throws an <code>ArrayIndexOutOfBoundsException</code>
* if the index was invalid.
* Throws an <code>IllegalArgumentException</code> if
* <code>fromIndex &gt; toIndex</code>.
*
* @param fromIndex the index of the lower end of the range
* @param toIndex the index of the upper end of the range
* @see #remove(int)
*/
public void removeRange(int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IllegalArgumentException("fromIndex must be <= toIndex");
}
for(int i = toIndex; i >= fromIndex; i--) {
delegate.removeElementAt(i);
}
fireIntervalRemoved(this, fromIndex, toIndex);
}
/*
public void addAll(Collection c) {
}
public void addAll(int index, Collection c) {
}
*/
}

View File

@@ -0,0 +1,849 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.EventListener;
import java.util.BitSet;
import java.io.Serializable;
import java.beans.Transient;
import javax.swing.event.*;
/**
* Default data model for list selections.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Philip Milne
* @author Hans Muller
* @see ListSelectionModel
*/
public class DefaultListSelectionModel implements ListSelectionModel, Cloneable, Serializable
{
private static final int MIN = -1;
private static final int MAX = Integer.MAX_VALUE;
private int selectionMode = MULTIPLE_INTERVAL_SELECTION;
private int minIndex = MAX;
private int maxIndex = MIN;
private int anchorIndex = -1;
private int leadIndex = -1;
private int firstAdjustedIndex = MAX;
private int lastAdjustedIndex = MIN;
private boolean isAdjusting = false;
private int firstChangedIndex = MAX;
private int lastChangedIndex = MIN;
private BitSet value = new BitSet(32);
protected EventListenerList listenerList = new EventListenerList();
protected boolean leadAnchorNotificationEnabled = true;
/** {@inheritDoc} */
public int getMinSelectionIndex() { return isSelectionEmpty() ? -1 : minIndex; }
/** {@inheritDoc} */
public int getMaxSelectionIndex() { return maxIndex; }
/** {@inheritDoc} */
public boolean getValueIsAdjusting() { return isAdjusting; }
/** {@inheritDoc} */
public int getSelectionMode() { return selectionMode; }
/**
* {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public void setSelectionMode(int selectionMode) {
switch (selectionMode) {
case SINGLE_SELECTION:
case SINGLE_INTERVAL_SELECTION:
case MULTIPLE_INTERVAL_SELECTION:
this.selectionMode = selectionMode;
break;
default:
throw new IllegalArgumentException("invalid selectionMode");
}
}
/** {@inheritDoc} */
public boolean isSelectedIndex(int index) {
return ((index < minIndex) || (index > maxIndex)) ? false : value.get(index);
}
/** {@inheritDoc} */
public boolean isSelectionEmpty() {
return (minIndex > maxIndex);
}
/** {@inheritDoc} */
public void addListSelectionListener(ListSelectionListener l) {
listenerList.add(ListSelectionListener.class, l);
}
/** {@inheritDoc} */
public void removeListSelectionListener(ListSelectionListener l) {
listenerList.remove(ListSelectionListener.class, l);
}
/**
* Returns an array of all the list selection listeners
* registered on this <code>DefaultListSelectionModel</code>.
*
* @return all of this model's <code>ListSelectionListener</code>s
* or an empty
* array if no list selection listeners are currently registered
*
* @see #addListSelectionListener
* @see #removeListSelectionListener
*
* @since 1.4
*/
public ListSelectionListener[] getListSelectionListeners() {
return listenerList.getListeners(ListSelectionListener.class);
}
/**
* Notifies listeners that we have ended a series of adjustments.
*/
protected void fireValueChanged(boolean isAdjusting) {
if (lastChangedIndex == MIN) {
return;
}
/* Change the values before sending the event to the
* listeners in case the event causes a listener to make
* another change to the selection.
*/
int oldFirstChangedIndex = firstChangedIndex;
int oldLastChangedIndex = lastChangedIndex;
firstChangedIndex = MAX;
lastChangedIndex = MIN;
fireValueChanged(oldFirstChangedIndex, oldLastChangedIndex, isAdjusting);
}
/**
* Notifies <code>ListSelectionListeners</code> that the value
* of the selection, in the closed interval <code>firstIndex</code>,
* <code>lastIndex</code>, has changed.
*/
protected void fireValueChanged(int firstIndex, int lastIndex) {
fireValueChanged(firstIndex, lastIndex, getValueIsAdjusting());
}
/**
* @param firstIndex the first index in the interval
* @param lastIndex the last index in the interval
* @param isAdjusting true if this is the final change in a series of
* adjustments
* @see EventListenerList
*/
protected void fireValueChanged(int firstIndex, int lastIndex, boolean isAdjusting)
{
Object[] listeners = listenerList.getListenerList();
ListSelectionEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == ListSelectionListener.class) {
if (e == null) {
e = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting);
}
((ListSelectionListener)listeners[i+1]).valueChanged(e);
}
}
}
private void fireValueChanged() {
if (lastAdjustedIndex == MIN) {
return;
}
/* If getValueAdjusting() is true, (eg. during a drag opereration)
* record the bounds of the changes so that, when the drag finishes (and
* setValueAdjusting(false) is called) we can post a single event
* with bounds covering all of these individual adjustments.
*/
if (getValueIsAdjusting()) {
firstChangedIndex = Math.min(firstChangedIndex, firstAdjustedIndex);
lastChangedIndex = Math.max(lastChangedIndex, lastAdjustedIndex);
}
/* Change the values before sending the event to the
* listeners in case the event causes a listener to make
* another change to the selection.
*/
int oldFirstAdjustedIndex = firstAdjustedIndex;
int oldLastAdjustedIndex = lastAdjustedIndex;
firstAdjustedIndex = MAX;
lastAdjustedIndex = MIN;
fireValueChanged(oldFirstAdjustedIndex, oldLastAdjustedIndex);
}
/**
* Returns an array of all the objects currently registered as
* <code><em>Foo</em>Listener</code>s
* upon this model.
* <code><em>Foo</em>Listener</code>s
* are registered using the <code>add<em>Foo</em>Listener</code> method.
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
* For example, you can query a <code>DefaultListSelectionModel</code>
* instance <code>m</code>
* for its list selection listeners
* with the following code:
*
* <pre>ListSelectionListener[] lsls = (ListSelectionListener[])(m.getListeners(ListSelectionListener.class));</pre>
*
* If no such listeners exist,
* this method returns an empty array.
*
* @param listenerType the type of listeners requested;
* this parameter should specify an interface
* that descends from <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s
* on this model,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code> doesn't
* specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getListSelectionListeners
*
* @since 1.3
*/
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
return listenerList.getListeners(listenerType);
}
// Updates first and last change indices
private void markAsDirty(int r) {
if (r == -1) {
return;
}
firstAdjustedIndex = Math.min(firstAdjustedIndex, r);
lastAdjustedIndex = Math.max(lastAdjustedIndex, r);
}
// Sets the state at this index and update all relevant state.
private void set(int r) {
if (value.get(r)) {
return;
}
value.set(r);
markAsDirty(r);
// Update minimum and maximum indices
minIndex = Math.min(minIndex, r);
maxIndex = Math.max(maxIndex, r);
}
// Clears the state at this index and update all relevant state.
private void clear(int r) {
if (!value.get(r)) {
return;
}
value.clear(r);
markAsDirty(r);
// Update minimum and maximum indices
/*
If (r > minIndex) the minimum has not changed.
The case (r < minIndex) is not possible because r'th value was set.
We only need to check for the case when lowest entry has been cleared,
and in this case we need to search for the first value set above it.
*/
if (r == minIndex) {
for(minIndex = minIndex + 1; minIndex <= maxIndex; minIndex++) {
if (value.get(minIndex)) {
break;
}
}
}
/*
If (r < maxIndex) the maximum has not changed.
The case (r > maxIndex) is not possible because r'th value was set.
We only need to check for the case when highest entry has been cleared,
and in this case we need to search for the first value set below it.
*/
if (r == maxIndex) {
for(maxIndex = maxIndex - 1; minIndex <= maxIndex; maxIndex--) {
if (value.get(maxIndex)) {
break;
}
}
}
/* Performance note: This method is called from inside a loop in
changeSelection() but we will only iterate in the loops
above on the basis of one iteration per deselected cell - in total.
Ie. the next time this method is called the work of the previous
deselection will not be repeated.
We also don't need to worry about the case when the min and max
values are in their unassigned states. This cannot happen because
this method's initial check ensures that the selection was not empty
and therefore that the minIndex and maxIndex had 'real' values.
If we have cleared the whole selection, set the minIndex and maxIndex
to their cannonical values so that the next set command always works
just by using Math.min and Math.max.
*/
if (isSelectionEmpty()) {
minIndex = MAX;
maxIndex = MIN;
}
}
/**
* Sets the value of the leadAnchorNotificationEnabled flag.
* @see #isLeadAnchorNotificationEnabled()
*/
public void setLeadAnchorNotificationEnabled(boolean flag) {
leadAnchorNotificationEnabled = flag;
}
/**
* Returns the value of the <code>leadAnchorNotificationEnabled</code> flag.
* When <code>leadAnchorNotificationEnabled</code> is true the model
* generates notification events with bounds that cover all the changes to
* the selection plus the changes to the lead and anchor indices.
* Setting the flag to false causes a narrowing of the event's bounds to
* include only the elements that have been selected or deselected since
* the last change. Either way, the model continues to maintain the lead
* and anchor variables internally. The default is true.
* <p>
* Note: It is possible for the lead or anchor to be changed without a
* change to the selection. Notification of these changes is often
* important, such as when the new lead or anchor needs to be updated in
* the view. Therefore, caution is urged when changing the default value.
*
* @return the value of the <code>leadAnchorNotificationEnabled</code> flag
* @see #setLeadAnchorNotificationEnabled(boolean)
*/
public boolean isLeadAnchorNotificationEnabled() {
return leadAnchorNotificationEnabled;
}
private void updateLeadAnchorIndices(int anchorIndex, int leadIndex) {
if (leadAnchorNotificationEnabled) {
if (this.anchorIndex != anchorIndex) {
markAsDirty(this.anchorIndex);
markAsDirty(anchorIndex);
}
if (this.leadIndex != leadIndex) {
markAsDirty(this.leadIndex);
markAsDirty(leadIndex);
}
}
this.anchorIndex = anchorIndex;
this.leadIndex = leadIndex;
}
private boolean contains(int a, int b, int i) {
return (i >= a) && (i <= b);
}
private void changeSelection(int clearMin, int clearMax,
int setMin, int setMax, boolean clearFirst) {
for(int i = Math.min(setMin, clearMin); i <= Math.max(setMax, clearMax); i++) {
boolean shouldClear = contains(clearMin, clearMax, i);
boolean shouldSet = contains(setMin, setMax, i);
if (shouldSet && shouldClear) {
if (clearFirst) {
shouldClear = false;
}
else {
shouldSet = false;
}
}
if (shouldSet) {
set(i);
}
if (shouldClear) {
clear(i);
}
}
fireValueChanged();
}
/**
* Change the selection with the effect of first clearing the values
* in the inclusive range [clearMin, clearMax] then setting the values
* in the inclusive range [setMin, setMax]. Do this in one pass so
* that no values are cleared if they would later be set.
*/
private void changeSelection(int clearMin, int clearMax, int setMin, int setMax) {
changeSelection(clearMin, clearMax, setMin, setMax, true);
}
/** {@inheritDoc} */
public void clearSelection() {
removeSelectionIntervalImpl(minIndex, maxIndex, false);
}
/**
* Changes the selection to be between {@code index0} and {@code index1}
* inclusive. {@code index0} doesn't have to be less than or equal to
* {@code index1}.
* <p>
* In {@code SINGLE_SELECTION} selection mode, only the second index
* is used.
* <p>
* If this represents a change to the current selection, then each
* {@code ListSelectionListener} is notified of the change.
* <p>
* If either index is {@code -1}, this method does nothing and returns
* without exception. Otherwise, if either index is less than {@code -1},
* an {@code IndexOutOfBoundsException} is thrown.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
* @throws IndexOutOfBoundsException if either index is less than {@code -1}
* (and neither index is {@code -1})
* @see #addListSelectionListener
*/
public void setSelectionInterval(int index0, int index1) {
if (index0 == -1 || index1 == -1) {
return;
}
if (getSelectionMode() == SINGLE_SELECTION) {
index0 = index1;
}
updateLeadAnchorIndices(index0, index1);
int clearMin = minIndex;
int clearMax = maxIndex;
int setMin = Math.min(index0, index1);
int setMax = Math.max(index0, index1);
changeSelection(clearMin, clearMax, setMin, setMax);
}
/**
* Changes the selection to be the set union of the current selection
* and the indices between {@code index0} and {@code index1} inclusive.
* <p>
* In {@code SINGLE_SELECTION} selection mode, this is equivalent
* to calling {@code setSelectionInterval}, and only the second index
* is used. In {@code SINGLE_INTERVAL_SELECTION} selection mode, this
* method behaves like {@code setSelectionInterval}, unless the given
* interval is immediately adjacent to or overlaps the existing selection,
* and can therefore be used to grow it.
* <p>
* If this represents a change to the current selection, then each
* {@code ListSelectionListener} is notified of the change. Note that
* {@code index0} doesn't have to be less than or equal to {@code index1}.
* <p>
* If either index is {@code -1}, this method does nothing and returns
* without exception. Otherwise, if either index is less than {@code -1},
* an {@code IndexOutOfBoundsException} is thrown.
*
* @param index0 one end of the interval.
* @param index1 other end of the interval
* @throws IndexOutOfBoundsException if either index is less than {@code -1}
* (and neither index is {@code -1})
* @see #addListSelectionListener
* @see #setSelectionInterval
*/
public void addSelectionInterval(int index0, int index1)
{
if (index0 == -1 || index1 == -1) {
return;
}
// If we only allow a single selection, channel through
// setSelectionInterval() to enforce the rule.
if (getSelectionMode() == SINGLE_SELECTION) {
setSelectionInterval(index0, index1);
return;
}
updateLeadAnchorIndices(index0, index1);
int clearMin = MAX;
int clearMax = MIN;
int setMin = Math.min(index0, index1);
int setMax = Math.max(index0, index1);
// If we only allow a single interval and this would result
// in multiple intervals, then set the selection to be just
// the new range.
if (getSelectionMode() == SINGLE_INTERVAL_SELECTION &&
(setMax < minIndex - 1 || setMin > maxIndex + 1)) {
setSelectionInterval(index0, index1);
return;
}
changeSelection(clearMin, clearMax, setMin, setMax);
}
/**
* Changes the selection to be the set difference of the current selection
* and the indices between {@code index0} and {@code index1} inclusive.
* {@code index0} doesn't have to be less than or equal to {@code index1}.
* <p>
* In {@code SINGLE_INTERVAL_SELECTION} selection mode, if the removal
* would produce two disjoint selections, the removal is extended through
* the greater end of the selection. For example, if the selection is
* {@code 0-10} and you supply indices {@code 5,6} (in any order) the
* resulting selection is {@code 0-4}.
* <p>
* If this represents a change to the current selection, then each
* {@code ListSelectionListener} is notified of the change.
* <p>
* If either index is {@code -1}, this method does nothing and returns
* without exception. Otherwise, if either index is less than {@code -1},
* an {@code IndexOutOfBoundsException} is thrown.
*
* @param index0 one end of the interval
* @param index1 other end of the interval
* @throws IndexOutOfBoundsException if either index is less than {@code -1}
* (and neither index is {@code -1})
* @see #addListSelectionListener
*/
public void removeSelectionInterval(int index0, int index1)
{
removeSelectionIntervalImpl(index0, index1, true);
}
// private implementation allowing the selection interval
// to be removed without affecting the lead and anchor
private void removeSelectionIntervalImpl(int index0, int index1,
boolean changeLeadAnchor) {
if (index0 == -1 || index1 == -1) {
return;
}
if (changeLeadAnchor) {
updateLeadAnchorIndices(index0, index1);
}
int clearMin = Math.min(index0, index1);
int clearMax = Math.max(index0, index1);
int setMin = MAX;
int setMax = MIN;
// If the removal would produce to two disjoint selections in a mode
// that only allows one, extend the removal to the end of the selection.
if (getSelectionMode() != MULTIPLE_INTERVAL_SELECTION &&
clearMin > minIndex && clearMax < maxIndex) {
clearMax = maxIndex;
}
changeSelection(clearMin, clearMax, setMin, setMax);
}
private void setState(int index, boolean state) {
if (state) {
set(index);
}
else {
clear(index);
}
}
/**
* Insert length indices beginning before/after index. If the value
* at index is itself selected and the selection mode is not
* SINGLE_SELECTION, set all of the newly inserted items as selected.
* Otherwise leave them unselected. This method is typically
* called to sync the selection model with a corresponding change
* in the data model.
*/
public void insertIndexInterval(int index, int length, boolean before)
{
/* The first new index will appear at insMinIndex and the last
* one will appear at insMaxIndex
*/
int insMinIndex = (before) ? index : index + 1;
int insMaxIndex = (insMinIndex + length) - 1;
/* Right shift the entire bitset by length, beginning with
* index-1 if before is true, index+1 if it's false (i.e. with
* insMinIndex).
*/
for(int i = maxIndex; i >= insMinIndex; i--) {
setState(i + length, value.get(i));
}
/* Initialize the newly inserted indices.
*/
boolean setInsertedValues = ((getSelectionMode() == SINGLE_SELECTION) ?
false : value.get(index));
for(int i = insMinIndex; i <= insMaxIndex; i++) {
setState(i, setInsertedValues);
}
int leadIndex = this.leadIndex;
if (leadIndex > index || (before && leadIndex == index)) {
leadIndex = this.leadIndex + length;
}
int anchorIndex = this.anchorIndex;
if (anchorIndex > index || (before && anchorIndex == index)) {
anchorIndex = this.anchorIndex + length;
}
if (leadIndex != this.leadIndex || anchorIndex != this.anchorIndex) {
updateLeadAnchorIndices(anchorIndex, leadIndex);
}
fireValueChanged();
}
/**
* Remove the indices in the interval index0,index1 (inclusive) from
* the selection model. This is typically called to sync the selection
* model width a corresponding change in the data model. Note
* that (as always) index0 need not be &lt;= index1.
*/
public void removeIndexInterval(int index0, int index1)
{
int rmMinIndex = Math.min(index0, index1);
int rmMaxIndex = Math.max(index0, index1);
int gapLength = (rmMaxIndex - rmMinIndex) + 1;
/* Shift the entire bitset to the left to close the index0, index1
* gap.
*/
for(int i = rmMinIndex; i <= maxIndex; i++) {
setState(i, value.get(i + gapLength));
}
int leadIndex = this.leadIndex;
if (leadIndex == 0 && rmMinIndex == 0) {
// do nothing
} else if (leadIndex > rmMaxIndex) {
leadIndex = this.leadIndex - gapLength;
} else if (leadIndex >= rmMinIndex) {
leadIndex = rmMinIndex - 1;
}
int anchorIndex = this.anchorIndex;
if (anchorIndex == 0 && rmMinIndex == 0) {
// do nothing
} else if (anchorIndex > rmMaxIndex) {
anchorIndex = this.anchorIndex - gapLength;
} else if (anchorIndex >= rmMinIndex) {
anchorIndex = rmMinIndex - 1;
}
if (leadIndex != this.leadIndex || anchorIndex != this.anchorIndex) {
updateLeadAnchorIndices(anchorIndex, leadIndex);
}
fireValueChanged();
}
/** {@inheritDoc} */
public void setValueIsAdjusting(boolean isAdjusting) {
if (isAdjusting != this.isAdjusting) {
this.isAdjusting = isAdjusting;
this.fireValueChanged(isAdjusting);
}
}
/**
* Returns a string that displays and identifies this
* object's properties.
*
* @return a <code>String</code> representation of this object
*/
public String toString() {
String s = ((getValueIsAdjusting()) ? "~" : "=") + value.toString();
return getClass().getName() + " " + Integer.toString(hashCode()) + " " + s;
}
/**
* Returns a clone of this selection model with the same selection.
* <code>listenerLists</code> are not duplicated.
*
* @exception CloneNotSupportedException if the selection model does not
* both (a) implement the Cloneable interface and (b) define a
* <code>clone</code> method.
*/
public Object clone() throws CloneNotSupportedException {
DefaultListSelectionModel clone = (DefaultListSelectionModel)super.clone();
clone.value = (BitSet)value.clone();
clone.listenerList = new EventListenerList();
return clone;
}
/** {@inheritDoc} */
@Transient
public int getAnchorSelectionIndex() {
return anchorIndex;
}
/** {@inheritDoc} */
@Transient
public int getLeadSelectionIndex() {
return leadIndex;
}
/**
* Set the anchor selection index, leaving all selection values unchanged.
* If leadAnchorNotificationEnabled is true, send a notification covering
* the old and new anchor cells.
*
* @see #getAnchorSelectionIndex
* @see #setLeadSelectionIndex
*/
public void setAnchorSelectionIndex(int anchorIndex) {
updateLeadAnchorIndices(anchorIndex, this.leadIndex);
fireValueChanged();
}
/**
* Set the lead selection index, leaving all selection values unchanged.
* If leadAnchorNotificationEnabled is true, send a notification covering
* the old and new lead cells.
*
* @param leadIndex the new lead selection index
*
* @see #setAnchorSelectionIndex
* @see #setLeadSelectionIndex
* @see #getLeadSelectionIndex
*
* @since 1.5
*/
public void moveLeadSelectionIndex(int leadIndex) {
// disallow a -1 lead unless the anchor is already -1
if (leadIndex == -1) {
if (this.anchorIndex != -1) {
return;
}
/* PENDING(shannonh) - The following check is nice, to be consistent with
setLeadSelectionIndex. However, it is not absolutely
necessary: One could work around it by setting the anchor
to something valid, modifying the lead, and then moving
the anchor back to -1. For this reason, there's no sense
in adding it at this time, as that would require
updating the spec and officially committing to it.
// otherwise, don't do anything if the anchor is -1
} else if (this.anchorIndex == -1) {
return;
*/
}
updateLeadAnchorIndices(this.anchorIndex, leadIndex);
fireValueChanged();
}
/**
* Sets the lead selection index, ensuring that values between the
* anchor and the new lead are either all selected or all deselected.
* If the value at the anchor index is selected, first clear all the
* values in the range [anchor, oldLeadIndex], then select all the values
* values in the range [anchor, newLeadIndex], where oldLeadIndex is the old
* leadIndex and newLeadIndex is the new one.
* <p>
* If the value at the anchor index is not selected, do the same thing in
* reverse selecting values in the old range and deselecting values in the
* new one.
* <p>
* Generate a single event for this change and notify all listeners.
* For the purposes of generating minimal bounds in this event, do the
* operation in a single pass; that way the first and last index inside the
* ListSelectionEvent that is broadcast will refer to cells that actually
* changed value because of this method. If, instead, this operation were
* done in two steps the effect on the selection state would be the same
* but two events would be generated and the bounds around the changed
* values would be wider, including cells that had been first cleared only
* to later be set.
* <p>
* This method can be used in the <code>mouseDragged</code> method
* of a UI class to extend a selection.
*
* @see #getLeadSelectionIndex
* @see #setAnchorSelectionIndex
*/
public void setLeadSelectionIndex(int leadIndex) {
int anchorIndex = this.anchorIndex;
// only allow a -1 lead if the anchor is already -1
if (leadIndex == -1) {
if (anchorIndex == -1) {
updateLeadAnchorIndices(anchorIndex, leadIndex);
fireValueChanged();
}
return;
// otherwise, don't do anything if the anchor is -1
} else if (anchorIndex == -1) {
return;
}
if (this.leadIndex == -1) {
this.leadIndex = leadIndex;
}
boolean shouldSelect = value.get(this.anchorIndex);
if (getSelectionMode() == SINGLE_SELECTION) {
anchorIndex = leadIndex;
shouldSelect = true;
}
int oldMin = Math.min(this.anchorIndex, this.leadIndex);
int oldMax = Math.max(this.anchorIndex, this.leadIndex);
int newMin = Math.min(anchorIndex, leadIndex);
int newMax = Math.max(anchorIndex, leadIndex);
updateLeadAnchorIndices(anchorIndex, leadIndex);
if (shouldSelect) {
changeSelection(oldMin, oldMax, newMin, newMax);
}
else {
changeSelection(newMin, newMax, oldMin, oldMax, false);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.event.*;
import java.io.Serializable;
import java.util.EventListener;
/**
* A generic implementation of SingleSelectionModel.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Dave Moore
*/
public class DefaultSingleSelectionModel implements SingleSelectionModel,
Serializable {
/* Only one ModelChangeEvent is needed per model instance since the
* event's only (read-only) state is the source property. The source
* of events generated here is always "this".
*/
protected transient ChangeEvent changeEvent = null;
/** The collection of registered listeners */
protected EventListenerList listenerList = new EventListenerList();
private int index = -1;
// implements javax.swing.SingleSelectionModel
public int getSelectedIndex() {
return index;
}
// implements javax.swing.SingleSelectionModel
public void setSelectedIndex(int index) {
if (this.index != index) {
this.index = index;
fireStateChanged();
}
}
// implements javax.swing.SingleSelectionModel
public void clearSelection() {
setSelectedIndex(-1);
}
// implements javax.swing.SingleSelectionModel
public boolean isSelected() {
boolean ret = false;
if (getSelectedIndex() != -1) {
ret = true;
}
return ret;
}
/**
* Adds a <code>ChangeListener</code> to the button.
*/
public void addChangeListener(ChangeListener l) {
listenerList.add(ChangeListener.class, l);
}
/**
* Removes a <code>ChangeListener</code> from the button.
*/
public void removeChangeListener(ChangeListener l) {
listenerList.remove(ChangeListener.class, l);
}
/**
* Returns an array of all the change listeners
* registered on this <code>DefaultSingleSelectionModel</code>.
*
* @return all of this model's <code>ChangeListener</code>s
* or an empty
* array if no change listeners are currently registered
*
* @see #addChangeListener
* @see #removeChangeListener
*
* @since 1.4
*/
public ChangeListener[] getChangeListeners() {
return listenerList.getListeners(ChangeListener.class);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. The event instance
* is created lazily.
* @see EventListenerList
*/
protected void fireStateChanged() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ChangeListener.class) {
// Lazily create the event:
if (changeEvent == null)
changeEvent = new ChangeEvent(this);
((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
}
}
}
/**
* Returns an array of all the objects currently registered as
* <code><em>Foo</em>Listener</code>s
* upon this model.
* <code><em>Foo</em>Listener</code>s
* are registered using the <code>add<em>Foo</em>Listener</code> method.
* <p>
* You can specify the <code>listenerType</code> argument
* with a class literal, such as <code><em>Foo</em>Listener.class</code>.
* For example, you can query a <code>DefaultSingleSelectionModel</code>
* instance <code>m</code>
* for its change listeners
* with the following code:
*
* <pre>ChangeListener[] cls = (ChangeListener[])(m.getListeners(ChangeListener.class));</pre>
*
* If no such listeners exist,
* this method returns an empty array.
*
* @param listenerType the type of listeners requested;
* this parameter should specify an interface
* that descends from <code>java.util.EventListener</code>
* @return an array of all objects registered as
* <code><em>Foo</em>Listener</code>s
* on this model,
* or an empty array if no such
* listeners have been added
* @exception ClassCastException if <code>listenerType</code> doesn't
* specify a class or interface that implements
* <code>java.util.EventListener</code>
*
* @see #getChangeListeners
*
* @since 1.3
*/
public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
return listenerList.getListeners(listenerType);
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.util.Set;
/**
* Provides a javax.swing.DefaultFocusManager view onto an arbitrary
* java.awt.KeyboardFocusManager. We subclass DefaultFocusManager instead of
* FocusManager because it seems more backward-compatible. It is likely that
* some pre-1.4 code assumes that the object returned by
* FocusManager.getCurrentManager is an instance of DefaultFocusManager unless
* set explicitly.
*/
final class DelegatingDefaultFocusManager extends DefaultFocusManager {
private final KeyboardFocusManager delegate;
DelegatingDefaultFocusManager(KeyboardFocusManager delegate) {
this.delegate = delegate;
setDefaultFocusTraversalPolicy(gluePolicy);
}
KeyboardFocusManager getDelegate() {
return delegate;
}
// Legacy methods which first appeared in javax.swing.FocusManager.
// Client code is most likely to invoke these methods.
public void processKeyEvent(Component focusedComponent, KeyEvent e) {
delegate.processKeyEvent(focusedComponent, e);
}
public void focusNextComponent(Component aComponent) {
delegate.focusNextComponent(aComponent);
}
public void focusPreviousComponent(Component aComponent) {
delegate.focusPreviousComponent(aComponent);
}
// Make sure that we delegate all new methods in KeyboardFocusManager
// as well as the legacy methods from Swing. It is theoretically possible,
// although unlikely, that a client app will treat this instance as a
// new-style KeyboardFocusManager. We might as well be safe.
//
// The JLS won't let us override the protected methods in
// KeyboardFocusManager such that they invoke the corresponding methods on
// the delegate. However, since client code would never be able to call
// those methods anyways, we don't have to worry about that problem.
public Component getFocusOwner() {
return delegate.getFocusOwner();
}
public void clearGlobalFocusOwner() {
delegate.clearGlobalFocusOwner();
}
public Component getPermanentFocusOwner() {
return delegate.getPermanentFocusOwner();
}
public Window getFocusedWindow() {
return delegate.getFocusedWindow();
}
public Window getActiveWindow() {
return delegate.getActiveWindow();
}
public FocusTraversalPolicy getDefaultFocusTraversalPolicy() {
return delegate.getDefaultFocusTraversalPolicy();
}
public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy
defaultPolicy) {
if (delegate != null) {
// Will be null when invoked from supers constructor.
delegate.setDefaultFocusTraversalPolicy(defaultPolicy);
}
}
public void
setDefaultFocusTraversalKeys(int id,
Set<? extends AWTKeyStroke> keystrokes)
{
delegate.setDefaultFocusTraversalKeys(id, keystrokes);
}
public Set<AWTKeyStroke> getDefaultFocusTraversalKeys(int id) {
return delegate.getDefaultFocusTraversalKeys(id);
}
public Container getCurrentFocusCycleRoot() {
return delegate.getCurrentFocusCycleRoot();
}
public void setGlobalCurrentFocusCycleRoot(Container newFocusCycleRoot) {
delegate.setGlobalCurrentFocusCycleRoot(newFocusCycleRoot);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
delegate.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
delegate.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
delegate.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
delegate.removePropertyChangeListener(propertyName, listener);
}
public void addVetoableChangeListener(VetoableChangeListener listener) {
delegate.addVetoableChangeListener(listener);
}
public void removeVetoableChangeListener(VetoableChangeListener listener) {
delegate.removeVetoableChangeListener(listener);
}
public void addVetoableChangeListener(String propertyName,
VetoableChangeListener listener) {
delegate.addVetoableChangeListener(propertyName, listener);
}
public void removeVetoableChangeListener(String propertyName,
VetoableChangeListener listener) {
delegate.removeVetoableChangeListener(propertyName, listener);
}
public void addKeyEventDispatcher(KeyEventDispatcher dispatcher) {
delegate.addKeyEventDispatcher(dispatcher);
}
public void removeKeyEventDispatcher(KeyEventDispatcher dispatcher) {
delegate.removeKeyEventDispatcher(dispatcher);
}
public boolean dispatchEvent(AWTEvent e) {
return delegate.dispatchEvent(e);
}
public boolean dispatchKeyEvent(KeyEvent e) {
return delegate.dispatchKeyEvent(e);
}
public void upFocusCycle(Component aComponent) {
delegate.upFocusCycle(aComponent);
}
public void downFocusCycle(Container aContainer) {
delegate.downFocusCycle(aContainer);
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
/** DesktopManager objects are owned by a JDesktopPane object. They are responsible
* for implementing L&amp;F specific behaviors for the JDesktopPane. JInternalFrame
* implementations should delegate specific behaviors to the DesktopManager. For
* instance, if a JInternalFrame was asked to iconify, it should try:
* <PRE>
* getDesktopPane().getDesktopManager().iconifyFrame(frame);
* </PRE>
* This delegation allows each L&amp;F to provide custom behaviors for desktop-specific
* actions. (For example, how and where the internal frame's icon would appear.)
* <p>This class provides a policy for the various JInternalFrame methods, it is not
* meant to be called directly rather the various JInternalFrame methods will call
* into the DesktopManager.</p>
*
* @see JDesktopPane
* @see JInternalFrame
* @see JInternalFrame.JDesktopIcon
*
* @author David Kloba
*/
public interface DesktopManager
{
/** If possible, display this frame in an appropriate location.
* Normally, this is not called, as the creator of the JInternalFrame
* will add the frame to the appropriate parent.
*/
void openFrame(JInternalFrame f);
/** Generally, this call should remove the frame from it's parent. */
void closeFrame(JInternalFrame f);
/** Generally, the frame should be resized to match it's parents bounds. */
void maximizeFrame(JInternalFrame f);
/** Generally, this indicates that the frame should be restored to it's
* size and position prior to a maximizeFrame() call.
*/
void minimizeFrame(JInternalFrame f);
/** Generally, remove this frame from it's parent and add an iconic representation. */
void iconifyFrame(JInternalFrame f);
/** Generally, remove any iconic representation that is present and restore the
* frame to it's original size and location.
*/
void deiconifyFrame(JInternalFrame f);
/**
* Generally, indicate that this frame has focus. This is usually called after
* the JInternalFrame's IS_SELECTED_PROPERTY has been set to true.
*/
void activateFrame(JInternalFrame f);
/**
* Generally, indicate that this frame has lost focus. This is usually called
* after the JInternalFrame's IS_SELECTED_PROPERTY has been set to false.
*/
void deactivateFrame(JInternalFrame f);
/** This method is normally called when the user has indicated that
* they will begin dragging a component around. This method should be called
* prior to any dragFrame() calls to allow the DesktopManager to prepare any
* necessary state. Normally <b>f</b> will be a JInternalFrame.
*/
void beginDraggingFrame(JComponent f);
/** The user has moved the frame. Calls to this method will be preceded by calls
* to beginDraggingFrame().
* Normally <b>f</b> will be a JInternalFrame.
*/
void dragFrame(JComponent f, int newX, int newY);
/** This method signals the end of the dragging session. Any state maintained by
* the DesktopManager can be removed here. Normally <b>f</b> will be a JInternalFrame.
*/
void endDraggingFrame(JComponent f);
/** This methods is normally called when the user has indicated that
* they will begin resizing the frame. This method should be called
* prior to any resizeFrame() calls to allow the DesktopManager to prepare any
* necessary state. Normally <b>f</b> will be a JInternalFrame.
*/
void beginResizingFrame(JComponent f, int direction);
/** The user has resized the component. Calls to this method will be preceded by calls
* to beginResizingFrame().
* Normally <b>f</b> will be a JInternalFrame.
*/
void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight);
/** This method signals the end of the resize session. Any state maintained by
* the DesktopManager can be removed here. Normally <b>f</b> will be a JInternalFrame.
*/
void endResizingFrame(JComponent f);
/** This is a primitive reshape method.*/
void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight);
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
/**
* Drop modes, used to determine the method by which a component
* tracks and indicates a drop location during drag and drop.
*
* @author Shannon Hickey
* @see JTable#setDropMode
* @see JList#setDropMode
* @see JTree#setDropMode
* @see javax.swing.text.JTextComponent#setDropMode
* @since 1.6
*/
public enum DropMode {
/**
* A component's own internal selection mechanism (or caret for text
* components) should be used to track the drop location.
*/
USE_SELECTION,
/**
* The drop location should be tracked in terms of the index of
* existing items. Useful for dropping on items in tables, lists,
* and trees.
*/
ON,
/**
* The drop location should be tracked in terms of the position
* where new data should be inserted. For components that manage
* a list of items (list and tree for example), the drop location
* should indicate the index where new data should be inserted.
* For text components the location should represent a position
* between characters. For components that manage tabular data
* (table for example), the drop location should indicate
* where to insert new rows, columns, or both, to accommodate
* the dropped data.
*/
INSERT,
/**
* The drop location should be tracked in terms of the row index
* where new rows should be inserted to accommodate the dropped
* data. This is useful for components that manage tabular data.
*/
INSERT_ROWS,
/**
* The drop location should be tracked in terms of the column index
* where new columns should be inserted to accommodate the dropped
* data. This is useful for components that manage tabular data.
*/
INSERT_COLS,
/**
* This mode is a combination of <code>ON</code>
* and <code>INSERT</code>, specifying that data can be
* dropped on existing items, or in insert locations
* as specified by <code>INSERT</code>.
*/
ON_OR_INSERT,
/**
* This mode is a combination of <code>ON</code>
* and <code>INSERT_ROWS</code>, specifying that data can be
* dropped on existing items, or as insert rows
* as specified by <code>INSERT_ROWS</code>.
*/
ON_OR_INSERT_ROWS,
/**
* This mode is a combination of <code>ON</code>
* and <code>INSERT_COLS</code>, specifying that data can be
* dropped on existing items, or as insert columns
* as specified by <code>INSERT_COLS</code>.
*/
ON_OR_INSERT_COLS
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
/**
* This class has been obsoleted by the 1.4 focus APIs. While client code may
* still use this class, developers are strongly encouraged to use
* <code>java.awt.KeyboardFocusManager</code> and
* <code>java.awt.DefaultKeyboardFocusManager</code> instead.
* <p>
* Please see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
* How to Use the Focus Subsystem</a>,
* a section in <em>The Java Tutorial</em>, and the
* <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
* for more information.
*
* @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
*
* @author Arnaud Weber
* @author David Mendenhall
*/
public abstract class FocusManager extends DefaultKeyboardFocusManager {
/**
* This field is obsolete, and its use is discouraged since its
* specification is incompatible with the 1.4 focus APIs.
* The current FocusManager is no longer a property of the UI.
* Client code must query for the current FocusManager using
* <code>KeyboardFocusManager.getCurrentKeyboardFocusManager()</code>.
* See the Focus Specification for more information.
*
* @see java.awt.KeyboardFocusManager#getCurrentKeyboardFocusManager
* @see <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
*/
public static final String FOCUS_MANAGER_CLASS_PROPERTY =
"FocusManagerClassName";
private static boolean enabled = true;
/**
* Returns the current <code>KeyboardFocusManager</code> instance
* for the calling thread's context.
*
* @return this thread's context's <code>KeyboardFocusManager</code>
* @see #setCurrentManager
*/
public static FocusManager getCurrentManager() {
KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
if (manager instanceof FocusManager) {
return (FocusManager)manager;
} else {
return new DelegatingDefaultFocusManager(manager);
}
}
/**
* Sets the current <code>KeyboardFocusManager</code> instance
* for the calling thread's context. If <code>null</code> is
* specified, then the current <code>KeyboardFocusManager</code>
* is replaced with a new instance of
* <code>DefaultKeyboardFocusManager</code>.
* <p>
* If a <code>SecurityManager</code> is installed,
* the calling thread must be granted the <code>AWTPermission</code>
* "replaceKeyboardFocusManager" in order to replace the
* the current <code>KeyboardFocusManager</code>.
* If this permission is not granted,
* this method will throw a <code>SecurityException</code>,
* and the current <code>KeyboardFocusManager</code> will be unchanged.
*
* @param aFocusManager the new <code>KeyboardFocusManager</code>
* for this thread's context
* @see #getCurrentManager
* @see java.awt.DefaultKeyboardFocusManager
* @throws SecurityException if the calling thread does not have permission
* to replace the current <code>KeyboardFocusManager</code>
*/
public static void setCurrentManager(FocusManager aFocusManager)
throws SecurityException
{
// Note: This method is not backward-compatible with 1.3 and earlier
// releases. It now throws a SecurityException in an applet, whereas
// in previous releases, it did not. This issue was discussed at
// length, and ultimately approved by Hans.
KeyboardFocusManager toSet =
(aFocusManager instanceof DelegatingDefaultFocusManager)
? ((DelegatingDefaultFocusManager)aFocusManager).getDelegate()
: aFocusManager;
KeyboardFocusManager.setCurrentKeyboardFocusManager(toSet);
}
/**
* Changes the current <code>KeyboardFocusManager</code>'s default
* <code>FocusTraversalPolicy</code> to
* <code>DefaultFocusTraversalPolicy</code>.
*
* @see java.awt.DefaultFocusTraversalPolicy
* @see java.awt.KeyboardFocusManager#setDefaultFocusTraversalPolicy
* @deprecated as of 1.4, replaced by
* <code>KeyboardFocusManager.setDefaultFocusTraversalPolicy(FocusTraversalPolicy)</code>
*/
@Deprecated
public static void disableSwingFocusManager() {
if (enabled) {
enabled = false;
KeyboardFocusManager.getCurrentKeyboardFocusManager().
setDefaultFocusTraversalPolicy(
new DefaultFocusTraversalPolicy());
}
}
/**
* Returns whether the application has invoked
* <code>disableSwingFocusManager()</code>.
*
* @see #disableSwingFocusManager
* @deprecated As of 1.4, replaced by
* <code>KeyboardFocusManager.getDefaultFocusTraversalPolicy()</code>
*/
@Deprecated
public static boolean isFocusManagerEnabled() {
return enabled;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
/**
* A private interface to access clip bounds in wrapped Graphics objects.
*
* @author Thomas Ball
*/
import java.awt.*;
interface GraphicsWrapper {
Graphics subGraphics();
boolean isClipIntersecting(Rectangle r);
int getClipX();
int getClipY();
int getClipWidth();
int getClipHeight();
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.image.*;
/**
* An image filter that "disables" an image by turning
* it into a grayscale image, and brightening the pixels
* in the image. Used by buttons to create an image for
* a disabled button.
*
* @author Jeff Dinkins
* @author Tom Ball
* @author Jim Graham
*/
public class GrayFilter extends RGBImageFilter {
private boolean brighter;
private int percent;
/**
* Creates a disabled image
*/
public static Image createDisabledImage (Image i) {
GrayFilter filter = new GrayFilter(true, 50);
ImageProducer prod = new FilteredImageSource(i.getSource(), filter);
Image grayImage = Toolkit.getDefaultToolkit().createImage(prod);
return grayImage;
}
/**
* Constructs a GrayFilter object that filters a color image to a
* grayscale image. Used by buttons to create disabled ("grayed out")
* button images.
*
* @param b a boolean -- true if the pixels should be brightened
* @param p an int in the range 0..100 that determines the percentage
* of gray, where 100 is the darkest gray, and 0 is the lightest
*/
public GrayFilter(boolean b, int p) {
brighter = b;
percent = p;
// canFilterIndexColorModel indicates whether or not it is acceptable
// to apply the color filtering of the filterRGB method to the color
// table entries of an IndexColorModel object in lieu of pixel by pixel
// filtering.
canFilterIndexColorModel = true;
}
/**
* Overrides <code>RGBImageFilter.filterRGB</code>.
*/
public int filterRGB(int x, int y, int rgb) {
// Use NTSC conversion formula.
int gray = (int)((0.30 * ((rgb >> 16) & 0xff) +
0.59 * ((rgb >> 8) & 0xff) +
0.11 * (rgb & 0xff)) / 3);
if (brighter) {
gray = (255 - ((255 - gray) * (100 - percent) / 100));
} else {
gray = (gray * (100 - percent) / 100);
}
if (gray < 0) gray = 0;
if (gray > 255) gray = 255;
return (rgb & 0xff000000) | (gray << 16) | (gray << 8) | (gray << 0);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Graphics;
import java.awt.Component;
/**
* A small fixed size picture, typically used to decorate components.
*
* @see ImageIcon
*/
public interface Icon
{
/**
* Draw the icon at the specified location. Icon implementations
* may use the Component argument to get properties useful for
* painting, e.g. the foreground or background color.
*/
void paintIcon(Component c, Graphics g, int x, int y);
/**
* Returns the icon's width.
*
* @return an int specifying the fixed width of the icon.
*/
int getIconWidth();
/**
* Returns the icon's height.
*
* @return an int specifying the fixed height of the icon.
*/
int getIconHeight();
}

View File

@@ -0,0 +1,715 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.image.*;
import java.beans.ConstructorProperties;
import java.beans.Transient;
import java.net.URL;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Locale;
import javax.accessibility.*;
import sun.awt.AppContext;
import java.lang.reflect.Field;
import java.security.*;
/**
* An implementation of the Icon interface that paints Icons
* from Images. Images that are created from a URL, filename or byte array
* are preloaded using MediaTracker to monitor the loaded state
* of the image.
*
* <p>
* For further information and examples of using image icons, see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/icon.html">How to Use Icons</a>
* in <em>The Java Tutorial.</em>
*
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author Jeff Dinkins
* @author Lynn Monsanto
*/
public class ImageIcon implements Icon, Serializable, Accessible {
/* Keep references to the filename and location so that
* alternate persistence schemes have the option to archive
* images symbolically rather than including the image data
* in the archive.
*/
transient private String filename;
transient private URL location;
transient Image image;
transient int loadStatus = 0;
ImageObserver imageObserver;
String description = null;
/**
* Do not use this shared component, which is used to track image loading.
* It is left for backward compatibility only.
* @deprecated since 1.8
*/
@Deprecated
protected final static Component component;
/**
* Do not use this shared media tracker, which is used to load images.
* It is left for backward compatibility only.
* @deprecated since 1.8
*/
@Deprecated
protected final static MediaTracker tracker;
static {
component = AccessController.doPrivileged(new PrivilegedAction<Component>() {
public Component run() {
try {
final Component component = createNoPermsComponent();
// 6482575 - clear the appContext field so as not to leak it
Field appContextField =
Component.class.getDeclaredField("appContext");
appContextField.setAccessible(true);
appContextField.set(component, null);
return component;
} catch (Throwable e) {
// We don't care about component.
// So don't prevent class initialisation.
e.printStackTrace();
return null;
}
}
});
tracker = new MediaTracker(component);
}
private static Component createNoPermsComponent() {
// 7020198 - set acc field to no permissions and no subject
// Note, will have appContext set.
return AccessController.doPrivileged(
new PrivilegedAction<Component>() {
public Component run() {
return new Component() {
};
}
},
new AccessControlContext(new ProtectionDomain[]{
new ProtectionDomain(null, null)
})
);
}
/**
* Id used in loading images from MediaTracker.
*/
private static int mediaTrackerID;
private final static Object TRACKER_KEY = new StringBuilder("TRACKER_KEY");
int width = -1;
int height = -1;
/**
* Creates an ImageIcon from the specified file. The image will
* be preloaded by using MediaTracker to monitor the loading state
* of the image.
* @param filename the name of the file containing the image
* @param description a brief textual description of the image
* @see #ImageIcon(String)
*/
public ImageIcon(String filename, String description) {
image = Toolkit.getDefaultToolkit().getImage(filename);
if (image == null) {
return;
}
this.filename = filename;
this.description = description;
loadImage(image);
}
/**
* Creates an ImageIcon from the specified file. The image will
* be preloaded by using MediaTracker to monitor the loading state
* of the image. The specified String can be a file name or a
* file path. When specifying a path, use the Internet-standard
* forward-slash ("/") as a separator.
* (The string is converted to an URL, so the forward-slash works
* on all systems.)
* For example, specify:
* <pre>
* new ImageIcon("images/myImage.gif") </pre>
* The description is initialized to the <code>filename</code> string.
*
* @param filename a String specifying a filename or path
* @see #getDescription
*/
@ConstructorProperties({"description"})
public ImageIcon (String filename) {
this(filename, filename);
}
/**
* Creates an ImageIcon from the specified URL. The image will
* be preloaded by using MediaTracker to monitor the loaded state
* of the image.
* @param location the URL for the image
* @param description a brief textual description of the image
* @see #ImageIcon(String)
*/
public ImageIcon(URL location, String description) {
image = Toolkit.getDefaultToolkit().getImage(location);
if (image == null) {
return;
}
this.location = location;
this.description = description;
loadImage(image);
}
/**
* Creates an ImageIcon from the specified URL. The image will
* be preloaded by using MediaTracker to monitor the loaded state
* of the image.
* The icon's description is initialized to be
* a string representation of the URL.
* @param location the URL for the image
* @see #getDescription
*/
public ImageIcon (URL location) {
this(location, location.toExternalForm());
}
/**
* Creates an ImageIcon from the image.
* @param image the image
* @param description a brief textual description of the image
*/
public ImageIcon(Image image, String description) {
this(image);
this.description = description;
}
/**
* Creates an ImageIcon from an image object.
* If the image has a "comment" property that is a string,
* then the string is used as the description of this icon.
* @param image the image
* @see #getDescription
* @see java.awt.Image#getProperty
*/
public ImageIcon (Image image) {
this.image = image;
Object o = image.getProperty("comment", imageObserver);
if (o instanceof String) {
description = (String) o;
}
loadImage(image);
}
/**
* Creates an ImageIcon from an array of bytes which were
* read from an image file containing a supported image format,
* such as GIF, JPEG, or (as of 1.3) PNG.
* Normally this array is created
* by reading an image using Class.getResourceAsStream(), but
* the byte array may also be statically stored in a class.
*
* @param imageData an array of pixels in an image format supported
* by the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
* @param description a brief textual description of the image
* @see java.awt.Toolkit#createImage
*/
public ImageIcon (byte[] imageData, String description) {
this.image = Toolkit.getDefaultToolkit().createImage(imageData);
if (image == null) {
return;
}
this.description = description;
loadImage(image);
}
/**
* Creates an ImageIcon from an array of bytes which were
* read from an image file containing a supported image format,
* such as GIF, JPEG, or (as of 1.3) PNG.
* Normally this array is created
* by reading an image using Class.getResourceAsStream(), but
* the byte array may also be statically stored in a class.
* If the resulting image has a "comment" property that is a string,
* then the string is used as the description of this icon.
*
* @param imageData an array of pixels in an image format supported by
* the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
* @see java.awt.Toolkit#createImage
* @see #getDescription
* @see java.awt.Image#getProperty
*/
public ImageIcon (byte[] imageData) {
this.image = Toolkit.getDefaultToolkit().createImage(imageData);
if (image == null) {
return;
}
Object o = image.getProperty("comment", imageObserver);
if (o instanceof String) {
description = (String) o;
}
loadImage(image);
}
/**
* Creates an uninitialized image icon.
*/
public ImageIcon() {
}
/**
* Loads the image, returning only when the image is loaded.
* @param image the image
*/
protected void loadImage(Image image) {
MediaTracker mTracker = getTracker();
synchronized(mTracker) {
int id = getNextID();
mTracker.addImage(image, id);
try {
mTracker.waitForID(id, 0);
} catch (InterruptedException e) {
System.out.println("INTERRUPTED while loading Image");
}
loadStatus = mTracker.statusID(id, false);
mTracker.removeImage(image, id);
width = image.getWidth(imageObserver);
height = image.getHeight(imageObserver);
}
}
/**
* Returns an ID to use with the MediaTracker in loading an image.
*/
private int getNextID() {
synchronized(getTracker()) {
return ++mediaTrackerID;
}
}
/**
* Returns the MediaTracker for the current AppContext, creating a new
* MediaTracker if necessary.
*/
private MediaTracker getTracker() {
Object trackerObj;
AppContext ac = AppContext.getAppContext();
// Opt: Only synchronize if trackerObj comes back null?
// If null, synchronize, re-check for null, and put new tracker
synchronized(ac) {
trackerObj = ac.get(TRACKER_KEY);
if (trackerObj == null) {
Component comp = new Component() {};
trackerObj = new MediaTracker(comp);
ac.put(TRACKER_KEY, trackerObj);
}
}
return (MediaTracker) trackerObj;
}
/**
* Returns the status of the image loading operation.
* @return the loading status as defined by java.awt.MediaTracker
* @see java.awt.MediaTracker#ABORTED
* @see java.awt.MediaTracker#ERRORED
* @see java.awt.MediaTracker#COMPLETE
*/
public int getImageLoadStatus() {
return loadStatus;
}
/**
* Returns this icon's <code>Image</code>.
* @return the <code>Image</code> object for this <code>ImageIcon</code>
*/
@Transient
public Image getImage() {
return image;
}
/**
* Sets the image displayed by this icon.
* @param image the image
*/
public void setImage(Image image) {
this.image = image;
loadImage(image);
}
/**
* Gets the description of the image. This is meant to be a brief
* textual description of the object. For example, it might be
* presented to a blind user to give an indication of the purpose
* of the image.
* The description may be null.
*
* @return a brief textual description of the image
*/
public String getDescription() {
return description;
}
/**
* Sets the description of the image. This is meant to be a brief
* textual description of the object. For example, it might be
* presented to a blind user to give an indication of the purpose
* of the image.
* @param description a brief textual description of the image
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Paints the icon.
* The top-left corner of the icon is drawn at
* the point (<code>x</code>, <code>y</code>)
* in the coordinate space of the graphics context <code>g</code>.
* If this icon has no image observer,
* this method uses the <code>c</code> component
* as the observer.
*
* @param c the component to be used as the observer
* if this icon has no image observer
* @param g the graphics context
* @param x the X coordinate of the icon's top-left corner
* @param y the Y coordinate of the icon's top-left corner
*/
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
if(imageObserver == null) {
g.drawImage(image, x, y, c);
} else {
g.drawImage(image, x, y, imageObserver);
}
}
/**
* Gets the width of the icon.
*
* @return the width in pixels of this icon
*/
public int getIconWidth() {
return width;
}
/**
* Gets the height of the icon.
*
* @return the height in pixels of this icon
*/
public int getIconHeight() {
return height;
}
/**
* Sets the image observer for the image. Set this
* property if the ImageIcon contains an animated GIF, so
* the observer is notified to update its display.
* For example:
* <pre>
* icon = new ImageIcon(...)
* button.setIcon(icon);
* icon.setImageObserver(button);
* </pre>
*
* @param observer the image observer
*/
public void setImageObserver(ImageObserver observer) {
imageObserver = observer;
}
/**
* Returns the image observer for the image.
*
* @return the image observer, which may be null
*/
@Transient
public ImageObserver getImageObserver() {
return imageObserver;
}
/**
* Returns a string representation of this image.
*
* @return a string representing this image
*/
public String toString() {
if (description != null) {
return description;
}
return super.toString();
}
private void readObject(ObjectInputStream s)
throws ClassNotFoundException, IOException
{
s.defaultReadObject();
int w = s.readInt();
int h = s.readInt();
int[] pixels = (int[])(s.readObject());
if (pixels != null) {
Toolkit tk = Toolkit.getDefaultToolkit();
ColorModel cm = ColorModel.getRGBdefault();
image = tk.createImage(new MemoryImageSource(w, h, cm, pixels, 0, w));
loadImage(image);
}
}
private void writeObject(ObjectOutputStream s)
throws IOException
{
s.defaultWriteObject();
int w = getIconWidth();
int h = getIconHeight();
int[] pixels = image != null? new int[w * h] : null;
if (image != null) {
try {
PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
pg.grabPixels();
if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
throw new IOException("failed to load image contents");
}
}
catch (InterruptedException e) {
throw new IOException("image load interrupted");
}
}
s.writeInt(w);
s.writeInt(h);
s.writeObject(pixels);
}
/**
* --- Accessibility Support ---
*/
private AccessibleImageIcon accessibleContext = null;
/**
* Gets the AccessibleContext associated with this ImageIcon.
* For image icons, the AccessibleContext takes the form of an
* AccessibleImageIcon.
* A new AccessibleImageIcon instance is created if necessary.
*
* @return an AccessibleImageIcon that serves as the
* AccessibleContext of this ImageIcon
* @beaninfo
* expert: true
* description: The AccessibleContext associated with this ImageIcon.
* @since 1.3
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleImageIcon();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>ImageIcon</code> class. It provides an implementation of the
* Java Accessibility API appropriate to image icon user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
* @since 1.3
*/
protected class AccessibleImageIcon extends AccessibleContext
implements AccessibleIcon, Serializable {
/*
* AccessibleContest implementation -----------------
*/
/**
* Gets the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.ICON;
}
/**
* Gets the state of this object.
*
* @return an instance of AccessibleStateSet containing the current
* state set of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet() {
return null;
}
/**
* Gets the Accessible parent of this object. If the parent of this
* object implements Accessible, this method should simply return
* getParent().
*
* @return the Accessible parent of this object -- can be null if this
* object does not have an Accessible parent
*/
public Accessible getAccessibleParent() {
return null;
}
/**
* Gets the index of this object in its accessible parent.
*
* @return the index of this object in its parent; -1 if this
* object does not have an accessible parent.
* @see #getAccessibleParent
*/
public int getAccessibleIndexInParent() {
return -1;
}
/**
* Returns the number of accessible children in the object. If all
* of the children of this object implement Accessible, than this
* method should return the number of children of this object.
*
* @return the number of accessible children in the object.
*/
public int getAccessibleChildrenCount() {
return 0;
}
/**
* Returns the nth Accessible child of the object.
*
* @param i zero-based index of child
* @return the nth Accessible child of the object
*/
public Accessible getAccessibleChild(int i) {
return null;
}
/**
* Returns the locale of this object.
*
* @return the locale of this object
*/
public Locale getLocale() throws IllegalComponentStateException {
return null;
}
/*
* AccessibleIcon implementation -----------------
*/
/**
* Gets the description of the icon. This is meant to be a brief
* textual description of the object. For example, it might be
* presented to a blind user to give an indication of the purpose
* of the icon.
*
* @return the description of the icon
*/
public String getAccessibleIconDescription() {
return ImageIcon.this.getDescription();
}
/**
* Sets the description of the icon. This is meant to be a brief
* textual description of the object. For example, it might be
* presented to a blind user to give an indication of the purpose
* of the icon.
*
* @param description the description of the icon
*/
public void setAccessibleIconDescription(String description) {
ImageIcon.this.setDescription(description);
}
/**
* Gets the height of the icon.
*
* @return the height of the icon
*/
public int getAccessibleIconHeight() {
return ImageIcon.this.height;
}
/**
* Gets the width of the icon.
*
* @return the width of the icon
*/
public int getAccessibleIconWidth() {
return ImageIcon.this.width;
}
private void readObject(ObjectInputStream s)
throws ClassNotFoundException, IOException
{
s.defaultReadObject();
}
private void writeObject(ObjectOutputStream s)
throws IOException
{
s.defaultWriteObject();
}
} // AccessibleImageIcon
}

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Set;
/**
* <code>InputMap</code> provides a binding between an input event
* (currently only <code>KeyStroke</code>s are used)
* and an <code>Object</code>. <code>InputMap</code>s
* are usually used with an <code>ActionMap</code>,
* to determine an <code>Action</code> to perform
* when a key is pressed.
* An <code>InputMap</code> can have a parent
* that is searched for bindings not defined in the <code>InputMap</code>.
* <p>As with <code>ActionMap</code> if you create a cycle, eg:
* <pre>
* InputMap am = new InputMap();
* InputMap bm = new InputMap():
* am.setParent(bm);
* bm.setParent(am);
* </pre>
* some of the methods will cause a StackOverflowError to be thrown.
*
* @author Scott Violet
* @since 1.3
*/
@SuppressWarnings("serial")
public class InputMap implements Serializable {
/** Handles the mapping between KeyStroke and Action name. */
private transient ArrayTable arrayTable;
/** Parent that handles any bindings we don't contain. */
private InputMap parent;
/**
* Creates an <code>InputMap</code> with no parent and no mappings.
*/
public InputMap() {
}
/**
* Sets this <code>InputMap</code>'s parent.
*
* @param map the <code>InputMap</code> that is the parent of this one
*/
public void setParent(InputMap map) {
this.parent = map;
}
/**
* Gets this <code>InputMap</code>'s parent.
*
* @return map the <code>InputMap</code> that is the parent of this one,
* or null if this <code>InputMap</code> has no parent
*/
public InputMap getParent() {
return parent;
}
/**
* Adds a binding for <code>keyStroke</code> to <code>actionMapKey</code>.
* If <code>actionMapKey</code> is null, this removes the current binding
* for <code>keyStroke</code>.
*/
public void put(KeyStroke keyStroke, Object actionMapKey) {
if (keyStroke == null) {
return;
}
if (actionMapKey == null) {
remove(keyStroke);
}
else {
if (arrayTable == null) {
arrayTable = new ArrayTable();
}
arrayTable.put(keyStroke, actionMapKey);
}
}
/**
* Returns the binding for <code>keyStroke</code>, messaging the
* parent <code>InputMap</code> if the binding is not locally defined.
*/
public Object get(KeyStroke keyStroke) {
if (arrayTable == null) {
InputMap parent = getParent();
if (parent != null) {
return parent.get(keyStroke);
}
return null;
}
Object value = arrayTable.get(keyStroke);
if (value == null) {
InputMap parent = getParent();
if (parent != null) {
return parent.get(keyStroke);
}
}
return value;
}
/**
* Removes the binding for <code>key</code> from this
* <code>InputMap</code>.
*/
public void remove(KeyStroke key) {
if (arrayTable != null) {
arrayTable.remove(key);
}
}
/**
* Removes all the mappings from this <code>InputMap</code>.
*/
public void clear() {
if (arrayTable != null) {
arrayTable.clear();
}
}
/**
* Returns the <code>KeyStroke</code>s that are bound in this <code>InputMap</code>.
*/
public KeyStroke[] keys() {
if (arrayTable == null) {
return null;
}
KeyStroke[] keys = new KeyStroke[arrayTable.size()];
arrayTable.getKeys(keys);
return keys;
}
/**
* Returns the number of <code>KeyStroke</code> bindings.
*/
public int size() {
if (arrayTable == null) {
return 0;
}
return arrayTable.size();
}
/**
* Returns an array of the <code>KeyStroke</code>s defined in this
* <code>InputMap</code> and its parent. This differs from <code>keys()</code> in that
* this method includes the keys defined in the parent.
*/
public KeyStroke[] allKeys() {
int count = size();
InputMap parent = getParent();
if (count == 0) {
if (parent != null) {
return parent.allKeys();
}
return keys();
}
if (parent == null) {
return keys();
}
KeyStroke[] keys = keys();
KeyStroke[] pKeys = parent.allKeys();
if (pKeys == null) {
return keys;
}
if (keys == null) {
// Should only happen if size() != keys.length, which should only
// happen if mutated from multiple threads (or a bogus subclass).
return pKeys;
}
HashMap<KeyStroke, KeyStroke> keyMap = new HashMap<KeyStroke, KeyStroke>();
int counter;
for (counter = keys.length - 1; counter >= 0; counter--) {
keyMap.put(keys[counter], keys[counter]);
}
for (counter = pKeys.length - 1; counter >= 0; counter--) {
keyMap.put(pKeys[counter], pKeys[counter]);
}
KeyStroke[] allKeys = new KeyStroke[keyMap.size()];
return keyMap.keySet().toArray(allKeys);
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
ArrayTable.writeArrayTable(s, arrayTable);
}
private void readObject(ObjectInputStream s) throws ClassNotFoundException,
IOException {
s.defaultReadObject();
for (int counter = s.readInt() - 1; counter >= 0; counter--) {
put((KeyStroke)s.readObject(), s.readObject());
}
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.*;
/**
* The purpose of this class is to help clients support smooth focus
* navigation through GUIs with text fields. Such GUIs often need
* to ensure that the text entered by the user is valid (for example,
* that it's in
* the proper format) before allowing the user to navigate out of
* the text field. To do this, clients create a subclass of
* <code>InputVerifier</code> and, using <code>JComponent</code>'s
* <code>setInputVerifier</code> method,
* attach an instance of their subclass to the <code>JComponent</code> whose input they
* want to validate. Before focus is transfered to another Swing component
* that requests it, the input verifier's <code>shouldYieldFocus</code> method is
* called. Focus is transfered only if that method returns <code>true</code>.
* <p>
* The following example has two text fields, with the first one expecting
* the string "pass" to be entered by the user. If that string is entered in
* the first text field, then the user can advance to the second text field
* either by clicking in it or by pressing TAB. However, if another string
* is entered in the first text field, then the user will be unable to
* transfer focus to the second text field.
*
* <pre>
* import java.awt.*;
* import java.util.*;
* import java.awt.event.*;
* import javax.swing.*;
*
* // This program demonstrates the use of the Swing InputVerifier class.
* // It creates two text fields; the first of the text fields expects the
* // string "pass" as input, and will allow focus to advance out of it
* // only after that string is typed in by the user.
*
* public class VerifierTest extends JFrame {
* public VerifierTest() {
* JTextField tf1 = new JTextField ("Type \"pass\" here");
* getContentPane().add (tf1, BorderLayout.NORTH);
* tf1.setInputVerifier(new PassVerifier());
*
* JTextField tf2 = new JTextField ("TextField2");
* getContentPane().add (tf2, BorderLayout.SOUTH);
*
* WindowListener l = new WindowAdapter() {
* public void windowClosing(WindowEvent e) {
* System.exit(0);
* }
* };
* addWindowListener(l);
* }
*
* class PassVerifier extends InputVerifier {
* public boolean verify(JComponent input) {
* JTextField tf = (JTextField) input;
* return "pass".equals(tf.getText());
* }
* }
*
* public static void main(String[] args) {
* Frame f = new VerifierTest();
* f.pack();
* f.setVisible(true);
* }
* }
* </pre>
*
* @since 1.3
*/
public abstract class InputVerifier {
/**
* Checks whether the JComponent's input is valid. This method should
* have no side effects. It returns a boolean indicating the status
* of the argument's input.
*
* @param input the JComponent to verify
* @return <code>true</code> when valid, <code>false</code> when invalid
* @see JComponent#setInputVerifier
* @see JComponent#getInputVerifier
*
*/
public abstract boolean verify(JComponent input);
/**
* Calls <code>verify(input)</code> to ensure that the input is valid.
* This method can have side effects. In particular, this method
* is called when the user attempts to advance focus out of the
* argument component into another Swing component in this window.
* If this method returns <code>true</code>, then the focus is transfered
* normally; if it returns <code>false</code>, then the focus remains in
* the argument component.
*
* @param input the JComponent to verify
* @return <code>true</code> when valid, <code>false</code> when invalid
* @see JComponent#setInputVerifier
* @see JComponent#getInputVerifier
*
*/
public boolean shouldYieldFocus(JComponent input) {
return verify(input);
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Component;
import java.awt.FocusTraversalPolicy;
/**
* A FocusTraversalPolicy which can optionally provide an algorithm for
* determining a JInternalFrame's initial Component. The initial Component is
* the first to receive focus when the JInternalFrame is first selected. By
* default, this is the same as the JInternalFrame's default Component to
* focus.
*
* @author David Mendenhall
*
* @since 1.4
*/
public abstract class InternalFrameFocusTraversalPolicy
extends FocusTraversalPolicy
{
/**
* Returns the Component that should receive the focus when a
* JInternalFrame is selected for the first time. Once the JInternalFrame
* has been selected by a call to <code>setSelected(true)</code>, the
* initial Component will not be used again. Instead, if the JInternalFrame
* loses and subsequently regains selection, or is made invisible or
* undisplayable and subsequently made visible and displayable, the
* JInternalFrame's most recently focused Component will become the focus
* owner. The default implementation of this method returns the
* JInternalFrame's default Component to focus.
*
* @param frame the JInternalFrame whose initial Component is to be
* returned
* @return the Component that should receive the focus when frame is
* selected for the first time, or null if no suitable Component
* can be found
* @see JInternalFrame#getMostRecentFocusOwner
* @throws IllegalArgumentException if window is null
*/
public Component getInitialComponent(JInternalFrame frame) {
return getDefaultComponent(frame);
}
}

View File

@@ -0,0 +1,568 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.beans.PropertyChangeListener;
import java.util.Locale;
import java.util.Vector;
import java.io.Serializable;
import javax.accessibility.*;
/**
* An extended version of <code>java.applet.Applet</code> that adds support for
* the JFC/Swing component architecture.
* You can find task-oriented documentation about using <code>JApplet</code>
* in <em>The Java Tutorial</em>,
* in the section
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/applet.html">How to Make Applets</a>.
* <p>
* The <code>JApplet</code> class is slightly incompatible with
* <code>java.applet.Applet</code>. <code>JApplet</code> contains a
* <code>JRootPane</code> as its only child. The <code>contentPane</code>
* should be the parent of any children of the <code>JApplet</code>.
* As a convenience, the {@code add}, {@code remove}, and {@code setLayout}
* methods of this class are overridden, so that they delegate calls
* to the corresponding methods of the {@code ContentPane}.
* For example, you can add a child component to an applet as follows:
* <pre>
* applet.add(child);
* </pre>
*
* And the child will be added to the <code>contentPane</code>.
* The <code>contentPane</code> will always be non-<code>null</code>.
* Attempting to set it to <code>null</code> will cause the
* <code>JApplet</code> to throw an exception. The default
* <code>contentPane</code> will have a <code>BorderLayout</code>
* manager set on it.
* Refer to {@link javax.swing.RootPaneContainer}
* for details on adding, removing and setting the <code>LayoutManager</code>
* of a <code>JApplet</code>.
* <p>
* Please see the <code>JRootPane</code> documentation for a
* complete description of the <code>contentPane</code>, <code>glassPane</code>,
* and <code>layeredPane</code> properties.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see javax.swing.RootPaneContainer
* @beaninfo
* attribute: isContainer true
* attribute: containerDelegate getContentPane
* description: Swing's Applet subclass.
*
* @author Arnaud Weber
*/
public class JApplet extends Applet implements Accessible,
RootPaneContainer,
TransferHandler.HasGetTransferHandler
{
/**
* @see #getRootPane
* @see #setRootPane
*/
protected JRootPane rootPane;
/**
* If true then calls to <code>add</code> and <code>setLayout</code>
* will be forwarded to the <code>contentPane</code>. This is initially
* false, but is set to true when the <code>JApplet</code> is constructed.
*
* @see #isRootPaneCheckingEnabled
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected boolean rootPaneCheckingEnabled = false;
/**
* The <code>TransferHandler</code> for this applet.
*/
private TransferHandler transferHandler;
/**
* Creates a swing applet instance.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see JComponent#getDefaultLocale
*/
public JApplet() throws HeadlessException {
super();
// Check the timerQ and restart if necessary.
TimerQueue q = TimerQueue.sharedInstance();
if(q != null) {
q.startIfNeeded();
}
/* Workaround for bug 4155072. The shared double buffer image
* may hang on to a reference to this applet; unfortunately
* Image.getGraphics() will continue to call JApplet.getForeground()
* and getBackground() even after this applet has been destroyed.
* So we ensure that these properties are non-null here.
*/
setForeground(Color.black);
setBackground(Color.white);
setLocale( JComponent.getDefaultLocale() );
setLayout(new BorderLayout());
setRootPane(createRootPane());
setRootPaneCheckingEnabled(true);
setFocusTraversalPolicyProvider(true);
sun.awt.SunToolkit.checkAndSetPolicy(this);
enableEvents(AWTEvent.KEY_EVENT_MASK);
}
/** Called by the constructor methods to create the default rootPane. */
protected JRootPane createRootPane() {
JRootPane rp = new JRootPane();
// NOTE: this uses setOpaque vs LookAndFeel.installProperty as there
// is NO reason for the RootPane not to be opaque. For painting to
// work the contentPane must be opaque, therefor the RootPane can
// also be opaque.
rp.setOpaque(true);
return rp;
}
/**
* Sets the {@code transferHandler} property, which is a mechanism to
* support transfer of data into this component. Use {@code null}
* if the component does not support data transfer operations.
* <p>
* If the system property {@code suppressSwingDropSupport} is {@code false}
* (the default) and the current drop target on this component is either
* {@code null} or not a user-set drop target, this method will change the
* drop target as follows: If {@code newHandler} is {@code null} it will
* clear the drop target. If not {@code null} it will install a new
* {@code DropTarget}.
* <p>
* Note: When used with {@code JApplet}, {@code TransferHandler} only
* provides data import capability, as the data export related methods
* are currently typed to {@code JComponent}.
* <p>
* Please see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html">
* How to Use Drag and Drop and Data Transfer</a>, a section in
* <em>The Java Tutorial</em>, for more information.
*
* @param newHandler the new {@code TransferHandler}
*
* @see TransferHandler
* @see #getTransferHandler
* @see java.awt.Component#setDropTarget
* @since 1.6
*
* @beaninfo
* bound: true
* hidden: true
* description: Mechanism for transfer of data into the component
*/
public void setTransferHandler(TransferHandler newHandler) {
TransferHandler oldHandler = transferHandler;
transferHandler = newHandler;
SwingUtilities.installSwingDropTargetAsNecessary(this, transferHandler);
firePropertyChange("transferHandler", oldHandler, newHandler);
}
/**
* Gets the <code>transferHandler</code> property.
*
* @return the value of the <code>transferHandler</code> property
*
* @see TransferHandler
* @see #setTransferHandler
* @since 1.6
*/
public TransferHandler getTransferHandler() {
return transferHandler;
}
/**
* Just calls <code>paint(g)</code>. This method was overridden to
* prevent an unnecessary call to clear the background.
*/
public void update(Graphics g) {
paint(g);
}
/**
* Sets the menubar for this applet.
* @param menuBar the menubar being placed in the applet
*
* @see #getJMenuBar
*
* @beaninfo
* hidden: true
* description: The menubar for accessing pulldown menus from this applet.
*/
public void setJMenuBar(JMenuBar menuBar) {
getRootPane().setMenuBar(menuBar);
}
/**
* Returns the menubar set on this applet.
*
* @see #setJMenuBar
*/
public JMenuBar getJMenuBar() {
return getRootPane().getMenuBar();
}
/**
* Returns whether calls to <code>add</code> and
* <code>setLayout</code> are forwarded to the <code>contentPane</code>.
*
* @return true if <code>add</code> and <code>setLayout</code>
* are forwarded; false otherwise
*
* @see #addImpl
* @see #setLayout
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected boolean isRootPaneCheckingEnabled() {
return rootPaneCheckingEnabled;
}
/**
* Sets whether calls to <code>add</code> and
* <code>setLayout</code> are forwarded to the <code>contentPane</code>.
*
* @param enabled true if <code>add</code> and <code>setLayout</code>
* are forwarded, false if they should operate directly on the
* <code>JApplet</code>.
*
* @see #addImpl
* @see #setLayout
* @see #isRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
* @beaninfo
* hidden: true
* description: Whether the add and setLayout methods are forwarded
*/
protected void setRootPaneCheckingEnabled(boolean enabled) {
rootPaneCheckingEnabled = enabled;
}
/**
* Adds the specified child <code>Component</code>.
* This method is overridden to conditionally forward calls to the
* <code>contentPane</code>.
* By default, children are added to the <code>contentPane</code> instead
* of the frame, refer to {@link javax.swing.RootPaneContainer} for
* details.
*
* @param comp the component to be enhanced
* @param constraints the constraints to be respected
* @param index the index
* @exception IllegalArgumentException if <code>index</code> is invalid
* @exception IllegalArgumentException if adding the container's parent
* to itself
* @exception IllegalArgumentException if adding a window to a container
*
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected void addImpl(Component comp, Object constraints, int index)
{
if(isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else {
super.addImpl(comp, constraints, index);
}
}
/**
* Removes the specified component from the container. If
* <code>comp</code> is not the <code>rootPane</code>, this will forward
* the call to the <code>contentPane</code>. This will do nothing if
* <code>comp</code> is not a child of the <code>JFrame</code> or
* <code>contentPane</code>.
*
* @param comp the component to be removed
* @throws NullPointerException if <code>comp</code> is null
* @see #add
* @see javax.swing.RootPaneContainer
*/
public void remove(Component comp) {
if (comp == rootPane) {
super.remove(comp);
} else {
getContentPane().remove(comp);
}
}
/**
* Sets the <code>LayoutManager</code>.
* Overridden to conditionally forward the call to the
* <code>contentPane</code>.
* Refer to {@link javax.swing.RootPaneContainer} for
* more information.
*
* @param manager the <code>LayoutManager</code>
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
public void setLayout(LayoutManager manager) {
if(isRootPaneCheckingEnabled()) {
getContentPane().setLayout(manager);
}
else {
super.setLayout(manager);
}
}
/**
* Returns the rootPane object for this applet.
*
* @see #setRootPane
* @see RootPaneContainer#getRootPane
*/
public JRootPane getRootPane() {
return rootPane;
}
/**
* Sets the rootPane property. This method is called by the constructor.
* @param root the rootPane object for this applet
*
* @see #getRootPane
*
* @beaninfo
* hidden: true
* description: the RootPane object for this applet.
*/
protected void setRootPane(JRootPane root) {
if(rootPane != null) {
remove(rootPane);
}
rootPane = root;
if(rootPane != null) {
boolean checkingEnabled = isRootPaneCheckingEnabled();
try {
setRootPaneCheckingEnabled(false);
add(rootPane, BorderLayout.CENTER);
}
finally {
setRootPaneCheckingEnabled(checkingEnabled);
}
}
}
/**
* Returns the contentPane object for this applet.
*
* @see #setContentPane
* @see RootPaneContainer#getContentPane
*/
public Container getContentPane() {
return getRootPane().getContentPane();
}
/**
* Sets the contentPane property. This method is called by the constructor.
* @param contentPane the contentPane object for this applet
*
* @exception java.awt.IllegalComponentStateException (a runtime
* exception) if the content pane parameter is null
* @see #getContentPane
* @see RootPaneContainer#setContentPane
*
* @beaninfo
* hidden: true
* description: The client area of the applet where child
* components are normally inserted.
*/
public void setContentPane(Container contentPane) {
getRootPane().setContentPane(contentPane);
}
/**
* Returns the layeredPane object for this applet.
*
* @exception java.awt.IllegalComponentStateException (a runtime
* exception) if the layered pane parameter is null
* @see #setLayeredPane
* @see RootPaneContainer#getLayeredPane
*/
public JLayeredPane getLayeredPane() {
return getRootPane().getLayeredPane();
}
/**
* Sets the layeredPane property. This method is called by the constructor.
* @param layeredPane the layeredPane object for this applet
*
* @see #getLayeredPane
* @see RootPaneContainer#setLayeredPane
*
* @beaninfo
* hidden: true
* description: The pane which holds the various applet layers.
*/
public void setLayeredPane(JLayeredPane layeredPane) {
getRootPane().setLayeredPane(layeredPane);
}
/**
* Returns the glassPane object for this applet.
*
* @see #setGlassPane
* @see RootPaneContainer#getGlassPane
*/
public Component getGlassPane() {
return getRootPane().getGlassPane();
}
/**
* Sets the glassPane property.
* This method is called by the constructor.
* @param glassPane the glassPane object for this applet
*
* @see #getGlassPane
* @see RootPaneContainer#setGlassPane
*
* @beaninfo
* hidden: true
* description: A transparent pane used for menu rendering.
*/
public void setGlassPane(Component glassPane) {
getRootPane().setGlassPane(glassPane);
}
/**
* {@inheritDoc}
*
* @since 1.6
*/
public Graphics getGraphics() {
JComponent.getGraphicsInvoked(this);
return super.getGraphics();
}
/**
* Repaints the specified rectangle of this component within
* <code>time</code> milliseconds. Refer to <code>RepaintManager</code>
* for details on how the repaint is handled.
*
* @param time maximum time in milliseconds before update
* @param x the <i>x</i> coordinate
* @param y the <i>y</i> coordinate
* @param width the width
* @param height the height
* @see RepaintManager
* @since 1.6
*/
public void repaint(long time, int x, int y, int width, int height) {
if (RepaintManager.HANDLE_TOP_LEVEL_PAINT) {
RepaintManager.currentManager(this).addDirtyRegion(
this, x, y, width, height);
}
else {
super.repaint(time, x, y, width, height);
}
}
/**
* Returns a string representation of this JApplet. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JApplet.
*/
protected String paramString() {
String rootPaneString = (rootPane != null ?
rootPane.toString() : "");
String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ?
"true" : "false");
return super.paramString() +
",rootPane=" + rootPaneString +
",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString;
}
/////////////////
// Accessibility support
////////////////
protected AccessibleContext accessibleContext = null;
/**
* Gets the AccessibleContext associated with this JApplet.
* For JApplets, the AccessibleContext takes the form of an
* AccessibleJApplet.
* A new AccessibleJApplet instance is created if necessary.
*
* @return an AccessibleJApplet that serves as the
* AccessibleContext of this JApplet
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJApplet();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JApplet</code> class.
*/
protected class AccessibleJApplet extends AccessibleApplet {
// everything moved to new parent, AccessibleApplet
}
}

View File

@@ -0,0 +1,325 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.beans.ConstructorProperties;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.plaf.*;
import javax.swing.event.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* An implementation of a "push" button.
* <p>
* Buttons can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a button has many benefits beyond directly
* configuring a button. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* See <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>
* in <em>The Java Tutorial</em>
* for information and examples of using buttons.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: An implementation of a \"push\" button.
*
* @author Jeff Dinkins
*/
@SuppressWarnings("serial")
public class JButton extends AbstractButton implements Accessible {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "ButtonUI";
/**
* Creates a button with no set text or icon.
*/
public JButton() {
this(null, null);
}
/**
* Creates a button with an icon.
*
* @param icon the Icon image to display on the button
*/
public JButton(Icon icon) {
this(null, icon);
}
/**
* Creates a button with text.
*
* @param text the text of the button
*/
@ConstructorProperties({"text"})
public JButton(String text) {
this(text, null);
}
/**
* Creates a button where properties are taken from the
* <code>Action</code> supplied.
*
* @param a the <code>Action</code> used to specify the new button
*
* @since 1.3
*/
public JButton(Action a) {
this();
setAction(a);
}
/**
* Creates a button with initial text and an icon.
*
* @param text the text of the button
* @param icon the Icon image to display on the button
*/
public JButton(String text, Icon icon) {
// Create the model
setModel(new DefaultButtonModel());
// initialize
init(text, icon);
}
/**
* Resets the UI property to a value from the current look and
* feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ButtonUI)UIManager.getUI(this));
}
/**
* Returns a string that specifies the name of the L&amp;F class
* that renders this component.
*
* @return the string "ButtonUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
* @beaninfo
* expert: true
* description: A string that specifies the name of the L&amp;F class.
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Gets the value of the <code>defaultButton</code> property,
* which if <code>true</code> means that this button is the current
* default button for its <code>JRootPane</code>.
* Most look and feels render the default button
* differently, and may potentially provide bindings
* to access the default button.
*
* @return the value of the <code>defaultButton</code> property
* @see JRootPane#setDefaultButton
* @see #isDefaultCapable
* @beaninfo
* description: Whether or not this button is the default button
*/
public boolean isDefaultButton() {
JRootPane root = SwingUtilities.getRootPane(this);
if (root != null) {
return root.getDefaultButton() == this;
}
return false;
}
/**
* Gets the value of the <code>defaultCapable</code> property.
*
* @return the value of the <code>defaultCapable</code> property
* @see #setDefaultCapable
* @see #isDefaultButton
* @see JRootPane#setDefaultButton
*/
public boolean isDefaultCapable() {
return defaultCapable;
}
/**
* Sets the <code>defaultCapable</code> property,
* which determines whether this button can be
* made the default button for its root pane.
* The default value of the <code>defaultCapable</code>
* property is <code>true</code> unless otherwise
* specified by the look and feel.
*
* @param defaultCapable <code>true</code> if this button will be
* capable of being the default button on the
* <code>RootPane</code>; otherwise <code>false</code>
* @see #isDefaultCapable
* @beaninfo
* bound: true
* attribute: visualUpdate true
* description: Whether or not this button can be the default button
*/
public void setDefaultCapable(boolean defaultCapable) {
boolean oldDefaultCapable = this.defaultCapable;
this.defaultCapable = defaultCapable;
firePropertyChange("defaultCapable", oldDefaultCapable, defaultCapable);
}
/**
* Overrides <code>JComponent.removeNotify</code> to check if
* this button is currently set as the default button on the
* <code>RootPane</code>, and if so, sets the <code>RootPane</code>'s
* default button to <code>null</code> to ensure the
* <code>RootPane</code> doesn't hold onto an invalid button reference.
*/
public void removeNotify() {
JRootPane root = SwingUtilities.getRootPane(this);
if (root != null && root.getDefaultButton() == this) {
root.setDefaultButton(null);
}
super.removeNotify();
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this <code>JButton</code>.
* This method is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JButton</code>
*/
protected String paramString() {
String defaultCapableString = (defaultCapable ? "true" : "false");
return super.paramString() +
",defaultCapable=" + defaultCapableString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the <code>AccessibleContext</code> associated with this
* <code>JButton</code>. For <code>JButton</code>s,
* the <code>AccessibleContext</code> takes the form of an
* <code>AccessibleJButton</code>.
* A new <code>AccessibleJButton</code> instance is created if necessary.
*
* @return an <code>AccessibleJButton</code> that serves as the
* <code>AccessibleContext</code> of this <code>JButton</code>
* @beaninfo
* expert: true
* description: The AccessibleContext associated with this Button.
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJButton();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JButton</code> class. It provides an implementation of the
* Java Accessibility API appropriate to button user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
protected class AccessibleJButton extends AccessibleAbstractButton {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PUSH_BUTTON;
}
} // inner class AccessibleJButton
}

View File

@@ -0,0 +1,350 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* An implementation of a check box -- an item that can be selected or
* deselected, and which displays its state to the user.
* By convention, any number of check boxes in a group can be selected.
* See <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>
* in <em>The Java Tutorial</em>
* for examples and information on using check boxes.
* <p>
* Buttons can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a button has many benefits beyond directly
* configuring a button. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JRadioButton
*
* @beaninfo
* attribute: isContainer false
* description: A component which can be selected or deselected.
*
* @author Jeff Dinkins
*/
public class JCheckBox extends JToggleButton implements Accessible {
/** Identifies a change to the flat property. */
public static final String BORDER_PAINTED_FLAT_CHANGED_PROPERTY = "borderPaintedFlat";
private boolean flat = false;
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "CheckBoxUI";
/**
* Creates an initially unselected check box button with no text, no icon.
*/
public JCheckBox () {
this(null, null, false);
}
/**
* Creates an initially unselected check box with an icon.
*
* @param icon the Icon image to display
*/
public JCheckBox(Icon icon) {
this(null, icon, false);
}
/**
* Creates a check box with an icon and specifies whether
* or not it is initially selected.
*
* @param icon the Icon image to display
* @param selected a boolean value indicating the initial selection
* state. If <code>true</code> the check box is selected
*/
public JCheckBox(Icon icon, boolean selected) {
this(null, icon, selected);
}
/**
* Creates an initially unselected check box with text.
*
* @param text the text of the check box.
*/
public JCheckBox (String text) {
this(text, null, false);
}
/**
* Creates a check box where properties are taken from the
* Action supplied.
*
* @since 1.3
*/
public JCheckBox(Action a) {
this();
setAction(a);
}
/**
* Creates a check box with text and specifies whether
* or not it is initially selected.
*
* @param text the text of the check box.
* @param selected a boolean value indicating the initial selection
* state. If <code>true</code> the check box is selected
*/
public JCheckBox (String text, boolean selected) {
this(text, null, selected);
}
/**
* Creates an initially unselected check box with
* the specified text and icon.
*
* @param text the text of the check box.
* @param icon the Icon image to display
*/
public JCheckBox(String text, Icon icon) {
this(text, icon, false);
}
/**
* Creates a check box with text and icon,
* and specifies whether or not it is initially selected.
*
* @param text the text of the check box.
* @param icon the Icon image to display
* @param selected a boolean value indicating the initial selection
* state. If <code>true</code> the check box is selected
*/
public JCheckBox (String text, Icon icon, boolean selected) {
super(text, icon, selected);
setUIProperty("borderPainted", Boolean.FALSE);
setHorizontalAlignment(LEADING);
}
/**
* Sets the <code>borderPaintedFlat</code> property,
* which gives a hint to the look and feel as to the
* appearance of the check box border.
* This is usually set to <code>true</code> when a
* <code>JCheckBox</code> instance is used as a
* renderer in a component such as a <code>JTable</code> or
* <code>JTree</code>. The default value for the
* <code>borderPaintedFlat</code> property is <code>false</code>.
* This method fires a property changed event.
* Some look and feels might not implement flat borders;
* they will ignore this property.
*
* @param b <code>true</code> requests that the border be painted flat;
* <code>false</code> requests normal borders
* @see #isBorderPaintedFlat
* @beaninfo
* bound: true
* attribute: visualUpdate true
* description: Whether the border is painted flat.
* @since 1.3
*/
public void setBorderPaintedFlat(boolean b) {
boolean oldValue = flat;
flat = b;
firePropertyChange(BORDER_PAINTED_FLAT_CHANGED_PROPERTY, oldValue, flat);
if (b != oldValue) {
revalidate();
repaint();
}
}
/**
* Gets the value of the <code>borderPaintedFlat</code> property.
*
* @return the value of the <code>borderPaintedFlat</code> property
* @see #setBorderPaintedFlat
* @since 1.3
*/
public boolean isBorderPaintedFlat() {
return flat;
}
/**
* Resets the UI property to a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ButtonUI)UIManager.getUI(this));
}
/**
* Returns a string that specifies the name of the L&amp;F class
* that renders this component.
*
* @return the string "CheckBoxUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
* @beaninfo
* expert: true
* description: A string that specifies the name of the L&amp;F class
*/
public String getUIClassID() {
return uiClassID;
}
/**
* The icon for checkboxs comes from the look and feel,
* not the Action; this is overriden to do nothing.
*/
void setIconFromAction(Action a) {
}
/*
* See readObject and writeObject in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* See JComponent.readObject() for information about serialization
* in Swing.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
if (getUIClassID().equals(uiClassID)) {
updateUI();
}
}
/**
* Returns a string representation of this JCheckBox. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
* specific new aspects of the JFC components.
*
* @return a string representation of this JCheckBox.
*/
protected String paramString() {
return super.paramString();
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JCheckBox.
* For JCheckBoxes, the AccessibleContext takes the form of an
* AccessibleJCheckBox.
* A new AccessibleJCheckBox instance is created if necessary.
*
* @return an AccessibleJCheckBox that serves as the
* AccessibleContext of this JCheckBox
* @beaninfo
* expert: true
* description: The AccessibleContext associated with this CheckBox.
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJCheckBox();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JCheckBox</code> class. It provides an implementation of the
* Java Accessibility API appropriate to check box user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJCheckBox extends AccessibleJToggleButton {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.CHECK_BOX;
}
} // inner class AccessibleJCheckBox
}

View File

@@ -0,0 +1,307 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.EventListener;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import javax.swing.plaf.*;
import javax.accessibility.*;
/**
* A menu item that can be selected or deselected. If selected, the menu
* item typically appears with a checkmark next to it. If unselected or
* deselected, the menu item appears without a checkmark. Like a regular
* menu item, a check box menu item can have either text or a graphic
* icon associated with it, or both.
* <p>
* Either <code>isSelected</code>/<code>setSelected</code> or
* <code>getState</code>/<code>setState</code> can be used
* to determine/specify the menu item's selection state. The
* preferred methods are <code>isSelected</code> and
* <code>setSelected</code>, which work for all menus and buttons.
* The <code>getState</code> and <code>setState</code> methods exist for
* compatibility with other component sets.
* <p>
* Menu items can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a menu item has many benefits beyond directly
* configuring a menu item. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* For further information and examples of using check box menu items,
* see <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: A menu item which can be selected or deselected.
*
* @author Georges Saab
* @author David Karlton
*/
public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
Accessible
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "CheckBoxMenuItemUI";
/**
* Creates an initially unselected check box menu item with no set text or icon.
*/
public JCheckBoxMenuItem() {
this(null, null, false);
}
/**
* Creates an initially unselected check box menu item with an icon.
*
* @param icon the icon of the CheckBoxMenuItem.
*/
public JCheckBoxMenuItem(Icon icon) {
this(null, icon, false);
}
/**
* Creates an initially unselected check box menu item with text.
*
* @param text the text of the CheckBoxMenuItem
*/
public JCheckBoxMenuItem(String text) {
this(text, null, false);
}
/**
* Creates a menu item whose properties are taken from the
* Action supplied.
*
* @since 1.3
*/
public JCheckBoxMenuItem(Action a) {
this();
setAction(a);
}
/**
* Creates an initially unselected check box menu item with the specified text and icon.
*
* @param text the text of the CheckBoxMenuItem
* @param icon the icon of the CheckBoxMenuItem
*/
public JCheckBoxMenuItem(String text, Icon icon) {
this(text, icon, false);
}
/**
* Creates a check box menu item with the specified text and selection state.
*
* @param text the text of the check box menu item.
* @param b the selected state of the check box menu item
*/
public JCheckBoxMenuItem(String text, boolean b) {
this(text, null, b);
}
/**
* Creates a check box menu item with the specified text, icon, and selection state.
*
* @param text the text of the check box menu item
* @param icon the icon of the check box menu item
* @param b the selected state of the check box menu item
*/
public JCheckBoxMenuItem(String text, Icon icon, boolean b) {
super(text, icon);
setModel(new JToggleButton.ToggleButtonModel());
setSelected(b);
setFocusable(false);
}
/**
* Returns the name of the L&amp;F class
* that renders this component.
*
* @return "CheckBoxMenuItemUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Returns the selected-state of the item. This method
* exists for AWT compatibility only. New code should
* use isSelected() instead.
*
* @return true if the item is selected
*/
public boolean getState() {
return isSelected();
}
/**
* Sets the selected-state of the item. This method
* exists for AWT compatibility only. New code should
* use setSelected() instead.
*
* @param b a boolean value indicating the item's
* selected-state, where true=selected
* @beaninfo
* description: The selection state of the check box menu item
* hidden: true
*/
public synchronized void setState(boolean b) {
setSelected(b);
}
/**
* Returns an array (length 1) containing the check box menu item
* label or null if the check box is not selected.
*
* @return an array containing one Object -- the text of the menu item
* -- if the item is selected; otherwise null
*/
public Object[] getSelectedObjects() {
if (isSelected() == false)
return null;
Object[] selectedObjects = new Object[1];
selectedObjects[0] = getText();
return selectedObjects;
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this JCheckBoxMenuItem. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JCheckBoxMenuItem.
*/
protected String paramString() {
return super.paramString();
}
/**
* Overriden to return true, JCheckBoxMenuItem supports
* the selected state.
*/
boolean shouldUpdateSelectedStateFromAction() {
return true;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JCheckBoxMenuItem.
* For JCheckBoxMenuItems, the AccessibleContext takes the form of an
* AccessibleJCheckBoxMenuItem.
* A new AccessibleJCheckBoxMenuItem instance is created if necessary.
*
* @return an AccessibleJCheckBoxMenuItem that serves as the
* AccessibleContext of this AccessibleJCheckBoxMenuItem
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJCheckBoxMenuItem();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JCheckBoxMenuItem</code> class. It provides an implementation
* of the Java Accessibility API appropriate to checkbox menu item
* user-interface elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJCheckBoxMenuItem extends AccessibleJMenuItem {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.CHECK_BOX;
}
} // inner class AccessibleJCheckBoxMenuItem
}

View File

@@ -0,0 +1,763 @@
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.colorchooser.*;
import javax.swing.plaf.ColorChooserUI;
import javax.accessibility.*;
import sun.swing.SwingUtilities2;
/**
* <code>JColorChooser</code> provides a pane of controls designed to allow
* a user to manipulate and select a color.
* For information about using color choosers, see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/colorchooser.html">How to Use Color Choosers</a>,
* a section in <em>The Java Tutorial</em>.
*
* <p>
*
* This class provides three levels of API:
* <ol>
* <li>A static convenience method which shows a modal color-chooser
* dialog and returns the color selected by the user.
* <li>A static convenience method for creating a color-chooser dialog
* where <code>ActionListeners</code> can be specified to be invoked when
* the user presses one of the dialog buttons.
* <li>The ability to create instances of <code>JColorChooser</code> panes
* directly (within any container). <code>PropertyChange</code> listeners
* can be added to detect when the current "color" property changes.
* </ol>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
*
* @beaninfo
* attribute: isContainer false
* description: A component that supports selecting a Color.
*
*
* @author James Gosling
* @author Amy Fowler
* @author Steve Wilson
*/
public class JColorChooser extends JComponent implements Accessible {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "ColorChooserUI";
private ColorSelectionModel selectionModel;
private JComponent previewPanel = ColorChooserComponentFactory.getPreviewPanel();
private AbstractColorChooserPanel[] chooserPanels = new AbstractColorChooserPanel[0];
private boolean dragEnabled;
/**
* The selection model property name.
*/
public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
/**
* The preview panel property name.
*/
public static final String PREVIEW_PANEL_PROPERTY = "previewPanel";
/**
* The chooserPanel array property name.
*/
public static final String CHOOSER_PANELS_PROPERTY = "chooserPanels";
/**
* Shows a modal color-chooser dialog and blocks until the
* dialog is hidden. If the user presses the "OK" button, then
* this method hides/disposes the dialog and returns the selected color.
* If the user presses the "Cancel" button or closes the dialog without
* pressing "OK", then this method hides/disposes the dialog and returns
* <code>null</code>.
*
* @param component the parent <code>Component</code> for the dialog
* @param title the String containing the dialog's title
* @param initialColor the initial Color set when the color-chooser is shown
* @return the selected color or <code>null</code> if the user opted out
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static Color showDialog(Component component,
String title, Color initialColor) throws HeadlessException {
final JColorChooser pane = new JColorChooser(initialColor != null?
initialColor : Color.white);
ColorTracker ok = new ColorTracker(pane);
JDialog dialog = createDialog(component, title, true, pane, ok, null);
dialog.addComponentListener(new ColorChooserDialog.DisposeOnClose());
dialog.show(); // blocks until user brings dialog down...
return ok.getColor();
}
/**
* Creates and returns a new dialog containing the specified
* <code>ColorChooser</code> pane along with "OK", "Cancel", and "Reset"
* buttons. If the "OK" or "Cancel" buttons are pressed, the dialog is
* automatically hidden (but not disposed). If the "Reset"
* button is pressed, the color-chooser's color will be reset to the
* color which was set the last time <code>show</code> was invoked on the
* dialog and the dialog will remain showing.
*
* @param c the parent component for the dialog
* @param title the title for the dialog
* @param modal a boolean. When true, the remainder of the program
* is inactive until the dialog is closed.
* @param chooserPane the color-chooser to be placed inside the dialog
* @param okListener the ActionListener invoked when "OK" is pressed
* @param cancelListener the ActionListener invoked when "Cancel" is pressed
* @return a new dialog containing the color-chooser pane
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
*/
public static JDialog createDialog(Component c, String title, boolean modal,
JColorChooser chooserPane, ActionListener okListener,
ActionListener cancelListener) throws HeadlessException {
Window window = JOptionPane.getWindowForComponent(c);
ColorChooserDialog dialog;
if (window instanceof Frame) {
dialog = new ColorChooserDialog((Frame)window, title, modal, c, chooserPane,
okListener, cancelListener);
} else {
dialog = new ColorChooserDialog((Dialog)window, title, modal, c, chooserPane,
okListener, cancelListener);
}
dialog.getAccessibleContext().setAccessibleDescription(title);
return dialog;
}
/**
* Creates a color chooser pane with an initial color of white.
*/
public JColorChooser() {
this(Color.white);
}
/**
* Creates a color chooser pane with the specified initial color.
*
* @param initialColor the initial color set in the chooser
*/
public JColorChooser(Color initialColor) {
this( new DefaultColorSelectionModel(initialColor) );
}
/**
* Creates a color chooser pane with the specified
* <code>ColorSelectionModel</code>.
*
* @param model the <code>ColorSelectionModel</code> to be used
*/
public JColorChooser(ColorSelectionModel model) {
selectionModel = model;
updateUI();
dragEnabled = false;
}
/**
* Returns the L&amp;F object that renders this component.
*
* @return the <code>ColorChooserUI</code> object that renders
* this component
*/
public ColorChooserUI getUI() {
return (ColorChooserUI)ui;
}
/**
* Sets the L&amp;F object that renders this component.
*
* @param ui the <code>ColorChooserUI</code> L&amp;F object
* @see UIDefaults#getUI
*
* @beaninfo
* bound: true
* hidden: true
* description: The UI object that implements the color chooser's LookAndFeel.
*/
public void setUI(ColorChooserUI ui) {
super.setUI(ui);
}
/**
* Notification from the <code>UIManager</code> that the L&amp;F has changed.
* Replaces the current UI object with the latest version from the
* <code>UIManager</code>.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ColorChooserUI)UIManager.getUI(this));
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "ColorChooserUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Gets the current color value from the color chooser.
* By default, this delegates to the model.
*
* @return the current color value of the color chooser
*/
public Color getColor() {
return selectionModel.getSelectedColor();
}
/**
* Sets the current color of the color chooser to the specified color.
* The <code>ColorSelectionModel</code> will fire a <code>ChangeEvent</code>
* @param color the color to be set in the color chooser
* @see JComponent#addPropertyChangeListener
*
* @beaninfo
* bound: false
* hidden: false
* description: The current color the chooser is to display.
*/
public void setColor(Color color) {
selectionModel.setSelectedColor(color);
}
/**
* Sets the current color of the color chooser to the
* specified RGB color. Note that the values of red, green,
* and blue should be between the numbers 0 and 255, inclusive.
*
* @param r an int specifying the amount of Red
* @param g an int specifying the amount of Green
* @param b an int specifying the amount of Blue
* @exception IllegalArgumentException if r,g,b values are out of range
* @see java.awt.Color
*/
public void setColor(int r, int g, int b) {
setColor(new Color(r,g,b));
}
/**
* Sets the current color of the color chooser to the
* specified color.
*
* @param c an integer value that sets the current color in the chooser
* where the low-order 8 bits specify the Blue value,
* the next 8 bits specify the Green value, and the 8 bits
* above that specify the Red value.
*/
public void setColor(int c) {
setColor((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);
}
/**
* Sets the <code>dragEnabled</code> property,
* which must be <code>true</code> to enable
* automatic drag handling (the first part of drag and drop)
* on this component.
* The <code>transferHandler</code> property needs to be set
* to a non-<code>null</code> value for the drag to do
* anything. The default value of the <code>dragEnabled</code>
* property
* is <code>false</code>.
*
* <p>
*
* When automatic drag handling is enabled,
* most look and feels begin a drag-and-drop operation
* when the user presses the mouse button over the preview panel.
* Some look and feels might not support automatic drag and drop;
* they will ignore this property. You can work around such
* look and feels by modifying the component
* to directly call the <code>exportAsDrag</code> method of a
* <code>TransferHandler</code>.
*
* @param b the value to set the <code>dragEnabled</code> property to
* @exception HeadlessException if
* <code>b</code> is <code>true</code> and
* <code>GraphicsEnvironment.isHeadless()</code>
* returns <code>true</code>
*
* @since 1.4
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see #getDragEnabled
* @see #setTransferHandler
* @see TransferHandler
*
* @beaninfo
* description: Determines whether automatic drag handling is enabled.
* bound: false
*/
public void setDragEnabled(boolean b) {
if (b && GraphicsEnvironment.isHeadless()) {
throw new HeadlessException();
}
dragEnabled = b;
}
/**
* Gets the value of the <code>dragEnabled</code> property.
*
* @return the value of the <code>dragEnabled</code> property
* @see #setDragEnabled
* @since 1.4
*/
public boolean getDragEnabled() {
return dragEnabled;
}
/**
* Sets the current preview panel.
* This will fire a <code>PropertyChangeEvent</code> for the property
* named "previewPanel".
*
* @param preview the <code>JComponent</code> which displays the current color
* @see JComponent#addPropertyChangeListener
*
* @beaninfo
* bound: true
* hidden: true
* description: The UI component which displays the current color.
*/
public void setPreviewPanel(JComponent preview) {
if (previewPanel != preview) {
JComponent oldPreview = previewPanel;
previewPanel = preview;
firePropertyChange(JColorChooser.PREVIEW_PANEL_PROPERTY, oldPreview, preview);
}
}
/**
* Returns the preview panel that shows a chosen color.
*
* @return a <code>JComponent</code> object -- the preview panel
*/
public JComponent getPreviewPanel() {
return previewPanel;
}
/**
* Adds a color chooser panel to the color chooser.
*
* @param panel the <code>AbstractColorChooserPanel</code> to be added
*/
public void addChooserPanel( AbstractColorChooserPanel panel ) {
AbstractColorChooserPanel[] oldPanels = getChooserPanels();
AbstractColorChooserPanel[] newPanels = new AbstractColorChooserPanel[oldPanels.length+1];
System.arraycopy(oldPanels, 0, newPanels, 0, oldPanels.length);
newPanels[newPanels.length-1] = panel;
setChooserPanels(newPanels);
}
/**
* Removes the Color Panel specified.
*
* @param panel a string that specifies the panel to be removed
* @return the color panel
* @exception IllegalArgumentException if panel is not in list of
* known chooser panels
*/
public AbstractColorChooserPanel removeChooserPanel( AbstractColorChooserPanel panel ) {
int containedAt = -1;
for (int i = 0; i < chooserPanels.length; i++) {
if (chooserPanels[i] == panel) {
containedAt = i;
break;
}
}
if (containedAt == -1) {
throw new IllegalArgumentException("chooser panel not in this chooser");
}
AbstractColorChooserPanel[] newArray = new AbstractColorChooserPanel[chooserPanels.length-1];
if (containedAt == chooserPanels.length-1) { // at end
System.arraycopy(chooserPanels, 0, newArray, 0, newArray.length);
}
else if (containedAt == 0) { // at start
System.arraycopy(chooserPanels, 1, newArray, 0, newArray.length);
}
else { // in middle
System.arraycopy(chooserPanels, 0, newArray, 0, containedAt);
System.arraycopy(chooserPanels, containedAt+1,
newArray, containedAt, (chooserPanels.length - containedAt - 1));
}
setChooserPanels(newArray);
return panel;
}
/**
* Specifies the Color Panels used to choose a color value.
*
* @param panels an array of <code>AbstractColorChooserPanel</code>
* objects
*
* @beaninfo
* bound: true
* hidden: true
* description: An array of different chooser types.
*/
public void setChooserPanels( AbstractColorChooserPanel[] panels) {
AbstractColorChooserPanel[] oldValue = chooserPanels;
chooserPanels = panels;
firePropertyChange(CHOOSER_PANELS_PROPERTY, oldValue, panels);
}
/**
* Returns the specified color panels.
*
* @return an array of <code>AbstractColorChooserPanel</code> objects
*/
public AbstractColorChooserPanel[] getChooserPanels() {
return chooserPanels;
}
/**
* Returns the data model that handles color selections.
*
* @return a <code>ColorSelectionModel</code> object
*/
public ColorSelectionModel getSelectionModel() {
return selectionModel;
}
/**
* Sets the model containing the selected color.
*
* @param newModel the new <code>ColorSelectionModel</code> object
*
* @beaninfo
* bound: true
* hidden: true
* description: The model which contains the currently selected color.
*/
public void setSelectionModel(ColorSelectionModel newModel ) {
ColorSelectionModel oldModel = selectionModel;
selectionModel = newModel;
firePropertyChange(JColorChooser.SELECTION_MODEL_PROPERTY, oldModel, newModel);
}
/**
* See <code>readObject</code> and <code>writeObject</code> in
* <code>JComponent</code> for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this <code>JColorChooser</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JColorChooser</code>
*/
protected String paramString() {
StringBuffer chooserPanelsString = new StringBuffer("");
for (int i=0; i<chooserPanels.length; i++) {
chooserPanelsString.append("[" + chooserPanels[i].toString()
+ "]");
}
String previewPanelString = (previewPanel != null ?
previewPanel.toString() : "");
return super.paramString() +
",chooserPanels=" + chooserPanelsString.toString() +
",previewPanel=" + previewPanelString;
}
/////////////////
// Accessibility support
////////////////
protected AccessibleContext accessibleContext = null;
/**
* Gets the AccessibleContext associated with this JColorChooser.
* For color choosers, the AccessibleContext takes the form of an
* AccessibleJColorChooser.
* A new AccessibleJColorChooser instance is created if necessary.
*
* @return an AccessibleJColorChooser that serves as the
* AccessibleContext of this JColorChooser
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJColorChooser();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JColorChooser</code> class. It provides an implementation of the
* Java Accessibility API appropriate to color chooser user-interface
* elements.
*/
protected class AccessibleJColorChooser extends AccessibleJComponent {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.COLOR_CHOOSER;
}
} // inner class AccessibleJColorChooser
}
/*
* Class which builds a color chooser dialog consisting of
* a JColorChooser with "Ok", "Cancel", and "Reset" buttons.
*
* Note: This needs to be fixed to deal with localization!
*/
class ColorChooserDialog extends JDialog {
private Color initialColor;
private JColorChooser chooserPane;
private JButton cancelButton;
public ColorChooserDialog(Dialog owner, String title, boolean modal,
Component c, JColorChooser chooserPane,
ActionListener okListener, ActionListener cancelListener)
throws HeadlessException {
super(owner, title, modal);
initColorChooserDialog(c, chooserPane, okListener, cancelListener);
}
public ColorChooserDialog(Frame owner, String title, boolean modal,
Component c, JColorChooser chooserPane,
ActionListener okListener, ActionListener cancelListener)
throws HeadlessException {
super(owner, title, modal);
initColorChooserDialog(c, chooserPane, okListener, cancelListener);
}
protected void initColorChooserDialog(Component c, JColorChooser chooserPane,
ActionListener okListener, ActionListener cancelListener) {
//setResizable(false);
this.chooserPane = chooserPane;
Locale locale = getLocale();
String okString = UIManager.getString("ColorChooser.okText", locale);
String cancelString = UIManager.getString("ColorChooser.cancelText", locale);
String resetString = UIManager.getString("ColorChooser.resetText", locale);
Container contentPane = getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(chooserPane, BorderLayout.CENTER);
/*
* Create Lower button panel
*/
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER));
JButton okButton = new JButton(okString);
getRootPane().setDefaultButton(okButton);
okButton.getAccessibleContext().setAccessibleDescription(okString);
okButton.setActionCommand("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
hide();
}
});
if (okListener != null) {
okButton.addActionListener(okListener);
}
buttonPane.add(okButton);
cancelButton = new JButton(cancelString);
cancelButton.getAccessibleContext().setAccessibleDescription(cancelString);
// The following few lines are used to register esc to close the dialog
Action cancelKeyAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
((AbstractButton)e.getSource()).fireActionPerformed(e);
}
};
KeyStroke cancelKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
InputMap inputMap = cancelButton.getInputMap(JComponent.
WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = cancelButton.getActionMap();
if (inputMap != null && actionMap != null) {
inputMap.put(cancelKeyStroke, "cancel");
actionMap.put("cancel", cancelKeyAction);
}
// end esc handling
cancelButton.setActionCommand("cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
hide();
}
});
if (cancelListener != null) {
cancelButton.addActionListener(cancelListener);
}
buttonPane.add(cancelButton);
JButton resetButton = new JButton(resetString);
resetButton.getAccessibleContext().setAccessibleDescription(resetString);
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
reset();
}
});
int mnemonic = SwingUtilities2.getUIDefaultsInt("ColorChooser.resetMnemonic", locale, -1);
if (mnemonic != -1) {
resetButton.setMnemonic(mnemonic);
}
buttonPane.add(resetButton);
contentPane.add(buttonPane, BorderLayout.SOUTH);
if (JDialog.isDefaultLookAndFeelDecorated()) {
boolean supportsWindowDecorations =
UIManager.getLookAndFeel().getSupportsWindowDecorations();
if (supportsWindowDecorations) {
getRootPane().setWindowDecorationStyle(JRootPane.COLOR_CHOOSER_DIALOG);
}
}
applyComponentOrientation(((c == null) ? getRootPane() : c).getComponentOrientation());
pack();
setLocationRelativeTo(c);
this.addWindowListener(new Closer());
}
public void show() {
initialColor = chooserPane.getColor();
super.show();
}
public void reset() {
chooserPane.setColor(initialColor);
}
class Closer extends WindowAdapter implements Serializable{
public void windowClosing(WindowEvent e) {
cancelButton.doClick(0);
Window w = e.getWindow();
w.hide();
}
}
static class DisposeOnClose extends ComponentAdapter implements Serializable{
public void componentHidden(ComponentEvent e) {
Window w = (Window)e.getComponent();
w.dispose();
}
}
}
class ColorTracker implements ActionListener, Serializable {
JColorChooser chooser;
Color color;
public ColorTracker(JColorChooser c) {
chooser = c;
}
public void actionPerformed(ActionEvent e) {
color = chooser.getColor();
}
public Color getColor() {
return color;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,633 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.awt.Component;
import java.awt.Container;
import java.awt.DefaultFocusTraversalPolicy;
import java.awt.FocusTraversalPolicy;
import java.awt.Window;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.beans.PropertyVetoException;
import java.util.Set;
import java.util.TreeSet;
import java.util.LinkedHashSet;
/**
* A container used to create a multiple-document interface or a virtual desktop.
* You create <code>JInternalFrame</code> objects and add them to the
* <code>JDesktopPane</code>. <code>JDesktopPane</code> extends
* <code>JLayeredPane</code> to manage the potentially overlapping internal
* frames. It also maintains a reference to an instance of
* <code>DesktopManager</code> that is set by the UI
* class for the current look and feel (L&amp;F). Note that <code>JDesktopPane</code>
* does not support borders.
* <p>
* This class is normally used as the parent of <code>JInternalFrames</code>
* to provide a pluggable <code>DesktopManager</code> object to the
* <code>JInternalFrames</code>. The <code>installUI</code> of the
* L&amp;F specific implementation is responsible for setting the
* <code>desktopManager</code> variable appropriately.
* When the parent of a <code>JInternalFrame</code> is a <code>JDesktopPane</code>,
* it should delegate most of its behavior to the <code>desktopManager</code>
* (closing, resizing, etc).
* <p>
* For further documentation and examples see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html">How to Use Internal Frames</a>,
* a section in <em>The Java Tutorial</em>.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JInternalFrame
* @see JInternalFrame.JDesktopIcon
* @see DesktopManager
*
* @author David Kloba
*/
public class JDesktopPane extends JLayeredPane implements Accessible
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "DesktopPaneUI";
transient DesktopManager desktopManager;
private transient JInternalFrame selectedFrame = null;
/**
* Indicates that the entire contents of the item being dragged
* should appear inside the desktop pane.
*
* @see #OUTLINE_DRAG_MODE
* @see #setDragMode
*/
public static final int LIVE_DRAG_MODE = 0;
/**
* Indicates that an outline only of the item being dragged
* should appear inside the desktop pane.
*
* @see #LIVE_DRAG_MODE
* @see #setDragMode
*/
public static final int OUTLINE_DRAG_MODE = 1;
private int dragMode = LIVE_DRAG_MODE;
private boolean dragModeSet = false;
private transient List<JInternalFrame> framesCache;
private boolean componentOrderCheckingEnabled = true;
private boolean componentOrderChanged = false;
/**
* Creates a new <code>JDesktopPane</code>.
*/
public JDesktopPane() {
setUIProperty("opaque", Boolean.TRUE);
setFocusCycleRoot(true);
setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
public Component getDefaultComponent(Container c) {
JInternalFrame jifArray[] = getAllFrames();
Component comp = null;
for (JInternalFrame jif : jifArray) {
comp = jif.getFocusTraversalPolicy().getDefaultComponent(jif);
if (comp != null) {
break;
}
}
return comp;
}
});
updateUI();
}
/**
* Returns the L&amp;F object that renders this component.
*
* @return the <code>DesktopPaneUI</code> object that
* renders this component
*/
public DesktopPaneUI getUI() {
return (DesktopPaneUI)ui;
}
/**
* Sets the L&amp;F object that renders this component.
*
* @param ui the DesktopPaneUI L&amp;F object
* @see UIDefaults#getUI
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel.
*/
public void setUI(DesktopPaneUI ui) {
super.setUI(ui);
}
/**
* Sets the "dragging style" used by the desktop pane.
* You may want to change to one mode or another for
* performance or aesthetic reasons.
*
* @param dragMode the style of drag to use for items in the Desktop
*
* @see #LIVE_DRAG_MODE
* @see #OUTLINE_DRAG_MODE
*
* @beaninfo
* bound: true
* description: Dragging style for internal frame children.
* enum: LIVE_DRAG_MODE JDesktopPane.LIVE_DRAG_MODE
* OUTLINE_DRAG_MODE JDesktopPane.OUTLINE_DRAG_MODE
* @since 1.3
*/
public void setDragMode(int dragMode) {
int oldDragMode = this.dragMode;
this.dragMode = dragMode;
firePropertyChange("dragMode", oldDragMode, this.dragMode);
dragModeSet = true;
}
/**
* Gets the current "dragging style" used by the desktop pane.
* @return either <code>Live_DRAG_MODE</code> or
* <code>OUTLINE_DRAG_MODE</code>
* @see #setDragMode
* @since 1.3
*/
public int getDragMode() {
return dragMode;
}
/**
* Returns the <code>DesktopManger</code> that handles
* desktop-specific UI actions.
*/
public DesktopManager getDesktopManager() {
return desktopManager;
}
/**
* Sets the <code>DesktopManger</code> that will handle
* desktop-specific UI actions. This may be overridden by
* {@code LookAndFeel}.
*
* @param d the <code>DesktopManager</code> to use
*
* @beaninfo
* bound: true
* description: Desktop manager to handle the internal frames in the
* desktop pane.
*/
public void setDesktopManager(DesktopManager d) {
DesktopManager oldValue = desktopManager;
desktopManager = d;
firePropertyChange("desktopManager", oldValue, desktopManager);
}
/**
* Notification from the <code>UIManager</code> that the L&amp;F has changed.
* Replaces the current UI object with the latest version from the
* <code>UIManager</code>.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((DesktopPaneUI)UIManager.getUI(this));
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "DesktopPaneUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Returns all <code>JInternalFrames</code> currently displayed in the
* desktop. Returns iconified frames as well as expanded frames.
*
* @return an array of <code>JInternalFrame</code> objects
*/
public JInternalFrame[] getAllFrames() {
return getAllFrames(this).toArray(new JInternalFrame[0]);
}
private static Collection<JInternalFrame> getAllFrames(Container parent) {
int i, count;
Collection<JInternalFrame> results = new LinkedHashSet<>();
count = parent.getComponentCount();
for (i = 0; i < count; i++) {
Component next = parent.getComponent(i);
if (next instanceof JInternalFrame) {
results.add((JInternalFrame) next);
} else if (next instanceof JInternalFrame.JDesktopIcon) {
JInternalFrame tmp = ((JInternalFrame.JDesktopIcon) next).getInternalFrame();
if (tmp != null) {
results.add(tmp);
}
} else if (next instanceof Container) {
results.addAll(getAllFrames((Container) next));
}
}
return results;
}
/** Returns the currently active <code>JInternalFrame</code>
* in this <code>JDesktopPane</code>, or <code>null</code>
* if no <code>JInternalFrame</code> is currently active.
*
* @return the currently active <code>JInternalFrame</code> or
* <code>null</code>
* @since 1.3
*/
public JInternalFrame getSelectedFrame() {
return selectedFrame;
}
/** Sets the currently active <code>JInternalFrame</code>
* in this <code>JDesktopPane</code>. This method is used to bridge
* the package gap between JDesktopPane and the platform implementation
* code and should not be called directly. To visually select the frame
* the client must call JInternalFrame.setSelected(true) to activate
* the frame.
* @see JInternalFrame#setSelected(boolean)
*
* @param f the internal frame that's currently selected
* @since 1.3
*/
public void setSelectedFrame(JInternalFrame f) {
selectedFrame = f;
}
/**
* Returns all <code>JInternalFrames</code> currently displayed in the
* specified layer of the desktop. Returns iconified frames as well
* expanded frames.
*
* @param layer an int specifying the desktop layer
* @return an array of <code>JInternalFrame</code> objects
* @see JLayeredPane
*/
public JInternalFrame[] getAllFramesInLayer(int layer) {
Collection<JInternalFrame> allFrames = getAllFrames(this);
Iterator<JInternalFrame> iterator = allFrames.iterator();
while (iterator.hasNext()) {
if (iterator.next().getLayer() != layer) {
iterator.remove();
}
}
return allFrames.toArray(new JInternalFrame[0]);
}
private List<JInternalFrame> getFrames() {
Component c;
Set<ComponentPosition> set = new TreeSet<ComponentPosition>();
for (int i = 0; i < getComponentCount(); i++) {
c = getComponent(i);
if (c instanceof JInternalFrame) {
set.add(new ComponentPosition((JInternalFrame)c, getLayer(c),
i));
}
else if (c instanceof JInternalFrame.JDesktopIcon) {
c = ((JInternalFrame.JDesktopIcon)c).getInternalFrame();
set.add(new ComponentPosition((JInternalFrame)c, getLayer(c),
i));
}
}
List<JInternalFrame> frames = new ArrayList<JInternalFrame>(
set.size());
for (ComponentPosition position : set) {
frames.add(position.component);
}
return frames;
}
private static class ComponentPosition implements
Comparable<ComponentPosition> {
private final JInternalFrame component;
private final int layer;
private final int zOrder;
ComponentPosition(JInternalFrame component, int layer, int zOrder) {
this.component = component;
this.layer = layer;
this.zOrder = zOrder;
}
public int compareTo(ComponentPosition o) {
int delta = o.layer - layer;
if (delta == 0) {
return zOrder - o.zOrder;
}
return delta;
}
}
private JInternalFrame getNextFrame(JInternalFrame f, boolean forward) {
verifyFramesCache();
if (f == null) {
return getTopInternalFrame();
}
int i = framesCache.indexOf(f);
if (i == -1 || framesCache.size() == 1) {
/* error */
return null;
}
if (forward) {
// navigate to the next frame
if (++i == framesCache.size()) {
/* wrap */
i = 0;
}
}
else {
// navigate to the previous frame
if (--i == -1) {
/* wrap */
i = framesCache.size() - 1;
}
}
return framesCache.get(i);
}
JInternalFrame getNextFrame(JInternalFrame f) {
return getNextFrame(f, true);
}
private JInternalFrame getTopInternalFrame() {
if (framesCache.size() == 0) {
return null;
}
return framesCache.get(0);
}
private void updateFramesCache() {
framesCache = getFrames();
}
private void verifyFramesCache() {
// If framesCache is dirty, then recreate it.
if (componentOrderChanged) {
componentOrderChanged = false;
updateFramesCache();
}
}
/**
* {@inheritDoc}
*/
@Override
public void remove(Component comp) {
super.remove(comp);
updateFramesCache();
}
/**
* Selects the next <code>JInternalFrame</code> in this desktop pane.
*
* @param forward a boolean indicating which direction to select in;
* <code>true</code> for forward, <code>false</code> for
* backward
* @return the JInternalFrame that was selected or <code>null</code>
* if nothing was selected
* @since 1.6
*/
public JInternalFrame selectFrame(boolean forward) {
JInternalFrame selectedFrame = getSelectedFrame();
JInternalFrame frameToSelect = getNextFrame(selectedFrame, forward);
if (frameToSelect == null) {
return null;
}
// Maintain navigation traversal order until an
// external stack change, such as a click on a frame.
setComponentOrderCheckingEnabled(false);
if (forward && selectedFrame != null) {
selectedFrame.moveToBack(); // For Windows MDI fidelity.
}
try { frameToSelect.setSelected(true);
} catch (PropertyVetoException pve) {}
setComponentOrderCheckingEnabled(true);
return frameToSelect;
}
/*
* Sets whether component order checking is enabled.
* @param enable a boolean value, where <code>true</code> means
* a change in component order will cause a change in the keyboard
* navigation order.
* @since 1.6
*/
void setComponentOrderCheckingEnabled(boolean enable) {
componentOrderCheckingEnabled = enable;
}
/**
* {@inheritDoc}
* @since 1.6
*/
protected void addImpl(Component comp, Object constraints, int index) {
super.addImpl(comp, constraints, index);
if (componentOrderCheckingEnabled) {
if (comp instanceof JInternalFrame ||
comp instanceof JInternalFrame.JDesktopIcon) {
componentOrderChanged = true;
}
}
}
/**
* {@inheritDoc}
* @since 1.6
*/
public void remove(int index) {
if (componentOrderCheckingEnabled) {
Component comp = getComponent(index);
if (comp instanceof JInternalFrame ||
comp instanceof JInternalFrame.JDesktopIcon) {
componentOrderChanged = true;
}
}
super.remove(index);
}
/**
* {@inheritDoc}
* @since 1.6
*/
public void removeAll() {
if (componentOrderCheckingEnabled) {
int count = getComponentCount();
for (int i = 0; i < count; i++) {
Component comp = getComponent(i);
if (comp instanceof JInternalFrame ||
comp instanceof JInternalFrame.JDesktopIcon) {
componentOrderChanged = true;
break;
}
}
}
super.removeAll();
}
/**
* {@inheritDoc}
* @since 1.6
*/
public void setComponentZOrder(Component comp, int index) {
super.setComponentZOrder(comp, index);
if (componentOrderCheckingEnabled) {
if (comp instanceof JInternalFrame ||
comp instanceof JInternalFrame.JDesktopIcon) {
componentOrderChanged = true;
}
}
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
void setUIProperty(String propertyName, Object value) {
if (propertyName == "dragMode") {
if (!dragModeSet) {
setDragMode(((Integer)value).intValue());
dragModeSet = false;
}
} else {
super.setUIProperty(propertyName, value);
}
}
/**
* Returns a string representation of this <code>JDesktopPane</code>.
* This method is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JDesktopPane</code>
*/
protected String paramString() {
String desktopManagerString = (desktopManager != null ?
desktopManager.toString() : "");
return super.paramString() +
",desktopManager=" + desktopManagerString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the <code>AccessibleContext</code> associated with this
* <code>JDesktopPane</code>. For desktop panes, the
* <code>AccessibleContext</code> takes the form of an
* <code>AccessibleJDesktopPane</code>.
* A new <code>AccessibleJDesktopPane</code> instance is created if necessary.
*
* @return an <code>AccessibleJDesktopPane</code> that serves as the
* <code>AccessibleContext</code> of this <code>JDesktopPane</code>
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJDesktopPane();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JDesktopPane</code> class. It provides an implementation of the
* Java Accessibility API appropriate to desktop pane user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJDesktopPane extends AccessibleJComponent {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.DESKTOP_PANE;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,945 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.LayoutManager;
import java.awt.event.WindowEvent;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleState;
import javax.accessibility.AccessibleStateSet;
/**
* An extended version of <code>java.awt.Frame</code> that adds support for
* the JFC/Swing component architecture.
* You can find task-oriented documentation about using <code>JFrame</code>
* in <em>The Java Tutorial</em>, in the section
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/frame.html">How to Make Frames</a>.
*
* <p>
* The <code>JFrame</code> class is slightly incompatible with <code>Frame</code>.
* Like all other JFC/Swing top-level containers,
* a <code>JFrame</code> contains a <code>JRootPane</code> as its only child.
* The <b>content pane</b> provided by the root pane should,
* as a rule, contain
* all the non-menu components displayed by the <code>JFrame</code>.
* This is different from the AWT <code>Frame</code> case.
* As a convenience, the {@code add}, {@code remove}, and {@code setLayout}
* methods of this class are overridden, so that they delegate calls
* to the corresponding methods of the {@code ContentPane}.
* For example, you can add a child component to a frame as follows:
* <pre>
* frame.add(child);
* </pre>
* And the child will be added to the contentPane.
* The content pane will
* always be non-null. Attempting to set it to null will cause the JFrame
* to throw an exception. The default content pane will have a BorderLayout
* manager set on it.
* Refer to {@link javax.swing.RootPaneContainer}
* for details on adding, removing and setting the <code>LayoutManager</code>
* of a <code>JFrame</code>.
* <p>
* Unlike a <code>Frame</code>, a <code>JFrame</code> has some notion of how to
* respond when the user attempts to close the window. The default behavior
* is to simply hide the JFrame when the user closes the window. To change the
* default behavior, you invoke the method
* {@link #setDefaultCloseOperation}.
* To make the <code>JFrame</code> behave the same as a <code>Frame</code>
* instance, use
* <code>setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE)</code>.
* <p>
* For more information on content panes
* and other features that root panes provide,
* see <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html">Using Top-Level Containers</a> in <em>The Java Tutorial</em>.
* <p>
* In a multi-screen environment, you can create a <code>JFrame</code>
* on a different screen device. See {@link java.awt.Frame} for more
* information.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JRootPane
* @see #setDefaultCloseOperation
* @see java.awt.event.WindowListener#windowClosing
* @see javax.swing.RootPaneContainer
*
* @beaninfo
* attribute: isContainer true
* attribute: containerDelegate getContentPane
* description: A toplevel window which can be minimized to an icon.
*
* @author Jeff Dinkins
* @author Georges Saab
* @author David Kloba
*/
public class JFrame extends Frame implements WindowConstants,
Accessible,
RootPaneContainer,
TransferHandler.HasGetTransferHandler
{
/**
* The exit application default window close operation. If a window
* has this set as the close operation and is closed in an applet,
* a <code>SecurityException</code> may be thrown.
* It is recommended you only use this in an application.
* <p>
* @since 1.3
*/
public static final int EXIT_ON_CLOSE = 3;
/**
* Key into the AppContext, used to check if should provide decorations
* by default.
*/
private static final Object defaultLookAndFeelDecoratedKey =
new StringBuffer("JFrame.defaultLookAndFeelDecorated");
private int defaultCloseOperation = HIDE_ON_CLOSE;
/**
* The <code>TransferHandler</code> for this frame.
*/
private TransferHandler transferHandler;
/**
* The <code>JRootPane</code> instance that manages the
* <code>contentPane</code>
* and optional <code>menuBar</code> for this frame, as well as the
* <code>glassPane</code>.
*
* @see JRootPane
* @see RootPaneContainer
*/
protected JRootPane rootPane;
/**
* If true then calls to <code>add</code> and <code>setLayout</code>
* will be forwarded to the <code>contentPane</code>. This is initially
* false, but is set to true when the <code>JFrame</code> is constructed.
*
* @see #isRootPaneCheckingEnabled
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected boolean rootPaneCheckingEnabled = false;
/**
* Constructs a new frame that is initially invisible.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see Component#setSize
* @see Component#setVisible
* @see JComponent#getDefaultLocale
*/
public JFrame() throws HeadlessException {
super();
frameInit();
}
/**
* Creates a <code>Frame</code> in the specified
* <code>GraphicsConfiguration</code> of
* a screen device and a blank title.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param gc the <code>GraphicsConfiguration</code> that is used
* to construct the new <code>Frame</code>;
* if <code>gc</code> is <code>null</code>, the system
* default <code>GraphicsConfiguration</code> is assumed
* @exception IllegalArgumentException if <code>gc</code> is not from
* a screen device. This exception is always thrown when
* GraphicsEnvironment.isHeadless() returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see JComponent#getDefaultLocale
* @since 1.3
*/
public JFrame(GraphicsConfiguration gc) {
super(gc);
frameInit();
}
/**
* Creates a new, initially invisible <code>Frame</code> with the
* specified title.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param title the title for the frame
* @exception HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see Component#setSize
* @see Component#setVisible
* @see JComponent#getDefaultLocale
*/
public JFrame(String title) throws HeadlessException {
super(title);
frameInit();
}
/**
* Creates a <code>JFrame</code> with the specified title and the
* specified <code>GraphicsConfiguration</code> of a screen device.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param title the title to be displayed in the
* frame's border. A <code>null</code> value is treated as
* an empty string, "".
* @param gc the <code>GraphicsConfiguration</code> that is used
* to construct the new <code>JFrame</code> with;
* if <code>gc</code> is <code>null</code>, the system
* default <code>GraphicsConfiguration</code> is assumed
* @exception IllegalArgumentException if <code>gc</code> is not from
* a screen device. This exception is always thrown when
* GraphicsEnvironment.isHeadless() returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see JComponent#getDefaultLocale
* @since 1.3
*/
public JFrame(String title, GraphicsConfiguration gc) {
super(title, gc);
frameInit();
}
/** Called by the constructors to init the <code>JFrame</code> properly. */
protected void frameInit() {
enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK);
setLocale( JComponent.getDefaultLocale() );
setRootPane(createRootPane());
setBackground(UIManager.getColor("control"));
setRootPaneCheckingEnabled(true);
if (JFrame.isDefaultLookAndFeelDecorated()) {
boolean supportsWindowDecorations =
UIManager.getLookAndFeel().getSupportsWindowDecorations();
if (supportsWindowDecorations) {
setUndecorated(true);
getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
}
}
sun.awt.SunToolkit.checkAndSetPolicy(this);
}
/**
* Called by the constructor methods to create the default
* <code>rootPane</code>.
*/
protected JRootPane createRootPane() {
JRootPane rp = new JRootPane();
// NOTE: this uses setOpaque vs LookAndFeel.installProperty as there
// is NO reason for the RootPane not to be opaque. For painting to
// work the contentPane must be opaque, therefor the RootPane can
// also be opaque.
rp.setOpaque(true);
return rp;
}
/**
* Processes window events occurring on this component.
* Hides the window or disposes of it, as specified by the setting
* of the <code>defaultCloseOperation</code> property.
*
* @param e the window event
* @see #setDefaultCloseOperation
* @see java.awt.Window#processWindowEvent
*/
protected void processWindowEvent(final WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
switch (defaultCloseOperation) {
case HIDE_ON_CLOSE:
setVisible(false);
break;
case DISPOSE_ON_CLOSE:
dispose();
break;
case EXIT_ON_CLOSE:
// This needs to match the checkExit call in
// setDefaultCloseOperation
System.exit(0);
break;
case DO_NOTHING_ON_CLOSE:
default:
}
}
}
/**
* Sets the operation that will happen by default when
* the user initiates a "close" on this frame.
* You must specify one of the following choices:
* <br><br>
* <ul>
* <li><code>DO_NOTHING_ON_CLOSE</code>
* (defined in <code>WindowConstants</code>):
* Don't do anything; require the
* program to handle the operation in the <code>windowClosing</code>
* method of a registered <code>WindowListener</code> object.
*
* <li><code>HIDE_ON_CLOSE</code>
* (defined in <code>WindowConstants</code>):
* Automatically hide the frame after
* invoking any registered <code>WindowListener</code>
* objects.
*
* <li><code>DISPOSE_ON_CLOSE</code>
* (defined in <code>WindowConstants</code>):
* Automatically hide and dispose the
* frame after invoking any registered <code>WindowListener</code>
* objects.
*
* <li><code>EXIT_ON_CLOSE</code>
* (defined in <code>JFrame</code>):
* Exit the application using the <code>System</code>
* <code>exit</code> method. Use this only in applications.
* </ul>
* <p>
* The value is set to <code>HIDE_ON_CLOSE</code> by default. Changes
* to the value of this property cause the firing of a property
* change event, with property name "defaultCloseOperation".
* <p>
* <b>Note</b>: When the last displayable window within the
* Java virtual machine (VM) is disposed of, the VM may
* terminate. See <a href="../../java/awt/doc-files/AWTThreadIssues.html">
* AWT Threading Issues</a> for more information.
*
* @param operation the operation which should be performed when the
* user closes the frame
* @exception IllegalArgumentException if defaultCloseOperation value
* isn't one of the above valid values
* @see #addWindowListener
* @see #getDefaultCloseOperation
* @see WindowConstants
* @throws SecurityException
* if <code>EXIT_ON_CLOSE</code> has been specified and the
* <code>SecurityManager</code> will
* not allow the caller to invoke <code>System.exit</code>
* @see java.lang.Runtime#exit(int)
*
* @beaninfo
* preferred: true
* bound: true
* enum: DO_NOTHING_ON_CLOSE WindowConstants.DO_NOTHING_ON_CLOSE
* HIDE_ON_CLOSE WindowConstants.HIDE_ON_CLOSE
* DISPOSE_ON_CLOSE WindowConstants.DISPOSE_ON_CLOSE
* EXIT_ON_CLOSE WindowConstants.EXIT_ON_CLOSE
* description: The frame's default close operation.
*/
public void setDefaultCloseOperation(int operation) {
if (operation != DO_NOTHING_ON_CLOSE &&
operation != HIDE_ON_CLOSE &&
operation != DISPOSE_ON_CLOSE &&
operation != EXIT_ON_CLOSE) {
throw new IllegalArgumentException("defaultCloseOperation must be one of: DO_NOTHING_ON_CLOSE, HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or EXIT_ON_CLOSE");
}
if (operation == EXIT_ON_CLOSE) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkExit(0);
}
}
if (this.defaultCloseOperation != operation) {
int oldValue = this.defaultCloseOperation;
this.defaultCloseOperation = operation;
firePropertyChange("defaultCloseOperation", oldValue, operation);
}
}
/**
* Returns the operation that occurs when the user
* initiates a "close" on this frame.
*
* @return an integer indicating the window-close operation
* @see #setDefaultCloseOperation
*/
public int getDefaultCloseOperation() {
return defaultCloseOperation;
}
/**
* Sets the {@code transferHandler} property, which is a mechanism to
* support transfer of data into this component. Use {@code null}
* if the component does not support data transfer operations.
* <p>
* If the system property {@code suppressSwingDropSupport} is {@code false}
* (the default) and the current drop target on this component is either
* {@code null} or not a user-set drop target, this method will change the
* drop target as follows: If {@code newHandler} is {@code null} it will
* clear the drop target. If not {@code null} it will install a new
* {@code DropTarget}.
* <p>
* Note: When used with {@code JFrame}, {@code TransferHandler} only
* provides data import capability, as the data export related methods
* are currently typed to {@code JComponent}.
* <p>
* Please see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html">
* How to Use Drag and Drop and Data Transfer</a>, a section in
* <em>The Java Tutorial</em>, for more information.
*
* @param newHandler the new {@code TransferHandler}
*
* @see TransferHandler
* @see #getTransferHandler
* @see java.awt.Component#setDropTarget
* @since 1.6
*
* @beaninfo
* bound: true
* hidden: true
* description: Mechanism for transfer of data into the component
*/
public void setTransferHandler(TransferHandler newHandler) {
TransferHandler oldHandler = transferHandler;
transferHandler = newHandler;
SwingUtilities.installSwingDropTargetAsNecessary(this, transferHandler);
firePropertyChange("transferHandler", oldHandler, newHandler);
}
/**
* Gets the <code>transferHandler</code> property.
*
* @return the value of the <code>transferHandler</code> property
*
* @see TransferHandler
* @see #setTransferHandler
* @since 1.6
*/
public TransferHandler getTransferHandler() {
return transferHandler;
}
/**
* Just calls <code>paint(g)</code>. This method was overridden to
* prevent an unnecessary call to clear the background.
*
* @param g the Graphics context in which to paint
*/
public void update(Graphics g) {
paint(g);
}
/**
* Sets the menubar for this frame.
* @param menubar the menubar being placed in the frame
*
* @see #getJMenuBar
*
* @beaninfo
* hidden: true
* description: The menubar for accessing pulldown menus from this frame.
*/
public void setJMenuBar(JMenuBar menubar) {
getRootPane().setMenuBar(menubar);
}
/**
* Returns the menubar set on this frame.
* @return the menubar for this frame
*
* @see #setJMenuBar
*/
public JMenuBar getJMenuBar() {
return getRootPane().getMenuBar();
}
/**
* Returns whether calls to <code>add</code> and
* <code>setLayout</code> are forwarded to the <code>contentPane</code>.
*
* @return true if <code>add</code> and <code>setLayout</code>
* are forwarded; false otherwise
*
* @see #addImpl
* @see #setLayout
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected boolean isRootPaneCheckingEnabled() {
return rootPaneCheckingEnabled;
}
/**
* Sets whether calls to <code>add</code> and
* <code>setLayout</code> are forwarded to the <code>contentPane</code>.
*
* @param enabled true if <code>add</code> and <code>setLayout</code>
* are forwarded, false if they should operate directly on the
* <code>JFrame</code>.
*
* @see #addImpl
* @see #setLayout
* @see #isRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
* @beaninfo
* hidden: true
* description: Whether the add and setLayout methods are forwarded
*/
protected void setRootPaneCheckingEnabled(boolean enabled) {
rootPaneCheckingEnabled = enabled;
}
/**
* Adds the specified child <code>Component</code>.
* This method is overridden to conditionally forward calls to the
* <code>contentPane</code>.
* By default, children are added to the <code>contentPane</code> instead
* of the frame, refer to {@link javax.swing.RootPaneContainer} for
* details.
*
* @param comp the component to be enhanced
* @param constraints the constraints to be respected
* @param index the index
* @exception IllegalArgumentException if <code>index</code> is invalid
* @exception IllegalArgumentException if adding the container's parent
* to itself
* @exception IllegalArgumentException if adding a window to a container
*
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected void addImpl(Component comp, Object constraints, int index)
{
if(isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else {
super.addImpl(comp, constraints, index);
}
}
/**
* Removes the specified component from the container. If
* <code>comp</code> is not the <code>rootPane</code>, this will forward
* the call to the <code>contentPane</code>. This will do nothing if
* <code>comp</code> is not a child of the <code>JFrame</code> or
* <code>contentPane</code>.
*
* @param comp the component to be removed
* @throws NullPointerException if <code>comp</code> is null
* @see #add
* @see javax.swing.RootPaneContainer
*/
public void remove(Component comp) {
if (comp == rootPane) {
super.remove(comp);
} else {
getContentPane().remove(comp);
}
}
/**
* Sets the <code>LayoutManager</code>.
* Overridden to conditionally forward the call to the
* <code>contentPane</code>.
* Refer to {@link javax.swing.RootPaneContainer} for
* more information.
*
* @param manager the <code>LayoutManager</code>
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
public void setLayout(LayoutManager manager) {
if(isRootPaneCheckingEnabled()) {
getContentPane().setLayout(manager);
}
else {
super.setLayout(manager);
}
}
/**
* Returns the <code>rootPane</code> object for this frame.
* @return the <code>rootPane</code> property
*
* @see #setRootPane
* @see RootPaneContainer#getRootPane
*/
public JRootPane getRootPane() {
return rootPane;
}
/**
* Sets the <code>rootPane</code> property.
* This method is called by the constructor.
* @param root the <code>rootPane</code> object for this frame
*
* @see #getRootPane
*
* @beaninfo
* hidden: true
* description: the RootPane object for this frame.
*/
protected void setRootPane(JRootPane root)
{
if(rootPane != null) {
remove(rootPane);
}
rootPane = root;
if(rootPane != null) {
boolean checkingEnabled = isRootPaneCheckingEnabled();
try {
setRootPaneCheckingEnabled(false);
add(rootPane, BorderLayout.CENTER);
}
finally {
setRootPaneCheckingEnabled(checkingEnabled);
}
}
}
/**
* {@inheritDoc}
*/
public void setIconImage(Image image) {
super.setIconImage(image);
}
/**
* Returns the <code>contentPane</code> object for this frame.
* @return the <code>contentPane</code> property
*
* @see #setContentPane
* @see RootPaneContainer#getContentPane
*/
public Container getContentPane() {
return getRootPane().getContentPane();
}
/**
* Sets the <code>contentPane</code> property.
* This method is called by the constructor.
* <p>
* Swing's painting architecture requires an opaque <code>JComponent</code>
* in the containment hierarchy. This is typically provided by the
* content pane. If you replace the content pane it is recommended you
* replace it with an opaque <code>JComponent</code>.
*
* @param contentPane the <code>contentPane</code> object for this frame
*
* @exception java.awt.IllegalComponentStateException (a runtime
* exception) if the content pane parameter is <code>null</code>
* @see #getContentPane
* @see RootPaneContainer#setContentPane
* @see JRootPane
*
* @beaninfo
* hidden: true
* description: The client area of the frame where child
* components are normally inserted.
*/
public void setContentPane(Container contentPane) {
getRootPane().setContentPane(contentPane);
}
/**
* Returns the <code>layeredPane</code> object for this frame.
* @return the <code>layeredPane</code> property
*
* @see #setLayeredPane
* @see RootPaneContainer#getLayeredPane
*/
public JLayeredPane getLayeredPane() {
return getRootPane().getLayeredPane();
}
/**
* Sets the <code>layeredPane</code> property.
* This method is called by the constructor.
* @param layeredPane the <code>layeredPane</code> object for this frame
*
* @exception java.awt.IllegalComponentStateException (a runtime
* exception) if the layered pane parameter is <code>null</code>
* @see #getLayeredPane
* @see RootPaneContainer#setLayeredPane
*
* @beaninfo
* hidden: true
* description: The pane that holds the various frame layers.
*/
public void setLayeredPane(JLayeredPane layeredPane) {
getRootPane().setLayeredPane(layeredPane);
}
/**
* Returns the <code>glassPane</code> object for this frame.
* @return the <code>glassPane</code> property
*
* @see #setGlassPane
* @see RootPaneContainer#getGlassPane
*/
public Component getGlassPane() {
return getRootPane().getGlassPane();
}
/**
* Sets the <code>glassPane</code> property.
* This method is called by the constructor.
* @param glassPane the <code>glassPane</code> object for this frame
*
* @see #getGlassPane
* @see RootPaneContainer#setGlassPane
*
* @beaninfo
* hidden: true
* description: A transparent pane used for menu rendering.
*/
public void setGlassPane(Component glassPane) {
getRootPane().setGlassPane(glassPane);
}
/**
* {@inheritDoc}
*
* @since 1.6
*/
public Graphics getGraphics() {
JComponent.getGraphicsInvoked(this);
return super.getGraphics();
}
/**
* Repaints the specified rectangle of this component within
* <code>time</code> milliseconds. Refer to <code>RepaintManager</code>
* for details on how the repaint is handled.
*
* @param time maximum time in milliseconds before update
* @param x the <i>x</i> coordinate
* @param y the <i>y</i> coordinate
* @param width the width
* @param height the height
* @see RepaintManager
* @since 1.6
*/
public void repaint(long time, int x, int y, int width, int height) {
if (RepaintManager.HANDLE_TOP_LEVEL_PAINT) {
RepaintManager.currentManager(this).addDirtyRegion(
this, x, y, width, height);
}
else {
super.repaint(time, x, y, width, height);
}
}
/**
* Provides a hint as to whether or not newly created <code>JFrame</code>s
* should have their Window decorations (such as borders, widgets to
* close the window, title...) provided by the current look
* and feel. If <code>defaultLookAndFeelDecorated</code> is true,
* the current <code>LookAndFeel</code> supports providing window
* decorations, and the current window manager supports undecorated
* windows, then newly created <code>JFrame</code>s will have their
* Window decorations provided by the current <code>LookAndFeel</code>.
* Otherwise, newly created <code>JFrame</code>s will have their
* Window decorations provided by the current window manager.
* <p>
* You can get the same effect on a single JFrame by doing the following:
* <pre>
* JFrame frame = new JFrame();
* frame.setUndecorated(true);
* frame.getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
* </pre>
*
* @param defaultLookAndFeelDecorated A hint as to whether or not current
* look and feel should provide window decorations
* @see javax.swing.LookAndFeel#getSupportsWindowDecorations
* @since 1.4
*/
public static void setDefaultLookAndFeelDecorated(boolean defaultLookAndFeelDecorated) {
if (defaultLookAndFeelDecorated) {
SwingUtilities.appContextPut(defaultLookAndFeelDecoratedKey, Boolean.TRUE);
} else {
SwingUtilities.appContextPut(defaultLookAndFeelDecoratedKey, Boolean.FALSE);
}
}
/**
* Returns true if newly created <code>JFrame</code>s should have their
* Window decorations provided by the current look and feel. This is only
* a hint, as certain look and feels may not support this feature.
*
* @return true if look and feel should provide Window decorations.
* @since 1.4
*/
public static boolean isDefaultLookAndFeelDecorated() {
Boolean defaultLookAndFeelDecorated =
(Boolean) SwingUtilities.appContextGet(defaultLookAndFeelDecoratedKey);
if (defaultLookAndFeelDecorated == null) {
defaultLookAndFeelDecorated = Boolean.FALSE;
}
return defaultLookAndFeelDecorated.booleanValue();
}
/**
* Returns a string representation of this <code>JFrame</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JFrame</code>
*/
protected String paramString() {
String defaultCloseOperationString;
if (defaultCloseOperation == HIDE_ON_CLOSE) {
defaultCloseOperationString = "HIDE_ON_CLOSE";
} else if (defaultCloseOperation == DISPOSE_ON_CLOSE) {
defaultCloseOperationString = "DISPOSE_ON_CLOSE";
} else if (defaultCloseOperation == DO_NOTHING_ON_CLOSE) {
defaultCloseOperationString = "DO_NOTHING_ON_CLOSE";
} else if (defaultCloseOperation == 3) {
defaultCloseOperationString = "EXIT_ON_CLOSE";
} else defaultCloseOperationString = "";
String rootPaneString = (rootPane != null ?
rootPane.toString() : "");
String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ?
"true" : "false");
return super.paramString() +
",defaultCloseOperation=" + defaultCloseOperationString +
",rootPane=" + rootPaneString +
",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString;
}
/////////////////
// Accessibility support
////////////////
/** The accessible context property. */
protected AccessibleContext accessibleContext = null;
/**
* Gets the AccessibleContext associated with this JFrame.
* For JFrames, the AccessibleContext takes the form of an
* AccessibleJFrame.
* A new AccessibleJFrame instance is created if necessary.
*
* @return an AccessibleJFrame that serves as the
* AccessibleContext of this JFrame
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJFrame();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JFrame</code> class. It provides an implementation of the
* Java Accessibility API appropriate to frame user-interface
* elements.
*/
protected class AccessibleJFrame extends AccessibleAWTFrame {
// AccessibleContext methods
/**
* Get the accessible name of this object.
*
* @return the localized name of the object -- can be null if this
* object does not have a name
*/
public String getAccessibleName() {
if (accessibleName != null) {
return accessibleName;
} else {
if (getTitle() == null) {
return super.getAccessibleName();
} else {
return getTitle();
}
}
}
/**
* Get the state of this object.
*
* @return an instance of AccessibleStateSet containing the current
* state set of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
if (isResizable()) {
states.add(AccessibleState.RESIZABLE);
}
if (getFocusOwner() != null) {
states.add(AccessibleState.ACTIVE);
}
// FIXME: [[[WDW - should also return ICONIFIED and ICONIFIABLE
// if we can ever figure these out]]]
return states;
}
} // inner class AccessibleJFrame
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,865 @@
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import sun.awt.AWTAccessor;
import javax.swing.plaf.LayerUI;
import javax.swing.border.Border;
import javax.accessibility.*;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* {@code JLayer} is a universal decorator for Swing components
* which enables you to implement various advanced painting effects as well as
* receive notifications of all {@code AWTEvent}s generated within its borders.
* <p>
* {@code JLayer} delegates the handling of painting and input events to a
* {@link javax.swing.plaf.LayerUI} object, which performs the actual decoration.
* <p>
* The custom painting implemented in the {@code LayerUI} and events notification
* work for the JLayer itself and all its subcomponents.
* This combination enables you to enrich existing components
* by adding new advanced functionality such as temporary locking of a hierarchy,
* data tips for compound components, enhanced mouse scrolling etc and so on.
* <p>
* {@code JLayer} is a good solution if you only need to do custom painting
* over compound component or catch input events from its subcomponents.
* <pre>
* import javax.swing.*;
* import javax.swing.plaf.LayerUI;
* import java.awt.*;
*
* public class JLayerSample {
*
* private static JLayer&lt;JComponent&gt; createLayer() {
* // This custom layerUI will fill the layer with translucent green
* // and print out all mouseMotion events generated within its borders
* LayerUI&lt;JComponent&gt; layerUI = new LayerUI&lt;JComponent&gt;() {
*
* public void paint(Graphics g, JComponent c) {
* // paint the layer as is
* super.paint(g, c);
* // fill it with the translucent green
* g.setColor(new Color(0, 128, 0, 128));
* g.fillRect(0, 0, c.getWidth(), c.getHeight());
* }
*
* public void installUI(JComponent c) {
* super.installUI(c);
* // enable mouse motion events for the layer's subcomponents
* ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK);
* }
*
* public void uninstallUI(JComponent c) {
* super.uninstallUI(c);
* // reset the layer event mask
* ((JLayer) c).setLayerEventMask(0);
* }
*
* // overridden method which catches MouseMotion events
* public void eventDispatched(AWTEvent e, JLayer&lt;? extends JComponent&gt; l) {
* System.out.println("AWTEvent detected: " + e);
* }
* };
* // create a component to be decorated with the layer
* JPanel panel = new JPanel();
* panel.add(new JButton("JButton"));
*
* // create the layer for the panel using our custom layerUI
* return new JLayer&lt;JComponent&gt;(panel, layerUI);
* }
*
* private static void createAndShowGUI() {
* final JFrame frame = new JFrame();
* frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
*
* // work with the layer as with any other Swing component
* frame.add(createLayer());
*
* frame.setSize(200, 200);
* frame.setLocationRelativeTo(null);
* frame.setVisible(true);
* }
*
* public static void main(String[] args) throws Exception {
* SwingUtilities.invokeAndWait(new Runnable() {
* public void run() {
* createAndShowGUI();
* }
* });
* }
* }
* </pre>
*
* <b>Note:</b> {@code JLayer} doesn't support the following methods:
* <ul>
* <li>{@link Container#add(java.awt.Component)}</li>
* <li>{@link Container#add(String, java.awt.Component)}</li>
* <li>{@link Container#add(java.awt.Component, int)}</li>
* <li>{@link Container#add(java.awt.Component, Object)}</li>
* <li>{@link Container#add(java.awt.Component, Object, int)}</li>
* </ul>
* using any of of them will cause {@code UnsupportedOperationException} to be thrown,
* to add a component to {@code JLayer}
* use {@link #setView(Component)} or {@link #setGlassPane(JPanel)}.
*
* @param <V> the type of {@code JLayer}'s view component
*
* @see #JLayer(Component)
* @see #setView(Component)
* @see #getView()
* @see javax.swing.plaf.LayerUI
* @see #JLayer(Component, LayerUI)
* @see #setUI(javax.swing.plaf.LayerUI)
* @see #getUI()
* @since 1.7
*
* @author Alexander Potochkin
*/
public final class JLayer<V extends Component>
extends JComponent
implements Scrollable, PropertyChangeListener, Accessible {
private V view;
// this field is necessary because JComponent.ui is transient
// when layerUI is serializable
private LayerUI<? super V> layerUI;
private JPanel glassPane;
private long eventMask;
private transient boolean isPainting;
private transient boolean isPaintingImmediately;
private static final LayerEventController eventController =
new LayerEventController();
/**
* Creates a new {@code JLayer} object with a {@code null} view component
* and default {@link javax.swing.plaf.LayerUI}.
*
* @see #setView
* @see #setUI
*/
public JLayer() {
this(null);
}
/**
* Creates a new {@code JLayer} object
* with default {@link javax.swing.plaf.LayerUI}.
*
* @param view the component to be decorated by this {@code JLayer}
*
* @see #setUI
*/
public JLayer(V view) {
this(view, new LayerUI<V>());
}
/**
* Creates a new {@code JLayer} object with the specified view component
* and {@link javax.swing.plaf.LayerUI} object.
*
* @param view the component to be decorated
* @param ui the {@link javax.swing.plaf.LayerUI} delegate
* to be used by this {@code JLayer}
*/
public JLayer(V view, LayerUI<V> ui) {
setGlassPane(createGlassPane());
setView(view);
setUI(ui);
}
/**
* Returns the {@code JLayer}'s view component or {@code null}.
* <br>This is a bound property.
*
* @return the {@code JLayer}'s view component
* or {@code null} if none exists
*
* @see #setView(Component)
*/
public V getView() {
return view;
}
/**
* Sets the {@code JLayer}'s view component, which can be {@code null}.
* <br>This is a bound property.
*
* @param view the view component for this {@code JLayer}
*
* @see #getView()
*/
public void setView(V view) {
Component oldView = getView();
if (oldView != null) {
super.remove(oldView);
}
if (view != null) {
super.addImpl(view, null, getComponentCount());
}
this.view = view;
firePropertyChange("view", oldView, view);
revalidate();
repaint();
}
/**
* Sets the {@link javax.swing.plaf.LayerUI} which will perform painting
* and receive input events for this {@code JLayer}.
*
* @param ui the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}
*/
public void setUI(LayerUI<? super V> ui) {
this.layerUI = ui;
super.setUI(ui);
}
/**
* Returns the {@link javax.swing.plaf.LayerUI} for this {@code JLayer}.
*
* @return the {@code LayerUI} for this {@code JLayer}
*/
public LayerUI<? super V> getUI() {
return layerUI;
}
/**
* Returns the {@code JLayer}'s glassPane component or {@code null}.
* <br>This is a bound property.
*
* @return the {@code JLayer}'s glassPane component
* or {@code null} if none exists
*
* @see #setGlassPane(JPanel)
*/
public JPanel getGlassPane() {
return glassPane;
}
/**
* Sets the {@code JLayer}'s glassPane component, which can be {@code null}.
* <br>This is a bound property.
*
* @param glassPane the glassPane component of this {@code JLayer}
*
* @see #getGlassPane()
*/
public void setGlassPane(JPanel glassPane) {
Component oldGlassPane = getGlassPane();
boolean isGlassPaneVisible = false;
if (oldGlassPane != null) {
isGlassPaneVisible = oldGlassPane.isVisible();
super.remove(oldGlassPane);
}
if (glassPane != null) {
AWTAccessor.getComponentAccessor().setMixingCutoutShape(glassPane,
new Rectangle());
glassPane.setVisible(isGlassPaneVisible);
super.addImpl(glassPane, null, 0);
}
this.glassPane = glassPane;
firePropertyChange("glassPane", oldGlassPane, glassPane);
revalidate();
repaint();
}
/**
* Called by the constructor methods to create a default {@code glassPane}.
* By default this method creates a new JPanel with visibility set to true
* and opacity set to false.
*
* @return the default {@code glassPane}
*/
public JPanel createGlassPane() {
return new DefaultLayerGlassPane();
}
/**
* Sets the layout manager for this container. This method is
* overridden to prevent the layout manager from being set.
* <p>Note: If {@code mgr} is non-{@code null}, this
* method will throw an exception as layout managers are not supported on
* a {@code JLayer}.
*
* @param mgr the specified layout manager
* @exception IllegalArgumentException this method is not supported
*/
public void setLayout(LayoutManager mgr) {
if (mgr != null) {
throw new IllegalArgumentException("JLayer.setLayout() not supported");
}
}
/**
* A non-{@code null} border, or non-zero insets, isn't supported, to prevent the geometry
* of this component from becoming complex enough to inhibit
* subclassing of {@code LayerUI} class. To create a {@code JLayer} with a border,
* add it to a {@code JPanel} that has a border.
* <p>Note: If {@code border} is non-{@code null}, this
* method will throw an exception as borders are not supported on
* a {@code JLayer}.
*
* @param border the {@code Border} to set
* @exception IllegalArgumentException this method is not supported
*/
public void setBorder(Border border) {
if (border != null) {
throw new IllegalArgumentException("JLayer.setBorder() not supported");
}
}
/**
* This method is not supported by {@code JLayer}
* and always throws {@code UnsupportedOperationException}
*
* @throws UnsupportedOperationException this method is not supported
*
* @see #setView(Component)
* @see #setGlassPane(JPanel)
*/
protected void addImpl(Component comp, Object constraints, int index) {
throw new UnsupportedOperationException(
"Adding components to JLayer is not supported, " +
"use setView() or setGlassPane() instead");
}
/**
* {@inheritDoc}
*/
public void remove(Component comp) {
if (comp == null) {
super.remove(comp);
} else if (comp == getView()) {
setView(null);
} else if (comp == getGlassPane()) {
setGlassPane(null);
} else {
super.remove(comp);
}
}
/**
* {@inheritDoc}
*/
public void removeAll() {
if (view != null) {
setView(null);
}
if (glassPane != null) {
setGlassPane(null);
}
}
/**
* Always returns {@code true} to cause painting to originate from {@code JLayer},
* or one of its ancestors.
*
* @return true
* @see JComponent#isPaintingOrigin()
*/
protected boolean isPaintingOrigin() {
return true;
}
/**
* Delegates its functionality to the
* {@link javax.swing.plaf.LayerUI#paintImmediately(int, int, int, int, JLayer)} method,
* if {@code LayerUI} is set.
*
* @param x the x value of the region to be painted
* @param y the y value of the region to be painted
* @param w the width of the region to be painted
* @param h the height of the region to be painted
*/
public void paintImmediately(int x, int y, int w, int h) {
if (!isPaintingImmediately && getUI() != null) {
isPaintingImmediately = true;
try {
getUI().paintImmediately(x, y, w, h, this);
} finally {
isPaintingImmediately = false;
}
} else {
super.paintImmediately(x, y, w, h);
}
}
/**
* Delegates all painting to the {@link javax.swing.plaf.LayerUI} object.
*
* @param g the {@code Graphics} to render to
*/
public void paint(Graphics g) {
if (!isPainting) {
isPainting = true;
try {
super.paintComponent(g);
} finally {
isPainting = false;
}
} else {
super.paint(g);
}
}
/**
* This method is empty, because all painting is done by
* {@link #paint(Graphics)} and
* {@link javax.swing.plaf.LayerUI#update(Graphics, JComponent)} methods
*/
protected void paintComponent(Graphics g) {
}
/**
* The {@code JLayer} overrides the default implementation of
* this method (in {@code JComponent}) to return {@code false}.
* This ensures
* that the drawing machinery will call the {@code JLayer}'s
* {@code paint}
* implementation rather than messaging the {@code JLayer}'s
* children directly.
*
* @return false
*/
public boolean isOptimizedDrawingEnabled() {
return false;
}
/**
* {@inheritDoc}
*/
public void propertyChange(PropertyChangeEvent evt) {
if (getUI() != null) {
getUI().applyPropertyChange(evt, this);
}
}
/**
* Enables the events from JLayer and <b>all its descendants</b>
* defined by the specified event mask parameter
* to be delivered to the
* {@link LayerUI#eventDispatched(AWTEvent, JLayer)} method.
* <p>
* Events are delivered provided that {@code LayerUI} is set
* for this {@code JLayer} and the {@code JLayer}
* is displayable.
* <p>
* The following example shows how to correctly use this method
* in the {@code LayerUI} implementations:
* <pre>
* public void installUI(JComponent c) {
* super.installUI(c);
* JLayer l = (JLayer) c;
* // this LayerUI will receive only key and focus events
* l.setLayerEventMask(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
* }
*
* public void uninstallUI(JComponent c) {
* super.uninstallUI(c);
* JLayer l = (JLayer) c;
* // JLayer must be returned to its initial state
* l.setLayerEventMask(0);
* }
* </pre>
*
* By default {@code JLayer} receives no events and its event mask is {@code 0}.
*
* @param layerEventMask the bitmask of event types to receive
*
* @see #getLayerEventMask()
* @see LayerUI#eventDispatched(AWTEvent, JLayer)
* @see Component#isDisplayable()
*/
public void setLayerEventMask(long layerEventMask) {
long oldEventMask = getLayerEventMask();
this.eventMask = layerEventMask;
firePropertyChange("layerEventMask", oldEventMask, layerEventMask);
if (layerEventMask != oldEventMask) {
disableEvents(oldEventMask);
enableEvents(eventMask);
if (isDisplayable()) {
eventController.updateAWTEventListener(
oldEventMask, layerEventMask);
}
}
}
/**
* Returns the bitmap of event mask to receive by this {@code JLayer}
* and its {@code LayerUI}.
* <p>
* It means that {@link javax.swing.plaf.LayerUI#eventDispatched(AWTEvent, JLayer)} method
* will only receive events that match the event mask.
* <p>
* By default {@code JLayer} receives no events.
*
* @return the bitmask of event types to receive for this {@code JLayer}
*/
public long getLayerEventMask() {
return eventMask;
}
/**
* Delegates its functionality to the {@link javax.swing.plaf.LayerUI#updateUI(JLayer)} method,
* if {@code LayerUI} is set.
*/
public void updateUI() {
if (getUI() != null) {
getUI().updateUI(this);
}
}
/**
* Returns the preferred size of the viewport for a view component.
* <p>
* If the view component of this layer implements {@link Scrollable}, this method delegates its
* implementation to the view component.
*
* @return the preferred size of the viewport for a view component
*
* @see Scrollable
*/
public Dimension getPreferredScrollableViewportSize() {
if (getView() instanceof Scrollable) {
return ((Scrollable)getView()).getPreferredScrollableViewportSize();
}
return getPreferredSize();
}
/**
* Returns a scroll increment, which is required for components
* that display logical rows or columns in order to completely expose
* one block of rows or columns, depending on the value of orientation.
* <p>
* If the view component of this layer implements {@link Scrollable}, this method delegates its
* implementation to the view component.
*
* @return the "block" increment for scrolling in the specified direction
*
* @see Scrollable
*/
public int getScrollableBlockIncrement(Rectangle visibleRect,
int orientation, int direction) {
if (getView() instanceof Scrollable) {
return ((Scrollable)getView()).getScrollableBlockIncrement(visibleRect,
orientation, direction);
}
return (orientation == SwingConstants.VERTICAL) ? visibleRect.height :
visibleRect.width;
}
/**
* Returns {@code false} to indicate that the height of the viewport does not
* determine the height of the layer, unless the preferred height
* of the layer is smaller than the height of the viewport.
* <p>
* If the view component of this layer implements {@link Scrollable}, this method delegates its
* implementation to the view component.
*
* @return whether the layer should track the height of the viewport
*
* @see Scrollable
*/
public boolean getScrollableTracksViewportHeight() {
if (getView() instanceof Scrollable) {
return ((Scrollable)getView()).getScrollableTracksViewportHeight();
}
return false;
}
/**
* Returns {@code false} to indicate that the width of the viewport does not
* determine the width of the layer, unless the preferred width
* of the layer is smaller than the width of the viewport.
* <p>
* If the view component of this layer implements {@link Scrollable}, this method delegates its
* implementation to the view component.
*
* @return whether the layer should track the width of the viewport
*
* @see Scrollable
*/
public boolean getScrollableTracksViewportWidth() {
if (getView() instanceof Scrollable) {
return ((Scrollable)getView()).getScrollableTracksViewportWidth();
}
return false;
}
/**
* Returns a scroll increment, which is required for components
* that display logical rows or columns in order to completely expose
* one new row or column, depending on the value of orientation.
* Ideally, components should handle a partially exposed row or column
* by returning the distance required to completely expose the item.
* <p>
* Scrolling containers, like {@code JScrollPane}, will use this method
* each time the user requests a unit scroll.
* <p>
* If the view component of this layer implements {@link Scrollable}, this method delegates its
* implementation to the view component.
*
* @return The "unit" increment for scrolling in the specified direction.
* This value should always be positive.
*
* @see Scrollable
*/
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
int direction) {
if (getView() instanceof Scrollable) {
return ((Scrollable) getView()).getScrollableUnitIncrement(
visibleRect, orientation, direction);
}
return 1;
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
if (layerUI != null) {
setUI(layerUI);
}
if (eventMask != 0) {
eventController.updateAWTEventListener(0, eventMask);
}
}
/**
* {@inheritDoc}
*/
public void addNotify() {
super.addNotify();
eventController.updateAWTEventListener(0, eventMask);
}
/**
* {@inheritDoc}
*/
public void removeNotify() {
super.removeNotify();
eventController.updateAWTEventListener(eventMask, 0);
}
/**
* Delegates its functionality to the {@link javax.swing.plaf.LayerUI#doLayout(JLayer)} method,
* if {@code LayerUI} is set.
*/
public void doLayout() {
if (getUI() != null) {
getUI().doLayout(this);
}
}
/**
* Gets the AccessibleContext associated with this {@code JLayer}.
*
* @return the AccessibleContext associated with this {@code JLayer}.
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJComponent() {
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PANEL;
}
};
}
return accessibleContext;
}
/**
* static AWTEventListener to be shared with all AbstractLayerUIs
*/
private static class LayerEventController implements AWTEventListener {
private ArrayList<Long> layerMaskList =
new ArrayList<Long>();
private long currentEventMask;
private static final long ACCEPTED_EVENTS =
AWTEvent.COMPONENT_EVENT_MASK |
AWTEvent.CONTAINER_EVENT_MASK |
AWTEvent.FOCUS_EVENT_MASK |
AWTEvent.KEY_EVENT_MASK |
AWTEvent.MOUSE_WHEEL_EVENT_MASK |
AWTEvent.MOUSE_MOTION_EVENT_MASK |
AWTEvent.MOUSE_EVENT_MASK |
AWTEvent.INPUT_METHOD_EVENT_MASK |
AWTEvent.HIERARCHY_EVENT_MASK |
AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK;
@SuppressWarnings("unchecked")
public void eventDispatched(AWTEvent event) {
Object source = event.getSource();
if (source instanceof Component) {
Component component = (Component) source;
while (component != null) {
if (component instanceof JLayer) {
JLayer l = (JLayer) component;
LayerUI ui = l.getUI();
if (ui != null &&
isEventEnabled(l.getLayerEventMask(), event.getID()) &&
(!(event instanceof InputEvent) || !((InputEvent)event).isConsumed())) {
ui.eventDispatched(event, l);
}
}
component = component.getParent();
}
}
}
private void updateAWTEventListener(long oldEventMask, long newEventMask) {
if (oldEventMask != 0) {
layerMaskList.remove(oldEventMask);
}
if (newEventMask != 0) {
layerMaskList.add(newEventMask);
}
long combinedMask = 0;
for (Long mask : layerMaskList) {
combinedMask |= mask;
}
// filter out all unaccepted events
combinedMask &= ACCEPTED_EVENTS;
if (combinedMask == 0) {
removeAWTEventListener();
} else if (getCurrentEventMask() != combinedMask) {
removeAWTEventListener();
addAWTEventListener(combinedMask);
}
currentEventMask = combinedMask;
}
private long getCurrentEventMask() {
return currentEventMask;
}
private void addAWTEventListener(final long eventMask) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
Toolkit.getDefaultToolkit().
addAWTEventListener(LayerEventController.this, eventMask);
return null;
}
});
}
private void removeAWTEventListener() {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
Toolkit.getDefaultToolkit().
removeAWTEventListener(LayerEventController.this);
return null;
}
});
}
private boolean isEventEnabled(long eventMask, int id) {
return (((eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 &&
id >= ComponentEvent.COMPONENT_FIRST &&
id <= ComponentEvent.COMPONENT_LAST)
|| ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 &&
id >= ContainerEvent.CONTAINER_FIRST &&
id <= ContainerEvent.CONTAINER_LAST)
|| ((eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0 &&
id >= FocusEvent.FOCUS_FIRST &&
id <= FocusEvent.FOCUS_LAST)
|| ((eventMask & AWTEvent.KEY_EVENT_MASK) != 0 &&
id >= KeyEvent.KEY_FIRST &&
id <= KeyEvent.KEY_LAST)
|| ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 &&
id == MouseEvent.MOUSE_WHEEL)
|| ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 &&
(id == MouseEvent.MOUSE_MOVED ||
id == MouseEvent.MOUSE_DRAGGED))
|| ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 &&
id != MouseEvent.MOUSE_MOVED &&
id != MouseEvent.MOUSE_DRAGGED &&
id != MouseEvent.MOUSE_WHEEL &&
id >= MouseEvent.MOUSE_FIRST &&
id <= MouseEvent.MOUSE_LAST)
|| ((eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 &&
id >= InputMethodEvent.INPUT_METHOD_FIRST &&
id <= InputMethodEvent.INPUT_METHOD_LAST)
|| ((eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 &&
id == HierarchyEvent.HIERARCHY_CHANGED)
|| ((eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 &&
(id == HierarchyEvent.ANCESTOR_MOVED ||
id == HierarchyEvent.ANCESTOR_RESIZED)));
}
}
/**
* The default glassPane for the {@link javax.swing.JLayer}.
* It is a subclass of {@code JPanel} which is non opaque by default.
*/
private static class DefaultLayerGlassPane extends JPanel {
/**
* Creates a new {@link DefaultLayerGlassPane}
*/
public DefaultLayerGlassPane() {
setOpaque(false);
}
/**
* First, implementation of this method iterates through
* glassPane's child components and returns {@code true}
* if any of them is visible and contains passed x,y point.
* After that it checks if no mouseListeners is attached to this component
* and no mouse cursor is set, then it returns {@code false},
* otherwise calls the super implementation of this method.
*
* @param x the <i>x</i> coordinate of the point
* @param y the <i>y</i> coordinate of the point
* @return true if this component logically contains x,y
*/
public boolean contains(int x, int y) {
for (int i = 0; i < getComponentCount(); i++) {
Component c = getComponent(i);
Point point = SwingUtilities.convertPoint(this, new Point(x, y), c);
if(c.isVisible() && c.contains(point)){
return true;
}
}
if (getMouseListeners().length == 0
&& getMouseMotionListeners().length == 0
&& getMouseWheelListeners().length == 0
&& !isCursorSet()) {
return false;
}
return super.contains(x, y);
}
}
}

View File

@@ -0,0 +1,786 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Hashtable;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import sun.awt.SunToolkit;
import javax.accessibility.*;
/**
* <code>JLayeredPane</code> adds depth to a JFC/Swing container,
* allowing components to overlap each other when needed.
* An <code>Integer</code> object specifies each component's depth in the
* container, where higher-numbered components sit &quot;on top&quot; of other
* components.
* For task-oriented documentation and examples of using layered panes see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html">How to Use a Layered Pane</a>,
* a section in <em>The Java Tutorial</em>.
*
* <TABLE STYLE="FLOAT:RIGHT" BORDER="0" SUMMARY="layout">
* <TR>
* <TD ALIGN="CENTER">
* <P STYLE="TEXT-ALIGN:CENTER"><IMG SRC="doc-files/JLayeredPane-1.gif"
* alt="The following text describes this image."
* WIDTH="269" HEIGHT="264" STYLE="FLOAT:BOTTOM; BORDER=0">
* </TD>
* </TR>
* </TABLE>
* For convenience, <code>JLayeredPane</code> divides the depth-range
* into several different layers. Putting a component into one of those
* layers makes it easy to ensure that components overlap properly,
* without having to worry about specifying numbers for specific depths:
* <DL>
* <DT><FONT SIZE="2">DEFAULT_LAYER</FONT></DT>
* <DD>The standard layer, where most components go. This the bottommost
* layer.
* <DT><FONT SIZE="2">PALETTE_LAYER</FONT></DT>
* <DD>The palette layer sits over the default layer. Useful for floating
* toolbars and palettes, so they can be positioned above other components.
* <DT><FONT SIZE="2">MODAL_LAYER</FONT></DT>
* <DD>The layer used for modal dialogs. They will appear on top of any
* toolbars, palettes, or standard components in the container.
* <DT><FONT SIZE="2">POPUP_LAYER</FONT></DT>
* <DD>The popup layer displays above dialogs. That way, the popup windows
* associated with combo boxes, tooltips, and other help text will appear
* above the component, palette, or dialog that generated them.
* <DT><FONT SIZE="2">DRAG_LAYER</FONT></DT>
* <DD>When dragging a component, reassigning it to the drag layer ensures
* that it is positioned over every other component in the container. When
* finished dragging, it can be reassigned to its normal layer.
* </DL>
* The <code>JLayeredPane</code> methods <code>moveToFront(Component)</code>,
* <code>moveToBack(Component)</code> and <code>setPosition</code> can be used
* to reposition a component within its layer. The <code>setLayer</code> method
* can also be used to change the component's current layer.
*
* <h2>Details</h2>
* <code>JLayeredPane</code> manages its list of children like
* <code>Container</code>, but allows for the definition of a several
* layers within itself. Children in the same layer are managed exactly
* like the normal <code>Container</code> object,
* with the added feature that when children components overlap, children
* in higher layers display above the children in lower layers.
* <p>
* Each layer is a distinct integer number. The layer attribute can be set
* on a <code>Component</code> by passing an <code>Integer</code>
* object during the add call.<br> For example:
* <PRE>
* layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
* or
* layeredPane.add(child, new Integer(10));
* </PRE>
* The layer attribute can also be set on a Component by calling<PRE>
* layeredPaneParent.setLayer(child, 10)</PRE>
* on the <code>JLayeredPane</code> that is the parent of component. The layer
* should be set <i>before</i> adding the child to the parent.
* <p>
* Higher number layers display above lower number layers. So, using
* numbers for the layers and letters for individual components, a
* representative list order would look like this:<PRE>
* 5a, 5b, 5c, 2a, 2b, 2c, 1a </PRE>
* where the leftmost components are closest to the top of the display.
* <p>
* A component can be moved to the top or bottom position within its
* layer by calling <code>moveToFront</code> or <code>moveToBack</code>.
* <p>
* The position of a component within a layer can also be specified directly.
* Valid positions range from 0 up to one less than the number of
* components in that layer. A value of -1 indicates the bottommost
* position. A value of 0 indicates the topmost position. Unlike layer
* numbers, higher position values are <i>lower</i> in the display.
* <blockquote>
* <b>Note:</b> This sequence (defined by java.awt.Container) is the reverse
* of the layer numbering sequence. Usually though, you will use <code>moveToFront</code>,
* <code>moveToBack</code>, and <code>setLayer</code>.
* </blockquote>
* Here are some examples using the method add(Component, layer, position):
* Calling add(5x, 5, -1) results in:<PRE>
* 5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a </PRE>
*
* Calling add(5z, 5, 2) results in:<PRE>
* 5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a </PRE>
*
* Calling add(3a, 3, 7) results in:<PRE>
* 5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a </PRE>
*
* Using normal paint/event mechanics results in 1a appearing at the bottom
* and 5a being above all other components.
* <p>
* <b>Note:</b> that these layers are simply a logical construct and LayoutManagers
* will affect all child components of this container without regard for
* layer settings.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @author David Kloba
*/
@SuppressWarnings("serial")
public class JLayeredPane extends JComponent implements Accessible {
/// Watch the values in getObjectForLayer()
/** Convenience object defining the Default layer. Equivalent to new Integer(0).*/
public final static Integer DEFAULT_LAYER = new Integer(0);
/** Convenience object defining the Palette layer. Equivalent to new Integer(100).*/
public final static Integer PALETTE_LAYER = new Integer(100);
/** Convenience object defining the Modal layer. Equivalent to new Integer(200).*/
public final static Integer MODAL_LAYER = new Integer(200);
/** Convenience object defining the Popup layer. Equivalent to new Integer(300).*/
public final static Integer POPUP_LAYER = new Integer(300);
/** Convenience object defining the Drag layer. Equivalent to new Integer(400).*/
public final static Integer DRAG_LAYER = new Integer(400);
/** Convenience object defining the Frame Content layer.
* This layer is normally only use to position the contentPane and menuBar
* components of JFrame.
* Equivalent to new Integer(-30000).
* @see JFrame
*/
public final static Integer FRAME_CONTENT_LAYER = new Integer(-30000);
/** Bound property */
public final static String LAYER_PROPERTY = "layeredContainerLayer";
// Hashtable to store layer values for non-JComponent components
private Hashtable<Component,Integer> componentToLayer;
private boolean optimizedDrawingPossible = true;
//////////////////////////////////////////////////////////////////////////////
//// Container Override methods
//////////////////////////////////////////////////////////////////////////////
/** Create a new JLayeredPane */
public JLayeredPane() {
setLayout(null);
}
private void validateOptimizedDrawing() {
boolean layeredComponentFound = false;
synchronized(getTreeLock()) {
Integer layer;
for (Component c : getComponents()) {
layer = null;
if(SunToolkit.isInstanceOf(c, "javax.swing.JInternalFrame") ||
(c instanceof JComponent &&
(layer = (Integer)((JComponent)c).
getClientProperty(LAYER_PROPERTY)) != null))
{
if(layer != null && layer.equals(FRAME_CONTENT_LAYER))
continue;
layeredComponentFound = true;
break;
}
}
}
if(layeredComponentFound)
optimizedDrawingPossible = false;
else
optimizedDrawingPossible = true;
}
protected void addImpl(Component comp, Object constraints, int index) {
int layer;
int pos;
if(constraints instanceof Integer) {
layer = ((Integer)constraints).intValue();
setLayer(comp, layer);
} else
layer = getLayer(comp);
pos = insertIndexForLayer(layer, index);
super.addImpl(comp, constraints, pos);
comp.validate();
comp.repaint();
validateOptimizedDrawing();
}
/**
* Remove the indexed component from this pane.
* This is the absolute index, ignoring layers.
*
* @param index an int specifying the component to remove
* @see #getIndexOf
*/
public void remove(int index) {
Component c = getComponent(index);
super.remove(index);
if (c != null && !(c instanceof JComponent)) {
getComponentToLayer().remove(c);
}
validateOptimizedDrawing();
}
/**
* Removes all the components from this container.
*
* @since 1.5
*/
public void removeAll() {
Component[] children = getComponents();
Hashtable<Component, Integer> cToL = getComponentToLayer();
for (int counter = children.length - 1; counter >= 0; counter--) {
Component c = children[counter];
if (c != null && !(c instanceof JComponent)) {
cToL.remove(c);
}
}
super.removeAll();
}
/**
* Returns false if components in the pane can overlap, which makes
* optimized drawing impossible. Otherwise, returns true.
*
* @return false if components can overlap, else true
* @see JComponent#isOptimizedDrawingEnabled
*/
public boolean isOptimizedDrawingEnabled() {
return optimizedDrawingPossible;
}
//////////////////////////////////////////////////////////////////////////////
//// New methods for managing layers
//////////////////////////////////////////////////////////////////////////////
/** Sets the layer property on a JComponent. This method does not cause
* any side effects like setLayer() (painting, add/remove, etc).
* Normally you should use the instance method setLayer(), in order to
* get the desired side-effects (like repainting).
*
* @param c the JComponent to move
* @param layer an int specifying the layer to move it to
* @see #setLayer
*/
public static void putLayer(JComponent c, int layer) {
/// MAKE SURE THIS AND setLayer(Component c, int layer, int position) are SYNCED
Integer layerObj;
layerObj = new Integer(layer);
c.putClientProperty(LAYER_PROPERTY, layerObj);
}
/** Gets the layer property for a JComponent, it
* does not cause any side effects like setLayer(). (painting, add/remove, etc)
* Normally you should use the instance method getLayer().
*
* @param c the JComponent to check
* @return an int specifying the component's layer
*/
public static int getLayer(JComponent c) {
Integer i;
if((i = (Integer)c.getClientProperty(LAYER_PROPERTY)) != null)
return i.intValue();
return DEFAULT_LAYER.intValue();
}
/** Convenience method that returns the first JLayeredPane which
* contains the specified component. Note that all JFrames have a
* JLayeredPane at their root, so any component in a JFrame will
* have a JLayeredPane parent.
*
* @param c the Component to check
* @return the JLayeredPane that contains the component, or
* null if no JLayeredPane is found in the component
* hierarchy
* @see JFrame
* @see JRootPane
*/
public static JLayeredPane getLayeredPaneAbove(Component c) {
if(c == null) return null;
Component parent = c.getParent();
while(parent != null && !(parent instanceof JLayeredPane))
parent = parent.getParent();
return (JLayeredPane)parent;
}
/** Sets the layer attribute on the specified component,
* making it the bottommost component in that layer.
* Should be called before adding to parent.
*
* @param c the Component to set the layer for
* @param layer an int specifying the layer to set, where
* lower numbers are closer to the bottom
*/
public void setLayer(Component c, int layer) {
setLayer(c, layer, -1);
}
/** Sets the layer attribute for the specified component and
* also sets its position within that layer.
*
* @param c the Component to set the layer for
* @param layer an int specifying the layer to set, where
* lower numbers are closer to the bottom
* @param position an int specifying the position within the
* layer, where 0 is the topmost position and -1
* is the bottommost position
*/
public void setLayer(Component c, int layer, int position) {
Integer layerObj;
layerObj = getObjectForLayer(layer);
if(layer == getLayer(c) && position == getPosition(c)) {
repaint(c.getBounds());
return;
}
/// MAKE SURE THIS AND putLayer(JComponent c, int layer) are SYNCED
if(c instanceof JComponent)
((JComponent)c).putClientProperty(LAYER_PROPERTY, layerObj);
else
getComponentToLayer().put(c, layerObj);
if(c.getParent() == null || c.getParent() != this) {
repaint(c.getBounds());
return;
}
int index = insertIndexForLayer(c, layer, position);
setComponentZOrder(c, index);
repaint(c.getBounds());
}
/**
* Returns the layer attribute for the specified Component.
*
* @param c the Component to check
* @return an int specifying the component's current layer
*/
public int getLayer(Component c) {
Integer i;
if(c instanceof JComponent)
i = (Integer)((JComponent)c).getClientProperty(LAYER_PROPERTY);
else
i = getComponentToLayer().get(c);
if(i == null)
return DEFAULT_LAYER.intValue();
return i.intValue();
}
/**
* Returns the index of the specified Component.
* This is the absolute index, ignoring layers.
* Index numbers, like position numbers, have the topmost component
* at index zero. Larger numbers are closer to the bottom.
*
* @param c the Component to check
* @return an int specifying the component's index
*/
public int getIndexOf(Component c) {
int i, count;
count = getComponentCount();
for(i = 0; i < count; i++) {
if(c == getComponent(i))
return i;
}
return -1;
}
/**
* Moves the component to the top of the components in its current layer
* (position 0).
*
* @param c the Component to move
* @see #setPosition(Component, int)
*/
public void moveToFront(Component c) {
setPosition(c, 0);
}
/**
* Moves the component to the bottom of the components in its current layer
* (position -1).
*
* @param c the Component to move
* @see #setPosition(Component, int)
*/
public void moveToBack(Component c) {
setPosition(c, -1);
}
/**
* Moves the component to <code>position</code> within its current layer,
* where 0 is the topmost position within the layer and -1 is the bottommost
* position.
* <p>
* <b>Note:</b> Position numbering is defined by java.awt.Container, and
* is the opposite of layer numbering. Lower position numbers are closer
* to the top (0 is topmost), and higher position numbers are closer to
* the bottom.
*
* @param c the Component to move
* @param position an int in the range -1..N-1, where N is the number of
* components in the component's current layer
*/
public void setPosition(Component c, int position) {
setLayer(c, getLayer(c), position);
}
/**
* Get the relative position of the component within its layer.
*
* @param c the Component to check
* @return an int giving the component's position, where 0 is the
* topmost position and the highest index value = the count
* count of components at that layer, minus 1
*
* @see #getComponentCountInLayer
*/
public int getPosition(Component c) {
int i, startLayer, curLayer, startLocation, pos = 0;
getComponentCount();
startLocation = getIndexOf(c);
if(startLocation == -1)
return -1;
startLayer = getLayer(c);
for(i = startLocation - 1; i >= 0; i--) {
curLayer = getLayer(getComponent(i));
if(curLayer == startLayer)
pos++;
else
return pos;
}
return pos;
}
/** Returns the highest layer value from all current children.
* Returns 0 if there are no children.
*
* @return an int indicating the layer of the topmost component in the
* pane, or zero if there are no children
*/
public int highestLayer() {
if(getComponentCount() > 0)
return getLayer(getComponent(0));
return 0;
}
/** Returns the lowest layer value from all current children.
* Returns 0 if there are no children.
*
* @return an int indicating the layer of the bottommost component in the
* pane, or zero if there are no children
*/
public int lowestLayer() {
int count = getComponentCount();
if(count > 0)
return getLayer(getComponent(count-1));
return 0;
}
/**
* Returns the number of children currently in the specified layer.
*
* @param layer an int specifying the layer to check
* @return an int specifying the number of components in that layer
*/
public int getComponentCountInLayer(int layer) {
int i, count, curLayer;
int layerCount = 0;
count = getComponentCount();
for(i = 0; i < count; i++) {
curLayer = getLayer(getComponent(i));
if(curLayer == layer) {
layerCount++;
/// Short circut the counting when we have them all
} else if(layerCount > 0 || curLayer < layer) {
break;
}
}
return layerCount;
}
/**
* Returns an array of the components in the specified layer.
*
* @param layer an int specifying the layer to check
* @return an array of Components contained in that layer
*/
public Component[] getComponentsInLayer(int layer) {
int i, count, curLayer;
int layerCount = 0;
Component[] results;
results = new Component[getComponentCountInLayer(layer)];
count = getComponentCount();
for(i = 0; i < count; i++) {
curLayer = getLayer(getComponent(i));
if(curLayer == layer) {
results[layerCount++] = getComponent(i);
/// Short circut the counting when we have them all
} else if(layerCount > 0 || curLayer < layer) {
break;
}
}
return results;
}
/**
* Paints this JLayeredPane within the specified graphics context.
*
* @param g the Graphics context within which to paint
*/
public void paint(Graphics g) {
if(isOpaque()) {
Rectangle r = g.getClipBounds();
Color c = getBackground();
if(c == null)
c = Color.lightGray;
g.setColor(c);
if (r != null) {
g.fillRect(r.x, r.y, r.width, r.height);
}
else {
g.fillRect(0, 0, getWidth(), getHeight());
}
}
super.paint(g);
}
//////////////////////////////////////////////////////////////////////////////
//// Implementation Details
//////////////////////////////////////////////////////////////////////////////
/**
* Returns the hashtable that maps components to layers.
*
* @return the Hashtable used to map components to their layers
*/
protected Hashtable<Component,Integer> getComponentToLayer() {
if(componentToLayer == null)
componentToLayer = new Hashtable<Component,Integer>(4);
return componentToLayer;
}
/**
* Returns the Integer object associated with a specified layer.
*
* @param layer an int specifying the layer
* @return an Integer object for that layer
*/
protected Integer getObjectForLayer(int layer) {
Integer layerObj;
switch(layer) {
case 0:
layerObj = DEFAULT_LAYER;
break;
case 100:
layerObj = PALETTE_LAYER;
break;
case 200:
layerObj = MODAL_LAYER;
break;
case 300:
layerObj = POPUP_LAYER;
break;
case 400:
layerObj = DRAG_LAYER;
break;
default:
layerObj = new Integer(layer);
}
return layerObj;
}
/**
* Primitive method that determines the proper location to
* insert a new child based on layer and position requests.
*
* @param layer an int specifying the layer
* @param position an int specifying the position within the layer
* @return an int giving the (absolute) insertion-index
*
* @see #getIndexOf
*/
protected int insertIndexForLayer(int layer, int position) {
return insertIndexForLayer(null, layer, position);
}
/**
* This method is an extended version of insertIndexForLayer()
* to support setLayer which uses Container.setZOrder which does
* not remove the component from the containment hierarchy though
* we need to ignore it when calculating the insertion index.
*
* @param comp component to ignore when determining index
* @param layer an int specifying the layer
* @param position an int specifying the position within the layer
* @return an int giving the (absolute) insertion-index
*
* @see #getIndexOf
*/
private int insertIndexForLayer(Component comp, int layer, int position) {
int i, count, curLayer;
int layerStart = -1;
int layerEnd = -1;
int componentCount = getComponentCount();
ArrayList<Component> compList =
new ArrayList<Component>(componentCount);
for (int index = 0; index < componentCount; index++) {
if (getComponent(index) != comp) {
compList.add(getComponent(index));
}
}
count = compList.size();
for (i = 0; i < count; i++) {
curLayer = getLayer(compList.get(i));
if (layerStart == -1 && curLayer == layer) {
layerStart = i;
}
if (curLayer < layer) {
if (i == 0) {
// layer is greater than any current layer
// [ ASSERT(layer > highestLayer()) ]
layerStart = 0;
layerEnd = 0;
} else {
layerEnd = i;
}
break;
}
}
// layer requested is lower than any current layer
// [ ASSERT(layer < lowestLayer()) ]
// put it on the bottom of the stack
if (layerStart == -1 && layerEnd == -1)
return count;
// In the case of a single layer entry handle the degenerative cases
if (layerStart != -1 && layerEnd == -1)
layerEnd = count;
if (layerEnd != -1 && layerStart == -1)
layerStart = layerEnd;
// If we are adding to the bottom, return the last element
if (position == -1)
return layerEnd;
// Otherwise make sure the requested position falls in the
// proper range
if (position > -1 && layerStart + position <= layerEnd)
return layerStart + position;
// Otherwise return the end of the layer
return layerEnd;
}
/**
* Returns a string representation of this JLayeredPane. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JLayeredPane.
*/
protected String paramString() {
String optimizedDrawingPossibleString = (optimizedDrawingPossible ?
"true" : "false");
return super.paramString() +
",optimizedDrawingPossible=" + optimizedDrawingPossibleString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JLayeredPane.
* For layered panes, the AccessibleContext takes the form of an
* AccessibleJLayeredPane.
* A new AccessibleJLayeredPane instance is created if necessary.
*
* @return an AccessibleJLayeredPane that serves as the
* AccessibleContext of this JLayeredPane
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJLayeredPane();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JLayeredPane</code> class. It provides an implementation of the
* Java Accessibility API appropriate to layered pane user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
protected class AccessibleJLayeredPane extends AccessibleJComponent {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.LAYERED_PANE;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,774 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.*;
import java.beans.Transient;
import java.util.Vector;
import java.util.Enumeration;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import javax.swing.event.*;
import javax.swing.border.Border;
import javax.swing.plaf.*;
import javax.accessibility.*;
/**
* An implementation of a menu bar. You add <code>JMenu</code> objects to the
* menu bar to construct a menu. When the user selects a <code>JMenu</code>
* object, its associated <code>JPopupMenu</code> is displayed, allowing the
* user to select one of the <code>JMenuItems</code> on it.
* <p>
* For information and examples of using menu bars see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
* <p>
* <strong>Warning:</strong>
* By default, pressing the Tab key does not transfer focus from a <code>
* JMenuBar</code> which is added to a container together with other Swing
* components, because the <code>focusTraversalKeysEnabled</code> property
* of <code>JMenuBar</code> is set to <code>false</code>. To resolve this,
* you should call the <code>JMenuBar.setFocusTraversalKeysEnabled(true)</code>
* method.
* @beaninfo
* attribute: isContainer true
* description: A container for holding and displaying menus.
*
* @author Georges Saab
* @author David Karlton
* @author Arnaud Weber
* @see JMenu
* @see JPopupMenu
* @see JMenuItem
*/
@SuppressWarnings("serial")
public class JMenuBar extends JComponent implements Accessible,MenuElement
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "MenuBarUI";
/*
* Model for the selected subcontrol.
*/
private transient SingleSelectionModel selectionModel;
private boolean paintBorder = true;
private Insets margin = null;
/* diagnostic aids -- should be false for production builds. */
private static final boolean TRACE = false; // trace creates and disposes
private static final boolean VERBOSE = false; // show reuse hits/misses
private static final boolean DEBUG = false; // show bad params, misc.
/**
* Creates a new menu bar.
*/
public JMenuBar() {
super();
setFocusTraversalKeysEnabled(false);
setSelectionModel(new DefaultSingleSelectionModel());
updateUI();
}
/**
* Returns the menubar's current UI.
* @see #setUI
*/
public MenuBarUI getUI() {
return (MenuBarUI)ui;
}
/**
* Sets the L&amp;F object that renders this component.
*
* @param ui the new MenuBarUI L&amp;F object
* @see UIDefaults#getUI
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel.
*/
public void setUI(MenuBarUI ui) {
super.setUI(ui);
}
/**
* Resets the UI property with a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((MenuBarUI)UIManager.getUI(this));
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "MenuBarUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Returns the model object that handles single selections.
*
* @return the <code>SingleSelectionModel</code> property
* @see SingleSelectionModel
*/
public SingleSelectionModel getSelectionModel() {
return selectionModel;
}
/**
* Sets the model object to handle single selections.
*
* @param model the <code>SingleSelectionModel</code> to use
* @see SingleSelectionModel
* @beaninfo
* bound: true
* description: The selection model, recording which child is selected.
*/
public void setSelectionModel(SingleSelectionModel model) {
SingleSelectionModel oldValue = selectionModel;
this.selectionModel = model;
firePropertyChange("selectionModel", oldValue, selectionModel);
}
/**
* Appends the specified menu to the end of the menu bar.
*
* @param c the <code>JMenu</code> component to add
* @return the menu component
*/
public JMenu add(JMenu c) {
super.add(c);
return c;
}
/**
* Returns the menu at the specified position in the menu bar.
*
* @param index an integer giving the position in the menu bar, where
* 0 is the first position
* @return the <code>JMenu</code> at that position, or <code>null</code> if
* if there is no <code>JMenu</code> at that position (ie. if
* it is a <code>JMenuItem</code>)
*/
public JMenu getMenu(int index) {
Component c = getComponentAtIndex(index);
if (c instanceof JMenu)
return (JMenu) c;
return null;
}
/**
* Returns the number of items in the menu bar.
*
* @return the number of items in the menu bar
*/
public int getMenuCount() {
return getComponentCount();
}
/**
* Sets the help menu that appears when the user selects the
* "help" option in the menu bar. This method is not yet implemented
* and will throw an exception.
*
* @param menu the JMenu that delivers help to the user
*/
public void setHelpMenu(JMenu menu) {
throw new Error("setHelpMenu() not yet implemented.");
}
/**
* Gets the help menu for the menu bar. This method is not yet
* implemented and will throw an exception.
*
* @return the <code>JMenu</code> that delivers help to the user
*/
@Transient
public JMenu getHelpMenu() {
throw new Error("getHelpMenu() not yet implemented.");
}
/**
* Returns the component at the specified index.
*
* @param i an integer specifying the position, where 0 is first
* @return the <code>Component</code> at the position,
* or <code>null</code> for an invalid index
* @deprecated replaced by <code>getComponent(int i)</code>
*/
@Deprecated
public Component getComponentAtIndex(int i) {
if(i < 0 || i >= getComponentCount()) {
return null;
}
return getComponent(i);
}
/**
* Returns the index of the specified component.
*
* @param c the <code>Component</code> to find
* @return an integer giving the component's position, where 0 is first;
* or -1 if it can't be found
*/
public int getComponentIndex(Component c) {
int ncomponents = this.getComponentCount();
Component[] component = this.getComponents();
for (int i = 0 ; i < ncomponents ; i++) {
Component comp = component[i];
if (comp == c)
return i;
}
return -1;
}
/**
* Sets the currently selected component, producing a
* a change to the selection model.
*
* @param sel the <code>Component</code> to select
*/
public void setSelected(Component sel) {
SingleSelectionModel model = getSelectionModel();
int index = getComponentIndex(sel);
model.setSelectedIndex(index);
}
/**
* Returns true if the menu bar currently has a component selected.
*
* @return true if a selection has been made, else false
*/
public boolean isSelected() {
return selectionModel.isSelected();
}
/**
* Returns true if the menu bars border should be painted.
*
* @return true if the border should be painted, else false
*/
public boolean isBorderPainted() {
return paintBorder;
}
/**
* Sets whether the border should be painted.
*
* @param b if true and border property is not <code>null</code>,
* the border is painted.
* @see #isBorderPainted
* @beaninfo
* bound: true
* attribute: visualUpdate true
* description: Whether the border should be painted.
*/
public void setBorderPainted(boolean b) {
boolean oldValue = paintBorder;
paintBorder = b;
firePropertyChange("borderPainted", oldValue, paintBorder);
if (b != oldValue) {
revalidate();
repaint();
}
}
/**
* Paints the menubar's border if <code>BorderPainted</code>
* property is true.
*
* @param g the <code>Graphics</code> context to use for painting
* @see JComponent#paint
* @see JComponent#setBorder
*/
protected void paintBorder(Graphics g) {
if (isBorderPainted()) {
super.paintBorder(g);
}
}
/**
* Sets the margin between the menubar's border and
* its menus. Setting to <code>null</code> will cause the menubar to
* use the default margins.
*
* @param m an Insets object containing the margin values
* @see Insets
* @beaninfo
* bound: true
* attribute: visualUpdate true
* description: The space between the menubar's border and its contents
*/
public void setMargin(Insets m) {
Insets old = margin;
this.margin = m;
firePropertyChange("margin", old, m);
if (old == null || !old.equals(m)) {
revalidate();
repaint();
}
}
/**
* Returns the margin between the menubar's border and
* its menus. If there is no previous margin, it will create
* a default margin with zero size.
*
* @return an <code>Insets</code> object containing the margin values
* @see Insets
*/
public Insets getMargin() {
if(margin == null) {
return new Insets(0,0,0,0);
} else {
return margin;
}
}
/**
* Implemented to be a <code>MenuElement</code> -- does nothing.
*
* @see #getSubElements
*/
public void processMouseEvent(MouseEvent event,MenuElement path[],MenuSelectionManager manager) {
}
/**
* Implemented to be a <code>MenuElement</code> -- does nothing.
*
* @see #getSubElements
*/
public void processKeyEvent(KeyEvent e,MenuElement path[],MenuSelectionManager manager) {
}
/**
* Implemented to be a <code>MenuElement</code> -- does nothing.
*
* @see #getSubElements
*/
public void menuSelectionChanged(boolean isIncluded) {
}
/**
* Implemented to be a <code>MenuElement</code> -- returns the
* menus in this menu bar.
* This is the reason for implementing the <code>MenuElement</code>
* interface -- so that the menu bar can be treated the same as
* other menu elements.
* @return an array of menu items in the menu bar.
*/
public MenuElement[] getSubElements() {
MenuElement result[];
Vector<MenuElement> tmp = new Vector<MenuElement>();
int c = getComponentCount();
int i;
Component m;
for(i=0 ; i < c ; i++) {
m = getComponent(i);
if(m instanceof MenuElement)
tmp.addElement((MenuElement) m);
}
result = new MenuElement[tmp.size()];
for(i=0,c=tmp.size() ; i < c ; i++)
result[i] = tmp.elementAt(i);
return result;
}
/**
* Implemented to be a <code>MenuElement</code>. Returns this object.
*
* @return the current <code>Component</code> (this)
* @see #getSubElements
*/
public Component getComponent() {
return this;
}
/**
* Returns a string representation of this <code>JMenuBar</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JMenuBar</code>
*/
protected String paramString() {
String paintBorderString = (paintBorder ?
"true" : "false");
String marginString = (margin != null ?
margin.toString() : "");
return super.paramString() +
",margin=" + marginString +
",paintBorder=" + paintBorderString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JMenuBar.
* For JMenuBars, the AccessibleContext takes the form of an
* AccessibleJMenuBar.
* A new AccessibleJMenuBar instance is created if necessary.
*
* @return an AccessibleJMenuBar that serves as the
* AccessibleContext of this JMenuBar
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJMenuBar();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JMenuBar</code> class. It provides an implementation of the
* Java Accessibility API appropriate to menu bar user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
protected class AccessibleJMenuBar extends AccessibleJComponent
implements AccessibleSelection {
/**
* Get the accessible state set of this object.
*
* @return an instance of AccessibleState containing the current state
* of the object
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
return states;
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.MENU_BAR;
}
/**
* Get the AccessibleSelection associated with this object. In the
* implementation of the Java Accessibility API for this class,
* return this object, which is responsible for implementing the
* AccessibleSelection interface on behalf of itself.
*
* @return this object
*/
public AccessibleSelection getAccessibleSelection() {
return this;
}
/**
* Returns 1 if a menu is currently selected in this menu bar.
*
* @return 1 if a menu is currently selected, else 0
*/
public int getAccessibleSelectionCount() {
if (isSelected()) {
return 1;
} else {
return 0;
}
}
/**
* Returns the currently selected menu if one is selected,
* otherwise null.
*/
public Accessible getAccessibleSelection(int i) {
if (isSelected()) {
if (i != 0) { // single selection model for JMenuBar
return null;
}
int j = getSelectionModel().getSelectedIndex();
if (getComponentAtIndex(j) instanceof Accessible) {
return (Accessible) getComponentAtIndex(j);
}
}
return null;
}
/**
* Returns true if the current child of this object is selected.
*
* @param i the zero-based index of the child in this Accessible
* object.
* @see AccessibleContext#getAccessibleChild
*/
public boolean isAccessibleChildSelected(int i) {
return (i == getSelectionModel().getSelectedIndex());
}
/**
* Selects the nth menu in the menu bar, forcing it to
* pop up. If another menu is popped up, this will force
* it to close. If the nth menu is already selected, this
* method has no effect.
*
* @param i the zero-based index of selectable items
* @see #getAccessibleStateSet
*/
public void addAccessibleSelection(int i) {
// first close up any open menu
int j = getSelectionModel().getSelectedIndex();
if (i == j) {
return;
}
if (j >= 0 && j < getMenuCount()) {
JMenu menu = getMenu(j);
if (menu != null) {
MenuSelectionManager.defaultManager().setSelectedPath(null);
// menu.setPopupMenuVisible(false);
}
}
// now popup the new menu
getSelectionModel().setSelectedIndex(i);
JMenu menu = getMenu(i);
if (menu != null) {
MenuElement me[] = new MenuElement[3];
me[0] = JMenuBar.this;
me[1] = menu;
me[2] = menu.getPopupMenu();
MenuSelectionManager.defaultManager().setSelectedPath(me);
// menu.setPopupMenuVisible(true);
}
}
/**
* Removes the nth selected item in the object from the object's
* selection. If the nth item isn't currently selected, this
* method has no effect. Otherwise, it closes the popup menu.
*
* @param i the zero-based index of selectable items
*/
public void removeAccessibleSelection(int i) {
if (i >= 0 && i < getMenuCount()) {
JMenu menu = getMenu(i);
if (menu != null) {
MenuSelectionManager.defaultManager().setSelectedPath(null);
// menu.setPopupMenuVisible(false);
}
getSelectionModel().setSelectedIndex(-1);
}
}
/**
* Clears the selection in the object, so that nothing in the
* object is selected. This will close any open menu.
*/
public void clearAccessibleSelection() {
int i = getSelectionModel().getSelectedIndex();
if (i >= 0 && i < getMenuCount()) {
JMenu menu = getMenu(i);
if (menu != null) {
MenuSelectionManager.defaultManager().setSelectedPath(null);
// menu.setPopupMenuVisible(false);
}
}
getSelectionModel().setSelectedIndex(-1);
}
/**
* Normally causes every selected item in the object to be selected
* if the object supports multiple selections. This method
* makes no sense in a menu bar, and so does nothing.
*/
public void selectAllAccessibleSelection() {
}
} // internal class AccessibleJMenuBar
/**
* Subclassed to check all the child menus.
* @since 1.3
*/
protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
int condition, boolean pressed) {
// See if we have a local binding.
boolean retValue = super.processKeyBinding(ks, e, condition, pressed);
if (!retValue) {
MenuElement[] subElements = getSubElements();
for (MenuElement subElement : subElements) {
if (processBindingForKeyStrokeRecursive(
subElement, ks, e, condition, pressed)) {
return true;
}
}
}
return retValue;
}
static boolean processBindingForKeyStrokeRecursive(MenuElement elem,
KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
if (elem == null) {
return false;
}
Component c = elem.getComponent();
if ( !(c.isVisible() || (c instanceof JPopupMenu)) || !c.isEnabled() ) {
return false;
}
if (c != null && c instanceof JComponent &&
((JComponent)c).processKeyBinding(ks, e, condition, pressed)) {
return true;
}
MenuElement[] subElements = elem.getSubElements();
for (MenuElement subElement : subElements) {
if (processBindingForKeyStrokeRecursive(subElement, ks, e, condition, pressed)) {
return true;
// We don't, pass along to children JMenu's
}
}
return false;
}
/**
* Overrides <code>JComponent.addNotify</code> to register this
* menu bar with the current keyboard manager.
*/
public void addNotify() {
super.addNotify();
KeyboardManager.getCurrentManager().registerMenuBar(this);
}
/**
* Overrides <code>JComponent.removeNotify</code> to unregister this
* menu bar with the current keyboard manager.
*/
public void removeNotify() {
super.removeNotify();
KeyboardManager.getCurrentManager().unregisterMenuBar(this);
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
Object[] kvData = new Object[4];
int n = 0;
if (selectionModel instanceof Serializable) {
kvData[n++] = "selectionModel";
kvData[n++] = selectionModel;
}
s.writeObject(kvData);
}
/**
* See JComponent.readObject() for information about serialization
* in Swing.
*/
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException
{
s.defaultReadObject();
Object[] kvData = (Object[])(s.readObject());
for(int i = 0; i < kvData.length; i += 2) {
if (kvData[i] == null) {
break;
}
else if (kvData[i].equals("selectionModel")) {
selectionModel = (SingleSelectionModel)kvData[i + 1];
}
}
}
}

View File

@@ -0,0 +1,949 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.EventListener;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import javax.swing.plaf.*;
import javax.swing.plaf.basic.*;
import javax.swing.event.*;
import javax.accessibility.*;
/**
* An implementation of an item in a menu. A menu item is essentially a button
* sitting in a list. When the user selects the "button", the action
* associated with the menu item is performed. A <code>JMenuItem</code>
* contained in a <code>JPopupMenu</code> performs exactly that function.
* <p>
* Menu items can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a menu item has many benefits beyond directly
* configuring a menu item. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* For further documentation and for examples, see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>
* in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: An item which can be selected in a menu.
*
* @author Georges Saab
* @author David Karlton
* @see JPopupMenu
* @see JMenu
* @see JCheckBoxMenuItem
* @see JRadioButtonMenuItem
*/
@SuppressWarnings("serial")
public class JMenuItem extends AbstractButton implements Accessible,MenuElement {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "MenuItemUI";
/* diagnostic aids -- should be false for production builds. */
private static final boolean TRACE = false; // trace creates and disposes
private static final boolean VERBOSE = false; // show reuse hits/misses
private static final boolean DEBUG = false; // show bad params, misc.
private boolean isMouseDragged = false;
/**
* Creates a <code>JMenuItem</code> with no set text or icon.
*/
public JMenuItem() {
this(null, (Icon)null);
}
/**
* Creates a <code>JMenuItem</code> with the specified icon.
*
* @param icon the icon of the <code>JMenuItem</code>
*/
public JMenuItem(Icon icon) {
this(null, icon);
}
/**
* Creates a <code>JMenuItem</code> with the specified text.
*
* @param text the text of the <code>JMenuItem</code>
*/
public JMenuItem(String text) {
this(text, (Icon)null);
}
/**
* Creates a menu item whose properties are taken from the
* specified <code>Action</code>.
*
* @param a the action of the <code>JMenuItem</code>
* @since 1.3
*/
public JMenuItem(Action a) {
this();
setAction(a);
}
/**
* Creates a <code>JMenuItem</code> with the specified text and icon.
*
* @param text the text of the <code>JMenuItem</code>
* @param icon the icon of the <code>JMenuItem</code>
*/
public JMenuItem(String text, Icon icon) {
setModel(new DefaultButtonModel());
init(text, icon);
initFocusability();
}
/**
* Creates a <code>JMenuItem</code> with the specified text and
* keyboard mnemonic.
*
* @param text the text of the <code>JMenuItem</code>
* @param mnemonic the keyboard mnemonic for the <code>JMenuItem</code>
*/
public JMenuItem(String text, int mnemonic) {
setModel(new DefaultButtonModel());
init(text, null);
setMnemonic(mnemonic);
initFocusability();
}
/**
* {@inheritDoc}
*/
public void setModel(ButtonModel newModel) {
super.setModel(newModel);
if(newModel instanceof DefaultButtonModel) {
((DefaultButtonModel)newModel).setMenuItem(true);
}
}
/**
* Inititalizes the focusability of the the <code>JMenuItem</code>.
* <code>JMenuItem</code>'s are focusable, but subclasses may
* want to be, this provides them the opportunity to override this
* and invoke something else, or nothing at all. Refer to
* {@link javax.swing.JMenu#initFocusability} for the motivation of
* this.
*/
void initFocusability() {
setFocusable(false);
}
/**
* Initializes the menu item with the specified text and icon.
*
* @param text the text of the <code>JMenuItem</code>
* @param icon the icon of the <code>JMenuItem</code>
*/
protected void init(String text, Icon icon) {
if(text != null) {
setText(text);
}
if(icon != null) {
setIcon(icon);
}
// Listen for Focus events
addFocusListener(new MenuItemFocusListener());
setUIProperty("borderPainted", Boolean.FALSE);
setFocusPainted(false);
setHorizontalTextPosition(JButton.TRAILING);
setHorizontalAlignment(JButton.LEADING);
updateUI();
}
private static class MenuItemFocusListener implements FocusListener,
Serializable {
public void focusGained(FocusEvent event) {}
public void focusLost(FocusEvent event) {
// When focus is lost, repaint if
// the focus information is painted
JMenuItem mi = (JMenuItem)event.getSource();
if(mi.isFocusPainted()) {
mi.repaint();
}
}
}
/**
* Sets the look and feel object that renders this component.
*
* @param ui the <code>JMenuItemUI</code> L&amp;F object
* @see UIDefaults#getUI
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel.
*/
public void setUI(MenuItemUI ui) {
super.setUI(ui);
}
/**
* Resets the UI property with a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((MenuItemUI)UIManager.getUI(this));
}
/**
* Returns the suffix used to construct the name of the L&amp;F class used to
* render this component.
*
* @return the string "MenuItemUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Identifies the menu item as "armed". If the mouse button is
* released while it is over this item, the menu's action event
* will fire. If the mouse button is released elsewhere, the
* event will not fire and the menu item will be disarmed.
*
* @param b true to arm the menu item so it can be selected
* @beaninfo
* description: Mouse release will fire an action event
* hidden: true
*/
public void setArmed(boolean b) {
ButtonModel model = getModel();
boolean oldValue = model.isArmed();
if(model.isArmed() != b) {
model.setArmed(b);
}
}
/**
* Returns whether the menu item is "armed".
*
* @return true if the menu item is armed, and it can be selected
* @see #setArmed
*/
public boolean isArmed() {
ButtonModel model = getModel();
return model.isArmed();
}
/**
* Enables or disables the menu item.
*
* @param b true to enable the item
* @beaninfo
* description: Does the component react to user interaction
* bound: true
* preferred: true
*/
public void setEnabled(boolean b) {
// Make sure we aren't armed!
if (!b && !UIManager.getBoolean("MenuItem.disabledAreNavigable")) {
setArmed(false);
}
super.setEnabled(b);
}
/**
* Returns true since <code>Menu</code>s, by definition,
* should always be on top of all other windows. If the menu is
* in an internal frame false is returned due to the rollover effect
* for windows laf where the menu is not always on top.
*/
// package private
boolean alwaysOnTop() {
// Fix for bug #4482165
if (SwingUtilities.getAncestorOfClass(JInternalFrame.class, this) !=
null) {
return false;
}
return true;
}
/* The keystroke which acts as the menu item's accelerator
*/
private KeyStroke accelerator;
/**
* Sets the key combination which invokes the menu item's
* action listeners without navigating the menu hierarchy. It is the
* UI's responsibility to install the correct action. Note that
* when the keyboard accelerator is typed, it will work whether or
* not the menu is currently displayed.
*
* @param keyStroke the <code>KeyStroke</code> which will
* serve as an accelerator
* @beaninfo
* description: The keystroke combination which will invoke the
* JMenuItem's actionlisteners without navigating the
* menu hierarchy
* bound: true
* preferred: true
*/
public void setAccelerator(KeyStroke keyStroke) {
KeyStroke oldAccelerator = accelerator;
this.accelerator = keyStroke;
repaint();
revalidate();
firePropertyChange("accelerator", oldAccelerator, accelerator);
}
/**
* Returns the <code>KeyStroke</code> which serves as an accelerator
* for the menu item.
* @return a <code>KeyStroke</code> object identifying the
* accelerator key
*/
public KeyStroke getAccelerator() {
return this.accelerator;
}
/**
* {@inheritDoc}
*
* @since 1.3
*/
protected void configurePropertiesFromAction(Action a) {
super.configurePropertiesFromAction(a);
configureAcceleratorFromAction(a);
}
void setIconFromAction(Action a) {
Icon icon = null;
if (a != null) {
icon = (Icon)a.getValue(Action.SMALL_ICON);
}
setIcon(icon);
}
void largeIconChanged(Action a) {
}
void smallIconChanged(Action a) {
setIconFromAction(a);
}
void configureAcceleratorFromAction(Action a) {
KeyStroke ks = (a==null) ? null :
(KeyStroke)a.getValue(Action.ACCELERATOR_KEY);
setAccelerator(ks);
}
/**
* {@inheritDoc}
* @since 1.6
*/
protected void actionPropertyChanged(Action action, String propertyName) {
if (propertyName == Action.ACCELERATOR_KEY) {
configureAcceleratorFromAction(action);
}
else {
super.actionPropertyChanged(action, propertyName);
}
}
/**
* Processes a mouse event forwarded from the
* <code>MenuSelectionManager</code> and changes the menu
* selection, if necessary, by using the
* <code>MenuSelectionManager</code>'s API.
* <p>
* Note: you do not have to forward the event to sub-components.
* This is done automatically by the <code>MenuSelectionManager</code>.
*
* @param e a <code>MouseEvent</code>
* @param path the <code>MenuElement</code> path array
* @param manager the <code>MenuSelectionManager</code>
*/
public void processMouseEvent(MouseEvent e,MenuElement path[],MenuSelectionManager manager) {
processMenuDragMouseEvent(
new MenuDragMouseEvent(e.getComponent(), e.getID(),
e.getWhen(),
e.getModifiers(), e.getX(), e.getY(),
e.getXOnScreen(), e.getYOnScreen(),
e.getClickCount(), e.isPopupTrigger(),
path, manager));
}
/**
* Processes a key event forwarded from the
* <code>MenuSelectionManager</code> and changes the menu selection,
* if necessary, by using <code>MenuSelectionManager</code>'s API.
* <p>
* Note: you do not have to forward the event to sub-components.
* This is done automatically by the <code>MenuSelectionManager</code>.
*
* @param e a <code>KeyEvent</code>
* @param path the <code>MenuElement</code> path array
* @param manager the <code>MenuSelectionManager</code>
*/
public void processKeyEvent(KeyEvent e,MenuElement path[],MenuSelectionManager manager) {
if (DEBUG) {
System.out.println("in JMenuItem.processKeyEvent/3 for " + getText() +
" " + KeyStroke.getKeyStrokeForEvent(e));
}
MenuKeyEvent mke = new MenuKeyEvent(e.getComponent(), e.getID(),
e.getWhen(), e.getModifiers(),
e.getKeyCode(), e.getKeyChar(),
path, manager);
processMenuKeyEvent(mke);
if (mke.isConsumed()) {
e.consume();
}
}
/**
* Handles mouse drag in a menu.
*
* @param e a <code>MenuDragMouseEvent</code> object
*/
public void processMenuDragMouseEvent(MenuDragMouseEvent e) {
switch (e.getID()) {
case MouseEvent.MOUSE_ENTERED:
isMouseDragged = false; fireMenuDragMouseEntered(e); break;
case MouseEvent.MOUSE_EXITED:
isMouseDragged = false; fireMenuDragMouseExited(e); break;
case MouseEvent.MOUSE_DRAGGED:
isMouseDragged = true; fireMenuDragMouseDragged(e); break;
case MouseEvent.MOUSE_RELEASED:
if(isMouseDragged) fireMenuDragMouseReleased(e); break;
default:
break;
}
}
/**
* Handles a keystroke in a menu.
*
* @param e a <code>MenuKeyEvent</code> object
*/
public void processMenuKeyEvent(MenuKeyEvent e) {
if (DEBUG) {
System.out.println("in JMenuItem.processMenuKeyEvent for " + getText()+
" " + KeyStroke.getKeyStrokeForEvent(e));
}
switch (e.getID()) {
case KeyEvent.KEY_PRESSED:
fireMenuKeyPressed(e); break;
case KeyEvent.KEY_RELEASED:
fireMenuKeyReleased(e); break;
case KeyEvent.KEY_TYPED:
fireMenuKeyTyped(e); break;
default:
break;
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuMouseDragEvent</code>
* @see EventListenerList
*/
protected void fireMenuDragMouseEntered(MenuDragMouseEvent event) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuDragMouseListener.class) {
// Lazily create the event:
((MenuDragMouseListener)listeners[i+1]).menuDragMouseEntered(event);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuDragMouseEvent</code>
* @see EventListenerList
*/
protected void fireMenuDragMouseExited(MenuDragMouseEvent event) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuDragMouseListener.class) {
// Lazily create the event:
((MenuDragMouseListener)listeners[i+1]).menuDragMouseExited(event);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuDragMouseEvent</code>
* @see EventListenerList
*/
protected void fireMenuDragMouseDragged(MenuDragMouseEvent event) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuDragMouseListener.class) {
// Lazily create the event:
((MenuDragMouseListener)listeners[i+1]).menuDragMouseDragged(event);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuDragMouseEvent</code>
* @see EventListenerList
*/
protected void fireMenuDragMouseReleased(MenuDragMouseEvent event) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuDragMouseListener.class) {
// Lazily create the event:
((MenuDragMouseListener)listeners[i+1]).menuDragMouseReleased(event);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuKeyEvent</code>
* @see EventListenerList
*/
protected void fireMenuKeyPressed(MenuKeyEvent event) {
if (DEBUG) {
System.out.println("in JMenuItem.fireMenuKeyPressed for " + getText()+
" " + KeyStroke.getKeyStrokeForEvent(event));
}
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuKeyListener.class) {
// Lazily create the event:
((MenuKeyListener)listeners[i+1]).menuKeyPressed(event);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuKeyEvent</code>
* @see EventListenerList
*/
protected void fireMenuKeyReleased(MenuKeyEvent event) {
if (DEBUG) {
System.out.println("in JMenuItem.fireMenuKeyReleased for " + getText()+
" " + KeyStroke.getKeyStrokeForEvent(event));
}
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuKeyListener.class) {
// Lazily create the event:
((MenuKeyListener)listeners[i+1]).menuKeyReleased(event);
}
}
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type.
*
* @param event a <code>MenuKeyEvent</code>
* @see EventListenerList
*/
protected void fireMenuKeyTyped(MenuKeyEvent event) {
if (DEBUG) {
System.out.println("in JMenuItem.fireMenuKeyTyped for " + getText()+
" " + KeyStroke.getKeyStrokeForEvent(event));
}
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==MenuKeyListener.class) {
// Lazily create the event:
((MenuKeyListener)listeners[i+1]).menuKeyTyped(event);
}
}
}
/**
* Called by the <code>MenuSelectionManager</code> when the
* <code>MenuElement</code> is selected or unselected.
*
* @param isIncluded true if this menu item is on the part of the menu
* path that changed, false if this menu is part of the
* a menu path that changed, but this particular part of
* that path is still the same
* @see MenuSelectionManager#setSelectedPath(MenuElement[])
*/
public void menuSelectionChanged(boolean isIncluded) {
setArmed(isIncluded);
}
/**
* This method returns an array containing the sub-menu
* components for this menu component.
*
* @return an array of <code>MenuElement</code>s
*/
public MenuElement[] getSubElements() {
return new MenuElement[0];
}
/**
* Returns the <code>java.awt.Component</code> used to paint
* this object. The returned component will be used to convert
* events and detect if an event is inside a menu component.
*
* @return the <code>Component</code> that paints this menu item
*/
public Component getComponent() {
return this;
}
/**
* Adds a <code>MenuDragMouseListener</code> to the menu item.
*
* @param l the <code>MenuDragMouseListener</code> to be added
*/
public void addMenuDragMouseListener(MenuDragMouseListener l) {
listenerList.add(MenuDragMouseListener.class, l);
}
/**
* Removes a <code>MenuDragMouseListener</code> from the menu item.
*
* @param l the <code>MenuDragMouseListener</code> to be removed
*/
public void removeMenuDragMouseListener(MenuDragMouseListener l) {
listenerList.remove(MenuDragMouseListener.class, l);
}
/**
* Returns an array of all the <code>MenuDragMouseListener</code>s added
* to this JMenuItem with addMenuDragMouseListener().
*
* @return all of the <code>MenuDragMouseListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public MenuDragMouseListener[] getMenuDragMouseListeners() {
return listenerList.getListeners(MenuDragMouseListener.class);
}
/**
* Adds a <code>MenuKeyListener</code> to the menu item.
*
* @param l the <code>MenuKeyListener</code> to be added
*/
public void addMenuKeyListener(MenuKeyListener l) {
listenerList.add(MenuKeyListener.class, l);
}
/**
* Removes a <code>MenuKeyListener</code> from the menu item.
*
* @param l the <code>MenuKeyListener</code> to be removed
*/
public void removeMenuKeyListener(MenuKeyListener l) {
listenerList.remove(MenuKeyListener.class, l);
}
/**
* Returns an array of all the <code>MenuKeyListener</code>s added
* to this JMenuItem with addMenuKeyListener().
*
* @return all of the <code>MenuKeyListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public MenuKeyListener[] getMenuKeyListeners() {
return listenerList.getListeners(MenuKeyListener.class);
}
/**
* See JComponent.readObject() for information about serialization
* in Swing.
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
if (getUIClassID().equals(uiClassID)) {
updateUI();
}
}
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this <code>JMenuItem</code>.
* This method is intended to be used only for debugging purposes,
* and the content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JMenuItem</code>
*/
protected String paramString() {
return super.paramString();
}
/////////////////
// Accessibility support
////////////////
/**
* Returns the <code>AccessibleContext</code> associated with this
* <code>JMenuItem</code>. For <code>JMenuItem</code>s,
* the <code>AccessibleContext</code> takes the form of an
* <code>AccessibleJMenuItem</code>.
* A new AccessibleJMenuItme instance is created if necessary.
*
* @return an <code>AccessibleJMenuItem</code> that serves as the
* <code>AccessibleContext</code> of this <code>JMenuItem</code>
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJMenuItem();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JMenuItem</code> class. It provides an implementation of the
* Java Accessibility API appropriate to menu item user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
protected class AccessibleJMenuItem extends AccessibleAbstractButton implements ChangeListener {
private boolean isArmed = false;
private boolean hasFocus = false;
private boolean isPressed = false;
private boolean isSelected = false;
AccessibleJMenuItem() {
super();
JMenuItem.this.addChangeListener(this);
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.MENU_ITEM;
}
private void fireAccessibilityFocusedEvent(JMenuItem toCheck) {
MenuElement [] path =
MenuSelectionManager.defaultManager().getSelectedPath();
if (path.length > 0) {
Object menuItem = path[path.length - 1];
if (toCheck == menuItem) {
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.FOCUSED);
}
}
}
/**
* Supports the change listener interface and fires property changes.
*/
public void stateChanged(ChangeEvent e) {
firePropertyChange(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY,
Boolean.valueOf(false), Boolean.valueOf(true));
if (JMenuItem.this.getModel().isArmed()) {
if (!isArmed) {
isArmed = true;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.ARMED);
// Fix for 4848220 moved here to avoid major memory leak
// Here we will fire the event in case of JMenuItem
// See bug 4910323 for details [zav]
fireAccessibilityFocusedEvent(JMenuItem.this);
}
} else {
if (isArmed) {
isArmed = false;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
AccessibleState.ARMED, null);
}
}
if (JMenuItem.this.isFocusOwner()) {
if (!hasFocus) {
hasFocus = true;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.FOCUSED);
}
} else {
if (hasFocus) {
hasFocus = false;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
AccessibleState.FOCUSED, null);
}
}
if (JMenuItem.this.getModel().isPressed()) {
if (!isPressed) {
isPressed = true;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.PRESSED);
}
} else {
if (isPressed) {
isPressed = false;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
AccessibleState.PRESSED, null);
}
}
if (JMenuItem.this.getModel().isSelected()) {
if (!isSelected) {
isSelected = true;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.CHECKED);
// Fix for 4848220 moved here to avoid major memory leak
// Here we will fire the event in case of JMenu
// See bug 4910323 for details [zav]
fireAccessibilityFocusedEvent(JMenuItem.this);
}
} else {
if (isSelected) {
isSelected = false;
firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
AccessibleState.CHECKED, null);
}
}
}
} // inner class AccessibleJMenuItem
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,248 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* <code>JPanel</code> is a generic lightweight container.
* For examples and task-oriented documentation for JPanel, see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/panel.html">How to Use Panels</a>,
* a section in <em>The Java Tutorial</em>.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* description: A generic lightweight container.
*
* @author Arnaud Weber
* @author Steve Wilson
*/
public class JPanel extends JComponent implements Accessible
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "PanelUI";
/**
* Creates a new JPanel with the specified layout manager and buffering
* strategy.
*
* @param layout the LayoutManager to use
* @param isDoubleBuffered a boolean, true for double-buffering, which
* uses additional memory space to achieve fast, flicker-free
* updates
*/
public JPanel(LayoutManager layout, boolean isDoubleBuffered) {
setLayout(layout);
setDoubleBuffered(isDoubleBuffered);
setUIProperty("opaque", Boolean.TRUE);
updateUI();
}
/**
* Create a new buffered JPanel with the specified layout manager
*
* @param layout the LayoutManager to use
*/
public JPanel(LayoutManager layout) {
this(layout, true);
}
/**
* Creates a new <code>JPanel</code> with <code>FlowLayout</code>
* and the specified buffering strategy.
* If <code>isDoubleBuffered</code> is true, the <code>JPanel</code>
* will use a double buffer.
*
* @param isDoubleBuffered a boolean, true for double-buffering, which
* uses additional memory space to achieve fast, flicker-free
* updates
*/
public JPanel(boolean isDoubleBuffered) {
this(new FlowLayout(), isDoubleBuffered);
}
/**
* Creates a new <code>JPanel</code> with a double buffer
* and a flow layout.
*/
public JPanel() {
this(true);
}
/**
* Resets the UI property with a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((PanelUI)UIManager.getUI(this));
}
/**
* Returns the look and feel (L&amp;amp;F) object that renders this component.
*
* @return the PanelUI object that renders this component
* @since 1.4
*/
public PanelUI getUI() {
return (PanelUI)ui;
}
/**
* Sets the look and feel (L&amp;F) object that renders this component.
*
* @param ui the PanelUI L&amp;F object
* @see UIDefaults#getUI
* @since 1.4
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel.
*/
public void setUI(PanelUI ui) {
super.setUI(ui);
}
/**
* Returns a string that specifies the name of the L&amp;F class
* that renders this component.
*
* @return "PanelUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
* @beaninfo
* expert: true
* description: A string that specifies the name of the L&amp;F class.
*/
public String getUIClassID() {
return uiClassID;
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this JPanel. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JPanel.
*/
protected String paramString() {
return super.paramString();
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JPanel.
* For JPanels, the AccessibleContext takes the form of an
* AccessibleJPanel.
* A new AccessibleJPanel instance is created if necessary.
*
* @return an AccessibleJPanel that serves as the
* AccessibleContext of this JPanel
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJPanel();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JPanel</code> class. It provides an implementation of the
* Java Accessibility API appropriate to panel user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJPanel extends AccessibleJComponent {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PANEL;
}
}
}

View File

@@ -0,0 +1,665 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.text.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.*;
import java.util.Arrays;
/**
* <code>JPasswordField</code> is a lightweight component that allows
* the editing of a single line of text where the view indicates
* something was typed, but does not show the original characters.
* You can find further information and examples in
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <code>JPasswordField</code> is intended
* to be source-compatible with <code>java.awt.TextField</code>
* used with <code>echoChar</code> set. It is provided separately
* to make it easier to safely change the UI for the
* <code>JTextField</code> without affecting password entries.
* <p>
* <strong>NOTE:</strong>
* By default, JPasswordField disables input methods; otherwise, input
* characters could be visible while they were composed using input methods.
* If an application needs the input methods support, please use the
* inherited method, <code>enableInputMethods(true)</code>.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: Allows the editing of a line of text but doesn't show the characters.
*
* @author Timothy Prinzing
*/
public class JPasswordField extends JTextField {
/**
* Constructs a new <code>JPasswordField</code>,
* with a default document, <code>null</code> starting
* text string, and 0 column width.
*/
public JPasswordField() {
this(null,null,0);
}
/**
* Constructs a new <code>JPasswordField</code> initialized
* with the specified text. The document model is set to the
* default, and the number of columns to 0.
*
* @param text the text to be displayed, <code>null</code> if none
*/
public JPasswordField(String text) {
this(null, text, 0);
}
/**
* Constructs a new empty <code>JPasswordField</code> with the specified
* number of columns. A default model is created, and the initial string
* is set to <code>null</code>.
*
* @param columns the number of columns &gt;= 0
*/
public JPasswordField(int columns) {
this(null, null, columns);
}
/**
* Constructs a new <code>JPasswordField</code> initialized with
* the specified text and columns. The document model is set to
* the default.
*
* @param text the text to be displayed, <code>null</code> if none
* @param columns the number of columns &gt;= 0
*/
public JPasswordField(String text, int columns) {
this(null, text, columns);
}
/**
* Constructs a new <code>JPasswordField</code> that uses the
* given text storage model and the given number of columns.
* This is the constructor through which the other constructors feed.
* The echo character is set to '*', but may be changed by the current
* Look and Feel. If the document model is
* <code>null</code>, a default one will be created.
*
* @param doc the text storage to use
* @param txt the text to be displayed, <code>null</code> if none
* @param columns the number of columns to use to calculate
* the preferred width &gt;= 0; if columns is set to zero, the
* preferred width will be whatever naturally results from
* the component implementation
*/
public JPasswordField(Document doc, String txt, int columns) {
super(doc, txt, columns);
// We could either leave this on, which wouldn't be secure,
// or obscure the composted text, which essentially makes displaying
// it useless. Therefore, we turn off input methods.
enableInputMethods(false);
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "PasswordFieldUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* {@inheritDoc}
* @since 1.6
*/
public void updateUI() {
if(!echoCharSet) {
echoChar = '*';
}
super.updateUI();
}
/**
* Returns the character to be used for echoing. The default is '*'.
* The default may be different depending on the currently running Look
* and Feel. For example, Metal/Ocean's default is a bullet character.
*
* @return the echo character, 0 if unset
* @see #setEchoChar
* @see #echoCharIsSet
*/
public char getEchoChar() {
return echoChar;
}
/**
* Sets the echo character for this <code>JPasswordField</code>.
* Note that this is largely a suggestion, since the
* view that gets installed can use whatever graphic techniques
* it desires to represent the field. Setting a value of 0 indicates
* that you wish to see the text as it is typed, similar to
* the behavior of a standard <code>JTextField</code>.
*
* @param c the echo character to display
* @see #echoCharIsSet
* @see #getEchoChar
* @beaninfo
* description: character to display in place of the real characters
* attribute: visualUpdate true
*/
public void setEchoChar(char c) {
echoChar = c;
echoCharSet = true;
repaint();
revalidate();
}
/**
* Returns true if this <code>JPasswordField</code> has a character
* set for echoing. A character is considered to be set if the echo
* character is not 0.
*
* @return true if a character is set for echoing
* @see #setEchoChar
* @see #getEchoChar
*/
public boolean echoCharIsSet() {
return echoChar != 0;
}
// --- JTextComponent methods ----------------------------------
/**
* Invokes <code>provideErrorFeedback</code> on the current
* look and feel, which typically initiates an error beep.
* The normal behavior of transferring the
* currently selected range in the associated text model
* to the system clipboard, and removing the contents from
* the model, is not acceptable for a password field.
*/
public void cut() {
if (getClientProperty("JPasswordField.cutCopyAllowed") != Boolean.TRUE) {
UIManager.getLookAndFeel().provideErrorFeedback(this);
} else {
super.cut();
}
}
/**
* Invokes <code>provideErrorFeedback</code> on the current
* look and feel, which typically initiates an error beep.
* The normal behavior of transferring the
* currently selected range in the associated text model
* to the system clipboard, and leaving the contents from
* the model, is not acceptable for a password field.
*/
public void copy() {
if (getClientProperty("JPasswordField.cutCopyAllowed") != Boolean.TRUE) {
UIManager.getLookAndFeel().provideErrorFeedback(this);
} else {
super.copy();
}
}
/**
* Returns the text contained in this <code>TextComponent</code>.
* If the underlying document is <code>null</code>, will give a
* <code>NullPointerException</code>.
* <p>
* For security reasons, this method is deprecated. Use the
<code>* getPassword</code> method instead.
* @deprecated As of Java 2 platform v1.2,
* replaced by <code>getPassword</code>.
* @return the text
*/
@Deprecated
public String getText() {
return super.getText();
}
/**
* Fetches a portion of the text represented by the
* component. Returns an empty string if length is 0.
* <p>
* For security reasons, this method is deprecated. Use the
* <code>getPassword</code> method instead.
* @deprecated As of Java 2 platform v1.2,
* replaced by <code>getPassword</code>.
* @param offs the offset &gt;= 0
* @param len the length &gt;= 0
* @return the text
* @exception BadLocationException if the offset or length are invalid
*/
@Deprecated
public String getText(int offs, int len) throws BadLocationException {
return super.getText(offs, len);
}
/**
* Returns the text contained in this <code>TextComponent</code>.
* If the underlying document is <code>null</code>, will give a
* <code>NullPointerException</code>. For stronger
* security, it is recommended that the returned character array be
* cleared after use by setting each character to zero.
*
* @return the text
*/
public char[] getPassword() {
Document doc = getDocument();
Segment txt = new Segment();
try {
doc.getText(0, doc.getLength(), txt); // use the non-String API
} catch (BadLocationException e) {
return null;
}
char[] retValue = new char[txt.count];
System.arraycopy(txt.array, txt.offset, retValue, 0, txt.count);
return retValue;
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
// --- variables -----------------------------------------------
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "PasswordFieldUI";
private char echoChar;
private boolean echoCharSet = false;
/**
* Returns a string representation of this <code>JPasswordField</code>.
* This method is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JPasswordField</code>
*/
protected String paramString() {
return super.paramString() +
",echoChar=" + echoChar;
}
/**
* This method is a hack to get around the fact that we cannot
* directly override setUIProperty because part of the inheritance hierarchy
* goes outside of the javax.swing package, and therefore calling a package
* private method isn't allowed. This method should return true if the property
* was handled, and false otherwise.
*/
boolean customSetUIProperty(String propertyName, Object value) {
if (propertyName == "echoChar") {
if (!echoCharSet) {
setEchoChar((Character)value);
echoCharSet = false;
}
return true;
}
return false;
}
/////////////////
// Accessibility support
////////////////
/**
* Returns the <code>AccessibleContext</code> associated with this
* <code>JPasswordField</code>. For password fields, the
* <code>AccessibleContext</code> takes the form of an
* <code>AccessibleJPasswordField</code>.
* A new <code>AccessibleJPasswordField</code> instance is created
* if necessary.
*
* @return an <code>AccessibleJPasswordField</code> that serves as the
* <code>AccessibleContext</code> of this
* <code>JPasswordField</code>
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJPasswordField();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JPasswordField</code> class. It provides an implementation of the
* Java Accessibility API appropriate to password field user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJPasswordField extends AccessibleJTextField {
/**
* Gets the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object (AccessibleRole.PASSWORD_TEXT)
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.PASSWORD_TEXT;
}
/**
* Gets the <code>AccessibleText</code> for the <code>JPasswordField</code>.
* The returned object also implements the
* <code>AccessibleExtendedText</code> interface.
*
* @return <code>AccessibleText</code> for the JPasswordField
* @see javax.accessibility.AccessibleContext
* @see javax.accessibility.AccessibleContext#getAccessibleText
* @see javax.accessibility.AccessibleText
* @see javax.accessibility.AccessibleExtendedText
*
* @since 1.6
*/
public AccessibleText getAccessibleText() {
return this;
}
/*
* Returns a String filled with password echo characters. The String
* contains one echo character for each character (including whitespace)
* that the user entered in the JPasswordField.
*/
private String getEchoString(String str) {
if (str == null) {
return null;
}
char[] buffer = new char[str.length()];
Arrays.fill(buffer, getEchoChar());
return new String(buffer);
}
/**
* Returns the <code>String</code> at a given <code>index</code>.
*
* @param part the <code>CHARACTER</code>, <code>WORD</code> or
* <code>SENTENCE</code> to retrieve
* @param index an index within the text
* @return a <code>String</code> if <code>part</code> and
* <code>index</code> are valid.
* Otherwise, <code>null</code> is returned
*
* @see javax.accessibility.AccessibleText#CHARACTER
* @see javax.accessibility.AccessibleText#WORD
* @see javax.accessibility.AccessibleText#SENTENCE
*
* @since 1.6
*/
public String getAtIndex(int part, int index) {
String str = null;
if (part == AccessibleText.CHARACTER) {
str = super.getAtIndex(part, index);
} else {
// Treat the text displayed in the JPasswordField
// as one word and sentence.
char password[] = getPassword();
if (password == null ||
index < 0 || index >= password.length) {
return null;
}
str = new String(password);
}
return getEchoString(str);
}
/**
* Returns the <code>String</code> after a given <code>index</code>.
*
* @param part the <code>CHARACTER</code>, <code>WORD</code> or
* <code>SENTENCE</code> to retrieve
* @param index an index within the text
* @return a <code>String</code> if <code>part</code> and
* <code>index</code> are valid.
* Otherwise, <code>null</code> is returned
*
* @see javax.accessibility.AccessibleText#CHARACTER
* @see javax.accessibility.AccessibleText#WORD
* @see javax.accessibility.AccessibleText#SENTENCE
*
* @since 1.6
*/
public String getAfterIndex(int part, int index) {
if (part == AccessibleText.CHARACTER) {
String str = super.getAfterIndex(part, index);
return getEchoString(str);
} else {
// There is no word or sentence after the text
// displayed in the JPasswordField.
return null;
}
}
/**
* Returns the <code>String</code> before a given <code>index</code>.
*
* @param part the <code>CHARACTER</code>, <code>WORD</code> or
* <code>SENTENCE</code> to retrieve
* @param index an index within the text
* @return a <code>String</code> if <code>part</code> and
* <code>index</code> are valid.
* Otherwise, <code>null</code> is returned
*
* @see javax.accessibility.AccessibleText#CHARACTER
* @see javax.accessibility.AccessibleText#WORD
* @see javax.accessibility.AccessibleText#SENTENCE
*
* @since 1.6
*/
public String getBeforeIndex(int part, int index) {
if (part == AccessibleText.CHARACTER) {
String str = super.getBeforeIndex(part, index);
return getEchoString(str);
} else {
// There is no word or sentence before the text
// displayed in the JPasswordField.
return null;
}
}
/**
* Returns the text between two <code>indices</code>.
*
* @param startIndex the start index in the text
* @param endIndex the end index in the text
* @return the text string if the indices are valid.
* Otherwise, <code>null</code> is returned
*
* @since 1.6
*/
public String getTextRange(int startIndex, int endIndex) {
String str = super.getTextRange(startIndex, endIndex);
return getEchoString(str);
}
/**
* Returns the <code>AccessibleTextSequence</code> at a given
* <code>index</code>.
*
* @param part the <code>CHARACTER</code>, <code>WORD</code>,
* <code>SENTENCE</code>, <code>LINE</code> or <code>ATTRIBUTE_RUN</code> to
* retrieve
* @param index an index within the text
* @return an <code>AccessibleTextSequence</code> specifying the text if
* <code>part</code> and <code>index</code> are valid. Otherwise,
* <code>null</code> is returned
*
* @see javax.accessibility.AccessibleText#CHARACTER
* @see javax.accessibility.AccessibleText#WORD
* @see javax.accessibility.AccessibleText#SENTENCE
* @see javax.accessibility.AccessibleExtendedText#LINE
* @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
*
* @since 1.6
*/
public AccessibleTextSequence getTextSequenceAt(int part, int index) {
if (part == AccessibleText.CHARACTER) {
AccessibleTextSequence seq = super.getTextSequenceAt(part, index);
if (seq == null) {
return null;
}
return new AccessibleTextSequence(seq.startIndex, seq.endIndex,
getEchoString(seq.text));
} else {
// Treat the text displayed in the JPasswordField
// as one word, sentence, line and attribute run
char password[] = getPassword();
if (password == null ||
index < 0 || index >= password.length) {
return null;
}
String text = new String(password);
return new AccessibleTextSequence(0, password.length - 1,
getEchoString(text));
}
}
/**
* Returns the <code>AccessibleTextSequence</code> after a given
* <code>index</code>.
*
* @param part the <code>CHARACTER</code>, <code>WORD</code>,
* <code>SENTENCE</code>, <code>LINE</code> or <code>ATTRIBUTE_RUN</code> to
* retrieve
* @param index an index within the text
* @return an <code>AccessibleTextSequence</code> specifying the text if
* <code>part</code> and <code>index</code> are valid. Otherwise,
* <code>null</code> is returned
*
* @see javax.accessibility.AccessibleText#CHARACTER
* @see javax.accessibility.AccessibleText#WORD
* @see javax.accessibility.AccessibleText#SENTENCE
* @see javax.accessibility.AccessibleExtendedText#LINE
* @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
*
* @since 1.6
*/
public AccessibleTextSequence getTextSequenceAfter(int part, int index) {
if (part == AccessibleText.CHARACTER) {
AccessibleTextSequence seq = super.getTextSequenceAfter(part, index);
if (seq == null) {
return null;
}
return new AccessibleTextSequence(seq.startIndex, seq.endIndex,
getEchoString(seq.text));
} else {
// There is no word, sentence, line or attribute run
// after the text displayed in the JPasswordField.
return null;
}
}
/**
* Returns the <code>AccessibleTextSequence</code> before a given
* <code>index</code>.
*
* @param part the <code>CHARACTER</code>, <code>WORD</code>,
* <code>SENTENCE</code>, <code>LINE</code> or <code>ATTRIBUTE_RUN</code> to
* retrieve
* @param index an index within the text
* @return an <code>AccessibleTextSequence</code> specifying the text if
* <code>part</code> and <code>index</code> are valid. Otherwise,
* <code>null</code> is returned
*
* @see javax.accessibility.AccessibleText#CHARACTER
* @see javax.accessibility.AccessibleText#WORD
* @see javax.accessibility.AccessibleText#SENTENCE
* @see javax.accessibility.AccessibleExtendedText#LINE
* @see javax.accessibility.AccessibleExtendedText#ATTRIBUTE_RUN
*
* @since 1.6
*/
public AccessibleTextSequence getTextSequenceBefore(int part, int index) {
if (part == AccessibleText.CHARACTER) {
AccessibleTextSequence seq = super.getTextSequenceBefore(part, index);
if (seq == null) {
return null;
}
return new AccessibleTextSequence(seq.startIndex, seq.endIndex,
getEchoString(seq.text));
} else {
// There is no word, sentence, line or attribute run
// before the text displayed in the JPasswordField.
return null;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,300 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* An implementation of a radio button -- an item that can be selected or
* deselected, and which displays its state to the user.
* Used with a {@link ButtonGroup} object to create a group of buttons
* in which only one button at a time can be selected. (Create a ButtonGroup
* object and use its <code>add</code> method to include the JRadioButton objects
* in the group.)
* <blockquote>
* <strong>Note:</strong>
* The ButtonGroup object is a logical grouping -- not a physical grouping.
* To create a button panel, you should still create a {@link JPanel} or similar
* container-object and add a {@link javax.swing.border.Border} to it to set it off from surrounding
* components.
* </blockquote>
* <p>
* Buttons can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a button has many benefits beyond directly
* configuring a button. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* See <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>
* in <em>The Java Tutorial</em>
* for further documentation.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: A component which can display it's state as selected or deselected.
*
* @see ButtonGroup
* @see JCheckBox
* @author Jeff Dinkins
*/
public class JRadioButton extends JToggleButton implements Accessible {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "RadioButtonUI";
/**
* Creates an initially unselected radio button
* with no set text.
*/
public JRadioButton () {
this(null, null, false);
}
/**
* Creates an initially unselected radio button
* with the specified image but no text.
*
* @param icon the image that the button should display
*/
public JRadioButton(Icon icon) {
this(null, icon, false);
}
/**
* Creates a radiobutton where properties are taken from the
* Action supplied.
*
* @since 1.3
*/
public JRadioButton(Action a) {
this();
setAction(a);
}
/**
* Creates a radio button with the specified image
* and selection state, but no text.
*
* @param icon the image that the button should display
* @param selected if true, the button is initially selected;
* otherwise, the button is initially unselected
*/
public JRadioButton(Icon icon, boolean selected) {
this(null, icon, selected);
}
/**
* Creates an unselected radio button with the specified text.
*
* @param text the string displayed on the radio button
*/
public JRadioButton (String text) {
this(text, null, false);
}
/**
* Creates a radio button with the specified text
* and selection state.
*
* @param text the string displayed on the radio button
* @param selected if true, the button is initially selected;
* otherwise, the button is initially unselected
*/
public JRadioButton (String text, boolean selected) {
this(text, null, selected);
}
/**
* Creates a radio button that has the specified text and image,
* and that is initially unselected.
*
* @param text the string displayed on the radio button
* @param icon the image that the button should display
*/
public JRadioButton(String text, Icon icon) {
this(text, icon, false);
}
/**
* Creates a radio button that has the specified text, image,
* and selection state.
*
* @param text the string displayed on the radio button
* @param icon the image that the button should display
*/
public JRadioButton (String text, Icon icon, boolean selected) {
super(text, icon, selected);
setBorderPainted(false);
setHorizontalAlignment(LEADING);
}
/**
* Resets the UI property to a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ButtonUI)UIManager.getUI(this));
}
/**
* Returns the name of the L&amp;F class
* that renders this component.
*
* @return String "RadioButtonUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
* @beaninfo
* expert: true
* description: A string that specifies the name of the L&amp;F class.
*/
public String getUIClassID() {
return uiClassID;
}
/**
* The icon for radio buttons comes from the look and feel,
* not the Action.
*/
void setIconFromAction(Action a) {
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this JRadioButton. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JRadioButton.
*/
protected String paramString() {
return super.paramString();
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JRadioButton.
* For JRadioButtons, the AccessibleContext takes the form of an
* AccessibleJRadioButton.
* A new AccessibleJRadioButton instance is created if necessary.
*
* @return an AccessibleJRadioButton that serves as the
* AccessibleContext of this JRadioButton
* @beaninfo
* expert: true
* description: The AccessibleContext associated with this Button
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJRadioButton();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JRadioButton</code> class. It provides an implementation of the
* Java Accessibility API appropriate to radio button
* user-interface elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJRadioButton extends AccessibleJToggleButton {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the object
* @see AccessibleRole
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.RADIO_BUTTON;
}
} // inner class AccessibleJRadioButton
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.EventListener;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import javax.swing.plaf.*;
import javax.accessibility.*;
/**
* An implementation of a radio button menu item.
* A <code>JRadioButtonMenuItem</code> is
* a menu item that is part of a group of menu items in which only one
* item in the group can be selected. The selected item displays its
* selected state. Selecting it causes any other selected item to
* switch to the unselected state.
* To control the selected state of a group of radio button menu items,
* use a <code>ButtonGroup</code> object.
* <p>
* Menu items can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a menu item has many benefits beyond directly
* configuring a menu item. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* For further documentation and examples see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: A component within a group of menu items which can be selected.
*
* @author Georges Saab
* @author David Karlton
* @see ButtonGroup
*/
public class JRadioButtonMenuItem extends JMenuItem implements Accessible {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "RadioButtonMenuItemUI";
/**
* Creates a <code>JRadioButtonMenuItem</code> with no set text or icon.
*/
public JRadioButtonMenuItem() {
this(null, null, false);
}
/**
* Creates a <code>JRadioButtonMenuItem</code> with an icon.
*
* @param icon the <code>Icon</code> to display on the
* <code>JRadioButtonMenuItem</code>
*/
public JRadioButtonMenuItem(Icon icon) {
this(null, icon, false);
}
/**
* Creates a <code>JRadioButtonMenuItem</code> with text.
*
* @param text the text of the <code>JRadioButtonMenuItem</code>
*/
public JRadioButtonMenuItem(String text) {
this(text, null, false);
}
/**
* Creates a radio button menu item whose properties are taken from the
* <code>Action</code> supplied.
*
* @param a the <code>Action</code> on which to base the radio
* button menu item
*
* @since 1.3
*/
public JRadioButtonMenuItem(Action a) {
this();
setAction(a);
}
/**
* Creates a radio button menu item with the specified text
* and <code>Icon</code>.
*
* @param text the text of the <code>JRadioButtonMenuItem</code>
* @param icon the icon to display on the <code>JRadioButtonMenuItem</code>
*/
public JRadioButtonMenuItem(String text, Icon icon) {
this(text, icon, false);
}
/**
* Creates a radio button menu item with the specified text
* and selection state.
*
* @param text the text of the <code>CheckBoxMenuItem</code>
* @param selected the selected state of the <code>CheckBoxMenuItem</code>
*/
public JRadioButtonMenuItem(String text, boolean selected) {
this(text);
setSelected(selected);
}
/**
* Creates a radio button menu item with the specified image
* and selection state, but no text.
*
* @param icon the image that the button should display
* @param selected if true, the button is initially selected;
* otherwise, the button is initially unselected
*/
public JRadioButtonMenuItem(Icon icon, boolean selected) {
this(null, icon, selected);
}
/**
* Creates a radio button menu item that has the specified
* text, image, and selection state. All other constructors
* defer to this one.
*
* @param text the string displayed on the radio button
* @param icon the image that the button should display
*/
public JRadioButtonMenuItem(String text, Icon icon, boolean selected) {
super(text, icon);
setModel(new JToggleButton.ToggleButtonModel());
setSelected(selected);
setFocusable(false);
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "RadioButtonMenuItemUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* See <code>readObject</code> and <code>writeObject</code> in
* <code>JComponent</code> for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this
* <code>JRadioButtonMenuItem</code>. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this
* <code>JRadioButtonMenuItem</code>
*/
protected String paramString() {
return super.paramString();
}
/**
* Overriden to return true, JRadioButtonMenuItem supports
* the selected state.
*/
boolean shouldUpdateSelectedStateFromAction() {
return true;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JRadioButtonMenuItem.
* For JRadioButtonMenuItems, the AccessibleContext takes the form of an
* AccessibleJRadioButtonMenuItem.
* A new AccessibleJRadioButtonMenuItem instance is created if necessary.
*
* @return an AccessibleJRadioButtonMenuItem that serves as the
* AccessibleContext of this JRadioButtonMenuItem
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJRadioButtonMenuItem();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JRadioButtonMenuItem</code> class. It provides an
* implementation of the Java Accessibility API appropriate to
* <code>JRadioButtonMenuItem</code> user-interface elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJRadioButtonMenuItem extends AccessibleJMenuItem {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.RADIO_BUTTON;
}
} // inner class AccessibleJRadioButtonMenuItem
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,933 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.io.Serializable;
import java.awt.Component;
import java.awt.Adjustable;
import java.awt.Dimension;
import java.awt.event.AdjustmentListener;
import java.awt.event.AdjustmentEvent;
import java.awt.Graphics;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* An implementation of a scrollbar. The user positions the knob in the
* scrollbar to determine the contents of the viewing area. The
* program typically adjusts the display so that the end of the
* scrollbar represents the end of the displayable contents, or 100%
* of the contents. The start of the scrollbar is the beginning of the
* displayable contents, or 0%. The position of the knob within
* those bounds then translates to the corresponding percentage of
* the displayable contents.
* <p>
* Typically, as the position of the knob in the scrollbar changes
* a corresponding change is made to the position of the JViewport on
* the underlying view, changing the contents of the JViewport.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JScrollPane
* @beaninfo
* attribute: isContainer false
* description: A component that helps determine the visible content range of an area.
*
* @author David Kloba
*/
public class JScrollBar extends JComponent implements Adjustable, Accessible
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "ScrollBarUI";
/**
* All changes from the model are treated as though the user moved
* the scrollbar knob.
*/
private ChangeListener fwdAdjustmentEvents = new ModelListener();
/**
* The model that represents the scrollbar's minimum, maximum, extent
* (aka "visibleAmount") and current value.
* @see #setModel
*/
protected BoundedRangeModel model;
/**
* @see #setOrientation
*/
protected int orientation;
/**
* @see #setUnitIncrement
*/
protected int unitIncrement;
/**
* @see #setBlockIncrement
*/
protected int blockIncrement;
private void checkOrientation(int orientation) {
switch (orientation) {
case VERTICAL:
case HORIZONTAL:
break;
default:
throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL");
}
}
/**
* Creates a scrollbar with the specified orientation,
* value, extent, minimum, and maximum.
* The "extent" is the size of the viewable area. It is also known
* as the "visible amount".
* <p>
* Note: Use <code>setBlockIncrement</code> to set the block
* increment to a size slightly smaller than the view's extent.
* That way, when the user jumps the knob to an adjacent position,
* one or two lines of the original contents remain in view.
*
* @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
*
* @see #setOrientation
* @see #setValue
* @see #setVisibleAmount
* @see #setMinimum
* @see #setMaximum
*/
public JScrollBar(int orientation, int value, int extent, int min, int max)
{
checkOrientation(orientation);
this.unitIncrement = 1;
this.blockIncrement = (extent == 0) ? 1 : extent;
this.orientation = orientation;
this.model = new DefaultBoundedRangeModel(value, extent, min, max);
this.model.addChangeListener(fwdAdjustmentEvents);
setRequestFocusEnabled(false);
updateUI();
}
/**
* Creates a scrollbar with the specified orientation
* and the following initial values:
* <pre>
* minimum = 0
* maximum = 100
* value = 0
* extent = 10
* </pre>
*/
public JScrollBar(int orientation) {
this(orientation, 0, 10, 0, 100);
}
/**
* Creates a vertical scrollbar with the following initial values:
* <pre>
* minimum = 0
* maximum = 100
* value = 0
* extent = 10
* </pre>
*/
public JScrollBar() {
this(VERTICAL);
}
/**
* Sets the {@literal L&F} object that renders this component.
*
* @param ui the <code>ScrollBarUI</code> {@literal L&F} object
* @see UIDefaults#getUI
* @since 1.4
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel
*/
public void setUI(ScrollBarUI ui) {
super.setUI(ui);
}
/**
* Returns the delegate that implements the look and feel for
* this component.
*
* @see JComponent#setUI
*/
public ScrollBarUI getUI() {
return (ScrollBarUI)ui;
}
/**
* Overrides <code>JComponent.updateUI</code>.
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ScrollBarUI)UIManager.getUI(this));
}
/**
* Returns the name of the LookAndFeel class for this component.
*
* @return "ScrollBarUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Returns the component's orientation (horizontal or vertical).
*
* @return VERTICAL or HORIZONTAL
* @see #setOrientation
* @see java.awt.Adjustable#getOrientation
*/
public int getOrientation() {
return orientation;
}
/**
* Set the scrollbar's orientation to either VERTICAL or
* HORIZONTAL.
*
* @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL
* @see #getOrientation
* @beaninfo
* preferred: true
* bound: true
* attribute: visualUpdate true
* description: The scrollbar's orientation.
* enum: VERTICAL JScrollBar.VERTICAL
* HORIZONTAL JScrollBar.HORIZONTAL
*/
public void setOrientation(int orientation)
{
checkOrientation(orientation);
int oldValue = this.orientation;
this.orientation = orientation;
firePropertyChange("orientation", oldValue, orientation);
if ((oldValue != orientation) && (accessibleContext != null)) {
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
((oldValue == VERTICAL)
? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL),
((orientation == VERTICAL)
? AccessibleState.VERTICAL : AccessibleState.HORIZONTAL));
}
if (orientation != oldValue) {
revalidate();
}
}
/**
* Returns data model that handles the scrollbar's four
* fundamental properties: minimum, maximum, value, extent.
*
* @see #setModel
*/
public BoundedRangeModel getModel() {
return model;
}
/**
* Sets the model that handles the scrollbar's four
* fundamental properties: minimum, maximum, value, extent.
*
* @see #getModel
* @beaninfo
* bound: true
* expert: true
* description: The scrollbar's BoundedRangeModel.
*/
public void setModel(BoundedRangeModel newModel) {
Integer oldValue = null;
BoundedRangeModel oldModel = model;
if (model != null) {
model.removeChangeListener(fwdAdjustmentEvents);
oldValue = Integer.valueOf(model.getValue());
}
model = newModel;
if (model != null) {
model.addChangeListener(fwdAdjustmentEvents);
}
firePropertyChange("model", oldModel, model);
if (accessibleContext != null) {
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
oldValue, new Integer(model.getValue()));
}
}
/**
* Returns the amount to change the scrollbar's value by,
* given a unit up/down request. A ScrollBarUI implementation
* typically calls this method when the user clicks on a scrollbar
* up/down arrow and uses the result to update the scrollbar's
* value. Subclasses my override this method to compute
* a value, e.g. the change required to scroll up or down one
* (variable height) line text or one row in a table.
* <p>
* The JScrollPane component creates scrollbars (by default)
* that override this method and delegate to the viewports
* Scrollable view, if it has one. The Scrollable interface
* provides a more specialized version of this method.
* <p>
* Some look and feels implement custom scrolling behavior
* and ignore this property.
*
* @param direction is -1 or 1 for up/down respectively
* @return the value of the unitIncrement property
* @see #setUnitIncrement
* @see #setValue
* @see Scrollable#getScrollableUnitIncrement
*/
public int getUnitIncrement(int direction) {
return unitIncrement;
}
/**
* Sets the unitIncrement property.
* <p>
* Note, that if the argument is equal to the value of Integer.MIN_VALUE,
* the most look and feels will not provide the scrolling to the right/down.
* <p>
* Some look and feels implement custom scrolling behavior
* and ignore this property.
*
* @see #getUnitIncrement
* @beaninfo
* preferred: true
* bound: true
* description: The scrollbar's unit increment.
*/
public void setUnitIncrement(int unitIncrement) {
int oldValue = this.unitIncrement;
this.unitIncrement = unitIncrement;
firePropertyChange("unitIncrement", oldValue, unitIncrement);
}
/**
* Returns the amount to change the scrollbar's value by,
* given a block (usually "page") up/down request. A ScrollBarUI
* implementation typically calls this method when the user clicks
* above or below the scrollbar "knob" to change the value
* up or down by large amount. Subclasses my override this
* method to compute a value, e.g. the change required to scroll
* up or down one paragraph in a text document.
* <p>
* The JScrollPane component creates scrollbars (by default)
* that override this method and delegate to the viewports
* Scrollable view, if it has one. The Scrollable interface
* provides a more specialized version of this method.
* <p>
* Some look and feels implement custom scrolling behavior
* and ignore this property.
*
* @param direction is -1 or 1 for up/down respectively
* @return the value of the blockIncrement property
* @see #setBlockIncrement
* @see #setValue
* @see Scrollable#getScrollableBlockIncrement
*/
public int getBlockIncrement(int direction) {
return blockIncrement;
}
/**
* Sets the blockIncrement property.
* <p>
* Note, that if the argument is equal to the value of Integer.MIN_VALUE,
* the most look and feels will not provide the scrolling to the right/down.
* <p>
* Some look and feels implement custom scrolling behavior
* and ignore this property.
*
* @see #getBlockIncrement()
* @beaninfo
* preferred: true
* bound: true
* description: The scrollbar's block increment.
*/
public void setBlockIncrement(int blockIncrement) {
int oldValue = this.blockIncrement;
this.blockIncrement = blockIncrement;
firePropertyChange("blockIncrement", oldValue, blockIncrement);
}
/**
* For backwards compatibility with java.awt.Scrollbar.
* @see Adjustable#getUnitIncrement
* @see #getUnitIncrement(int)
*/
public int getUnitIncrement() {
return unitIncrement;
}
/**
* For backwards compatibility with java.awt.Scrollbar.
* @see Adjustable#getBlockIncrement
* @see #getBlockIncrement(int)
*/
public int getBlockIncrement() {
return blockIncrement;
}
/**
* Returns the scrollbar's value.
* @return the model's value property
* @see #setValue
*/
public int getValue() {
return getModel().getValue();
}
/**
* Sets the scrollbar's value. This method just forwards the value
* to the model.
*
* @see #getValue
* @see BoundedRangeModel#setValue
* @beaninfo
* preferred: true
* description: The scrollbar's current value.
*/
public void setValue(int value) {
BoundedRangeModel m = getModel();
int oldValue = m.getValue();
m.setValue(value);
if (accessibleContext != null) {
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
Integer.valueOf(oldValue),
Integer.valueOf(m.getValue()));
}
}
/**
* Returns the scrollbar's extent, aka its "visibleAmount". In many
* scrollbar look and feel implementations the size of the
* scrollbar "knob" or "thumb" is proportional to the extent.
*
* @return the value of the model's extent property
* @see #setVisibleAmount
*/
public int getVisibleAmount() {
return getModel().getExtent();
}
/**
* Set the model's extent property.
*
* @see #getVisibleAmount
* @see BoundedRangeModel#setExtent
* @beaninfo
* preferred: true
* description: The amount of the view that is currently visible.
*/
public void setVisibleAmount(int extent) {
getModel().setExtent(extent);
}
/**
* Returns the minimum value supported by the scrollbar
* (usually zero).
*
* @return the value of the model's minimum property
* @see #setMinimum
*/
public int getMinimum() {
return getModel().getMinimum();
}
/**
* Sets the model's minimum property.
*
* @see #getMinimum
* @see BoundedRangeModel#setMinimum
* @beaninfo
* preferred: true
* description: The scrollbar's minimum value.
*/
public void setMinimum(int minimum) {
getModel().setMinimum(minimum);
}
/**
* The maximum value of the scrollbar is maximum - extent.
*
* @return the value of the model's maximum property
* @see #setMaximum
*/
public int getMaximum() {
return getModel().getMaximum();
}
/**
* Sets the model's maximum property. Note that the scrollbar's value
* can only be set to maximum - extent.
*
* @see #getMaximum
* @see BoundedRangeModel#setMaximum
* @beaninfo
* preferred: true
* description: The scrollbar's maximum value.
*/
public void setMaximum(int maximum) {
getModel().setMaximum(maximum);
}
/**
* True if the scrollbar knob is being dragged.
*
* @return the value of the model's valueIsAdjusting property
* @see #setValueIsAdjusting
*/
public boolean getValueIsAdjusting() {
return getModel().getValueIsAdjusting();
}
/**
* Sets the model's valueIsAdjusting property. Scrollbar look and
* feel implementations should set this property to true when
* a knob drag begins, and to false when the drag ends. The
* scrollbar model will not generate ChangeEvents while
* valueIsAdjusting is true.
*
* @see #getValueIsAdjusting
* @see BoundedRangeModel#setValueIsAdjusting
* @beaninfo
* expert: true
* description: True if the scrollbar thumb is being dragged.
*/
public void setValueIsAdjusting(boolean b) {
BoundedRangeModel m = getModel();
boolean oldValue = m.getValueIsAdjusting();
m.setValueIsAdjusting(b);
if ((oldValue != b) && (accessibleContext != null)) {
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
((oldValue) ? AccessibleState.BUSY : null),
((b) ? AccessibleState.BUSY : null));
}
}
/**
* Sets the four BoundedRangeModel properties after forcing
* the arguments to obey the usual constraints:
* <pre>
* minimum &le; value &le; value+extent &le; maximum
* </pre>
*
*
* @see BoundedRangeModel#setRangeProperties
* @see #setValue
* @see #setVisibleAmount
* @see #setMinimum
* @see #setMaximum
*/
public void setValues(int newValue, int newExtent, int newMin, int newMax)
{
BoundedRangeModel m = getModel();
int oldValue = m.getValue();
m.setRangeProperties(newValue, newExtent, newMin, newMax, m.getValueIsAdjusting());
if (accessibleContext != null) {
accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_VALUE_PROPERTY,
Integer.valueOf(oldValue),
Integer.valueOf(m.getValue()));
}
}
/**
* Adds an AdjustmentListener. Adjustment listeners are notified
* each time the scrollbar's model changes. Adjustment events are
* provided for backwards compatibility with java.awt.Scrollbar.
* <p>
* Note that the AdjustmentEvents type property will always have a
* placeholder value of AdjustmentEvent.TRACK because all changes
* to a BoundedRangeModels value are considered equivalent. To change
* the value of a BoundedRangeModel one just sets its value property,
* i.e. model.setValue(123). No information about the origin of the
* change, e.g. it's a block decrement, is provided. We don't try
* fabricate the origin of the change here.
*
* @param l the AdjustmentLister to add
* @see #removeAdjustmentListener
* @see BoundedRangeModel#addChangeListener
*/
public void addAdjustmentListener(AdjustmentListener l) {
listenerList.add(AdjustmentListener.class, l);
}
/**
* Removes an AdjustmentEvent listener.
*
* @param l the AdjustmentLister to remove
* @see #addAdjustmentListener
*/
public void removeAdjustmentListener(AdjustmentListener l) {
listenerList.remove(AdjustmentListener.class, l);
}
/**
* Returns an array of all the <code>AdjustmentListener</code>s added
* to this JScrollBar with addAdjustmentListener().
*
* @return all of the <code>AdjustmentListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public AdjustmentListener[] getAdjustmentListeners() {
return listenerList.getListeners(AdjustmentListener.class);
}
/**
* Notify listeners that the scrollbar's model has changed.
*
* @see #addAdjustmentListener
* @see EventListenerList
*/
protected void fireAdjustmentValueChanged(int id, int type, int value) {
fireAdjustmentValueChanged(id, type, value, getValueIsAdjusting());
}
/**
* Notify listeners that the scrollbar's model has changed.
*
* @see #addAdjustmentListener
* @see EventListenerList
*/
private void fireAdjustmentValueChanged(int id, int type, int value,
boolean isAdjusting) {
Object[] listeners = listenerList.getListenerList();
AdjustmentEvent e = null;
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i]==AdjustmentListener.class) {
if (e == null) {
e = new AdjustmentEvent(this, id, type, value, isAdjusting);
}
((AdjustmentListener)listeners[i+1]).adjustmentValueChanged(e);
}
}
}
/**
* This class listens to ChangeEvents on the model and forwards
* AdjustmentEvents for the sake of backwards compatibility.
* Unfortunately there's no way to determine the proper
* type of the AdjustmentEvent as all updates to the model's
* value are considered equivalent.
*/
private class ModelListener implements ChangeListener, Serializable {
public void stateChanged(ChangeEvent e) {
Object obj = e.getSource();
if (obj instanceof BoundedRangeModel) {
int id = AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED;
int type = AdjustmentEvent.TRACK;
BoundedRangeModel model = (BoundedRangeModel)obj;
int value = model.getValue();
boolean isAdjusting = model.getValueIsAdjusting();
fireAdjustmentValueChanged(id, type, value, isAdjusting);
}
}
}
// PENDING(hmuller) - the next three methods should be removed
/**
* The scrollbar is flexible along it's scrolling axis and
* rigid along the other axis.
*/
public Dimension getMinimumSize() {
Dimension pref = getPreferredSize();
if (orientation == VERTICAL) {
return new Dimension(pref.width, 5);
} else {
return new Dimension(5, pref.height);
}
}
/**
* The scrollbar is flexible along it's scrolling axis and
* rigid along the other axis.
*/
public Dimension getMaximumSize() {
Dimension pref = getPreferredSize();
if (getOrientation() == VERTICAL) {
return new Dimension(pref.width, Short.MAX_VALUE);
} else {
return new Dimension(Short.MAX_VALUE, pref.height);
}
}
/**
* Enables the component so that the knob position can be changed.
* When the disabled, the knob position cannot be changed.
*
* @param x a boolean value, where true enables the component and
* false disables it
*/
public void setEnabled(boolean x) {
super.setEnabled(x);
Component[] children = getComponents();
for (Component child : children) {
child.setEnabled(x);
}
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this JScrollBar. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JScrollBar.
*/
protected String paramString() {
String orientationString = (orientation == HORIZONTAL ?
"HORIZONTAL" : "VERTICAL");
return super.paramString() +
",blockIncrement=" + blockIncrement +
",orientation=" + orientationString +
",unitIncrement=" + unitIncrement;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JScrollBar.
* For JScrollBar, the AccessibleContext takes the form of an
* AccessibleJScrollBar.
* A new AccessibleJScrollBar instance is created if necessary.
*
* @return an AccessibleJScrollBar that serves as the
* AccessibleContext of this JScrollBar
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJScrollBar();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JScrollBar</code> class. It provides an implementation of the
* Java Accessibility API appropriate to scroll bar user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJScrollBar extends AccessibleJComponent
implements AccessibleValue {
/**
* Get the state set of this object.
*
* @return an instance of AccessibleState containing the current state
* of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
if (getValueIsAdjusting()) {
states.add(AccessibleState.BUSY);
}
if (getOrientation() == VERTICAL) {
states.add(AccessibleState.VERTICAL);
} else {
states.add(AccessibleState.HORIZONTAL);
}
return states;
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.SCROLL_BAR;
}
/**
* Get the AccessibleValue associated with this object. In the
* implementation of the Java Accessibility API for this class,
* return this object, which is responsible for implementing the
* AccessibleValue interface on behalf of itself.
*
* @return this object
*/
public AccessibleValue getAccessibleValue() {
return this;
}
/**
* Get the accessible value of this object.
*
* @return The current value of this object.
*/
public Number getCurrentAccessibleValue() {
return Integer.valueOf(getValue());
}
/**
* Set the value of this object as a Number.
*
* @return True if the value was set.
*/
public boolean setCurrentAccessibleValue(Number n) {
// TIGER - 4422535
if (n == null) {
return false;
}
setValue(n.intValue());
return true;
}
/**
* Get the minimum accessible value of this object.
*
* @return The minimum value of this object.
*/
public Number getMinimumAccessibleValue() {
return Integer.valueOf(getMinimum());
}
/**
* Get the maximum accessible value of this object.
*
* @return The maximum value of this object.
*/
public Number getMaximumAccessibleValue() {
// TIGER - 4422362
return new Integer(model.getMaximum() - model.getExtent());
}
} // AccessibleJScrollBar
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* <code>JSeparator</code> provides a general purpose component for
* implementing divider lines - most commonly used as a divider
* between menu items that breaks them up into logical groupings.
* Instead of using <code>JSeparator</code> directly,
* you can use the <code>JMenu</code> or <code>JPopupMenu</code>
* <code>addSeparator</code> method to create and add a separator.
* <code>JSeparator</code>s may also be used elsewhere in a GUI
* wherever a visual divider is useful.
*
* <p>
*
* For more information and examples see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/menu.html">How to Use Menus</a>,
* a section in <em>The Java Tutorial.</em>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: A divider between menu items.
*
* @author Georges Saab
* @author Jeff Shapiro
*/
@SuppressWarnings("serial")
public class JSeparator extends JComponent implements SwingConstants, Accessible
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "SeparatorUI";
private int orientation = HORIZONTAL;
/** Creates a new horizontal separator. */
public JSeparator()
{
this( HORIZONTAL );
}
/**
* Creates a new separator with the specified horizontal or
* vertical orientation.
*
* @param orientation an integer specifying
* <code>SwingConstants.HORIZONTAL</code> or
* <code>SwingConstants.VERTICAL</code>
* @exception IllegalArgumentException if <code>orientation</code>
* is neither <code>SwingConstants.HORIZONTAL</code> nor
* <code>SwingConstants.VERTICAL</code>
*/
public JSeparator( int orientation )
{
checkOrientation( orientation );
this.orientation = orientation;
setFocusable(false);
updateUI();
}
/**
* Returns the L&amp;F object that renders this component.
*
* @return the SeparatorUI object that renders this component
*/
public SeparatorUI getUI() {
return (SeparatorUI)ui;
}
/**
* Sets the L&amp;F object that renders this component.
*
* @param ui the SeparatorUI L&amp;F object
* @see UIDefaults#getUI
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel.
*/
public void setUI(SeparatorUI ui) {
super.setUI(ui);
}
/**
* Resets the UI property to a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((SeparatorUI)UIManager.getUI(this));
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "SeparatorUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* See <code>readObject</code> and <code>writeObject</code> in
* <code>JComponent</code> for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns the orientation of this separator.
*
* @return The value of the orientation property, one of the
* following constants defined in <code>SwingConstants</code>:
* <code>VERTICAL</code>, or
* <code>HORIZONTAL</code>.
*
* @see SwingConstants
* @see #setOrientation
*/
public int getOrientation() {
return this.orientation;
}
/**
* Sets the orientation of the separator.
* The default value of this property is HORIZONTAL.
* @param orientation either <code>SwingConstants.HORIZONTAL</code>
* or <code>SwingConstants.VERTICAL</code>
* @exception IllegalArgumentException if <code>orientation</code>
* is neither <code>SwingConstants.HORIZONTAL</code>
* nor <code>SwingConstants.VERTICAL</code>
*
* @see SwingConstants
* @see #getOrientation
* @beaninfo
* bound: true
* preferred: true
* enum: HORIZONTAL SwingConstants.HORIZONTAL
* VERTICAL SwingConstants.VERTICAL
* attribute: visualUpdate true
* description: The orientation of the separator.
*/
public void setOrientation( int orientation ) {
if (this.orientation == orientation) {
return;
}
int oldValue = this.orientation;
checkOrientation( orientation );
this.orientation = orientation;
firePropertyChange("orientation", oldValue, orientation);
revalidate();
repaint();
}
private void checkOrientation( int orientation )
{
switch ( orientation )
{
case VERTICAL:
case HORIZONTAL:
break;
default:
throw new IllegalArgumentException( "orientation must be one of: VERTICAL, HORIZONTAL" );
}
}
/**
* Returns a string representation of this <code>JSeparator</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JSeparator</code>
*/
protected String paramString() {
String orientationString = (orientation == HORIZONTAL ?
"HORIZONTAL" : "VERTICAL");
return super.paramString() +
",orientation=" + orientationString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JSeparator.
* For separators, the AccessibleContext takes the form of an
* AccessibleJSeparator.
* A new AccessibleJSeparator instance is created if necessary.
*
* @return an AccessibleJSeparator that serves as the
* AccessibleContext of this JSeparator
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJSeparator();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JSeparator</code> class. It provides an implementation of the
* Java Accessibility API appropriate to separator user-interface elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
protected class AccessibleJSeparator extends AccessibleJComponent {
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.SEPARATOR;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,814 @@
/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import javax.swing.text.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.util.Collections;
import java.util.Set;
import java.util.StringTokenizer;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* A <code>JTextArea</code> is a multi-line area that displays plain text.
* It is intended to be a lightweight component that provides source
* compatibility with the <code>java.awt.TextArea</code> class where it can
* reasonably do so.
* You can find information and examples of using all the text components in
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/text.html">Using Text Components</a>,
* a section in <em>The Java Tutorial.</em>
*
* <p>
* This component has capabilities not found in the
* <code>java.awt.TextArea</code> class. The superclass should be
* consulted for additional capabilities.
* Alternative multi-line text classes with
* more capabilities are <code>JTextPane</code> and <code>JEditorPane</code>.
* <p>
* The <code>java.awt.TextArea</code> internally handles scrolling.
* <code>JTextArea</code> is different in that it doesn't manage scrolling,
* but implements the swing <code>Scrollable</code> interface. This allows it
* to be placed inside a <code>JScrollPane</code> if scrolling
* behavior is desired, and used directly if scrolling is not desired.
* <p>
* The <code>java.awt.TextArea</code> has the ability to do line wrapping.
* This was controlled by the horizontal scrolling policy. Since
* scrolling is not done by <code>JTextArea</code> directly, backward
* compatibility must be provided another way. <code>JTextArea</code> has
* a bound property for line wrapping that controls whether or
* not it will wrap lines. By default, the line wrapping property
* is set to false (not wrapped).
* <p>
* <code>java.awt.TextArea</code> has two properties <code>rows</code>
* and <code>columns</code> that are used to determine the preferred size.
* <code>JTextArea</code> uses these properties to indicate the
* preferred size of the viewport when placed inside a <code>JScrollPane</code>
* to match the functionality provided by <code>java.awt.TextArea</code>.
* <code>JTextArea</code> has a preferred size of what is needed to
* display all of the text, so that it functions properly inside of
* a <code>JScrollPane</code>. If the value for <code>rows</code>
* or <code>columns</code> is equal to zero,
* the preferred size along that axis is used for
* the viewport preferred size along the same axis.
* <p>
* The <code>java.awt.TextArea</code> could be monitored for changes by adding
* a <code>TextListener</code> for <code>TextEvent</code>s.
* In the <code>JTextComponent</code> based
* components, changes are broadcasted from the model via a
* <code>DocumentEvent</code> to <code>DocumentListeners</code>.
* The <code>DocumentEvent</code> gives
* the location of the change and the kind of change if desired.
* The code fragment might look something like:
* <pre>
* DocumentListener myListener = ??;
* JTextArea myArea = ??;
* myArea.getDocument().addDocumentListener(myListener);
* </pre>
*
* <dl>
* <dt><b><font size=+1>Newlines</font></b>
* <dd>
* For a discussion on how newlines are handled, see
* <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
* </dl>
*
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: A multi-line area that displays plain text.
*
* @author Timothy Prinzing
* @see JTextPane
* @see JEditorPane
*/
public class JTextArea extends JTextComponent {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "TextAreaUI";
/**
* Constructs a new TextArea. A default model is set, the initial string
* is null, and rows/columns are set to 0.
*/
public JTextArea() {
this(null, null, 0, 0);
}
/**
* Constructs a new TextArea with the specified text displayed.
* A default model is created and rows/columns are set to 0.
*
* @param text the text to be displayed, or null
*/
public JTextArea(String text) {
this(null, text, 0, 0);
}
/**
* Constructs a new empty TextArea with the specified number of
* rows and columns. A default model is created, and the initial
* string is null.
*
* @param rows the number of rows &gt;= 0
* @param columns the number of columns &gt;= 0
* @exception IllegalArgumentException if the rows or columns
* arguments are negative.
*/
public JTextArea(int rows, int columns) {
this(null, null, rows, columns);
}
/**
* Constructs a new TextArea with the specified text and number
* of rows and columns. A default model is created.
*
* @param text the text to be displayed, or null
* @param rows the number of rows &gt;= 0
* @param columns the number of columns &gt;= 0
* @exception IllegalArgumentException if the rows or columns
* arguments are negative.
*/
public JTextArea(String text, int rows, int columns) {
this(null, text, rows, columns);
}
/**
* Constructs a new JTextArea with the given document model, and defaults
* for all of the other arguments (null, 0, 0).
*
* @param doc the model to use
*/
public JTextArea(Document doc) {
this(doc, null, 0, 0);
}
/**
* Constructs a new JTextArea with the specified number of rows
* and columns, and the given model. All of the constructors
* feed through this constructor.
*
* @param doc the model to use, or create a default one if null
* @param text the text to be displayed, null if none
* @param rows the number of rows &gt;= 0
* @param columns the number of columns &gt;= 0
* @exception IllegalArgumentException if the rows or columns
* arguments are negative.
*/
public JTextArea(Document doc, String text, int rows, int columns) {
super();
this.rows = rows;
this.columns = columns;
if (doc == null) {
doc = createDefaultModel();
}
setDocument(doc);
if (text != null) {
setText(text);
select(0, 0);
}
if (rows < 0) {
throw new IllegalArgumentException("rows: " + rows);
}
if (columns < 0) {
throw new IllegalArgumentException("columns: " + columns);
}
LookAndFeel.installProperty(this,
"focusTraversalKeysForward",
JComponent.
getManagingFocusForwardTraversalKeys());
LookAndFeel.installProperty(this,
"focusTraversalKeysBackward",
JComponent.
getManagingFocusBackwardTraversalKeys());
}
/**
* Returns the class ID for the UI.
*
* @return the ID ("TextAreaUI")
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Creates the default implementation of the model
* to be used at construction if one isn't explicitly
* given. A new instance of PlainDocument is returned.
*
* @return the default document model
*/
protected Document createDefaultModel() {
return new PlainDocument();
}
/**
* Sets the number of characters to expand tabs to.
* This will be multiplied by the maximum advance for
* variable width fonts. A PropertyChange event ("tabSize") is fired
* when the tab size changes.
*
* @param size number of characters to expand to
* @see #getTabSize
* @beaninfo
* preferred: true
* bound: true
* description: the number of characters to expand tabs to
*/
public void setTabSize(int size) {
Document doc = getDocument();
if (doc != null) {
int old = getTabSize();
doc.putProperty(PlainDocument.tabSizeAttribute, Integer.valueOf(size));
firePropertyChange("tabSize", old, size);
}
}
/**
* Gets the number of characters used to expand tabs. If the document is
* null or doesn't have a tab setting, return a default of 8.
*
* @return the number of characters
*/
public int getTabSize() {
int size = 8;
Document doc = getDocument();
if (doc != null) {
Integer i = (Integer) doc.getProperty(PlainDocument.tabSizeAttribute);
if (i != null) {
size = i.intValue();
}
}
return size;
}
/**
* Sets the line-wrapping policy of the text area. If set
* to true the lines will be wrapped if they are too long
* to fit within the allocated width. If set to false,
* the lines will always be unwrapped. A <code>PropertyChange</code>
* event ("lineWrap") is fired when the policy is changed.
* By default this property is false.
*
* @param wrap indicates if lines should be wrapped
* @see #getLineWrap
* @beaninfo
* preferred: true
* bound: true
* description: should lines be wrapped
*/
public void setLineWrap(boolean wrap) {
boolean old = this.wrap;
this.wrap = wrap;
firePropertyChange("lineWrap", old, wrap);
}
/**
* Gets the line-wrapping policy of the text area. If set
* to true the lines will be wrapped if they are too long
* to fit within the allocated width. If set to false,
* the lines will always be unwrapped.
*
* @return if lines will be wrapped
*/
public boolean getLineWrap() {
return wrap;
}
/**
* Sets the style of wrapping used if the text area is wrapping
* lines. If set to true the lines will be wrapped at word
* boundaries (whitespace) if they are too long
* to fit within the allocated width. If set to false,
* the lines will be wrapped at character boundaries.
* By default this property is false.
*
* @param word indicates if word boundaries should be used
* for line wrapping
* @see #getWrapStyleWord
* @beaninfo
* preferred: false
* bound: true
* description: should wrapping occur at word boundaries
*/
public void setWrapStyleWord(boolean word) {
boolean old = this.word;
this.word = word;
firePropertyChange("wrapStyleWord", old, word);
}
/**
* Gets the style of wrapping used if the text area is wrapping
* lines. If set to true the lines will be wrapped at word
* boundaries (ie whitespace) if they are too long
* to fit within the allocated width. If set to false,
* the lines will be wrapped at character boundaries.
*
* @return if the wrap style should be word boundaries
* instead of character boundaries
* @see #setWrapStyleWord
*/
public boolean getWrapStyleWord() {
return word;
}
/**
* Translates an offset into the components text to a
* line number.
*
* @param offset the offset &gt;= 0
* @return the line number &gt;= 0
* @exception BadLocationException thrown if the offset is
* less than zero or greater than the document length.
*/
public int getLineOfOffset(int offset) throws BadLocationException {
Document doc = getDocument();
if (offset < 0) {
throw new BadLocationException("Can't translate offset to line", -1);
} else if (offset > doc.getLength()) {
throw new BadLocationException("Can't translate offset to line", doc.getLength()+1);
} else {
Element map = getDocument().getDefaultRootElement();
return map.getElementIndex(offset);
}
}
/**
* Determines the number of lines contained in the area.
*
* @return the number of lines &gt; 0
*/
public int getLineCount() {
Element map = getDocument().getDefaultRootElement();
return map.getElementCount();
}
/**
* Determines the offset of the start of the given line.
*
* @param line the line number to translate &gt;= 0
* @return the offset &gt;= 0
* @exception BadLocationException thrown if the line is
* less than zero or greater or equal to the number of
* lines contained in the document (as reported by
* getLineCount).
*/
public int getLineStartOffset(int line) throws BadLocationException {
int lineCount = getLineCount();
if (line < 0) {
throw new BadLocationException("Negative line", -1);
} else if (line >= lineCount) {
throw new BadLocationException("No such line", getDocument().getLength()+1);
} else {
Element map = getDocument().getDefaultRootElement();
Element lineElem = map.getElement(line);
return lineElem.getStartOffset();
}
}
/**
* Determines the offset of the end of the given line.
*
* @param line the line &gt;= 0
* @return the offset &gt;= 0
* @exception BadLocationException Thrown if the line is
* less than zero or greater or equal to the number of
* lines contained in the document (as reported by
* getLineCount).
*/
public int getLineEndOffset(int line) throws BadLocationException {
int lineCount = getLineCount();
if (line < 0) {
throw new BadLocationException("Negative line", -1);
} else if (line >= lineCount) {
throw new BadLocationException("No such line", getDocument().getLength()+1);
} else {
Element map = getDocument().getDefaultRootElement();
Element lineElem = map.getElement(line);
int endOffset = lineElem.getEndOffset();
// hide the implicit break at the end of the document
return ((line == lineCount - 1) ? (endOffset - 1) : endOffset);
}
}
// --- java.awt.TextArea methods ---------------------------------
/**
* Inserts the specified text at the specified position. Does nothing
* if the model is null or if the text is null or empty.
*
* @param str the text to insert
* @param pos the position at which to insert &gt;= 0
* @exception IllegalArgumentException if pos is an
* invalid position in the model
* @see TextComponent#setText
* @see #replaceRange
*/
public void insert(String str, int pos) {
Document doc = getDocument();
if (doc != null) {
try {
doc.insertString(pos, str, null);
} catch (BadLocationException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
}
/**
* Appends the given text to the end of the document. Does nothing if
* the model is null or the string is null or empty.
*
* @param str the text to insert
* @see #insert
*/
public void append(String str) {
Document doc = getDocument();
if (doc != null) {
try {
doc.insertString(doc.getLength(), str, null);
} catch (BadLocationException e) {
}
}
}
/**
* Replaces text from the indicated start to end position with the
* new text specified. Does nothing if the model is null. Simply
* does a delete if the new string is null or empty.
*
* @param str the text to use as the replacement
* @param start the start position &gt;= 0
* @param end the end position &gt;= start
* @exception IllegalArgumentException if part of the range is an
* invalid position in the model
* @see #insert
*/
public void replaceRange(String str, int start, int end) {
if (end < start) {
throw new IllegalArgumentException("end before start");
}
Document doc = getDocument();
if (doc != null) {
try {
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).replace(start, end - start, str,
null);
}
else {
doc.remove(start, end - start);
doc.insertString(start, str, null);
}
} catch (BadLocationException e) {
throw new IllegalArgumentException(e.getMessage());
}
}
}
/**
* Returns the number of rows in the TextArea.
*
* @return the number of rows &gt;= 0
*/
public int getRows() {
return rows;
}
/**
* Sets the number of rows for this TextArea. Calls invalidate() after
* setting the new value.
*
* @param rows the number of rows &gt;= 0
* @exception IllegalArgumentException if rows is less than 0
* @see #getRows
* @beaninfo
* description: the number of rows preferred for display
*/
public void setRows(int rows) {
int oldVal = this.rows;
if (rows < 0) {
throw new IllegalArgumentException("rows less than zero.");
}
if (rows != oldVal) {
this.rows = rows;
invalidate();
}
}
/**
* Defines the meaning of the height of a row. This defaults to
* the height of the font.
*
* @return the height &gt;= 1
*/
protected int getRowHeight() {
if (rowHeight == 0) {
FontMetrics metrics = getFontMetrics(getFont());
rowHeight = metrics.getHeight();
}
return rowHeight;
}
/**
* Returns the number of columns in the TextArea.
*
* @return number of columns &gt;= 0
*/
public int getColumns() {
return columns;
}
/**
* Sets the number of columns for this TextArea. Does an invalidate()
* after setting the new value.
*
* @param columns the number of columns &gt;= 0
* @exception IllegalArgumentException if columns is less than 0
* @see #getColumns
* @beaninfo
* description: the number of columns preferred for display
*/
public void setColumns(int columns) {
int oldVal = this.columns;
if (columns < 0) {
throw new IllegalArgumentException("columns less than zero.");
}
if (columns != oldVal) {
this.columns = columns;
invalidate();
}
}
/**
* Gets column width.
* The meaning of what a column is can be considered a fairly weak
* notion for some fonts. This method is used to define the width
* of a column. By default this is defined to be the width of the
* character <em>m</em> for the font used. This method can be
* redefined to be some alternative amount.
*
* @return the column width &gt;= 1
*/
protected int getColumnWidth() {
if (columnWidth == 0) {
FontMetrics metrics = getFontMetrics(getFont());
columnWidth = metrics.charWidth('m');
}
return columnWidth;
}
// --- Component methods -----------------------------------------
/**
* Returns the preferred size of the TextArea. This is the
* maximum of the size needed to display the text and the
* size requested for the viewport.
*
* @return the size
*/
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
d = (d == null) ? new Dimension(400,400) : d;
Insets insets = getInsets();
if (columns != 0) {
d.width = Math.max(d.width, columns * getColumnWidth() +
insets.left + insets.right);
}
if (rows != 0) {
d.height = Math.max(d.height, rows * getRowHeight() +
insets.top + insets.bottom);
}
return d;
}
/**
* Sets the current font. This removes cached row height and column
* width so the new font will be reflected, and calls revalidate().
*
* @param f the font to use as the current font
*/
public void setFont(Font f) {
super.setFont(f);
rowHeight = 0;
columnWidth = 0;
}
/**
* Returns a string representation of this JTextArea. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JTextArea.
*/
protected String paramString() {
String wrapString = (wrap ?
"true" : "false");
String wordString = (word ?
"true" : "false");
return super.paramString() +
",colums=" + columns +
",columWidth=" + columnWidth +
",rows=" + rows +
",rowHeight=" + rowHeight +
",word=" + wordString +
",wrap=" + wrapString;
}
// --- Scrollable methods ----------------------------------------
/**
* Returns true if a viewport should always force the width of this
* Scrollable to match the width of the viewport. This is implemented
* to return true if the line wrapping policy is true, and false
* if lines are not being wrapped.
*
* @return true if a viewport should force the Scrollables width
* to match its own.
*/
public boolean getScrollableTracksViewportWidth() {
return (wrap) ? true : super.getScrollableTracksViewportWidth();
}
/**
* Returns the preferred size of the viewport if this component
* is embedded in a JScrollPane. This uses the desired column
* and row settings if they have been set, otherwise the superclass
* behavior is used.
*
* @return The preferredSize of a JViewport whose view is this Scrollable.
* @see JViewport#getPreferredSize
*/
public Dimension getPreferredScrollableViewportSize() {
Dimension size = super.getPreferredScrollableViewportSize();
size = (size == null) ? new Dimension(400,400) : size;
Insets insets = getInsets();
size.width = (columns == 0) ? size.width :
columns * getColumnWidth() + insets.left + insets.right;
size.height = (rows == 0) ? size.height :
rows * getRowHeight() + insets.top + insets.bottom;
return size;
}
/**
* Components that display logical rows or columns should compute
* the scroll increment that will completely expose one new row
* or column, depending on the value of orientation. This is implemented
* to use the values returned by the <code>getRowHeight</code> and
* <code>getColumnWidth</code> methods.
* <p>
* Scrolling containers, like JScrollPane, will use this method
* each time the user requests a unit scroll.
*
* @param visibleRect the view area visible within the viewport
* @param orientation Either SwingConstants.VERTICAL or
* SwingConstants.HORIZONTAL.
* @param direction Less than zero to scroll up/left,
* greater than zero for down/right.
* @return The "unit" increment for scrolling in the specified direction
* @exception IllegalArgumentException for an invalid orientation
* @see JScrollBar#setUnitIncrement
* @see #getRowHeight
* @see #getColumnWidth
*/
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
switch (orientation) {
case SwingConstants.VERTICAL:
return getRowHeight();
case SwingConstants.HORIZONTAL:
return getColumnWidth();
default:
throw new IllegalArgumentException("Invalid orientation: " + orientation);
}
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JTextArea.
* For JTextAreas, the AccessibleContext takes the form of an
* AccessibleJTextArea.
* A new AccessibleJTextArea instance is created if necessary.
*
* @return an AccessibleJTextArea that serves as the
* AccessibleContext of this JTextArea
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJTextArea();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JTextArea</code> class. It provides an implementation of the
* Java Accessibility API appropriate to text area user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJTextArea extends AccessibleJTextComponent {
/**
* Gets the state set of this object.
*
* @return an instance of AccessibleStateSet describing the states
* of the object
* @see AccessibleStateSet
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
states.add(AccessibleState.MULTI_LINE);
return states;
}
}
// --- variables -------------------------------------------------
private int rows;
private int columns;
private int columnWidth;
private int rowHeight;
private boolean wrap;
private boolean word;
}

View File

@@ -0,0 +1,961 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import sun.swing.SwingUtilities2;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.text.*;
import javax.swing.plaf.*;
import javax.swing.event.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.Serializable;
/**
* <code>JTextField</code> is a lightweight component that allows the editing
* of a single line of text.
* For information on and examples of using text fields,
* see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/textfield.html">How to Use Text Fields</a>
* in <em>The Java Tutorial.</em>
*
* <p>
* <code>JTextField</code> is intended to be source-compatible
* with <code>java.awt.TextField</code> where it is reasonable to do so. This
* component has capabilities not found in the <code>java.awt.TextField</code>
* class. The superclass should be consulted for additional capabilities.
* <p>
* <code>JTextField</code> has a method to establish the string used as the
* command string for the action event that gets fired. The
* <code>java.awt.TextField</code> used the text of the field as the command
* string for the <code>ActionEvent</code>.
* <code>JTextField</code> will use the command
* string set with the <code>setActionCommand</code> method if not <code>null</code>,
* otherwise it will use the text of the field as a compatibility with
* <code>java.awt.TextField</code>.
* <p>
* The method <code>setEchoChar</code> and <code>getEchoChar</code>
* are not provided directly to avoid a new implementation of a
* pluggable look-and-feel inadvertently exposing password characters.
* To provide password-like services a separate class <code>JPasswordField</code>
* extends <code>JTextField</code> to provide this service with an independently
* pluggable look-and-feel.
* <p>
* The <code>java.awt.TextField</code> could be monitored for changes by adding
* a <code>TextListener</code> for <code>TextEvent</code>'s.
* In the <code>JTextComponent</code> based
* components, changes are broadcasted from the model via a
* <code>DocumentEvent</code> to <code>DocumentListeners</code>.
* The <code>DocumentEvent</code> gives
* the location of the change and the kind of change if desired.
* The code fragment might look something like:
* <pre><code>
* &nbsp; DocumentListener myListener = ??;
* &nbsp; JTextField myArea = ??;
* &nbsp; myArea.getDocument().addDocumentListener(myListener);
* </code></pre>
* <p>
* The horizontal alignment of <code>JTextField</code> can be set to be left
* justified, leading justified, centered, right justified or trailing justified.
* Right/trailing justification is useful if the required size
* of the field text is smaller than the size allocated to it.
* This is determined by the <code>setHorizontalAlignment</code>
* and <code>getHorizontalAlignment</code> methods. The default
* is to be leading justified.
* <p>
* How the text field consumes VK_ENTER events depends
* on whether the text field has any action listeners.
* If so, then VK_ENTER results in the listeners
* getting an ActionEvent,
* and the VK_ENTER event is consumed.
* This is compatible with how AWT text fields handle VK_ENTER events.
* If the text field has no action listeners, then as of v 1.3 the VK_ENTER
* event is not consumed. Instead, the bindings of ancestor components
* are processed, which enables the default button feature of
* JFC/Swing to work.
* <p>
* Customized fields can easily be created by extending the model and
* changing the default model provided. For example, the following piece
* of code will create a field that holds only upper case characters. It
* will work even if text is pasted into from the clipboard or it is altered via
* programmatic changes.
* <pre><code>
&nbsp;public class UpperCaseField extends JTextField {
&nbsp;
&nbsp; public UpperCaseField(int cols) {
&nbsp; super(cols);
&nbsp; }
&nbsp;
&nbsp; protected Document createDefaultModel() {
&nbsp; return new UpperCaseDocument();
&nbsp; }
&nbsp;
&nbsp; static class UpperCaseDocument extends PlainDocument {
&nbsp;
&nbsp; public void insertString(int offs, String str, AttributeSet a)
&nbsp; throws BadLocationException {
&nbsp;
&nbsp; if (str == null) {
&nbsp; return;
&nbsp; }
&nbsp; char[] upper = str.toCharArray();
&nbsp; for (int i = 0; i &lt; upper.length; i++) {
&nbsp; upper[i] = Character.toUpperCase(upper[i]);
&nbsp; }
&nbsp; super.insertString(offs, new String(upper), a);
&nbsp; }
&nbsp; }
&nbsp;}
* </code></pre>
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: A component which allows for the editing of a single line of text.
*
* @author Timothy Prinzing
* @see #setActionCommand
* @see JPasswordField
* @see #addActionListener
*/
public class JTextField extends JTextComponent implements SwingConstants {
/**
* Constructs a new <code>TextField</code>. A default model is created,
* the initial string is <code>null</code>,
* and the number of columns is set to 0.
*/
public JTextField() {
this(null, null, 0);
}
/**
* Constructs a new <code>TextField</code> initialized with the
* specified text. A default model is created and the number of
* columns is 0.
*
* @param text the text to be displayed, or <code>null</code>
*/
public JTextField(String text) {
this(null, text, 0);
}
/**
* Constructs a new empty <code>TextField</code> with the specified
* number of columns.
* A default model is created and the initial string is set to
* <code>null</code>.
*
* @param columns the number of columns to use to calculate
* the preferred width; if columns is set to zero, the
* preferred width will be whatever naturally results from
* the component implementation
*/
public JTextField(int columns) {
this(null, null, columns);
}
/**
* Constructs a new <code>TextField</code> initialized with the
* specified text and columns. A default model is created.
*
* @param text the text to be displayed, or <code>null</code>
* @param columns the number of columns to use to calculate
* the preferred width; if columns is set to zero, the
* preferred width will be whatever naturally results from
* the component implementation
*/
public JTextField(String text, int columns) {
this(null, text, columns);
}
/**
* Constructs a new <code>JTextField</code> that uses the given text
* storage model and the given number of columns.
* This is the constructor through which the other constructors feed.
* If the document is <code>null</code>, a default model is created.
*
* @param doc the text storage to use; if this is <code>null</code>,
* a default will be provided by calling the
* <code>createDefaultModel</code> method
* @param text the initial string to display, or <code>null</code>
* @param columns the number of columns to use to calculate
* the preferred width &gt;= 0; if <code>columns</code>
* is set to zero, the preferred width will be whatever
* naturally results from the component implementation
* @exception IllegalArgumentException if <code>columns</code> &lt; 0
*/
public JTextField(Document doc, String text, int columns) {
if (columns < 0) {
throw new IllegalArgumentException("columns less than zero.");
}
visibility = new DefaultBoundedRangeModel();
visibility.addChangeListener(new ScrollRepainter());
this.columns = columns;
if (doc == null) {
doc = createDefaultModel();
}
setDocument(doc);
if (text != null) {
setText(text);
}
}
/**
* Gets the class ID for a UI.
*
* @return the string "TextFieldUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Associates the editor with a text document.
* The currently registered factory is used to build a view for
* the document, which gets displayed by the editor after revalidation.
* A PropertyChange event ("document") is propagated to each listener.
*
* @param doc the document to display/edit
* @see #getDocument
* @beaninfo
* description: the text document model
* bound: true
* expert: true
*/
public void setDocument(Document doc) {
if (doc != null) {
doc.putProperty("filterNewlines", Boolean.TRUE);
}
super.setDocument(doc);
}
/**
* Calls to <code>revalidate</code> that come from within the
* textfield itself will
* be handled by validating the textfield, unless the textfield
* is contained within a <code>JViewport</code>,
* in which case this returns false.
*
* @return if the parent of this textfield is a <code>JViewPort</code>
* return false, otherwise return true
*
* @see JComponent#revalidate
* @see JComponent#isValidateRoot
* @see java.awt.Container#isValidateRoot
*/
@Override
public boolean isValidateRoot() {
return !(SwingUtilities.getUnwrappedParent(this) instanceof JViewport);
}
/**
* Returns the horizontal alignment of the text.
* Valid keys are:
* <ul>
* <li><code>JTextField.LEFT</code>
* <li><code>JTextField.CENTER</code>
* <li><code>JTextField.RIGHT</code>
* <li><code>JTextField.LEADING</code>
* <li><code>JTextField.TRAILING</code>
* </ul>
*
* @return the horizontal alignment
*/
public int getHorizontalAlignment() {
return horizontalAlignment;
}
/**
* Sets the horizontal alignment of the text.
* Valid keys are:
* <ul>
* <li><code>JTextField.LEFT</code>
* <li><code>JTextField.CENTER</code>
* <li><code>JTextField.RIGHT</code>
* <li><code>JTextField.LEADING</code>
* <li><code>JTextField.TRAILING</code>
* </ul>
* <code>invalidate</code> and <code>repaint</code> are called when the
* alignment is set,
* and a <code>PropertyChange</code> event ("horizontalAlignment") is fired.
*
* @param alignment the alignment
* @exception IllegalArgumentException if <code>alignment</code>
* is not a valid key
* @beaninfo
* preferred: true
* bound: true
* description: Set the field alignment to LEFT, CENTER, RIGHT,
* LEADING (the default) or TRAILING
* enum: LEFT JTextField.LEFT CENTER JTextField.CENTER RIGHT JTextField.RIGHT
* LEADING JTextField.LEADING TRAILING JTextField.TRAILING
*/
public void setHorizontalAlignment(int alignment) {
if (alignment == horizontalAlignment) return;
int oldValue = horizontalAlignment;
if ((alignment == LEFT) || (alignment == CENTER) ||
(alignment == RIGHT)|| (alignment == LEADING) ||
(alignment == TRAILING)) {
horizontalAlignment = alignment;
} else {
throw new IllegalArgumentException("horizontalAlignment");
}
firePropertyChange("horizontalAlignment", oldValue, horizontalAlignment);
invalidate();
repaint();
}
/**
* Creates the default implementation of the model
* to be used at construction if one isn't explicitly
* given. An instance of <code>PlainDocument</code> is returned.
*
* @return the default model implementation
*/
protected Document createDefaultModel() {
return new PlainDocument();
}
/**
* Returns the number of columns in this <code>TextField</code>.
*
* @return the number of columns &gt;= 0
*/
public int getColumns() {
return columns;
}
/**
* Sets the number of columns in this <code>TextField</code>,
* and then invalidate the layout.
*
* @param columns the number of columns &gt;= 0
* @exception IllegalArgumentException if <code>columns</code>
* is less than 0
* @beaninfo
* description: the number of columns preferred for display
*/
public void setColumns(int columns) {
int oldVal = this.columns;
if (columns < 0) {
throw new IllegalArgumentException("columns less than zero.");
}
if (columns != oldVal) {
this.columns = columns;
invalidate();
}
}
/**
* Returns the column width.
* The meaning of what a column is can be considered a fairly weak
* notion for some fonts. This method is used to define the width
* of a column. By default this is defined to be the width of the
* character <em>m</em> for the font used. This method can be
* redefined to be some alternative amount
*
* @return the column width &gt;= 1
*/
protected int getColumnWidth() {
if (columnWidth == 0) {
FontMetrics metrics = getFontMetrics(getFont());
columnWidth = metrics.charWidth('m');
}
return columnWidth;
}
/**
* Returns the preferred size <code>Dimensions</code> needed for this
* <code>TextField</code>. If a non-zero number of columns has been
* set, the width is set to the columns multiplied by
* the column width.
*
* @return the dimension of this textfield
*/
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (columns != 0) {
Insets insets = getInsets();
size.width = columns * getColumnWidth() +
insets.left + insets.right;
}
return size;
}
/**
* Sets the current font. This removes cached row height and column
* width so the new font will be reflected.
* <code>revalidate</code> is called after setting the font.
*
* @param f the new font
*/
public void setFont(Font f) {
super.setFont(f);
columnWidth = 0;
}
/**
* Adds the specified action listener to receive
* action events from this textfield.
*
* @param l the action listener to be added
*/
public synchronized void addActionListener(ActionListener l) {
listenerList.add(ActionListener.class, l);
}
/**
* Removes the specified action listener so that it no longer
* receives action events from this textfield.
*
* @param l the action listener to be removed
*/
public synchronized void removeActionListener(ActionListener l) {
if ((l != null) && (getAction() == l)) {
setAction(null);
} else {
listenerList.remove(ActionListener.class, l);
}
}
/**
* Returns an array of all the <code>ActionListener</code>s added
* to this JTextField with addActionListener().
*
* @return all of the <code>ActionListener</code>s added or an empty
* array if no listeners have been added
* @since 1.4
*/
public synchronized ActionListener[] getActionListeners() {
return listenerList.getListeners(ActionListener.class);
}
/**
* Notifies all listeners that have registered interest for
* notification on this event type. The event instance
* is lazily created.
* The listener list is processed in last to
* first order.
* @see EventListenerList
*/
protected void fireActionPerformed() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
int modifiers = 0;
AWTEvent currentEvent = EventQueue.getCurrentEvent();
if (currentEvent instanceof InputEvent) {
modifiers = ((InputEvent)currentEvent).getModifiers();
} else if (currentEvent instanceof ActionEvent) {
modifiers = ((ActionEvent)currentEvent).getModifiers();
}
ActionEvent e =
new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
(command != null) ? command : getText(),
EventQueue.getMostRecentEventTime(), modifiers);
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ActionListener.class) {
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
/**
* Sets the command string used for action events.
*
* @param command the command string
*/
public void setActionCommand(String command) {
this.command = command;
}
private Action action;
private PropertyChangeListener actionPropertyChangeListener;
/**
* Sets the <code>Action</code> for the <code>ActionEvent</code> source.
* The new <code>Action</code> replaces
* any previously set <code>Action</code> but does not affect
* <code>ActionListeners</code> independently
* added with <code>addActionListener</code>.
* If the <code>Action</code> is already a registered
* <code>ActionListener</code>
* for the <code>ActionEvent</code> source, it is not re-registered.
* <p>
* Setting the <code>Action</code> results in immediately changing
* all the properties described in <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a>.
* Subsequently, the textfield's properties are automatically updated
* as the <code>Action</code>'s properties change.
* <p>
* This method uses three other methods to set
* and help track the <code>Action</code>'s property values.
* It uses the <code>configurePropertiesFromAction</code> method
* to immediately change the textfield's properties.
* To track changes in the <code>Action</code>'s property values,
* this method registers the <code>PropertyChangeListener</code>
* returned by <code>createActionPropertyChangeListener</code>. The
* default {@code PropertyChangeListener} invokes the
* {@code actionPropertyChanged} method when a property in the
* {@code Action} changes.
*
* @param a the <code>Action</code> for the <code>JTextField</code>,
* or <code>null</code>
* @since 1.3
* @see Action
* @see #getAction
* @see #configurePropertiesFromAction
* @see #createActionPropertyChangeListener
* @see #actionPropertyChanged
* @beaninfo
* bound: true
* attribute: visualUpdate true
* description: the Action instance connected with this ActionEvent source
*/
public void setAction(Action a) {
Action oldValue = getAction();
if (action==null || !action.equals(a)) {
action = a;
if (oldValue!=null) {
removeActionListener(oldValue);
oldValue.removePropertyChangeListener(actionPropertyChangeListener);
actionPropertyChangeListener = null;
}
configurePropertiesFromAction(action);
if (action!=null) {
// Don't add if it is already a listener
if (!isListener(ActionListener.class, action)) {
addActionListener(action);
}
// Reverse linkage:
actionPropertyChangeListener = createActionPropertyChangeListener(action);
action.addPropertyChangeListener(actionPropertyChangeListener);
}
firePropertyChange("action", oldValue, action);
}
}
private boolean isListener(Class c, ActionListener a) {
boolean isListener = false;
Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==c && listeners[i+1]==a) {
isListener=true;
}
}
return isListener;
}
/**
* Returns the currently set <code>Action</code> for this
* <code>ActionEvent</code> source, or <code>null</code>
* if no <code>Action</code> is set.
*
* @return the <code>Action</code> for this <code>ActionEvent</code> source,
* or <code>null</code>
* @since 1.3
* @see Action
* @see #setAction
*/
public Action getAction() {
return action;
}
/**
* Sets the properties on this textfield to match those in the specified
* <code>Action</code>. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details as to which properties this sets.
*
* @param a the <code>Action</code> from which to get the properties,
* or <code>null</code>
* @since 1.3
* @see Action
* @see #setAction
*/
protected void configurePropertiesFromAction(Action a) {
AbstractAction.setEnabledFromAction(this, a);
AbstractAction.setToolTipTextFromAction(this, a);
setActionCommandFromAction(a);
}
/**
* Updates the textfield's state in response to property changes in
* associated action. This method is invoked from the
* {@code PropertyChangeListener} returned from
* {@code createActionPropertyChangeListener}. Subclasses do not normally
* need to invoke this. Subclasses that support additional {@code Action}
* properties should override this and
* {@code configurePropertiesFromAction}.
* <p>
* Refer to the table at <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for a list of
* the properties this method sets.
*
* @param action the <code>Action</code> associated with this textfield
* @param propertyName the name of the property that changed
* @since 1.6
* @see Action
* @see #configurePropertiesFromAction
*/
protected void actionPropertyChanged(Action action, String propertyName) {
if (propertyName == Action.ACTION_COMMAND_KEY) {
setActionCommandFromAction(action);
} else if (propertyName == "enabled") {
AbstractAction.setEnabledFromAction(this, action);
} else if (propertyName == Action.SHORT_DESCRIPTION) {
AbstractAction.setToolTipTextFromAction(this, action);
}
}
private void setActionCommandFromAction(Action action) {
setActionCommand((action == null) ? null :
(String)action.getValue(Action.ACTION_COMMAND_KEY));
}
/**
* Creates and returns a <code>PropertyChangeListener</code> that is
* responsible for listening for changes from the specified
* <code>Action</code> and updating the appropriate properties.
* <p>
* <b>Warning:</b> If you subclass this do not create an anonymous
* inner class. If you do the lifetime of the textfield will be tied to
* that of the <code>Action</code>.
*
* @param a the textfield's action
* @since 1.3
* @see Action
* @see #setAction
*/
protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
return new TextFieldActionPropertyChangeListener(this, a);
}
private static class TextFieldActionPropertyChangeListener extends
ActionPropertyChangeListener<JTextField> {
TextFieldActionPropertyChangeListener(JTextField tf, Action a) {
super(tf, a);
}
protected void actionPropertyChanged(JTextField textField,
Action action,
PropertyChangeEvent e) {
if (AbstractAction.shouldReconfigure(e)) {
textField.configurePropertiesFromAction(action);
} else {
textField.actionPropertyChanged(action, e.getPropertyName());
}
}
}
/**
* Fetches the command list for the editor. This is
* the list of commands supported by the plugged-in UI
* augmented by the collection of commands that the
* editor itself supports. These are useful for binding
* to events, such as in a keymap.
*
* @return the command list
*/
public Action[] getActions() {
return TextAction.augmentList(super.getActions(), defaultActions);
}
/**
* Processes action events occurring on this textfield by
* dispatching them to any registered <code>ActionListener</code> objects.
* This is normally called by the controller registered with
* textfield.
*/
public void postActionEvent() {
fireActionPerformed();
}
// --- Scrolling support -----------------------------------
/**
* Gets the visibility of the text field. This can
* be adjusted to change the location of the visible
* area if the size of the field is greater than
* the area that was allocated to the field.
*
* <p>
* The fields look-and-feel implementation manages
* the values of the minimum, maximum, and extent
* properties on the <code>BoundedRangeModel</code>.
*
* @return the visibility
* @see BoundedRangeModel
*/
public BoundedRangeModel getHorizontalVisibility() {
return visibility;
}
/**
* Gets the scroll offset, in pixels.
*
* @return the offset &gt;= 0
*/
public int getScrollOffset() {
return visibility.getValue();
}
/**
* Sets the scroll offset, in pixels.
*
* @param scrollOffset the offset &gt;= 0
*/
public void setScrollOffset(int scrollOffset) {
visibility.setValue(scrollOffset);
}
/**
* Scrolls the field left or right.
*
* @param r the region to scroll
*/
public void scrollRectToVisible(Rectangle r) {
// convert to coordinate system of the bounded range
Insets i = getInsets();
int x0 = r.x + visibility.getValue() - i.left;
int x1 = x0 + r.width;
if (x0 < visibility.getValue()) {
// Scroll to the left
visibility.setValue(x0);
} else if(x1 > visibility.getValue() + visibility.getExtent()) {
// Scroll to the right
visibility.setValue(x1 - visibility.getExtent());
}
}
/**
* Returns true if the receiver has an <code>ActionListener</code>
* installed.
*/
boolean hasActionListener() {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ActionListener.class) {
return true;
}
}
return false;
}
// --- variables -------------------------------------------
/**
* Name of the action to send notification that the
* contents of the field have been accepted. Typically
* this is bound to a carriage-return.
*/
public static final String notifyAction = "notify-field-accept";
private BoundedRangeModel visibility;
private int horizontalAlignment = LEADING;
private int columns;
private int columnWidth;
private String command;
private static final Action[] defaultActions = {
new NotifyAction()
};
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "TextFieldUI";
// --- Action implementations -----------------------------------
// Note that JFormattedTextField.CommitAction extends this
static class NotifyAction extends TextAction {
NotifyAction() {
super(notifyAction);
}
public void actionPerformed(ActionEvent e) {
JTextComponent target = getFocusedComponent();
if (target instanceof JTextField) {
JTextField field = (JTextField) target;
field.postActionEvent();
}
}
public boolean isEnabled() {
JTextComponent target = getFocusedComponent();
if (target instanceof JTextField) {
return ((JTextField)target).hasActionListener();
}
return false;
}
}
class ScrollRepainter implements ChangeListener, Serializable {
public void stateChanged(ChangeEvent e) {
repaint();
}
}
/**
* See <code>readObject</code> and <code>writeObject</code> in
* <code>JComponent</code> for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this <code>JTextField</code>.
* This method is intended to be used only for debugging purposes,
* and the content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JTextField</code>
*/
protected String paramString() {
String horizontalAlignmentString;
if (horizontalAlignment == LEFT) {
horizontalAlignmentString = "LEFT";
} else if (horizontalAlignment == CENTER) {
horizontalAlignmentString = "CENTER";
} else if (horizontalAlignment == RIGHT) {
horizontalAlignmentString = "RIGHT";
} else if (horizontalAlignment == LEADING) {
horizontalAlignmentString = "LEADING";
} else if (horizontalAlignment == TRAILING) {
horizontalAlignmentString = "TRAILING";
} else horizontalAlignmentString = "";
String commandString = (command != null ?
command : "");
return super.paramString() +
",columns=" + columns +
",columnWidth=" + columnWidth +
",command=" + commandString +
",horizontalAlignment=" + horizontalAlignmentString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the <code>AccessibleContext</code> associated with this
* <code>JTextField</code>. For <code>JTextFields</code>,
* the <code>AccessibleContext</code> takes the form of an
* <code>AccessibleJTextField</code>.
* A new <code>AccessibleJTextField</code> instance is created
* if necessary.
*
* @return an <code>AccessibleJTextField</code> that serves as the
* <code>AccessibleContext</code> of this <code>JTextField</code>
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJTextField();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JTextField</code> class. It provides an implementation of the
* Java Accessibility API appropriate to text field user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJTextField extends AccessibleJTextComponent {
/**
* Gets the state set of this object.
*
* @return an instance of AccessibleStateSet describing the states
* of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
states.add(AccessibleState.SINGLE_LINE);
return states;
}
}
}

View File

@@ -0,0 +1,493 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import javax.swing.text.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
/**
* A text component that can be marked up with attributes that are
* represented graphically.
* You can find how-to information and examples of using text panes in
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/text.html">Using Text Components</a>,
* a section in <em>The Java Tutorial.</em>
*
* <p>
* This component models paragraphs
* that are composed of runs of character level attributes. Each
* paragraph may have a logical style attached to it which contains
* the default attributes to use if not overridden by attributes set
* on the paragraph or character run. Components and images may
* be embedded in the flow of text.
*
* <dl>
* <dt><b><font size=+1>Newlines</font></b>
* <dd>
* For a discussion on how newlines are handled, see
* <a href="text/DefaultEditorKit.html">DefaultEditorKit</a>.
* </dl>
*
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer true
* description: A text component that can be marked up with attributes that are graphically represented.
*
* @author Timothy Prinzing
* @see javax.swing.text.StyledEditorKit
*/
public class JTextPane extends JEditorPane {
/**
* Creates a new <code>JTextPane</code>. A new instance of
* <code>StyledEditorKit</code> is
* created and set, and the document model set to <code>null</code>.
*/
public JTextPane() {
super();
EditorKit editorKit = createDefaultEditorKit();
String contentType = editorKit.getContentType();
if (contentType != null
&& getEditorKitClassNameForContentType(contentType) ==
defaultEditorKitMap.get(contentType)) {
setEditorKitForContentType(contentType, editorKit);
}
setEditorKit(editorKit);
}
/**
* Creates a new <code>JTextPane</code>, with a specified document model.
* A new instance of <code>javax.swing.text.StyledEditorKit</code>
* is created and set.
*
* @param doc the document model
*/
public JTextPane(StyledDocument doc) {
this();
setStyledDocument(doc);
}
/**
* Returns the class ID for the UI.
*
* @return the string "TextPaneUI"
*
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Associates the editor with a text document. This
* must be a <code>StyledDocument</code>.
*
* @param doc the document to display/edit
* @exception IllegalArgumentException if <code>doc</code> can't
* be narrowed to a <code>StyledDocument</code> which is the
* required type of model for this text component
*/
public void setDocument(Document doc) {
if (doc instanceof StyledDocument) {
super.setDocument(doc);
} else {
throw new IllegalArgumentException("Model must be StyledDocument");
}
}
/**
* Associates the editor with a text document.
* The currently registered factory is used to build a view for
* the document, which gets displayed by the editor.
*
* @param doc the document to display/edit
*/
public void setStyledDocument(StyledDocument doc) {
super.setDocument(doc);
}
/**
* Fetches the model associated with the editor.
*
* @return the model
*/
public StyledDocument getStyledDocument() {
return (StyledDocument) getDocument();
}
/**
* Replaces the currently selected content with new content
* represented by the given string. If there is no selection
* this amounts to an insert of the given text. If there
* is no replacement text this amounts to a removal of the
* current selection. The replacement text will have the
* attributes currently defined for input at the point of
* insertion. If the document is not editable, beep and return.
*
* @param content the content to replace the selection with
*/
@Override
public void replaceSelection(String content) {
replaceSelection(content, true);
}
private void replaceSelection(String content, boolean checkEditable) {
if (checkEditable && !isEditable()) {
UIManager.getLookAndFeel().provideErrorFeedback(JTextPane.this);
return;
}
Document doc = getStyledDocument();
if (doc != null) {
try {
Caret caret = getCaret();
boolean composedTextSaved = saveComposedText(caret.getDot());
int p0 = Math.min(caret.getDot(), caret.getMark());
int p1 = Math.max(caret.getDot(), caret.getMark());
AttributeSet attr = getInputAttributes().copyAttributes();
if (doc instanceof AbstractDocument) {
((AbstractDocument)doc).replace(p0, p1 - p0, content,attr);
}
else {
if (p0 != p1) {
doc.remove(p0, p1 - p0);
}
if (content != null && content.length() > 0) {
doc.insertString(p0, content, attr);
}
}
if (composedTextSaved) {
restoreComposedText();
}
} catch (BadLocationException e) {
UIManager.getLookAndFeel().provideErrorFeedback(JTextPane.this);
}
}
}
/**
* Inserts a component into the document as a replacement
* for the currently selected content. If there is no
* selection the component is effectively inserted at the
* current position of the caret. This is represented in
* the associated document as an attribute of one character
* of content.
* <p>
* The component given is the actual component used by the
* JTextPane. Since components cannot be a child of more than
* one container, this method should not be used in situations
* where the model is shared by text components.
* <p>
* The component is placed relative to the text baseline
* according to the value returned by
* <code>Component.getAlignmentY</code>. For Swing components
* this value can be conveniently set using the method
* <code>JComponent.setAlignmentY</code>. For example, setting
* a value of <code>0.75</code> will cause 75 percent of the
* component to be above the baseline, and 25 percent of the
* component to be below the baseline.
*
* @param c the component to insert
*/
public void insertComponent(Component c) {
MutableAttributeSet inputAttributes = getInputAttributes();
inputAttributes.removeAttributes(inputAttributes);
StyleConstants.setComponent(inputAttributes, c);
replaceSelection(" ", false);
inputAttributes.removeAttributes(inputAttributes);
}
/**
* Inserts an icon into the document as a replacement
* for the currently selected content. If there is no
* selection the icon is effectively inserted at the
* current position of the caret. This is represented in
* the associated document as an attribute of one character
* of content.
*
* @param g the icon to insert
* @see Icon
*/
public void insertIcon(Icon g) {
MutableAttributeSet inputAttributes = getInputAttributes();
inputAttributes.removeAttributes(inputAttributes);
StyleConstants.setIcon(inputAttributes, g);
replaceSelection(" ", false);
inputAttributes.removeAttributes(inputAttributes);
}
/**
* Adds a new style into the logical style hierarchy. Style attributes
* resolve from bottom up so an attribute specified in a child
* will override an attribute specified in the parent.
*
* @param nm the name of the style (must be unique within the
* collection of named styles). The name may be <code>null</code>
* if the style is unnamed, but the caller is responsible
* for managing the reference returned as an unnamed style can't
* be fetched by name. An unnamed style may be useful for things
* like character attribute overrides such as found in a style
* run.
* @param parent the parent style. This may be <code>null</code>
* if unspecified
* attributes need not be resolved in some other style.
* @return the new <code>Style</code>
*/
public Style addStyle(String nm, Style parent) {
StyledDocument doc = getStyledDocument();
return doc.addStyle(nm, parent);
}
/**
* Removes a named non-<code>null</code> style previously added to
* the document.
*
* @param nm the name of the style to remove
*/
public void removeStyle(String nm) {
StyledDocument doc = getStyledDocument();
doc.removeStyle(nm);
}
/**
* Fetches a named non-<code>null</code> style previously added.
*
* @param nm the name of the style
* @return the <code>Style</code>
*/
public Style getStyle(String nm) {
StyledDocument doc = getStyledDocument();
return doc.getStyle(nm);
}
/**
* Sets the logical style to use for the paragraph at the
* current caret position. If attributes aren't explicitly set
* for character and paragraph attributes they will resolve
* through the logical style assigned to the paragraph, which
* in term may resolve through some hierarchy completely
* independent of the element hierarchy in the document.
*
* @param s the logical style to assign to the paragraph,
* or <code>null</code> for no style
*/
public void setLogicalStyle(Style s) {
StyledDocument doc = getStyledDocument();
doc.setLogicalStyle(getCaretPosition(), s);
}
/**
* Fetches the logical style assigned to the paragraph represented
* by the current position of the caret, or <code>null</code>.
*
* @return the <code>Style</code>
*/
public Style getLogicalStyle() {
StyledDocument doc = getStyledDocument();
return doc.getLogicalStyle(getCaretPosition());
}
/**
* Fetches the character attributes in effect at the
* current location of the caret, or <code>null</code>.
*
* @return the attributes, or <code>null</code>
*/
public AttributeSet getCharacterAttributes() {
StyledDocument doc = getStyledDocument();
Element run = doc.getCharacterElement(getCaretPosition());
if (run != null) {
return run.getAttributes();
}
return null;
}
/**
* Applies the given attributes to character
* content. If there is a selection, the attributes
* are applied to the selection range. If there
* is no selection, the attributes are applied to
* the input attribute set which defines the attributes
* for any new text that gets inserted.
*
* @param attr the attributes
* @param replace if true, then replace the existing attributes first
*/
public void setCharacterAttributes(AttributeSet attr, boolean replace) {
int p0 = getSelectionStart();
int p1 = getSelectionEnd();
if (p0 != p1) {
StyledDocument doc = getStyledDocument();
doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
} else {
MutableAttributeSet inputAttributes = getInputAttributes();
if (replace) {
inputAttributes.removeAttributes(inputAttributes);
}
inputAttributes.addAttributes(attr);
}
}
/**
* Fetches the current paragraph attributes in effect
* at the location of the caret, or <code>null</code> if none.
*
* @return the attributes
*/
public AttributeSet getParagraphAttributes() {
StyledDocument doc = getStyledDocument();
Element paragraph = doc.getParagraphElement(getCaretPosition());
if (paragraph != null) {
return paragraph.getAttributes();
}
return null;
}
/**
* Applies the given attributes to paragraphs. If
* there is a selection, the attributes are applied
* to the paragraphs that intersect the selection.
* If there is no selection, the attributes are applied
* to the paragraph at the current caret position.
*
* @param attr the non-<code>null</code> attributes
* @param replace if true, replace the existing attributes first
*/
public void setParagraphAttributes(AttributeSet attr, boolean replace) {
int p0 = getSelectionStart();
int p1 = getSelectionEnd();
StyledDocument doc = getStyledDocument();
doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
}
/**
* Gets the input attributes for the pane.
*
* @return the attributes
*/
public MutableAttributeSet getInputAttributes() {
return getStyledEditorKit().getInputAttributes();
}
/**
* Gets the editor kit.
*
* @return the editor kit
*/
protected final StyledEditorKit getStyledEditorKit() {
return (StyledEditorKit) getEditorKit();
}
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "TextPaneUI";
/**
* See <code>readObject</code> and <code>writeObject</code> in
* <code>JComponent</code> for more
* information about serialization in Swing.
*
* @param s the output stream
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
// --- JEditorPane ------------------------------------
/**
* Creates the <code>EditorKit</code> to use by default. This
* is implemented to return <code>javax.swing.text.StyledEditorKit</code>.
*
* @return the editor kit
*/
protected EditorKit createDefaultEditorKit() {
return new StyledEditorKit();
}
/**
* Sets the currently installed kit for handling
* content. This is the bound property that
* establishes the content type of the editor.
*
* @param kit the desired editor behavior
* @exception IllegalArgumentException if kit is not a
* <code>StyledEditorKit</code>
*/
public final void setEditorKit(EditorKit kit) {
if (kit instanceof StyledEditorKit) {
super.setEditorKit(kit);
} else {
throw new IllegalArgumentException("Must be StyledEditorKit");
}
}
/**
* Returns a string representation of this <code>JTextPane</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JTextPane</code>
*/
protected String paramString() {
return super.paramString();
}
}

View File

@@ -0,0 +1,424 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
/**
* An implementation of a two-state button.
* The <code>JRadioButton</code> and <code>JCheckBox</code> classes
* are subclasses of this class.
* For information on using them see
* <a
href="https://docs.oracle.com/javase/tutorial/uiswing/components/button.html">How to Use Buttons, Check Boxes, and Radio Buttons</a>,
* a section in <em>The Java Tutorial</em>.
* <p>
* Buttons can be configured, and to some degree controlled, by
* <code><a href="Action.html">Action</a></code>s. Using an
* <code>Action</code> with a button has many benefits beyond directly
* configuring a button. Refer to <a href="Action.html#buttonActions">
* Swing Components Supporting <code>Action</code></a> for more
* details, and you can find more information in <a
* href="https://docs.oracle.com/javase/tutorial/uiswing/misc/action.html">How
* to Use Actions</a>, a section in <em>The Java Tutorial</em>.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer false
* description: An implementation of a two-state button.
*
* @see JRadioButton
* @see JCheckBox
* @author Jeff Dinkins
*/
public class JToggleButton extends AbstractButton implements Accessible {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "ToggleButtonUI";
/**
* Creates an initially unselected toggle button
* without setting the text or image.
*/
public JToggleButton () {
this(null, null, false);
}
/**
* Creates an initially unselected toggle button
* with the specified image but no text.
*
* @param icon the image that the button should display
*/
public JToggleButton(Icon icon) {
this(null, icon, false);
}
/**
* Creates a toggle button with the specified image
* and selection state, but no text.
*
* @param icon the image that the button should display
* @param selected if true, the button is initially selected;
* otherwise, the button is initially unselected
*/
public JToggleButton(Icon icon, boolean selected) {
this(null, icon, selected);
}
/**
* Creates an unselected toggle button with the specified text.
*
* @param text the string displayed on the toggle button
*/
public JToggleButton (String text) {
this(text, null, false);
}
/**
* Creates a toggle button with the specified text
* and selection state.
*
* @param text the string displayed on the toggle button
* @param selected if true, the button is initially selected;
* otherwise, the button is initially unselected
*/
public JToggleButton (String text, boolean selected) {
this(text, null, selected);
}
/**
* Creates a toggle button where properties are taken from the
* Action supplied.
*
* @since 1.3
*/
public JToggleButton(Action a) {
this();
setAction(a);
}
/**
* Creates a toggle button that has the specified text and image,
* and that is initially unselected.
*
* @param text the string displayed on the button
* @param icon the image that the button should display
*/
public JToggleButton(String text, Icon icon) {
this(text, icon, false);
}
/**
* Creates a toggle button with the specified text, image, and
* selection state.
*
* @param text the text of the toggle button
* @param icon the image that the button should display
* @param selected if true, the button is initially selected;
* otherwise, the button is initially unselected
*/
public JToggleButton (String text, Icon icon, boolean selected) {
// Create the model
setModel(new ToggleButtonModel());
model.setSelected(selected);
// initialize
init(text, icon);
}
/**
* Resets the UI property to a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ButtonUI)UIManager.getUI(this));
}
/**
* Returns a string that specifies the name of the l&amp;f class
* that renders this component.
*
* @return String "ToggleButtonUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
* @beaninfo
* description: A string that specifies the name of the L&amp;F class
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Overriden to return true, JToggleButton supports
* the selected state.
*/
boolean shouldUpdateSelectedStateFromAction() {
return true;
}
// *********************************************************************
/**
* The ToggleButton model
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
public static class ToggleButtonModel extends DefaultButtonModel {
/**
* Creates a new ToggleButton Model
*/
public ToggleButtonModel () {
}
/**
* Checks if the button is selected.
*/
public boolean isSelected() {
// if(getGroup() != null) {
// return getGroup().isSelected(this);
// } else {
return (stateMask & SELECTED) != 0;
// }
}
/**
* Sets the selected state of the button.
* @param b true selects the toggle button,
* false deselects the toggle button.
*/
public void setSelected(boolean b) {
ButtonGroup group = getGroup();
if (group != null) {
// use the group model instead
group.setSelected(this, b);
b = group.isSelected(this);
}
if (isSelected() == b) {
return;
}
if (b) {
stateMask |= SELECTED;
} else {
stateMask &= ~SELECTED;
}
// Send ChangeEvent
fireStateChanged();
// Send ItemEvent
fireItemStateChanged(
new ItemEvent(this,
ItemEvent.ITEM_STATE_CHANGED,
this,
this.isSelected() ? ItemEvent.SELECTED : ItemEvent.DESELECTED));
}
/**
* Sets the pressed state of the toggle button.
*/
public void setPressed(boolean b) {
if ((isPressed() == b) || !isEnabled()) {
return;
}
if (b == false && isArmed()) {
setSelected(!this.isSelected());
}
if (b) {
stateMask |= PRESSED;
} else {
stateMask &= ~PRESSED;
}
fireStateChanged();
if(!isPressed() && isArmed()) {
int modifiers = 0;
AWTEvent currentEvent = EventQueue.getCurrentEvent();
if (currentEvent instanceof InputEvent) {
modifiers = ((InputEvent)currentEvent).getModifiers();
} else if (currentEvent instanceof ActionEvent) {
modifiers = ((ActionEvent)currentEvent).getModifiers();
}
fireActionPerformed(
new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
getActionCommand(),
EventQueue.getMostRecentEventTime(),
modifiers));
}
}
}
/**
* See readObject() and writeObject() in JComponent for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this JToggleButton. This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this JToggleButton.
*/
protected String paramString() {
return super.paramString();
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JToggleButton.
* For toggle buttons, the AccessibleContext takes the form of an
* AccessibleJToggleButton.
* A new AccessibleJToggleButton instance is created if necessary.
*
* @return an AccessibleJToggleButton that serves as the
* AccessibleContext of this JToggleButton
* @beaninfo
* expert: true
* description: The AccessibleContext associated with this ToggleButton.
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJToggleButton();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JToggleButton</code> class. It provides an implementation of the
* Java Accessibility API appropriate to toggle button user-interface
* elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
protected class AccessibleJToggleButton extends AccessibleAbstractButton
implements ItemListener {
public AccessibleJToggleButton() {
super();
JToggleButton.this.addItemListener(this);
}
/**
* Fire accessible property change events when the state of the
* toggle button changes.
*/
public void itemStateChanged(ItemEvent e) {
JToggleButton tb = (JToggleButton) e.getSource();
if (JToggleButton.this.accessibleContext != null) {
if (tb.isSelected()) {
JToggleButton.this.accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
null, AccessibleState.CHECKED);
} else {
JToggleButton.this.accessibleContext.firePropertyChange(
AccessibleContext.ACCESSIBLE_STATE_PROPERTY,
AccessibleState.CHECKED, null);
}
}
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.TOGGLE_BUTTON;
}
} // inner class AccessibleJToggleButton
}

View File

@@ -0,0 +1,871 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.event.*;
import java.beans.*;
import javax.swing.border.Border;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Hashtable;
/**
* <code>JToolBar</code> provides a component that is useful for
* displaying commonly used <code>Action</code>s or controls.
* For examples and information on using tool bars see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/toolbar.html">How to Use Tool Bars</a>,
* a section in <em>The Java Tutorial</em>.
*
* <p>
* With most look and feels,
* the user can drag out a tool bar into a separate window
* (unless the <code>floatable</code> property is set to <code>false</code>).
* For drag-out to work correctly, it is recommended that you add
* <code>JToolBar</code> instances to one of the four "sides" of a
* container whose layout manager is a <code>BorderLayout</code>,
* and do not add children to any of the other four "sides".
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @beaninfo
* attribute: isContainer true
* description: A component which displays commonly used controls or Actions.
*
* @author Georges Saab
* @author Jeff Shapiro
* @see Action
*/
public class JToolBar extends JComponent implements SwingConstants, Accessible
{
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "ToolBarUI";
private boolean paintBorder = true;
private Insets margin = null;
private boolean floatable = true;
private int orientation = HORIZONTAL;
/**
* Creates a new tool bar; orientation defaults to <code>HORIZONTAL</code>.
*/
public JToolBar()
{
this( HORIZONTAL );
}
/**
* Creates a new tool bar with the specified <code>orientation</code>.
* The <code>orientation</code> must be either <code>HORIZONTAL</code>
* or <code>VERTICAL</code>.
*
* @param orientation the orientation desired
*/
public JToolBar( int orientation )
{
this(null, orientation);
}
/**
* Creates a new tool bar with the specified <code>name</code>. The
* name is used as the title of the undocked tool bar. The default
* orientation is <code>HORIZONTAL</code>.
*
* @param name the name of the tool bar
* @since 1.3
*/
public JToolBar( String name ) {
this(name, HORIZONTAL);
}
/**
* Creates a new tool bar with a specified <code>name</code> and
* <code>orientation</code>.
* All other constructors call this constructor.
* If <code>orientation</code> is an invalid value, an exception will
* be thrown.
*
* @param name the name of the tool bar
* @param orientation the initial orientation -- it must be
* either <code>HORIZONTAL</code> or <code>VERTICAL</code>
* @exception IllegalArgumentException if orientation is neither
* <code>HORIZONTAL</code> nor <code>VERTICAL</code>
* @since 1.3
*/
public JToolBar( String name , int orientation) {
setName(name);
checkOrientation( orientation );
this.orientation = orientation;
DefaultToolBarLayout layout = new DefaultToolBarLayout( orientation );
setLayout( layout );
addPropertyChangeListener( layout );
updateUI();
}
/**
* Returns the tool bar's current UI.
* @see #setUI
*/
public ToolBarUI getUI() {
return (ToolBarUI)ui;
}
/**
* Sets the L&amp;F object that renders this component.
*
* @param ui the <code>ToolBarUI</code> L&amp;F object
* @see UIDefaults#getUI
* @beaninfo
* bound: true
* hidden: true
* attribute: visualUpdate true
* description: The UI object that implements the Component's LookAndFeel.
*/
public void setUI(ToolBarUI ui) {
super.setUI(ui);
}
/**
* Notification from the <code>UIFactory</code> that the L&amp;F has changed.
* Called to replace the UI with the latest version from the
* <code>UIFactory</code>.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ToolBarUI)UIManager.getUI(this));
// GTKLookAndFeel installs a different LayoutManager, and sets it
// to null after changing the look and feel, so, install the default
// if the LayoutManager is null.
if (getLayout() == null) {
setLayout(new DefaultToolBarLayout(getOrientation()));
}
invalidate();
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "ToolBarUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Returns the index of the specified component.
* (Note: Separators occupy index positions.)
*
* @param c the <code>Component</code> to find
* @return an integer indicating the component's position,
* where 0 is first
*/
public int getComponentIndex(Component c) {
int ncomponents = this.getComponentCount();
Component[] component = this.getComponents();
for (int i = 0 ; i < ncomponents ; i++) {
Component comp = component[i];
if (comp == c)
return i;
}
return -1;
}
/**
* Returns the component at the specified index.
*
* @param i the component's position, where 0 is first
* @return the <code>Component</code> at that position,
* or <code>null</code> for an invalid index
*
*/
public Component getComponentAtIndex(int i) {
int ncomponents = this.getComponentCount();
if ( i >= 0 && i < ncomponents) {
Component[] component = this.getComponents();
return component[i];
}
return null;
}
/**
* Sets the margin between the tool bar's border and
* its buttons. Setting to <code>null</code> causes the tool bar to
* use the default margins. The tool bar's default <code>Border</code>
* object uses this value to create the proper margin.
* However, if a non-default border is set on the tool bar,
* it is that <code>Border</code> object's responsibility to create the
* appropriate margin space (otherwise this property will
* effectively be ignored).
*
* @param m an <code>Insets</code> object that defines the space
* between the border and the buttons
* @see Insets
* @beaninfo
* description: The margin between the tool bar's border and contents
* bound: true
* expert: true
*/
public void setMargin(Insets m)
{
Insets old = margin;
margin = m;
firePropertyChange("margin", old, m);
revalidate();
repaint();
}
/**
* Returns the margin between the tool bar's border and
* its buttons.
*
* @return an <code>Insets</code> object containing the margin values
* @see Insets
*/
public Insets getMargin()
{
if(margin == null) {
return new Insets(0,0,0,0);
} else {
return margin;
}
}
/**
* Gets the <code>borderPainted</code> property.
*
* @return the value of the <code>borderPainted</code> property
* @see #setBorderPainted
*/
public boolean isBorderPainted()
{
return paintBorder;
}
/**
* Sets the <code>borderPainted</code> property, which is
* <code>true</code> if the border should be painted.
* The default value for this property is <code>true</code>.
* Some look and feels might not implement painted borders;
* they will ignore this property.
*
* @param b if true, the border is painted
* @see #isBorderPainted
* @beaninfo
* description: Does the tool bar paint its borders?
* bound: true
* expert: true
*/
public void setBorderPainted(boolean b)
{
if ( paintBorder != b )
{
boolean old = paintBorder;
paintBorder = b;
firePropertyChange("borderPainted", old, b);
revalidate();
repaint();
}
}
/**
* Paints the tool bar's border if the <code>borderPainted</code> property
* is <code>true</code>.
*
* @param g the <code>Graphics</code> context in which the painting
* is done
* @see JComponent#paint
* @see JComponent#setBorder
*/
protected void paintBorder(Graphics g)
{
if (isBorderPainted())
{
super.paintBorder(g);
}
}
/**
* Gets the <code>floatable</code> property.
*
* @return the value of the <code>floatable</code> property
*
* @see #setFloatable
*/
public boolean isFloatable()
{
return floatable;
}
/**
* Sets the <code>floatable</code> property,
* which must be <code>true</code> for the user to move the tool bar.
* Typically, a floatable tool bar can be
* dragged into a different position within the same container
* or out into its own window.
* The default value of this property is <code>true</code>.
* Some look and feels might not implement floatable tool bars;
* they will ignore this property.
*
* @param b if <code>true</code>, the tool bar can be moved;
* <code>false</code> otherwise
* @see #isFloatable
* @beaninfo
* description: Can the tool bar be made to float by the user?
* bound: true
* preferred: true
*/
public void setFloatable( boolean b )
{
if ( floatable != b )
{
boolean old = floatable;
floatable = b;
firePropertyChange("floatable", old, b);
revalidate();
repaint();
}
}
/**
* Returns the current orientation of the tool bar. The value is either
* <code>HORIZONTAL</code> or <code>VERTICAL</code>.
*
* @return an integer representing the current orientation -- either
* <code>HORIZONTAL</code> or <code>VERTICAL</code>
* @see #setOrientation
*/
public int getOrientation()
{
return this.orientation;
}
/**
* Sets the orientation of the tool bar. The orientation must have
* either the value <code>HORIZONTAL</code> or <code>VERTICAL</code>.
* If <code>orientation</code> is
* an invalid value, an exception will be thrown.
*
* @param o the new orientation -- either <code>HORIZONTAL</code> or
* <code>VERTICAL</code>
* @exception IllegalArgumentException if orientation is neither
* <code>HORIZONTAL</code> nor <code>VERTICAL</code>
* @see #getOrientation
* @beaninfo
* description: The current orientation of the tool bar
* bound: true
* preferred: true
* enum: HORIZONTAL SwingConstants.HORIZONTAL
* VERTICAL SwingConstants.VERTICAL
*/
public void setOrientation( int o )
{
checkOrientation( o );
if ( orientation != o )
{
int old = orientation;
orientation = o;
firePropertyChange("orientation", old, o);
revalidate();
repaint();
}
}
/**
* Sets the rollover state of this toolbar. If the rollover state is true
* then the border of the toolbar buttons will be drawn only when the
* mouse pointer hovers over them. The default value of this property
* is false.
* <p>
* The implementation of a look and feel may choose to ignore this
* property.
*
* @param rollover true for rollover toolbar buttons; otherwise false
* @since 1.4
* @beaninfo
* bound: true
* preferred: true
* attribute: visualUpdate true
* description: Will draw rollover button borders in the toolbar.
*/
public void setRollover(boolean rollover) {
putClientProperty("JToolBar.isRollover",
rollover ? Boolean.TRUE : Boolean.FALSE);
}
/**
* Returns the rollover state.
*
* @return true if rollover toolbar buttons are to be drawn; otherwise false
* @see #setRollover(boolean)
* @since 1.4
*/
public boolean isRollover() {
Boolean rollover = (Boolean)getClientProperty("JToolBar.isRollover");
if (rollover != null) {
return rollover.booleanValue();
}
return false;
}
private void checkOrientation( int orientation )
{
switch ( orientation )
{
case VERTICAL:
case HORIZONTAL:
break;
default:
throw new IllegalArgumentException( "orientation must be one of: VERTICAL, HORIZONTAL" );
}
}
/**
* Appends a separator of default size to the end of the tool bar.
* The default size is determined by the current look and feel.
*/
public void addSeparator()
{
addSeparator(null);
}
/**
* Appends a separator of a specified size to the end
* of the tool bar.
*
* @param size the <code>Dimension</code> of the separator
*/
public void addSeparator( Dimension size )
{
JToolBar.Separator s = new JToolBar.Separator( size );
add(s);
}
/**
* Adds a new <code>JButton</code> which dispatches the action.
*
* @param a the <code>Action</code> object to add as a new menu item
* @return the new button which dispatches the action
*/
public JButton add(Action a) {
JButton b = createActionComponent(a);
b.setAction(a);
add(b);
return b;
}
/**
* Factory method which creates the <code>JButton</code> for
* <code>Action</code>s added to the <code>JToolBar</code>.
* The default name is empty if a <code>null</code> action is passed.
*
* @param a the <code>Action</code> for the button to be added
* @return the newly created button
* @see Action
* @since 1.3
*/
protected JButton createActionComponent(Action a) {
JButton b = new JButton() {
protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
PropertyChangeListener pcl = createActionChangeListener(this);
if (pcl==null) {
pcl = super.createActionPropertyChangeListener(a);
}
return pcl;
}
};
if (a != null && (a.getValue(Action.SMALL_ICON) != null ||
a.getValue(Action.LARGE_ICON_KEY) != null)) {
b.setHideActionText(true);
}
b.setHorizontalTextPosition(JButton.CENTER);
b.setVerticalTextPosition(JButton.BOTTOM);
return b;
}
/**
* Returns a properly configured <code>PropertyChangeListener</code>
* which updates the control as changes to the <code>Action</code> occur,
* or <code>null</code> if the default
* property change listener for the control is desired.
*
* @return <code>null</code>
*/
protected PropertyChangeListener createActionChangeListener(JButton b) {
return null;
}
/**
* If a <code>JButton</code> is being added, it is initially
* set to be disabled.
*
* @param comp the component to be enhanced
* @param constraints the constraints to be enforced on the component
* @param index the index of the component
*
*/
protected void addImpl(Component comp, Object constraints, int index) {
if (comp instanceof Separator) {
if (getOrientation() == VERTICAL) {
( (Separator)comp ).setOrientation(JSeparator.HORIZONTAL);
} else {
( (Separator)comp ).setOrientation(JSeparator.VERTICAL);
}
}
super.addImpl(comp, constraints, index);
if (comp instanceof JButton) {
((JButton)comp).setDefaultCapable(false);
}
}
/**
* A toolbar-specific separator. An object with dimension but
* no contents used to divide buttons on a tool bar into groups.
*/
static public class Separator extends JSeparator
{
private Dimension separatorSize;
/**
* Creates a new toolbar separator with the default size
* as defined by the current look and feel.
*/
public Separator()
{
this( null ); // let the UI define the default size
}
/**
* Creates a new toolbar separator with the specified size.
*
* @param size the <code>Dimension</code> of the separator
*/
public Separator( Dimension size )
{
super( JSeparator.HORIZONTAL );
setSeparatorSize(size);
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "ToolBarSeparatorUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID()
{
return "ToolBarSeparatorUI";
}
/**
* Sets the size of the separator.
*
* @param size the new <code>Dimension</code> of the separator
*/
public void setSeparatorSize( Dimension size )
{
if (size != null) {
separatorSize = size;
} else {
super.updateUI();
}
this.invalidate();
}
/**
* Returns the size of the separator
*
* @return the <code>Dimension</code> object containing the separator's
* size (This is a reference, NOT a copy!)
*/
public Dimension getSeparatorSize()
{
return separatorSize;
}
/**
* Returns the minimum size for the separator.
*
* @return the <code>Dimension</code> object containing the separator's
* minimum size
*/
public Dimension getMinimumSize()
{
if (separatorSize != null) {
return separatorSize.getSize();
} else {
return super.getMinimumSize();
}
}
/**
* Returns the maximum size for the separator.
*
* @return the <code>Dimension</code> object containing the separator's
* maximum size
*/
public Dimension getMaximumSize()
{
if (separatorSize != null) {
return separatorSize.getSize();
} else {
return super.getMaximumSize();
}
}
/**
* Returns the preferred size for the separator.
*
* @return the <code>Dimension</code> object containing the separator's
* preferred size
*/
public Dimension getPreferredSize()
{
if (separatorSize != null) {
return separatorSize.getSize();
} else {
return super.getPreferredSize();
}
}
}
/**
* See <code>readObject</code> and <code>writeObject</code> in
* <code>JComponent</code> for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this <code>JToolBar</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JToolBar</code>.
*/
protected String paramString() {
String paintBorderString = (paintBorder ?
"true" : "false");
String marginString = (margin != null ?
margin.toString() : "");
String floatableString = (floatable ?
"true" : "false");
String orientationString = (orientation == HORIZONTAL ?
"HORIZONTAL" : "VERTICAL");
return super.paramString() +
",floatable=" + floatableString +
",margin=" + marginString +
",orientation=" + orientationString +
",paintBorder=" + paintBorderString;
}
private class DefaultToolBarLayout
implements LayoutManager2, Serializable, PropertyChangeListener, UIResource {
BoxLayout lm;
DefaultToolBarLayout(int orientation) {
if (orientation == JToolBar.VERTICAL) {
lm = new BoxLayout(JToolBar.this, BoxLayout.PAGE_AXIS);
} else {
lm = new BoxLayout(JToolBar.this, BoxLayout.LINE_AXIS);
}
}
public void addLayoutComponent(String name, Component comp) {
lm.addLayoutComponent(name, comp);
}
public void addLayoutComponent(Component comp, Object constraints) {
lm.addLayoutComponent(comp, constraints);
}
public void removeLayoutComponent(Component comp) {
lm.removeLayoutComponent(comp);
}
public Dimension preferredLayoutSize(Container target) {
return lm.preferredLayoutSize(target);
}
public Dimension minimumLayoutSize(Container target) {
return lm.minimumLayoutSize(target);
}
public Dimension maximumLayoutSize(Container target) {
return lm.maximumLayoutSize(target);
}
public void layoutContainer(Container target) {
lm.layoutContainer(target);
}
public float getLayoutAlignmentX(Container target) {
return lm.getLayoutAlignmentX(target);
}
public float getLayoutAlignmentY(Container target) {
return lm.getLayoutAlignmentY(target);
}
public void invalidateLayout(Container target) {
lm.invalidateLayout(target);
}
public void propertyChange(PropertyChangeEvent e) {
String name = e.getPropertyName();
if( name.equals("orientation") ) {
int o = ((Integer)e.getNewValue()).intValue();
if (o == JToolBar.VERTICAL)
lm = new BoxLayout(JToolBar.this, BoxLayout.PAGE_AXIS);
else {
lm = new BoxLayout(JToolBar.this, BoxLayout.LINE_AXIS);
}
}
}
}
public void setLayout(LayoutManager mgr) {
LayoutManager oldMgr = getLayout();
if (oldMgr instanceof PropertyChangeListener) {
removePropertyChangeListener((PropertyChangeListener)oldMgr);
}
super.setLayout(mgr);
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JToolBar.
* For tool bars, the AccessibleContext takes the form of an
* AccessibleJToolBar.
* A new AccessibleJToolBar instance is created if necessary.
*
* @return an AccessibleJToolBar that serves as the
* AccessibleContext of this JToolBar
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJToolBar();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JToolBar</code> class. It provides an implementation of the
* Java Accessibility API appropriate to toolbar user-interface elements.
*/
protected class AccessibleJToolBar extends AccessibleJComponent {
/**
* Get the state of this object.
*
* @return an instance of AccessibleStateSet containing the current
* state set of the object
* @see AccessibleState
*/
public AccessibleStateSet getAccessibleStateSet() {
AccessibleStateSet states = super.getAccessibleStateSet();
// FIXME: [[[WDW - need to add orientation from BoxLayout]]]
// FIXME: [[[WDW - need to do SELECTABLE if SelectionModel is added]]]
return states;
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.TOOL_BAR;
}
} // inner class AccessibleJToolBar
}

View File

@@ -0,0 +1,292 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import javax.swing.plaf.*;
import javax.accessibility.*;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.util.Objects;
/**
* Used to display a "Tip" for a Component. Typically components provide api
* to automate the process of using <code>ToolTip</code>s.
* For example, any Swing component can use the <code>JComponent</code>
* <code>setToolTipText</code> method to specify the text
* for a standard tooltip. A component that wants to create a custom
* <code>ToolTip</code>
* display can override <code>JComponent</code>'s <code>createToolTip</code>
* method and use a subclass of this class.
* <p>
* See <a href="https://docs.oracle.com/javase/tutorial/uiswing/components/tooltip.html">How to Use Tool Tips</a>
* in <em>The Java Tutorial</em>
* for further documentation.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JComponent#setToolTipText
* @see JComponent#createToolTip
* @author Dave Moore
* @author Rich Shiavi
*/
@SuppressWarnings("serial")
public class JToolTip extends JComponent implements Accessible {
/**
* @see #getUIClassID
* @see #readObject
*/
private static final String uiClassID = "ToolTipUI";
String tipText;
JComponent component;
/** Creates a tool tip. */
public JToolTip() {
setOpaque(true);
updateUI();
}
/**
* Returns the L&amp;F object that renders this component.
*
* @return the <code>ToolTipUI</code> object that renders this component
*/
public ToolTipUI getUI() {
return (ToolTipUI)ui;
}
/**
* Resets the UI property to a value from the current look and feel.
*
* @see JComponent#updateUI
*/
public void updateUI() {
setUI((ToolTipUI)UIManager.getUI(this));
}
/**
* Returns the name of the L&amp;F class that renders this component.
*
* @return the string "ToolTipUI"
* @see JComponent#getUIClassID
* @see UIDefaults#getUI
*/
public String getUIClassID() {
return uiClassID;
}
/**
* Sets the text to show when the tool tip is displayed.
* The string <code>tipText</code> may be <code>null</code>.
*
* @param tipText the <code>String</code> to display
* @beaninfo
* preferred: true
* bound: true
* description: Sets the text of the tooltip
*/
public void setTipText(String tipText) {
String oldValue = this.tipText;
this.tipText = tipText;
firePropertyChange("tiptext", oldValue, tipText);
if (!Objects.equals(oldValue, tipText)) {
revalidate();
repaint();
}
}
/**
* Returns the text that is shown when the tool tip is displayed.
* The returned value may be <code>null</code>.
*
* @return the <code>String</code> that is displayed
*/
public String getTipText() {
return tipText;
}
/**
* Specifies the component that the tooltip describes.
* The component <code>c</code> may be <code>null</code>
* and will have no effect.
* <p>
* This is a bound property.
*
* @param c the <code>JComponent</code> being described
* @see JComponent#createToolTip
* @beaninfo
* bound: true
* description: Sets the component that the tooltip describes.
*/
public void setComponent(JComponent c) {
JComponent oldValue = this.component;
component = c;
firePropertyChange("component", oldValue, c);
}
/**
* Returns the component the tooltip applies to.
* The returned value may be <code>null</code>.
*
* @return the component that the tooltip describes
*
* @see JComponent#createToolTip
*/
public JComponent getComponent() {
return component;
}
/**
* Always returns true since tooltips, by definition,
* should always be on top of all other windows.
*/
// package private
boolean alwaysOnTop() {
return true;
}
/**
* See <code>readObject</code> and <code>writeObject</code>
* in <code>JComponent</code> for more
* information about serialization in Swing.
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
if (getUIClassID().equals(uiClassID)) {
byte count = JComponent.getWriteObjCounter(this);
JComponent.setWriteObjCounter(this, --count);
if (count == 0 && ui != null) {
ui.installUI(this);
}
}
}
/**
* Returns a string representation of this <code>JToolTip</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JToolTip</code>
*/
protected String paramString() {
String tipTextString = (tipText != null ?
tipText : "");
return super.paramString() +
",tipText=" + tipTextString;
}
/////////////////
// Accessibility support
////////////////
/**
* Gets the AccessibleContext associated with this JToolTip.
* For tool tips, the AccessibleContext takes the form of an
* AccessibleJToolTip.
* A new AccessibleJToolTip instance is created if necessary.
*
* @return an AccessibleJToolTip that serves as the
* AccessibleContext of this JToolTip
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJToolTip();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JToolTip</code> class. It provides an implementation of the
* Java Accessibility API appropriate to tool tip user-interface elements.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*/
@SuppressWarnings("serial")
protected class AccessibleJToolTip extends AccessibleJComponent {
/**
* Get the accessible description of this object.
*
* @return a localized String describing this object.
*/
public String getAccessibleDescription() {
String description = accessibleDescription;
// fallback to client property
if (description == null) {
description = (String)getClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY);
}
if (description == null) {
description = getTipText();
}
return description;
}
/**
* Get the role of this object.
*
* @return an instance of AccessibleRole describing the role of the
* object
*/
public AccessibleRole getAccessibleRole() {
return AccessibleRole.TOOL_TIP;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,673 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.util.Locale;
import java.util.Vector;
import java.io.Serializable;
import javax.accessibility.*;
/**
* A <code>JWindow</code> is a container that can be displayed anywhere on the
* user's desktop. It does not have the title bar, window-management buttons,
* or other trimmings associated with a <code>JFrame</code>, but it is still a
* "first-class citizen" of the user's desktop, and can exist anywhere
* on it.
* <p>
* The <code>JWindow</code> component contains a <code>JRootPane</code>
* as its only child. The <code>contentPane</code> should be the parent
* of any children of the <code>JWindow</code>.
* As a convenience, the {@code add}, {@code remove}, and {@code setLayout}
* methods of this class are overridden, so that they delegate calls
* to the corresponding methods of the {@code ContentPane}.
* For example, you can add a child component to a window as follows:
* <pre>
* window.add(child);
* </pre>
* And the child will be added to the contentPane.
* The <code>contentPane</code> will always be non-<code>null</code>.
* Attempting to set it to <code>null</code> will cause the <code>JWindow</code>
* to throw an exception. The default <code>contentPane</code> will have a
* <code>BorderLayout</code> manager set on it.
* Refer to {@link javax.swing.RootPaneContainer}
* for details on adding, removing and setting the <code>LayoutManager</code>
* of a <code>JWindow</code>.
* <p>
* Please see the {@link JRootPane} documentation for a complete description of
* the <code>contentPane</code>, <code>glassPane</code>, and
* <code>layeredPane</code> components.
* <p>
* In a multi-screen environment, you can create a <code>JWindow</code>
* on a different screen device. See {@link java.awt.Window} for more
* information.
* <p>
* <strong>Warning:</strong> Swing is not thread safe. For more
* information see <a
* href="package-summary.html#threading">Swing's Threading
* Policy</a>.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see JRootPane
*
* @beaninfo
* attribute: isContainer true
* attribute: containerDelegate getContentPane
* description: A toplevel window which has no system border or controls.
*
* @author David Kloba
*/
@SuppressWarnings("serial")
public class JWindow extends Window implements Accessible,
RootPaneContainer,
TransferHandler.HasGetTransferHandler
{
/**
* The <code>JRootPane</code> instance that manages the
* <code>contentPane</code>
* and optional <code>menuBar</code> for this frame, as well as the
* <code>glassPane</code>.
*
* @see #getRootPane
* @see #setRootPane
*/
protected JRootPane rootPane;
/**
* If true then calls to <code>add</code> and <code>setLayout</code>
* will be forwarded to the <code>contentPane</code>. This is initially
* false, but is set to true when the <code>JWindow</code> is constructed.
*
* @see #isRootPaneCheckingEnabled
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected boolean rootPaneCheckingEnabled = false;
/**
* The <code>TransferHandler</code> for this window.
*/
private TransferHandler transferHandler;
/**
* Creates a window with no specified owner. This window will not be
* focusable.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @throws HeadlessException if
* <code>GraphicsEnvironment.isHeadless()</code> returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see #isFocusableWindow
* @see JComponent#getDefaultLocale
*/
public JWindow() {
this((Frame)null);
}
/**
* Creates a window with the specified <code>GraphicsConfiguration</code>
* of a screen device. This window will not be focusable.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param gc the <code>GraphicsConfiguration</code> that is used
* to construct the new window with; if gc is <code>null</code>,
* the system default <code>GraphicsConfiguration</code>
* is assumed
* @throws HeadlessException If
* <code>GraphicsEnvironment.isHeadless()</code> returns true.
* @throws IllegalArgumentException if <code>gc</code> is not from
* a screen device.
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see #isFocusableWindow
* @see JComponent#getDefaultLocale
*
* @since 1.3
*/
public JWindow(GraphicsConfiguration gc) {
this(null, gc);
super.setFocusableWindowState(false);
}
/**
* Creates a window with the specified owner frame.
* If <code>owner</code> is <code>null</code>, the shared owner
* will be used and this window will not be focusable. Also,
* this window will not be focusable unless its owner is showing
* on the screen.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param owner the frame from which the window is displayed
* @throws HeadlessException if GraphicsEnvironment.isHeadless()
* returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see #isFocusableWindow
* @see JComponent#getDefaultLocale
*/
public JWindow(Frame owner) {
super(owner == null? SwingUtilities.getSharedOwnerFrame() : owner);
if (owner == null) {
WindowListener ownerShutdownListener =
SwingUtilities.getSharedOwnerFrameShutdownListener();
addWindowListener(ownerShutdownListener);
}
windowInit();
}
/**
* Creates a window with the specified owner window. This window
* will not be focusable unless its owner is showing on the screen.
* If <code>owner</code> is <code>null</code>, the shared owner
* will be used and this window will not be focusable.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param owner the window from which the window is displayed
* @throws HeadlessException if
* <code>GraphicsEnvironment.isHeadless()</code> returns true.
* @see java.awt.GraphicsEnvironment#isHeadless
* @see #isFocusableWindow
* @see JComponent#getDefaultLocale
*/
public JWindow(Window owner) {
super(owner == null ? (Window)SwingUtilities.getSharedOwnerFrame() :
owner);
if (owner == null) {
WindowListener ownerShutdownListener =
SwingUtilities.getSharedOwnerFrameShutdownListener();
addWindowListener(ownerShutdownListener);
}
windowInit();
}
/**
* Creates a window with the specified owner window and
* <code>GraphicsConfiguration</code> of a screen device. If
* <code>owner</code> is <code>null</code>, the shared owner will be used
* and this window will not be focusable.
* <p>
* This constructor sets the component's locale property to the value
* returned by <code>JComponent.getDefaultLocale</code>.
*
* @param owner the window from which the window is displayed
* @param gc the <code>GraphicsConfiguration</code> that is used
* to construct the new window with; if gc is <code>null</code>,
* the system default <code>GraphicsConfiguration</code>
* is assumed, unless <code>owner</code> is also null, in which
* case the <code>GraphicsConfiguration</code> from the
* shared owner frame will be used.
* @throws HeadlessException if
* <code>GraphicsEnvironment.isHeadless()</code> returns true.
* @throws IllegalArgumentException if <code>gc</code> is not from
* a screen device.
*
* @see java.awt.GraphicsEnvironment#isHeadless
* @see #isFocusableWindow
* @see JComponent#getDefaultLocale
*
* @since 1.3
*/
public JWindow(Window owner, GraphicsConfiguration gc) {
super(owner == null ? (Window)SwingUtilities.getSharedOwnerFrame() :
owner, gc);
if (owner == null) {
WindowListener ownerShutdownListener =
SwingUtilities.getSharedOwnerFrameShutdownListener();
addWindowListener(ownerShutdownListener);
}
windowInit();
}
/**
* Called by the constructors to init the <code>JWindow</code> properly.
*/
protected void windowInit() {
setLocale( JComponent.getDefaultLocale() );
setRootPane(createRootPane());
setRootPaneCheckingEnabled(true);
sun.awt.SunToolkit.checkAndSetPolicy(this);
}
/**
* Called by the constructor methods to create the default
* <code>rootPane</code>.
*/
protected JRootPane createRootPane() {
JRootPane rp = new JRootPane();
// NOTE: this uses setOpaque vs LookAndFeel.installProperty as there
// is NO reason for the RootPane not to be opaque. For painting to
// work the contentPane must be opaque, therefor the RootPane can
// also be opaque.
rp.setOpaque(true);
return rp;
}
/**
* Returns whether calls to <code>add</code> and
* <code>setLayout</code> are forwarded to the <code>contentPane</code>.
*
* @return true if <code>add</code> and <code>setLayout</code>
* are forwarded; false otherwise
*
* @see #addImpl
* @see #setLayout
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected boolean isRootPaneCheckingEnabled() {
return rootPaneCheckingEnabled;
}
/**
* Sets the {@code transferHandler} property, which is a mechanism to
* support transfer of data into this component. Use {@code null}
* if the component does not support data transfer operations.
* <p>
* If the system property {@code suppressSwingDropSupport} is {@code false}
* (the default) and the current drop target on this component is either
* {@code null} or not a user-set drop target, this method will change the
* drop target as follows: If {@code newHandler} is {@code null} it will
* clear the drop target. If not {@code null} it will install a new
* {@code DropTarget}.
* <p>
* Note: When used with {@code JWindow}, {@code TransferHandler} only
* provides data import capability, as the data export related methods
* are currently typed to {@code JComponent}.
* <p>
* Please see
* <a href="https://docs.oracle.com/javase/tutorial/uiswing/dnd/index.html">
* How to Use Drag and Drop and Data Transfer</a>, a section in
* <em>The Java Tutorial</em>, for more information.
*
* @param newHandler the new {@code TransferHandler}
*
* @see TransferHandler
* @see #getTransferHandler
* @see java.awt.Component#setDropTarget
* @since 1.6
*
* @beaninfo
* bound: true
* hidden: true
* description: Mechanism for transfer of data into the component
*/
public void setTransferHandler(TransferHandler newHandler) {
TransferHandler oldHandler = transferHandler;
transferHandler = newHandler;
SwingUtilities.installSwingDropTargetAsNecessary(this, transferHandler);
firePropertyChange("transferHandler", oldHandler, newHandler);
}
/**
* Gets the <code>transferHandler</code> property.
*
* @return the value of the <code>transferHandler</code> property
*
* @see TransferHandler
* @see #setTransferHandler
* @since 1.6
*/
public TransferHandler getTransferHandler() {
return transferHandler;
}
/**
* Calls <code>paint(g)</code>. This method was overridden to
* prevent an unnecessary call to clear the background.
*
* @param g the <code>Graphics</code> context in which to paint
*/
public void update(Graphics g) {
paint(g);
}
/**
* Sets whether calls to <code>add</code> and
* <code>setLayout</code> are forwarded to the <code>contentPane</code>.
*
* @param enabled true if <code>add</code> and <code>setLayout</code>
* are forwarded, false if they should operate directly on the
* <code>JWindow</code>.
*
* @see #addImpl
* @see #setLayout
* @see #isRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
* @beaninfo
* hidden: true
* description: Whether the add and setLayout methods are forwarded
*/
protected void setRootPaneCheckingEnabled(boolean enabled) {
rootPaneCheckingEnabled = enabled;
}
/**
* Adds the specified child <code>Component</code>.
* This method is overridden to conditionally forward calls to the
* <code>contentPane</code>.
* By default, children are added to the <code>contentPane</code> instead
* of the frame, refer to {@link javax.swing.RootPaneContainer} for
* details.
*
* @param comp the component to be enhanced
* @param constraints the constraints to be respected
* @param index the index
* @exception IllegalArgumentException if <code>index</code> is invalid
* @exception IllegalArgumentException if adding the container's parent
* to itself
* @exception IllegalArgumentException if adding a window to a container
*
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
protected void addImpl(Component comp, Object constraints, int index)
{
if(isRootPaneCheckingEnabled()) {
getContentPane().add(comp, constraints, index);
}
else {
super.addImpl(comp, constraints, index);
}
}
/**
* Removes the specified component from the container. If
* <code>comp</code> is not the <code>rootPane</code>, this will forward
* the call to the <code>contentPane</code>. This will do nothing if
* <code>comp</code> is not a child of the <code>JWindow</code> or
* <code>contentPane</code>.
*
* @param comp the component to be removed
* @throws NullPointerException if <code>comp</code> is null
* @see #add
* @see javax.swing.RootPaneContainer
*/
public void remove(Component comp) {
if (comp == rootPane) {
super.remove(comp);
} else {
getContentPane().remove(comp);
}
}
/**
* Sets the <code>LayoutManager</code>.
* Overridden to conditionally forward the call to the
* <code>contentPane</code>.
* Refer to {@link javax.swing.RootPaneContainer} for
* more information.
*
* @param manager the <code>LayoutManager</code>
* @see #setRootPaneCheckingEnabled
* @see javax.swing.RootPaneContainer
*/
public void setLayout(LayoutManager manager) {
if(isRootPaneCheckingEnabled()) {
getContentPane().setLayout(manager);
}
else {
super.setLayout(manager);
}
}
/**
* Returns the <code>rootPane</code> object for this window.
* @return the <code>rootPane</code> property for this window
*
* @see #setRootPane
* @see RootPaneContainer#getRootPane
*/
public JRootPane getRootPane() {
return rootPane;
}
/**
* Sets the new <code>rootPane</code> object for this window.
* This method is called by the constructor.
*
* @param root the new <code>rootPane</code> property
* @see #getRootPane
*
* @beaninfo
* hidden: true
* description: the RootPane object for this window.
*/
protected void setRootPane(JRootPane root) {
if(rootPane != null) {
remove(rootPane);
}
rootPane = root;
if(rootPane != null) {
boolean checkingEnabled = isRootPaneCheckingEnabled();
try {
setRootPaneCheckingEnabled(false);
add(rootPane, BorderLayout.CENTER);
}
finally {
setRootPaneCheckingEnabled(checkingEnabled);
}
}
}
/**
* Returns the <code>Container</code> which is the <code>contentPane</code>
* for this window.
*
* @return the <code>contentPane</code> property
* @see #setContentPane
* @see RootPaneContainer#getContentPane
*/
public Container getContentPane() {
return getRootPane().getContentPane();
}
/**
* Sets the <code>contentPane</code> property for this window.
* This method is called by the constructor.
*
* @param contentPane the new <code>contentPane</code>
*
* @exception IllegalComponentStateException (a runtime
* exception) if the content pane parameter is <code>null</code>
* @see #getContentPane
* @see RootPaneContainer#setContentPane
*
* @beaninfo
* hidden: true
* description: The client area of the window where child
* components are normally inserted.
*/
public void setContentPane(Container contentPane) {
getRootPane().setContentPane(contentPane);
}
/**
* Returns the <code>layeredPane</code> object for this window.
*
* @return the <code>layeredPane</code> property
* @see #setLayeredPane
* @see RootPaneContainer#getLayeredPane
*/
public JLayeredPane getLayeredPane() {
return getRootPane().getLayeredPane();
}
/**
* Sets the <code>layeredPane</code> property.
* This method is called by the constructor.
*
* @param layeredPane the new <code>layeredPane</code> object
*
* @exception IllegalComponentStateException (a runtime
* exception) if the content pane parameter is <code>null</code>
* @see #getLayeredPane
* @see RootPaneContainer#setLayeredPane
*
* @beaninfo
* hidden: true
* description: The pane which holds the various window layers.
*/
public void setLayeredPane(JLayeredPane layeredPane) {
getRootPane().setLayeredPane(layeredPane);
}
/**
* Returns the <code>glassPane Component</code> for this window.
*
* @return the <code>glassPane</code> property
* @see #setGlassPane
* @see RootPaneContainer#getGlassPane
*/
public Component getGlassPane() {
return getRootPane().getGlassPane();
}
/**
* Sets the <code>glassPane</code> property.
* This method is called by the constructor.
* @param glassPane the <code>glassPane</code> object for this window
*
* @see #getGlassPane
* @see RootPaneContainer#setGlassPane
*
* @beaninfo
* hidden: true
* description: A transparent pane used for menu rendering.
*/
public void setGlassPane(Component glassPane) {
getRootPane().setGlassPane(glassPane);
}
/**
* {@inheritDoc}
*
* @since 1.6
*/
public Graphics getGraphics() {
JComponent.getGraphicsInvoked(this);
return super.getGraphics();
}
/**
* Repaints the specified rectangle of this component within
* <code>time</code> milliseconds. Refer to <code>RepaintManager</code>
* for details on how the repaint is handled.
*
* @param time maximum time in milliseconds before update
* @param x the <i>x</i> coordinate
* @param y the <i>y</i> coordinate
* @param width the width
* @param height the height
* @see RepaintManager
* @since 1.6
*/
public void repaint(long time, int x, int y, int width, int height) {
if (RepaintManager.HANDLE_TOP_LEVEL_PAINT) {
RepaintManager.currentManager(this).addDirtyRegion(
this, x, y, width, height);
}
else {
super.repaint(time, x, y, width, height);
}
}
/**
* Returns a string representation of this <code>JWindow</code>.
* This method
* is intended to be used only for debugging purposes, and the
* content and format of the returned string may vary between
* implementations. The returned string may be empty but may not
* be <code>null</code>.
*
* @return a string representation of this <code>JWindow</code>
*/
protected String paramString() {
String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ?
"true" : "false");
return super.paramString() +
",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString;
}
/////////////////
// Accessibility support
////////////////
/** The accessible context property. */
protected AccessibleContext accessibleContext = null;
/**
* Gets the AccessibleContext associated with this JWindow.
* For JWindows, the AccessibleContext takes the form of an
* AccessibleJWindow.
* A new AccessibleJWindow instance is created if necessary.
*
* @return an AccessibleJWindow that serves as the
* AccessibleContext of this JWindow
*/
public AccessibleContext getAccessibleContext() {
if (accessibleContext == null) {
accessibleContext = new AccessibleJWindow();
}
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>JWindow</code> class. It provides an implementation of the
* Java Accessibility API appropriate to window user-interface
* elements.
*/
@SuppressWarnings("serial")
protected class AccessibleJWindow extends AccessibleAWTWindow {
// everything is in the new parent, AccessibleAWTWindow
}
}

View File

@@ -0,0 +1,316 @@
/*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.awt.AWTKeyStroke;
import java.awt.event.KeyEvent;
/**
* A KeyStroke represents a key action on the keyboard, or equivalent input
* device. KeyStrokes can correspond to only a press or release of a particular
* key, just as KEY_PRESSED and KEY_RELEASED KeyEvents do; alternately, they
* can correspond to typing a specific Java character, just as KEY_TYPED
* KeyEvents do. In all cases, KeyStrokes can specify modifiers (alt, shift,
* control, meta, altGraph, or a combination thereof) which must be present during the
* action for an exact match.
* <p>
* KeyStrokes are used to define high-level (semantic) action events. Instead
* of trapping every keystroke and throwing away the ones you are not
* interested in, those keystrokes you care about automatically initiate
* actions on the Components with which they are registered.
* <p>
* KeyStrokes are immutable, and are intended to be unique. Client code cannot
* create a KeyStroke; a variant of <code>getKeyStroke</code> must be used
* instead. These factory methods allow the KeyStroke implementation to cache
* and share instances efficiently.
* <p>
* <strong>Warning:</strong>
* Serialized objects of this class will not be compatible with
* future Swing releases. The current serialization support is
* appropriate for short term storage or RMI between applications running
* the same version of Swing. As of 1.4, support for long term storage
* of all JavaBeans&trade;
* has been added to the <code>java.beans</code> package.
* Please see {@link java.beans.XMLEncoder}.
*
* @see javax.swing.text.Keymap
* @see #getKeyStroke
*
* @author Arnaud Weber
* @author David Mendenhall
*/
public class KeyStroke extends AWTKeyStroke {
/**
* Serial Version ID.
*/
private static final long serialVersionUID = -9060180771037902530L;
private KeyStroke() {
}
private KeyStroke(char keyChar, int keyCode, int modifiers,
boolean onKeyRelease) {
super(keyChar, keyCode, modifiers, onKeyRelease);
}
/**
* Returns a shared instance of a <code>KeyStroke</code>
* that represents a <code>KEY_TYPED</code> event for the
* specified character.
*
* @param keyChar the character value for a keyboard key
* @return a KeyStroke object for that key
*/
public static KeyStroke getKeyStroke(char keyChar) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyChar);
}
}
/**
* Returns an instance of a KeyStroke, specifying whether the key is
* considered to be activated when it is pressed or released. Unlike all
* other factory methods in this class, the instances returned by this
* method are not necessarily cached or shared.
*
* @param keyChar the character value for a keyboard key
* @param onKeyRelease <code>true</code> if this KeyStroke corresponds to a
* key release; <code>false</code> otherwise.
* @return a KeyStroke object for that key
* @deprecated use getKeyStroke(char)
*/
@Deprecated
public static KeyStroke getKeyStroke(char keyChar, boolean onKeyRelease) {
return new KeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, onKeyRelease);
}
/**
* Returns a shared instance of a {@code KeyStroke}
* that represents a {@code KEY_TYPED} event for the
* specified Character object and a
* set of modifiers. Note that the first parameter is of type Character
* rather than char. This is to avoid inadvertent clashes with calls to
* <code>getKeyStroke(int keyCode, int modifiers)</code>.
*
* The modifiers consist of any combination of following:<ul>
* <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
* <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
* <li>java.awt.event.InputEvent.META_DOWN_MASK
* <li>java.awt.event.InputEvent.ALT_DOWN_MASK
* <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
* </ul>
* The old modifiers listed below also can be used, but they are
* mapped to _DOWN_ modifiers. <ul>
* <li>java.awt.event.InputEvent.SHIFT_MASK
* <li>java.awt.event.InputEvent.CTRL_MASK
* <li>java.awt.event.InputEvent.META_MASK
* <li>java.awt.event.InputEvent.ALT_MASK
* <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
* </ul>
* also can be used, but they are mapped to _DOWN_ modifiers.
*
* Since these numbers are all different powers of two, any combination of
* them is an integer in which each bit represents a different modifier
* key. Use 0 to specify no modifiers.
*
* @param keyChar the Character object for a keyboard character
* @param modifiers a bitwise-ored combination of any modifiers
* @return an KeyStroke object for that key
* @throws IllegalArgumentException if keyChar is null
*
* @see java.awt.event.InputEvent
* @since 1.3
*/
public static KeyStroke getKeyStroke(Character keyChar, int modifiers) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyChar, modifiers);
}
}
/**
* Returns a shared instance of a KeyStroke, given a numeric key code and a
* set of modifiers, specifying whether the key is activated when it is
* pressed or released.
* <p>
* The "virtual key" constants defined in java.awt.event.KeyEvent can be
* used to specify the key code. For example:<ul>
* <li>java.awt.event.KeyEvent.VK_ENTER
* <li>java.awt.event.KeyEvent.VK_TAB
* <li>java.awt.event.KeyEvent.VK_SPACE
* </ul>
* Alternatively, the key code may be obtained by calling
* <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
*
* The modifiers consist of any combination of:<ul>
* <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
* <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
* <li>java.awt.event.InputEvent.META_DOWN_MASK
* <li>java.awt.event.InputEvent.ALT_DOWN_MASK
* <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
* </ul>
* The old modifiers <ul>
* <li>java.awt.event.InputEvent.SHIFT_MASK
* <li>java.awt.event.InputEvent.CTRL_MASK
* <li>java.awt.event.InputEvent.META_MASK
* <li>java.awt.event.InputEvent.ALT_MASK
* <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
* </ul>
* also can be used, but they are mapped to _DOWN_ modifiers.
*
* Since these numbers are all different powers of two, any combination of
* them is an integer in which each bit represents a different modifier
* key. Use 0 to specify no modifiers.
*
* @param keyCode an int specifying the numeric code for a keyboard key
* @param modifiers a bitwise-ored combination of any modifiers
* @param onKeyRelease <code>true</code> if the KeyStroke should represent
* a key release; <code>false</code> otherwise.
* @return a KeyStroke object for that key
*
* @see java.awt.event.KeyEvent
* @see java.awt.event.InputEvent
*/
public static KeyStroke getKeyStroke(int keyCode, int modifiers,
boolean onKeyRelease) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyCode, modifiers,
onKeyRelease);
}
}
/**
* Returns a shared instance of a KeyStroke, given a numeric key code and a
* set of modifiers. The returned KeyStroke will correspond to a key press.
* <p>
* The "virtual key" constants defined in java.awt.event.KeyEvent can be
* used to specify the key code. For example:<ul>
* <li>java.awt.event.KeyEvent.VK_ENTER
* <li>java.awt.event.KeyEvent.VK_TAB
* <li>java.awt.event.KeyEvent.VK_SPACE
* </ul>
* Alternatively, the key code may be obtained by calling
* <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
*
* The modifiers consist of any combination of:<ul>
* <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
* <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
* <li>java.awt.event.InputEvent.META_DOWN_MASK
* <li>java.awt.event.InputEvent.ALT_DOWN_MASK
* <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
* </ul>
* The old modifiers <ul>
* <li>java.awt.event.InputEvent.SHIFT_MASK
* <li>java.awt.event.InputEvent.CTRL_MASK
* <li>java.awt.event.InputEvent.META_MASK
* <li>java.awt.event.InputEvent.ALT_MASK
* <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
* </ul>
* also can be used, but they are mapped to _DOWN_ modifiers.
*
* Since these numbers are all different powers of two, any combination of
* them is an integer in which each bit represents a different modifier
* key. Use 0 to specify no modifiers.
*
* @param keyCode an int specifying the numeric code for a keyboard key
* @param modifiers a bitwise-ored combination of any modifiers
* @return a KeyStroke object for that key
*
* @see java.awt.event.KeyEvent
* @see java.awt.event.InputEvent
*/
public static KeyStroke getKeyStroke(int keyCode, int modifiers) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStroke(keyCode, modifiers);
}
}
/**
* Returns a KeyStroke which represents the stroke which generated a given
* KeyEvent.
* <p>
* This method obtains the keyChar from a KeyTyped event, and the keyCode
* from a KeyPressed or KeyReleased event. The KeyEvent modifiers are
* obtained for all three types of KeyEvent.
*
* @param anEvent the KeyEvent from which to obtain the KeyStroke
* @throws NullPointerException if <code>anEvent</code> is null
* @return the KeyStroke that precipitated the event
*/
public static KeyStroke getKeyStrokeForEvent(KeyEvent anEvent) {
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
return (KeyStroke)getAWTKeyStrokeForEvent(anEvent);
}
}
/**
* Parses a string and returns a <code>KeyStroke</code>.
* The string must have the following syntax:
* <pre>
* &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)
*
* modifiers := shift | control | ctrl | meta | alt | altGraph
* typedID := typed &lt;typedKey&gt;
* typedKey := string of length 1 giving Unicode character.
* pressedReleasedID := (pressed | released) key
* key := KeyEvent key code name, i.e. the name following "VK_".
* </pre>
* If typed, pressed or released is not specified, pressed is assumed. Here
* are some examples:
* <pre>
* "INSERT" =&gt; getKeyStroke(KeyEvent.VK_INSERT, 0);
* "control DELETE" =&gt; getKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);
* "alt shift X" =&gt; getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
* "alt shift released X" =&gt; getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
* "typed a" =&gt; getKeyStroke('a');
* </pre>
*
* In order to maintain backward-compatibility, specifying a null String,
* or a String which is formatted incorrectly, returns null.
*
* @param s a String formatted as described above
* @return a KeyStroke object for that String, or null if the specified
* String is null, or is formatted incorrectly
*
* @see java.awt.event.KeyEvent
*/
public static KeyStroke getKeyStroke(String s) {
if (s == null || s.length() == 0) {
return null;
}
synchronized (AWTKeyStroke.class) {
registerSubclass(KeyStroke.class);
try {
return (KeyStroke)getAWTKeyStroke(s);
} catch (IllegalArgumentException e) {
return null;
}
}
}
}

View File

@@ -0,0 +1,392 @@
/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.beans.*;
import javax.swing.event.*;
import sun.awt.EmbeddedFrame;
/**
* The KeyboardManager class is used to help dispatch keyboard actions for the
* WHEN_IN_FOCUSED_WINDOW style actions. Actions with other conditions are handled
* directly in JComponent.
*
* Here's a description of the symantics of how keyboard dispatching should work
* atleast as I understand it.
*
* KeyEvents are dispatched to the focused component. The focus manager gets first
* crack at processing this event. If the focus manager doesn't want it, then
* the JComponent calls super.processKeyEvent() this allows listeners a chance
* to process the event.
*
* If none of the listeners "consumes" the event then the keybindings get a shot.
* This is where things start to get interesting. First, KeyStokes defined with the
* WHEN_FOCUSED condition get a chance. If none of these want the event, then the component
* walks though it's parents looked for actions of type WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.
*
* If no one has taken it yet, then it winds up here. We then look for components registered
* for WHEN_IN_FOCUSED_WINDOW events and fire to them. Note that if none of those are found
* then we pass the event to the menubars and let them have a crack at it. They're handled differently.
*
* Lastly, we check if we're looking at an internal frame. If we are and no one wanted the event
* then we move up to the InternalFrame's creator and see if anyone wants the event (and so on and so on).
*
*
* @see InputMap
*/
class KeyboardManager {
static KeyboardManager currentManager = new KeyboardManager();
/**
* maps top-level containers to a sub-hashtable full of keystrokes
*/
Hashtable<Container, Hashtable> containerMap = new Hashtable<Container, Hashtable>();
/**
* Maps component/keystroke pairs to a topLevel container
* This is mainly used for fast unregister operations
*/
Hashtable<ComponentKeyStrokePair, Container> componentKeyStrokeMap = new Hashtable<ComponentKeyStrokePair, Container>();
public static KeyboardManager getCurrentManager() {
return currentManager;
}
public static void setCurrentManager(KeyboardManager km) {
currentManager = km;
}
/**
* register keystrokes here which are for the WHEN_IN_FOCUSED_WINDOW
* case.
* Other types of keystrokes will be handled by walking the hierarchy
* That simplifies some potentially hairy stuff.
*/
public void registerKeyStroke(KeyStroke k, JComponent c) {
Container topContainer = getTopAncestor(c);
if (topContainer == null) {
return;
}
Hashtable keyMap = containerMap.get(topContainer);
if (keyMap == null) { // lazy evaluate one
keyMap = registerNewTopContainer(topContainer);
}
Object tmp = keyMap.get(k);
if (tmp == null) {
keyMap.put(k,c);
} else if (tmp instanceof Vector) { // if there's a Vector there then add to it.
Vector v = (Vector)tmp;
if (!v.contains(c)) { // only add if this keystroke isn't registered for this component
v.addElement(c);
}
} else if (tmp instanceof JComponent) {
// if a JComponent is there then remove it and replace it with a vector
// Then add the old compoennt and the new compoent to the vector
// then insert the vector in the table
if (tmp != c) { // this means this is already registered for this component, no need to dup
Vector<JComponent> v = new Vector<JComponent>();
v.addElement((JComponent) tmp);
v.addElement(c);
keyMap.put(k, v);
}
} else {
System.out.println("Unexpected condition in registerKeyStroke");
Thread.dumpStack();
}
componentKeyStrokeMap.put(new ComponentKeyStrokePair(c,k), topContainer);
// Check for EmbeddedFrame case, they know how to process accelerators even
// when focus is not in Java
if (topContainer instanceof EmbeddedFrame) {
((EmbeddedFrame)topContainer).registerAccelerator(k);
}
}
/**
* Find the top focusable Window, Applet, or InternalFrame
*/
private static Container getTopAncestor(JComponent c) {
for(Container p = c.getParent(); p != null; p = p.getParent()) {
if (p instanceof Window && ((Window)p).isFocusableWindow() ||
p instanceof Applet || p instanceof JInternalFrame) {
return p;
}
}
return null;
}
public void unregisterKeyStroke(KeyStroke ks, JComponent c) {
// component may have already been removed from the hierarchy, we
// need to look up the container using the componentKeyStrokeMap.
ComponentKeyStrokePair ckp = new ComponentKeyStrokePair(c,ks);
Container topContainer = componentKeyStrokeMap.get(ckp);
if (topContainer == null) { // never heard of this pairing, so bail
return;
}
Hashtable keyMap = containerMap.get(topContainer);
if (keyMap == null) { // this should never happen, but I'm being safe
Thread.dumpStack();
return;
}
Object tmp = keyMap.get(ks);
if (tmp == null) { // this should never happen, but I'm being safe
Thread.dumpStack();
return;
}
if (tmp instanceof JComponent && tmp == c) {
keyMap.remove(ks); // remove the KeyStroke from the Map
//System.out.println("removed a stroke" + ks);
} else if (tmp instanceof Vector ) { // this means there is more than one component reg for this key
Vector v = (Vector)tmp;
v.removeElement(c);
if ( v.isEmpty() ) {
keyMap.remove(ks); // remove the KeyStroke from the Map
//System.out.println("removed a ks vector");
}
}
if ( keyMap.isEmpty() ) { // if no more bindings in this table
containerMap.remove(topContainer); // remove table to enable GC
//System.out.println("removed a container");
}
componentKeyStrokeMap.remove(ckp);
// Check for EmbeddedFrame case, they know how to process accelerators even
// when focus is not in Java
if (topContainer instanceof EmbeddedFrame) {
((EmbeddedFrame)topContainer).unregisterAccelerator(ks);
}
}
/**
* This method is called when the focused component (and none of
* its ancestors) want the key event. This will look up the keystroke
* to see if any chidren (or subchildren) of the specified container
* want a crack at the event.
* If one of them wants it, then it will "DO-THE-RIGHT-THING"
*/
public boolean fireKeyboardAction(KeyEvent e, boolean pressed, Container topAncestor) {
if (e.isConsumed()) {
System.out.println("Acquired pre-used event!");
Thread.dumpStack();
}
// There may be two keystrokes associated with a low-level key event;
// in this case a keystroke made of an extended key code has a priority.
KeyStroke ks;
KeyStroke ksE = null;
if(e.getID() == KeyEvent.KEY_TYPED) {
ks=KeyStroke.getKeyStroke(e.getKeyChar());
} else {
if(e.getKeyCode() != e.getExtendedKeyCode()) {
ksE=KeyStroke.getKeyStroke(e.getExtendedKeyCode(), e.getModifiers(), !pressed);
}
ks=KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers(), !pressed);
}
Hashtable keyMap = containerMap.get(topAncestor);
if (keyMap != null) { // this container isn't registered, so bail
Object tmp = null;
// extended code has priority
if( ksE != null ) {
tmp = keyMap.get(ksE);
if( tmp != null ) {
ks = ksE;
}
}
if( tmp == null ) {
tmp = keyMap.get(ks);
}
if (tmp == null) {
// don't do anything
} else if ( tmp instanceof JComponent) {
JComponent c = (JComponent)tmp;
if ( c.isShowing() && c.isEnabled() ) { // only give it out if enabled and visible
fireBinding(c, ks, e, pressed);
}
} else if ( tmp instanceof Vector) { //more than one comp registered for this
Vector v = (Vector)tmp;
// There is no well defined order for WHEN_IN_FOCUSED_WINDOW
// bindings, but we give precedence to those bindings just
// added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW
// bindings are accessed before those of the JRootPane (they
// both have a WHEN_IN_FOCUSED_WINDOW binding for enter).
for (int counter = v.size() - 1; counter >= 0; counter--) {
JComponent c = (JComponent)v.elementAt(counter);
//System.out.println("Trying collision: " + c + " vector = "+ v.size());
if ( c.isShowing() && c.isEnabled() ) { // don't want to give these out
fireBinding(c, ks, e, pressed);
if (e.isConsumed())
return true;
}
}
} else {
System.out.println( "Unexpected condition in fireKeyboardAction " + tmp);
// This means that tmp wasn't null, a JComponent, or a Vector. What is it?
Thread.dumpStack();
}
}
if (e.isConsumed()) {
return true;
}
// if no one else handled it, then give the menus a crack
// The're handled differently. The key is to let any JMenuBars
// process the event
if ( keyMap != null) {
Vector v = (Vector)keyMap.get(JMenuBar.class);
if (v != null) {
Enumeration iter = v.elements();
while (iter.hasMoreElements()) {
JMenuBar mb = (JMenuBar)iter.nextElement();
if ( mb.isShowing() && mb.isEnabled() ) { // don't want to give these out
boolean extended = (ksE != null) && !ksE.equals(ks);
if (extended) {
fireBinding(mb, ksE, e, pressed);
}
if (!extended || !e.isConsumed()) {
fireBinding(mb, ks, e, pressed);
}
if (e.isConsumed()) {
return true;
}
}
}
}
}
return e.isConsumed();
}
void fireBinding(JComponent c, KeyStroke ks, KeyEvent e, boolean pressed) {
if (c.processKeyBinding(ks, e, JComponent.WHEN_IN_FOCUSED_WINDOW,
pressed)) {
e.consume();
}
}
public void registerMenuBar(JMenuBar mb) {
Container top = getTopAncestor(mb);
if (top == null) {
return;
}
Hashtable keyMap = containerMap.get(top);
if (keyMap == null) { // lazy evaluate one
keyMap = registerNewTopContainer(top);
}
// use the menubar class as the key
Vector menuBars = (Vector)keyMap.get(JMenuBar.class);
if (menuBars == null) { // if we don't have a list of menubars,
// then make one.
menuBars = new Vector();
keyMap.put(JMenuBar.class, menuBars);
}
if (!menuBars.contains(mb)) {
menuBars.addElement(mb);
}
}
public void unregisterMenuBar(JMenuBar mb) {
Container topContainer = getTopAncestor(mb);
if (topContainer == null) {
return;
}
Hashtable keyMap = containerMap.get(topContainer);
if (keyMap!=null) {
Vector v = (Vector)keyMap.get(JMenuBar.class);
if (v != null) {
v.removeElement(mb);
if (v.isEmpty()) {
keyMap.remove(JMenuBar.class);
if (keyMap.isEmpty()) {
// remove table to enable GC
containerMap.remove(topContainer);
}
}
}
}
}
protected Hashtable registerNewTopContainer(Container topContainer) {
Hashtable keyMap = new Hashtable();
containerMap.put(topContainer, keyMap);
return keyMap;
}
/**
* This class is used to create keys for a hashtable
* which looks up topContainers based on component, keystroke pairs
* This is used to make unregistering KeyStrokes fast
*/
class ComponentKeyStrokePair {
Object component;
Object keyStroke;
public ComponentKeyStrokePair(Object comp, Object key) {
component = comp;
keyStroke = key;
}
public boolean equals(Object o) {
if ( !(o instanceof ComponentKeyStrokePair)) {
return false;
}
ComponentKeyStrokePair ckp = (ComponentKeyStrokePair)o;
return ((component.equals(ckp.component)) && (keyStroke.equals(ckp.keyStroke)));
}
public int hashCode() {
return component.hashCode() * keyStroke.hashCode();
}
}
} // end KeyboardManager

View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.swing;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Window;
/**
* Comparator which attempts to sort Components based on their size and
* position. Code adapted from original javax.swing.DefaultFocusManager
* implementation.
*
* @author David Mendenhall
*/
final class LayoutComparator implements Comparator<Component>, java.io.Serializable {
private static final int ROW_TOLERANCE = 10;
private boolean horizontal = true;
private boolean leftToRight = true;
void setComponentOrientation(ComponentOrientation orientation) {
horizontal = orientation.isHorizontal();
leftToRight = orientation.isLeftToRight();
}
public int compare(Component a, Component b) {
if (a == b) {
return 0;
}
// Row/Column algorithm only applies to siblings. If 'a' and 'b'
// aren't siblings, then we need to find their most inferior
// ancestors which share a parent. Compute the ancestory lists for
// each Component and then search from the Window down until the
// hierarchy branches.
if (a.getParent() != b.getParent()) {
LinkedList<Component> aAncestory = new LinkedList<Component>();
for(; a != null; a = a.getParent()) {
aAncestory.add(a);
if (a instanceof Window) {
break;
}
}
if (a == null) {
// 'a' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
LinkedList<Component> bAncestory = new LinkedList<Component>();
for(; b != null; b = b.getParent()) {
bAncestory.add(b);
if (b instanceof Window) {
break;
}
}
if (b == null) {
// 'b' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
for (ListIterator<Component>
aIter = aAncestory.listIterator(aAncestory.size()),
bIter = bAncestory.listIterator(bAncestory.size()); ;) {
if (aIter.hasPrevious()) {
a = aIter.previous();
} else {
// a is an ancestor of b
return -1;
}
if (bIter.hasPrevious()) {
b = bIter.previous();
} else {
// b is an ancestor of a
return 1;
}
if (a != b) {
break;
}
}
}
int ax = a.getX(), ay = a.getY(), bx = b.getX(), by = b.getY();
int zOrder = a.getParent().getComponentZOrder(a) - b.getParent().getComponentZOrder(b);
if (horizontal) {
if (leftToRight) {
// LT - Western Europe (optional for Japanese, Chinese, Korean)
if (Math.abs(ay - by) < ROW_TOLERANCE) {
return (ax < bx) ? -1 : ((ax > bx) ? 1 : zOrder);
} else {
return (ay < by) ? -1 : 1;
}
} else { // !leftToRight
// RT - Middle East (Arabic, Hebrew)
if (Math.abs(ay - by) < ROW_TOLERANCE) {
return (ax > bx) ? -1 : ((ax < bx) ? 1 : zOrder);
} else {
return (ay < by) ? -1 : 1;
}
}
} else { // !horizontal
if (leftToRight) {
// TL - Mongolian
if (Math.abs(ax - bx) < ROW_TOLERANCE) {
return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
} else {
return (ax < bx) ? -1 : 1;
}
} else { // !leftToRight
// TR - Japanese, Chinese, Korean
if (Math.abs(ax - bx) < ROW_TOLERANCE) {
return (ay < by) ? -1 : ((ay > by) ? 1 : zOrder);
} else {
return (ax > bx) ? -1 : 1;
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More