diff options
author | Graydon Hoare <graydon@gcc.gnu.org> | 2004-05-27 06:17:44 +0000 |
---|---|---|
committer | Graydon Hoare <graydon@gcc.gnu.org> | 2004-05-27 06:17:44 +0000 |
commit | c5d2de6b4c976dc152c8618ab3e8e1319018dc30 (patch) | |
tree | 2ffcb4d3889f27364cadf6d34acb5b88d5881e8a /libjava/java | |
parent | e314a036a8942fe4ce5d9fd586f0a8bac90f6df3 (diff) | |
download | gcc-c5d2de6b4c976dc152c8618ab3e8e1319018dc30.zip gcc-c5d2de6b4c976dc152c8618ab3e8e1319018dc30.tar.gz gcc-c5d2de6b4c976dc152c8618ab3e8e1319018dc30.tar.bz2 |
[multiple changes]
2004-05-25 David Jee <djee@redhat.com>
* java/awt/Container.java
(remove): Set component's parent to null only after we removed the
component from its parent's layout manager.
2004-05-25 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java
(GtkComponentPeer): Set bounds regardless of whether awtComponent
is valid.
* gnu/java/awt/peer/gtk/GtkListPeer.java
(getSize): Change native method declaration.
(minimumSize): Pass visible row count into getSize().
(preferredSize): Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkListPeer.c
(Java_gnu_java_awt_peer_gtk_GtkListPeer_getSize): Use scroll window's
natural size. Use visible row count to determine the final height
value to return.
2004-05-21 Graydon Hoare <graydon@redhat.com>
* gnu/java/awt/peer/gtk/GdkGraphics2D.java
(setClip): Minor correction to order of operations.
* javax/swing/JScrollPane.java: Extend sketchy implementation.
* javax/swing/ScrollPaneLayout.java: Likewise.
* javax/swing/JViewPort.java: Likewise.
* javax/swing/ViewportLayout.java: Likewise.
* javax/swing/JComponent.java: Rewrite.
* javax/swing/RepaintManager.java: Likewise.
* javax/swing/JLayeredPane.java: Change validate() to revalidate().
* javax/swing/JList.java
(setSelectedIndices):
(getSelectedIndices):
(getSelectedValues): New functions.
(getPreferredScrollableViewportSize): Return preferred size.
(getScrollableUnitIncrement):
(getScrollableBlockIncrement): Initial implementations.
* javax/swing/JRootPane.java: Clean up slightly.
(getUI):
(setUI):
(updateUI):
(getUIClassID):
(isValidateRoot): Add overrides from JComponent.
* javax/swing/JScrollBar.java: Set default orientation to VERTICAL.
* javax/swing/UIManager.java (getDimension): Return the dimension.
* javax/swing/plaf/basic/BasicButtonUI.java: Set component opaque.
* javax/swing/plaf/basic/BasicLabelUI.java: Likewise.
* javax/swing/plaf/basic/BasicMenuItemUI.java: Likewise.
* javax/swing/plaf/basic/BasicProgressBarUI.java: Likewise.
* javax/swing/plaf/basic/BasicSeparatorUI.java: Likewise.
* javax/swing/plaf/basic/BasicSliderUI.java: Likewise.
* javax/swing/plaf/basic/BasicTabbedPaneUI.java: Likewise.
* javax/swing/plaf/basic/BasicRootPaneUI.java:
Likewise, and set background.
* javax/swing/plaf/basic/BasicListUI.java:
Likewise, and improve a bit.
* javax/swing/plaf/basic/BasicScrollBarUI.java:
Likewise, and adjust calculations.
* javax/swing/plaf/basic/BasicViewportUI.java:
Likewise, and improve a bit.
* javax/swing/plaf/basic/BasicLookAndFeel.java
(Button.margin): Shrink.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGlyphVector.c:
Hack to set horizontal always, workaround pango.
* jni/gtk-peer/gtkcairopeer.h: Change to match pattern API.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c:
Synchronize more often, check cairo status after ops,
handle changes to cairo pattern API, check for disposal.
2004-05-21 Olga Rodimina <rodimina@redhat.com>
* javax/swing/plaf/basic/BasicMenuItemUI.java:
(BasicMenuItemUI): Create propertyChangeListener.
(getPath):Implemented.
(installListeners): Add propertyChangeListener to menuItem.
(uninstallListeners): Remove propertyChangeListener from menuItem.
(update): Implemented.
* javax/swing/plaf/basic/BasicMenuUI.MouseInputHandler:
(mouseEntered): Take insets of popup menu into account when
calculating position of popup menu.
2004-05-18 Olga Rodimina <rodimina@redhat.com>
* Makefile.am: Added new file.
* Makefile.in: Regenerate.
* javax/swing/JMenuBar.java:
Started implementation.
* javax/swing/JPopupMenu.java:
(setVisible): Fixed location of lightweight/mediumweight
popup menu.
(show): Fixed location of PopupMenu.
* javax/swing/plaf/basic/BasicMenuBarUI.java:
New file. UI Delegate for JMenuBar.
* javax/swing/plaf/basic/BasicMenuUI.MouseInputHandler:
(mouseEntered): Corrected position of the submenu.
2004-05-18 Thomas Fitzsimmons <fitzsim@redhat.com>
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c: Remove calls
to _gtk_accel_group_attach.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkPopupMenuPeer.c:
Likewise.
* gnu/java/awt/peer/gtk/GtkButtonPeer.java: Give gtkSetFont
package access. Don't override setFont.
* gnu/java/awt/peer/gtk/GtkCheckboxPeer.java: Likewise.
* gnu/java/awt/peer/gtk/GtkComponentPeer.java: Give
gtkWidgetRequestFocus package access.
* gnu/java/awt/peer/gtk/GtkLabelPeer.java: Don't override
setFont.
* gnu/java/awt/peer/gtk/GtkListPeer.java: Override gtkSetFont.
Give gtkWidgetRequestFocus package access.
* gnu/java/awt/peer/gtk/GtkTextAreaPeer.java: Give
gtkWidgetRequestFocus package access. Don't override setFont.
* gnu/java/awt/peer/gtk/GtkTextFieldPeer.java: Don't override
setFont.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c
(gtkSetLabel): Move call to gtk_bin_get_child into GDK critical
region.
(gtkSetFont): Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkListPeer.c (gtkSetFont):
Implement.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextAreaPeer.c
(gtkSetFont): Whitespace fix.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(gtkWidgetSetUsize): Remove method.
2004-05-18 David Jee <djee@redhat.com>
* java/awt/image/MemoryImageSource.java
(newPixels(int,int,int,int,boolean)): Set only the specified
rectangle of pixels.
(newPixels(byte[],ColorModel,int,int)): Implement.
(newPixels(int[],ColorModel,int,int)): Implement.
2004-05-18 Olga Rodimina <rodimina@redhat.com>
* Makefile.am: Added new file.
* Makefile.in: Regenerate.
* javax/swing/JMenu.java: Started
implementation.
* javax/swing/JPopupMenu.java:
(insert): If specified index is -1, then
add component at the end.
(isPopupTrigger): Reimplemented.
(JPopupMenu.LightWeightPopup): setBounds
of the lightWeightPopup before adding it
to the layeredPane.
(javax/swing/plaf/basic/BasicIconFactory.java):
(getMenuArrowIcon): Implemented.
* javax/swing/plaf/basic/BasicMenuItemUI.java:
(getPreferredSize): Add size of the arrow icon
if this menu item is instance of JMenu.
(paintMenuItem): Paint arrow icon if this
menu item is a submenu.
* javax/swing/plaf/basic/BasicMenuUI.java:
New File. UI Delegate for JMenu.
2004-05-17 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java (postKeyEvent):
Post KEY_TYPED events.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
(generates_key_typed_event): Remove function.
2004-05-17 Olga Rodimina <rodimina@redhat.com>
* javax/swing/JRootPane.java
(JRootPane.RootLayout): Reimplemented to
set bounds of contentPane and menuBar.
(setJMenuBar): Add menu bar to the layered pane.
(createLayeredPane): Set layout of layeredPane
to null.
* javax/swing/JLayeredPane.java:
(addImpl): Calculate index of the component in the
layeredPane according to the specified position within
the layer.
2004-05-17 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkImagePainter.java
(setPixels): Change color model to the default model after
converting pixels.
* java/awt/image/MemoryImageSource.java
(newPixels): Set only the specified rectangle of pixels.
2004-05-13 Thomas Fitzsimmons <fitzsim@redhat.com>
* libgcj.spec.in (lib): Add -l-java-awt -l-java-applet
-l-java-beans -l-javax-accessibility -l-javax-swing.
* java/awt/AWTEvent.java (toString): Print source's name rather
than the source itself.
2004-05-12 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkToolkit.java (loadSystemColors): Make
native.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c
(gdk_color_to_java_color): New function.
* jni/gtk-peer/gtkpeer.h: Add SystemColor defines.
2004-05-12 David Jee <djee@redhat.com>
* java/awt/image/RGBImageFilter.java:
Initialize origmodel as null.
(makeColor): Fix pixel component order.
(filterRGBPixels): Fix pixel iteration.
(setPixels): Add extra checks for index color model. Convert pixels
to default color model if necessary.
(convertColorModelToDefault): New override method for byte pixels.
(convertColorModelToDefault): For int pixels, fix pixel iteration.
(makeColorbyDefaultCM): New override method for byte pixels.
(makeColorbyDefaultCM): For int pixel, add color model as argument.
(makeColor): Fix pixel component order.
2004-05-11 Kim Ho <kho@redhat.com>
* javax/swing/Box.java:
Comment out more parts of Box.Filler.
2004-05-11 Kim Ho <kho@redhat.com>
* javax/swing/Box.java:
Remove reference to AccessibleAWTComponent so
it compiles again.
2004-05-10 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkListPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkListPeer.c: Update
implementation of list peer to use GtkTreeView instead of
deprecated GtkCList.
2004-05-07 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java
(gtkWidgetDispatchKeyEvent): Remove keyChar parameter.
(handleEvent): Remove keyChar argument to
gtkWidgetDispatchKeyEvent calls.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c: Fix
compiler warnings.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c: Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkMenuPeer.c: Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextComponentPeer.c:
Likewise.
2004-05-06 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java
(gtkWidgetRequestFocus): Mark protected.
(GtkComponentPeer): Only set the peer's bounds if its component
is valid.
* java/awt/Component.java (static): Set the default keyboard
focus manager.
(requestFocus(), requestFocus(boolean), requestFocusInWindow(),
requestFocusInWindow(temporary)): Don't request focus if the
component is not showing. Get tree lock before traversing
component hierarchy.
* java/awt/DefaultKeyboardFocusManager.java (dispatchEvent):
Only set the global focus owner if it is not a Window.
(processKeyEvent): Consume keystrokes associated with the focus
traversal keystroke.
(focusPreviousComponent, focusNextComponent, upFocusCycle,
downFocusCycle): Call requestFocusInWindow instead of
requestFocus.
* java/awt/EventDispatchThread.java (run): Move setting of
default keyboard focus manager to Component.java.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(awt_keycode_to_keysym): New function.
(gtkWidgetDispatchKeyEvent): Finish implementation.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
(pre_event_handler): Add FIXME comment.
* gnu/java/awt/peer/gtk/GtkTextAreaPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextAreaPeer.c
(gtkWidgetRequestFocus): New method.
* java/awt/TextArea.java (TextArea): Set focus traversal keys to
disable Tab and Shift-Tab keystrokes.
(addNotify, appendText, insertText, replaceText): Simplify peer
retrieval code.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkTextComponentPeer.c
(connectSignals): Remove connections to "commit" signals.
Remove C++-style comments.
* gnu/java/awt/peer/gtk/GtkButtonPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkButtonPeer.c
(handleEvent): Activate GTK button when the space bar key is
pressed.
(gtkActivate): New method.
2004-05-06 David Jee <djee@redhat.com>
* java/awt/image/CropImageFilter.java
(setPixels): Implement for byte array pixels.
* java/awt/image/ReplicateScaleFilter.java
(setPixels): Implement for byte array pixels.
(replicatePixels): Overload for byte array pixels.
2004-05-06 Kim Ho <kho@redhat.com>
* javax/swing/Box.java:
(getAccessibleContext): Return an instance of the
correct class.
2004-05-05 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GdkGraphics.java
(drawImage): When component is null, use SystemColor.window as
the default bgcolor.
* gnu/java/awt/peer/gtk/GtkImage.java
(setPixels): We can avoid iterating through the pixel rows only
when height is 1.
* java/awt/Image.java
(getScaledInstance): Partially implement.
* java/awt/image/CropImageFilter.java
(setProperties): Fix "filter" property.
(setPixels): Implement.
* java/awt/image/ReplicateScaleFilter.java
(setDimensions): Use scaled dimensions.
(setPixels): Implement.
(replicatePixels): New method.
2004-05-05 David Jee <djee@redhat.com>
* gnu/java/awt/peer/gtk/GtkImagePainter.java
(convertPixels): If either pixels or model is null, return null.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkImagePainter.c
(Java_gnu_java_awt_peer_gtk_GtkImagePainter_drawPixels): If jpixels
is null, do nothing and return.
2004-05-03 Kim Ho <kho@redhat.com>
* gnu/java/awt/peer/gtk/GtkDialogPeer.java:
(getGraphics): Like GtkFramePeer, the Graphics
object needs to be translate to account for
window decorations.
(postMouseEvent): New method. Account for
translation.
(postExposeEvent): ditto.
* javax/swing/Box.java: Stubbed.
* javax/swing/JDialog.java: Ran through jalopy
to fix indentation.
(JDialog): Call SwingUtilities' getOwnerFrame
for null owners.
(setLayout): Check isRootPaneCheckingEnabled
* javax/swing/JOptionPane.java: Re-implemented.
* javax/swing/SwingUtilities.java:
(getOwnerFrame): Static method to grab a default
owner frame for Dialogs that don't specify owners.
* javax/swing/event/SwingPropertyChangeSupport.java:
(firePropertyChange): Fix early exit condition.
* javax/swing/plaf/basic/BasicLabelUI.java:
(paint): Avoid painting text if it is null
or empty.
* javax/swing/plaf/basic/BasicOptionPaneUI.java:
Implement.
2004-05-03 Olga Rodimina <rodimina@redhat.com>
* Makefile.am: Added new file.
* Makefile.in: Regenerate.
* javax/swing/JPopupMenu.java:
Started implementation.
* javax/swing/JWindow.java
(JWindow): call super() if parent for window
is not specified.
* javax/swing/plaf/basic/BasicPopupMenuUI.java:
New File. UI Delegate for JPopupMenu.
2004-04-30 Olga Rodimina <rodimina@redhat.com>
* javax/swing/JApplet.java: Indicated that JApplet
implements RootPaneContainer and made method of this
interface public.
* javax/swing/JFrame.java: Ditto.
* javax/swing/JWindow.java: Ditto.
2004-04-29 Thomas Fitzsimmons <fitzsim@redhat.com>
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
(nativeSetBounds): Call gdk_window_move in addition to
gtk_window_move.
* java/applet/Applet.java (preferredSize): Call parent's
preferredSize if the applet stub is null.
(minimumSize): Likewise for parent's minimumSize.
2004-04-27 Olga Rodimina <rodimina@redhat.com>
* javax/swing/JMenuItem.java
(createActionPropertyChangeListener): Implemented.
(processMouseEvent): Ditto.
(fireMenuDragMouseEntered): Ditto.
(fireMenuDragMouseExited): Ditto.
(fireMenuDragMouseDragged): Ditto.
(fireMenuDragMouseReleased): Ditto.
(menuSelectionChanged): Ditto.
(getSubElements): Ditto.
(getComponent): Ditto.
(addMenuDragMouseListener): Ditto.
(removeMenuDragMouseListener):Ditto.
(addMenuKeyListener): Ditto.
(removeMenuKeyListener): Ditto.
* javax/swing/plaf/basic/BasicMenuItemUI.java
(doClick): Imlemented.
* javax/swing/plaf/basic/BasicMenuItemUI.MouseInputHandler:
Don't handle mouse events here. Pass them to
MenuSelectionManager.
2004-04-26 Olga Rodimina <rodimina@redhat.com>
Used correct version of jalopy configuration
file to fix style in the files below.
2004-04-26 Olga Rodimina <rodimina@redhat.com>
* javax/swing/JCheckBoxMenuItem.java:
Fixed style and removed unnecessary comments.
* javax/swing/JMenuItem.java: Ditto.
* javax/swing/JRadioButtonMenuItem.java: Ditto.
* javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java: Ditto.
* javax/swing/plaf/basic/BasicMenuItemUI.java: Ditto.
* javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java: Ditto.
2004-04-23 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu_java_awt_peer_gtk_GtkWindowPeer.c: Change FIXME comment to
C-style.
* gnu_java_awt_peer_gtk_GtkWindowPeer.c: Add FIXME comment.
* java/awt/ContainerOrderFocusTraversalPolicy.java
(getComponentAfter): Start from current component and work up
the component hierarchy until an acceptable component is found.
Synchronize on tree lock.
(getComponentBefore): Likewise.
2004-04-22 Thomas Fitzsimmons <fitzsim@redhat.com>
* gnu/java/awt/peer/gtk/GtkComponentPeer.java: Remove
focus-related debugging messages.
* java/awt/DefaultKeyboardFocusManager.java: Likewise.
* java/awt/EventDispatchThread.java: Likewise.
* java/awt/KeyboardFocusManager.java: Likewise.
* java/awt/Window.java: Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c: Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c: Likewise.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c: Change
new C++-style comments to C-style comments.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c: Likewise.
* gnu/java/awt/peer/gtk/GtkComponentPeer.java,
jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c
(handleEvent): Dispatch key press and key release events to
backing widget.
(requestFocus): Post a FOCUS_GAINED event to the event queue.
(gtkWidgetRequestFocus): New method.
(gtkWidgetDispatchKeyEvent): Likewise.
* java/awt/Component.java (requestFocus, requestFocus(boolean),
requestFocusInWindow, requestFocusInWindow(boolean),
getFocusCycleRootAncestor, nextFocus, transferFocus,
transferFocusBackward, transferFocusUpCycle, hasFocus,
isFocusOwner): Implement and document focus-handling methods.
(setFocusTraversalKeys): Inherit focus traversal keys when
keystrokes argument is null. Fix focus-handling documentation
throughout class.
* java/awt/Container.java (setFocusTraversalKeys,
getFocusTraversalKeys, areFocusTraversalKeysSet,
isFocusCycleRoot, setFocusTraversalPolicy,
getFocusTraversalPolicy, isFocusTraversalPolicySet,
setFocusCycleRoot, isFocusCycleRoot, transferFocusDownCycle):
Implement and document focus-handling methods.
(transferFocusBackward): Remove method.
(readObject, writeObject): Implement and document serialization
methods.
* java/awt/ContainerOrderFocusTraversalPolicy.java: Implement
and document.
* java/awt/DefaultFocusTraversalPolicy.java: Implement and
document.
* java/awt/DefaultKeyboardFocusManager.java: Implement and
partially document.
* java/awt/EventDispatchThread.java (run): Set default keyboard
focus manager. Attempt to dispatch each event to the keyboard
focus manager before normal dispatch.
* java/awt/KeyboardFocusManager.java: Implement and partially
document.
* java/awt/Window.java (Window): Set focusCycleRoot to true.
(show): Focus initial component when window is shown for the
first time.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c
(pre_event_handler): Replace complex key press and key release
logic with simple callbacks into GtkComponentPeer.
* jni/gtk-peer/gtkpeer.h: Fix FOCUS_GAINED/FOCUS_LOST reversal.
2004-04-21 Olga Rodimina <rodimina@redhat.com>
* javax/swing/MenuSelectionManager.java
(componentForPoint): Added new method.
(defaultManager): New Method. Implemented.
(getSelectedPath): Ditto.
(isComponentPartOfCurrentMenu): Ditto.
(processKeyEvent): Added new method.
(processMouseEvent): New Method. Implemented.
(setSelectedPath): Ditto.
(getPath): Ditto.
2004-04-19 Kim Ho <kho@redhat.com>
* java/awt/Container.java:
(remove): Set the component's parent to null.
(getComponentAt): Implement.
* javax/swing/JComponent.java:
(JComponent): Initialize defaultLocale
(getDefaultLocale): Implement.
(setDefaultLocale): ditto.
* javax/swing/JSlider.java:
(JSlider): Fix calculation of value.
* javax/swing/JSplitPane.java: Implement.
* javax/swing/plaf/basic/BasicLookAndFeel.java:
Change SplitPane's default divider size.
* javax/swing/plaf/basic/BasicScrollBarUI.java:
(paint): Remove unused code.
* javax/swing/plaf/basic/BasicSplitPaneDivider.java:
Added comments and ran through jalopy.
(setBasicSplitPaneUI): Get reference to hidden divider
and set up one touch buttons if necessary.
(setBorder): Fire propertyChangeEvent only if
borders are different.
(getPreferredSize): Defer to layout manager.
(propertyChange): Implement.
(oneTouchExpandableChanged): ditto.
(createLeftOneTouchButton): Use BasicArrowButton.
(createRightOneTouchButton): ditto.
(moveDividerTo): New method. Moves the divider
to a set location based on the last divider location.
(BasicSplitPaneDivider::MouseHandler): Implement.
(BasicSplitPaneDivider::OneTouchButton): Removed.
(BasicSplitPaneDivider::DragController): Implement.
(BasicSplitPaneDivider::VerticalDragController):
ditto.
(BasicSplitPaneDivider::DividerLayout): ditto.
* javax/swing/plaf/basic/BasicSplitPaneUI.java: Reimplement.
* javax/swing/plaf/basic/BasicTabbedPaneUI.java:
(calculateLayoutInfo): Don't show component if it's
null.
(paintTab): Fix title paint logic.
From-SVN: r82314
Diffstat (limited to 'libjava/java')
-rw-r--r-- | libjava/java/applet/Applet.java | 4 | ||||
-rw-r--r-- | libjava/java/awt/AWTEvent.java | 12 | ||||
-rw-r--r-- | libjava/java/awt/Component.java | 571 | ||||
-rw-r--r-- | libjava/java/awt/Container.java | 333 | ||||
-rw-r--r-- | libjava/java/awt/ContainerOrderFocusTraversalPolicy.java | 275 | ||||
-rw-r--r-- | libjava/java/awt/DefaultFocusTraversalPolicy.java | 66 | ||||
-rw-r--r-- | libjava/java/awt/DefaultKeyboardFocusManager.java | 418 | ||||
-rw-r--r-- | libjava/java/awt/EventDispatchThread.java | 12 | ||||
-rw-r--r-- | libjava/java/awt/Image.java | 16 | ||||
-rw-r--r-- | libjava/java/awt/KeyboardFocusManager.java | 807 | ||||
-rw-r--r-- | libjava/java/awt/TextArea.java | 40 | ||||
-rw-r--r-- | libjava/java/awt/Window.java | 33 | ||||
-rw-r--r-- | libjava/java/awt/image/CropImageFilter.java | 47 | ||||
-rw-r--r-- | libjava/java/awt/image/MemoryImageSource.java | 34 | ||||
-rw-r--r-- | libjava/java/awt/image/RGBImageFilter.java | 82 | ||||
-rw-r--r-- | libjava/java/awt/image/ReplicateScaleFilter.java | 87 |
16 files changed, 2258 insertions, 579 deletions
diff --git a/libjava/java/applet/Applet.java b/libjava/java/applet/Applet.java index 27c8aaf..009b18c 100644 --- a/libjava/java/applet/Applet.java +++ b/libjava/java/applet/Applet.java @@ -483,7 +483,7 @@ public class Applet extends Panel */ public Dimension preferredSize() { - return getDimensions (); + return stub == null ? super.preferredSize () : getDimensions (); } /** @@ -494,7 +494,7 @@ public class Applet extends Panel */ public Dimension minimumSize() { - return getDimensions (); + return stub == null ? super.minimumSize () : getDimensions (); } /** diff --git a/libjava/java/awt/AWTEvent.java b/libjava/java/awt/AWTEvent.java index 41cdad5..a084dcf 100644 --- a/libjava/java/awt/AWTEvent.java +++ b/libjava/java/awt/AWTEvent.java @@ -231,15 +231,15 @@ public abstract class AWTEvent extends EventObject } /** - * Returns a string representation of this event. This is in the format - * <code>getClass().getName() + '[' + paramString() + "] on " - * + source</code>. + * Create a string that represents this event in the format + * <code>classname[eventstring] on sourcecomponentname</code>. * - * @return a string representation of this event + * @return a string representing this event */ - public String toString() + public String toString () { - return getClass().getName() + "[" + paramString() + "] on " + source; + return getClass ().getName () + "[" + paramString () + "] on " + + ((Component) source).getName (); } /** diff --git a/libjava/java/awt/Component.java b/libjava/java/awt/Component.java index d52818a..3ca2b4f 100644 --- a/libjava/java/awt/Component.java +++ b/libjava/java/awt/Component.java @@ -383,18 +383,18 @@ public abstract class Component boolean focusable = true; /** - * Tracks whether this component uses default focus traversal, or has a - * different policy. + * Tracks whether this component's {@link #isFocusTraversable} + * method has been overridden. * - * @see #isFocusTraversableOverridden() * @since 1.4 */ int isFocusTraversableOverridden; /** - * The focus traversal keys, if not inherited from the parent or default - * keyboard manager. These sets will contain only AWTKeyStrokes that - * represent press and release events to use as focus control. + * The focus traversal keys, if not inherited from the parent or + * default keyboard focus manager. These sets will contain only + * AWTKeyStrokes that represent press and release events to use as + * focus control. * * @see #getFocusTraversalKeys(int) * @see #setFocusTraversalKeys(int, Set) @@ -557,6 +557,12 @@ public abstract class Component transient BufferStrategy bufferStrategy; /** + * true if requestFocus was called on this component when its + * top-level ancestor was not focusable. + */ + private transient FocusEvent pendingFocusRequest = null; + + /** * The system properties that affect image updating. */ private static transient boolean incrementalDraw; @@ -566,6 +572,8 @@ public abstract class Component { incrementalDraw = Boolean.getBoolean ("awt.image.incrementalDraw"); redrawRate = Long.getLong ("awt.image.redrawrate"); + // Set the default KeyboardFocusManager. + KeyboardFocusManager.setCurrentKeyboardFocusManager (null); } // Public and protected API. @@ -2963,6 +2971,7 @@ public abstract class Component { if (focusListener == null) return; + switch (e.id) { case FocusEvent.FOCUS_GAINED: @@ -3411,13 +3420,18 @@ public abstract class Component } /** - * Sets the focus traversal keys for a given type of focus events. Normally, - * the default values should match the operating system's native choices. To - * disable a given traversal, use <code>Collections.EMPTY_SET</code>. The - * event dispatcher will consume PRESSED, RELEASED, and TYPED events for the - * specified key, although focus can only transfer on PRESSED or RELEASED. + * Sets the focus traversal keys for one of the three focus + * traversal directions supported by Components: {@link + * #KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS}, {@link + * #KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS}, or {@link + * #KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS}. Normally, the + * default values should match the operating system's native + * choices. To disable a given traversal, use + * <code>Collections.EMPTY_SET</code>. The event dispatcher will + * consume PRESSED, RELEASED, and TYPED events for the specified + * key, although focus can only transfer on PRESSED or RELEASED. * - * <p>The defauts are: + * <p>The defaults are: * <table> * <th><td>Identifier</td><td>Meaning</td><td>Default</td></th> * <tr><td>KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS</td> @@ -3430,10 +3444,13 @@ public abstract class Component * <td>Go up a traversal cycle</td><td>None</td></tr> * </table> * - * <p>Specifying null allows inheritance from the parent, or from the current - * KeyboardFocusManager default set. If not null, the set must contain only - * AWTKeyStrokes that are not already focus keys and are not KEY_TYPED - * events. + * If keystrokes is null, this component's focus traversal key set + * is inherited from one of its ancestors. If none of its ancestors + * has its own set of focus traversal keys, the focus traversal keys + * are set to the defaults retrieved from the current + * KeyboardFocusManager. If not null, the set must contain only + * AWTKeyStrokes that are not already focus keys and are not + * KEY_TYPED events. * * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or * UP_CYCLE_TRAVERSAL_KEYS @@ -3448,7 +3465,24 @@ public abstract class Component public void setFocusTraversalKeys(int id, Set keystrokes) { if (keystrokes == null) - throw new IllegalArgumentException(); + { + Container parent = getParent (); + + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + Set sa; Set sb; String name; @@ -3476,50 +3510,60 @@ public abstract class Component name = "upCycleFocusTraversalKeys"; break; default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException (); } - int i = keystrokes.size(); - Iterator iter = keystrokes.iterator(); + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + while (--i >= 0) { - Object o = iter.next(); - if (! (o instanceof AWTKeyStroke) - || sa.contains(o) || sb.contains(o) + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) - throw new IllegalArgumentException(); + throw new IllegalArgumentException (); } + if (focusTraversalKeys == null) focusTraversalKeys = new Set[3]; - keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes)); - firePropertyChange(name, focusTraversalKeys[id], keystrokes); + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + focusTraversalKeys[id] = keystrokes; } /** - * Returns the set of keys for a given focus traversal action, as defined - * in <code>setFocusTraversalKeys</code>. If not set, this is inherited from - * the parent component, which may have gotten it from the - * KeyboardFocusManager. + * Returns the set of keys for a given focus traversal action, as + * defined in <code>setFocusTraversalKeys</code>. If not set, this + * is inherited from the parent component, which may have gotten it + * from the KeyboardFocusManager. * - * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or - * UP_CYCLE_TRAVERSAL_KEYS + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS * @throws IllegalArgumentException if id is invalid - * @see #setFocusTraversalKeys(int, Set) + * @see #setFocusTraversalKeys (int, Set) * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS * @since 1.4 */ - public Set getFocusTraversalKeys(int id) + public Set getFocusTraversalKeys (int id) { - if (id < KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS - || id > KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) throw new IllegalArgumentException(); + Set s = null; + if (focusTraversalKeys != null) s = focusTraversalKeys[id]; + if (s == null && parent != null) - s = parent.getFocusTraversalKeys(id); + s = parent.getFocusTraversalKeys (id); + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() .getDefaultFocusTraversalKeys(id)) : s; } @@ -3528,269 +3572,417 @@ public abstract class Component * Tests whether the focus traversal keys for a given action are explicitly * set or inherited. * - * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, or - * UP_CYCLE_TRAVERSAL_KEYS + * @param id one of FORWARD_TRAVERSAL_KEYS, BACKWARD_TRAVERSAL_KEYS, + * or UP_CYCLE_TRAVERSAL_KEYS * @return true if that set is explicitly specified * @throws IllegalArgumentException if id is invalid - * @see #getFocusTraversalKeys(int) + * @see #getFocusTraversalKeys (int) * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS * @since 1.4 */ - public boolean areFocusTraversalKeysSet(int id) + public boolean areFocusTraversalKeysSet (int id) { - if (id < KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS - || id > KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) - throw new IllegalArgumentException(); + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + return focusTraversalKeys != null && focusTraversalKeys[id] != null; } /** - * Sets whether focus traversal keys are enabled, which consumes traversal - * keys and performs the focus event automatically. + * Enable or disable focus traversal keys on this Component. If + * they are, then the keyboard focus manager consumes and acts on + * key press and release events that trigger focus traversal, and + * discards the corresponding key typed events. If focus traversal + * keys are disabled, then all key events that would otherwise + * trigger focus traversal are sent to this Component. * * @param focusTraversalKeysEnabled the new value of the flag - * @see #getFocusTraversalKeysEnabled() - * @see #setFocusTraversalKeys(int, Set) - * @see #getFocusTraversalKeys(int) + * @see #getFocusTraversalKeysEnabled () + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) * @since 1.4 */ - public void setFocusTraversalKeysEnabled(boolean focusTraversalKeysEnabled) + public void setFocusTraversalKeysEnabled (boolean focusTraversalKeysEnabled) { - firePropertyChange("focusTraversalKeysEnabled", - this.focusTraversalKeysEnabled, - focusTraversalKeysEnabled); + firePropertyChange ("focusTraversalKeysEnabled", + this.focusTraversalKeysEnabled, + focusTraversalKeysEnabled); this.focusTraversalKeysEnabled = focusTraversalKeysEnabled; } /** - * Tests whether focus traversal keys are enabled. If they are, then focus - * traversal keys are consumed and focus events performed automatically, - * without the component seeing the keystrokes. + * Check whether or not focus traversal keys are enabled on this + * Component. If they are, then the keyboard focus manager consumes + * and acts on key press and release events that trigger focus + * traversal, and discards the corresponding key typed events. If + * focus traversal keys are disabled, then all key events that would + * otherwise trigger focus traversal are sent to this Component. * - * @return true if focus traversal is enabled - * @see #setFocusTraversalKeysEnabled(boolean) - * @see #setFocusTraversalKeys(int, Set) - * @see #getFocusTraversalKeys(int) + * @return true if focus traversal keys are enabled + * @see #setFocusTraversalKeysEnabled (boolean) + * @see #setFocusTraversalKeys (int, Set) + * @see #getFocusTraversalKeys (int) * @since 1.4 */ - public boolean getFocusTraversalKeysEnabled() + public boolean getFocusTraversalKeysEnabled () { return focusTraversalKeysEnabled; } /** - * Requests that this component be given focus. A <code>FOCUS_GAINED</code> - * event will be fired if and only if this request is successful. To be - * successful, the component must be displayable, visible, and focusable, - * and the top-level Window must be able to receive focus. Thus, this - * request may fail, or be delayed until the window receives focus. It is - * recommended that <code>requestFocusInWindow</code> be used where - * possible to be more platform-independent. + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. * - * @see #requestFocusInWindow() + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow} should be used instead. + * + * @see #requestFocusInWindow () * @see FocusEvent - * @see #addFocusListener(FocusListener) - * @see #isFocusable() - * @see #isDisplayable() - * @see KeyboardFocusManager#clearGlobalFocusOwner() + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () */ - public void requestFocus() + public void requestFocus () { - // If there's no peer then this component can't get the focus. We - // treat it as a silent rejection of the request. - if (peer != null) - peer.requestFocus(); + if (isDisplayable () + && isShowing () + && isFocusable ()) + { + synchronized (getTreeLock ()) + { + // Find this Component's top-level ancestor. + Container parent = getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + Window toplevel = (Window) parent; + if (toplevel.isFocusableWindow ()) + { + if (peer != null) + // This call will cause a FOCUS_GAINED event to be + // posted to the system event queue if the native + // windowing system grants the focus request. + peer.requestFocus (); + else + { + // Either our peer hasn't been created yet or we're a + // lightweight component. In either case we want to + // post a FOCUS_GAINED event. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED)); + } + } + else + pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED); + } + } } /** - * Requests that this component be given focus. A <code>FOCUS_GAINED</code> - * event will be fired if and only if this request is successful. To be - * successful, the component must be displayable, visible, and focusable, - * and the top-level Window must be able to receive focus. Thus, this - * request may fail, or be delayed until the window receives focus. It is - * recommended that <code>requestFocusInWindow</code> be used where - * possible to be more platform-independent. + * Request that this Component be given the keyboard input focus and + * that its top-level ancestor become the focused Window. + * + * For the request to be granted, the Component must be focusable, + * displayable and showing and the top-level Window to which it + * belongs must be focusable. If the request is initially denied on + * the basis that the top-level Window is not focusable, the request + * will be remembered and granted when the Window does become + * focused. + * + * Never assume that this Component is the focus owner until it + * receives a FOCUS_GAINED event. + * + * The behaviour of this method is platform-dependent. + * {@link #requestFocusInWindow} should be used instead. * - * <p>If the return value is false, the request is guaranteed to fail. If - * it is true, it will likely succeed unless the action is vetoed or - * something in the native windowing system intervenes. The temporary flag, - * and thus this method in general, is not designed for public use; rather - * it is a hook for lightweight components to notify their container in - * an attempt to reduce the amount of repainting necessary. + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. * * @param temporary true if the focus request is temporary * @return true if the request has a chance of success - * @see #requestFocusInWindow() + * @see #requestFocusInWindow () * @see FocusEvent - * @see #addFocusListener(FocusListener) - * @see #isFocusable() - * @see #isDisplayable() - * @see KeyboardFocusManager#clearGlobalFocusOwner() + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () * @since 1.4 */ - protected boolean requestFocus(boolean temporary) + protected boolean requestFocus (boolean temporary) { - // XXX Implement correctly. - requestFocus(); + if (isDisplayable () + && isShowing () + && isFocusable ()) + { + synchronized (getTreeLock ()) + { + // Find this Component's top-level ancestor. + Container parent = getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + Window toplevel = (Window) parent; + if (toplevel.isFocusableWindow ()) + { + if (peer != null) + // This call will cause a FOCUS_GAINED event to be + // posted to the system event queue if the native + // windowing system grants the focus request. + peer.requestFocus (); + else + { + // Either our peer hasn't been created yet or we're a + // lightweight component. In either case we want to + // post a FOCUS_GAINED event. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary)); + } + } + else + // FIXME: need to add a focus listener to our top-level + // ancestor, so that we can post this event when it becomes + // the focused window. + pendingFocusRequest = new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary); + } + } + // Always return true. return true; } /** - * Requests that this component be given focus, if it resides in the - * top-level window which already has focus. A <code>FOCUS_GAINED</code> - * event will be fired if and only if this request is successful. To be - * successful, the component must be displayable, visible, and focusable, - * and the top-level Window must be focused. + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * <code>FOCUS_GAINED</code> event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. * - * <p>If the return value is false, the request is guaranteed to fail. If - * it is true, it will likely succeed unless the action is vetoed or - * something in the native windowing system intervenes. The temporary flag, - * and thus this method in general, is not designed for public use; rather - * it is a hook for lightweight components to notify their container in - * an attempt to reduce the amount of repainting necessary. + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. * * @return true if the request has a chance of success - * @see #requestFocus() + * @see #requestFocus () * @see FocusEvent - * @see #addFocusListener(FocusListener) - * @see #isFocusable() - * @see #isDisplayable() - * @see KeyboardFocusManager#clearGlobalFocusOwner() + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () * @since 1.4 */ - public boolean requestFocusInWindow() + public boolean requestFocusInWindow () { - // XXX Implement correctly. - requestFocus(); - return true; + return requestFocusInWindow (false); } /** - * Requests that this component be given focus, if it resides in the - * top-level window which already has focus. A <code>FOCUS_GAINED</code> - * event will be fired if and only if this request is successful. To be - * successful, the component must be displayable, visible, and focusable, - * and the top-level Window must be focused. + * Request that this component be given the keyboard input focus, if + * its top-level ancestor is the currently focused Window. A + * <code>FOCUS_GAINED</code> event will be fired if and only if this + * request is successful. To be successful, the component must be + * displayable, showing, and focusable, and its ancestor top-level + * Window must be focused. * - * <p>If the return value is false, the request is guaranteed to fail. If - * it is true, it will likely succeed unless the action is vetoed or - * something in the native windowing system intervenes. The temporary flag, - * and thus this method in general, is not designed for public use; rather - * it is a hook for lightweight components to notify their container in - * an attempt to reduce the amount of repainting necessary. + * If the return value is false, the request is guaranteed to fail. + * If the return value is true, the request will succeed unless it + * is vetoed or something in the native windowing system intervenes, + * preventing this Component's top-level ancestor from becoming + * focused. This method is meant to be called by derived + * lightweight Components that want to avoid unnecessary repainting + * when they know a given focus transfer need only be temporary. * * @param temporary true if the focus request is temporary * @return true if the request has a chance of success - * @see #requestFocus() + * @see #requestFocus () * @see FocusEvent - * @see #addFocusListener(FocusListener) - * @see #isFocusable() - * @see #isDisplayable() - * @see KeyboardFocusManager#clearGlobalFocusOwner() + * @see #addFocusListener (FocusListener) + * @see #isFocusable () + * @see #isDisplayable () + * @see KeyboardFocusManager#clearGlobalFocusOwner () * @since 1.4 */ - protected boolean requestFocusInWindow(boolean temporary) + protected boolean requestFocusInWindow (boolean temporary) { - // XXX Implement correctly. - requestFocus(); - return true; + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Window focusedWindow = manager.getFocusedWindow (); + + if (isDisplayable () + && isShowing () + && isFocusable ()) + { + if (focusedWindow != null) + { + synchronized (getTreeLock ()) + { + Container parent = getParent (); + + while (parent != null + && !(parent instanceof Window)) + parent = parent.getParent (); + + Window toplevel = (Window) parent; + + // Check if top-level ancestor is currently focused window. + if (focusedWindow == toplevel) + { + if (peer != null) + // This call will cause a FOCUS_GAINED event to be + // posted to the system event queue if the native + // windowing system grants the focus request. + peer.requestFocus (); + else + { + // Either our peer hasn't been created yet or we're a + // lightweight component. In either case we want to + // post a FOCUS_GAINED event. + EventQueue eq = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + eq.postEvent (new FocusEvent(this, FocusEvent.FOCUS_GAINED, temporary)); + } + } + else + return false; + } + } + + return true; + } + return false; } /** - * Transfers focus to the next component in the focus traversal order, as - * though this were the current focus owner. + * Transfers focus to the next component in the focus traversal + * order, as though this were the current focus owner. * * @see #requestFocus() * @since 1.1 */ - public void transferFocus() + public void transferFocus () { - Component next; - if (parent == null) - next = findNextFocusComponent(null); - else - next = parent.findNextFocusComponent(this); - if (next != null && next != this) - next.requestFocus(); + nextFocus (); } /** - * Returns the root container that owns the focus cycle where this component - * resides. A focus cycle root is in two cycles, one as the ancestor, and - * one as the focusable element; this call always returns the ancestor. + * Returns the root container that owns the focus cycle where this + * component resides. A focus cycle root is in two cycles, one as + * the ancestor, and one as the focusable element; this call always + * returns the ancestor. * * @return the ancestor container that owns the focus cycle * @since 1.4 */ - public Container getFocusCycleRootAncestor() + public Container getFocusCycleRootAncestor () { - // XXX Implement. - throw new Error("not implemented"); + if (this instanceof Window + && ((Container) this).isFocusCycleRoot ()) + return (Container) this; + + Container parent = getParent (); + + while (parent != null + && !parent.isFocusCycleRoot ()) + parent = parent.getParent (); + + return parent; } /** - * Tests if the container is the ancestor of the focus cycle that this - * component belongs to. + * Tests if the container is the ancestor of the focus cycle that + * this component belongs to. * * @param c the container to test * @return true if c is the focus cycle root * @since 1.4 */ - public boolean isFocusCycleRoot(Container c) + public boolean isFocusCycleRoot (Container c) { - return c == getFocusCycleRootAncestor(); + return c == getFocusCycleRootAncestor (); } /** - * AWT 1.0 focus event processor. + * AWT 1.0 focus event processor. Transfers focus to the next + * component in the focus traversal order, as though this were the + * current focus owner. * - * @deprecated use {@link #transferFocus()} instead + * @deprecated use {@link #transferFocus ()} instead */ - public void nextFocus() + public void nextFocus () { - transferFocus(); + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.focusNextComponent (this); } /** - * Transfers focus to the previous component in the focus traversal order, as - * though this were the current focus owner. + * Transfers focus to the previous component in the focus traversal + * order, as though this were the current focus owner. * - * @see #requestFocus() + * @see #requestFocus () * @since 1.4 */ - public void transferFocusBackward() + public void transferFocusBackward () { - // XXX Implement. - throw new Error("not implemented"); + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.focusPreviousComponent (this); } /** - * Transfers focus to the focus cycle root of this component. However, if - * this is a Window, the default focus owner in the window in the current - * focus cycle is focused instead. + * Transfers focus to the focus cycle root of this component. + * However, if this is a Window, the default focus owner in the + * window in the current focus cycle is focused instead. * - * @see #requestFocus() - * @see #isFocusCycleRoot() + * @see #requestFocus () + * @see #isFocusCycleRoot () * @since 1.4 */ - public void transferFocusUpCycle() + public void transferFocusUpCycle () { - // XXX Implement. - throw new Error("not implemented"); + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.upFocusCycle (this); } /** - * Tests if this component is the focus owner. Use {@link #isFocusOwner()} - * instead. + * Tests if this component is the focus owner. Use {@link + * #isFocusOwner ()} instead. * * @return true if this component owns focus * @since 1.2 */ - public boolean hasFocus() + public boolean hasFocus () { - return isFocusOwner(); + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Component focusOwner = manager.getFocusOwner (); + + return this == focusOwner; } /** @@ -3801,8 +3993,7 @@ public abstract class Component */ public boolean isFocusOwner() { - // XXX Implement. - throw new Error("not implemented"); + return hasFocus (); } /** @@ -4337,6 +4528,8 @@ p * <li>the set of backward traversal keys * making the request. This is overridden by Container; when called for an * ordinary component there is no child and so we always return null. * + * FIXME: is this still needed, in light of focus traversal policies? + * * @param child the component making the request * @return the next component to focus on */ @@ -4897,23 +5090,23 @@ p * <li>the set of backward traversal keys * Tests whether this component can accept focus. * * @return true if this is focus traversable - * @see #getAccessibleStateSet() + * @see #getAccessibleStateSet () * @see AccessibleState#FOCUSABLE * @see AccessibleState#FOCUSED */ - public boolean isFocusTraversable() + public boolean isFocusTraversable () { - return Component.this.isFocusTraversable(); + return Component.this.isFocusTraversable (); } /** * Requests focus for this component. * - * @see #isFocusTraversable() + * @see #isFocusTraversable () */ - public void requestFocus() + public void requestFocus () { - Component.this.requestFocus(); + Component.this.requestFocus (); } /** diff --git a/libjava/java/awt/Container.java b/libjava/java/awt/Container.java index d666559..0482e65 100644 --- a/libjava/java/awt/Container.java +++ b/libjava/java/awt/Container.java @@ -46,10 +46,16 @@ import java.awt.peer.ContainerPeer; import java.awt.peer.LightweightPeer; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.io.ObjectInputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.io.Serializable; +import java.util.Collections; import java.util.EventListener; +import java.util.Iterator; +import java.util.HashSet; import java.util.Set; import javax.accessibility.Accessible; import javax.swing.SwingUtilities; @@ -93,6 +99,21 @@ public class Container extends Component transient ContainerListener containerListener; transient PropertyChangeSupport changeSupport; + /** The focus traversal policy that determines how focus is + transferred between this Container and its children. */ + private FocusTraversalPolicy focusTraversalPolicy; + + /** + * The focus traversal keys, if not inherited from the parent or default + * keyboard manager. These sets will contain only AWTKeyStrokes that + * represent press and release events to use as focus control. + * + * @see #getFocusTraversalKeys(int) + * @see #setFocusTraversalKeys(int, Set) + * @since 1.4 + */ + transient Set[] focusTraversalKeys; + /** * Default constructor for subclasses. */ @@ -397,6 +418,8 @@ public class Container extends Component if (layoutMgr != null) layoutMgr.removeLayoutComponent(r); + r.parent = null; + // Post event to notify of adding the container. ContainerEvent ce = new ContainerEvent(this, ContainerEvent.COMPONENT_REMOVED, @@ -853,6 +876,11 @@ public class Container extends Component { return locate (x, y); } + + public Component getComponentAt(int index) + { + return component[index]; + } /** * Returns the component located at the specified point. This is done @@ -1068,9 +1096,89 @@ public class Container extends Component throw new IllegalArgumentException (); if (keystrokes == null) - throw new IllegalArgumentException (); + { + Container parent = getParent (); - throw new Error ("not implemented"); + while (parent != null) + { + if (parent.areFocusTraversalKeysSet (id)) + { + keystrokes = parent.getFocusTraversalKeys (id); + break; + } + parent = parent.getParent (); + } + + if (keystrokes == null) + keystrokes = KeyboardFocusManager.getCurrentKeyboardFocusManager (). + getDefaultFocusTraversalKeys (id); + } + + Set sa; + Set sb; + Set sc; + String name; + switch (id) + { + case KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "forwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "backwardFocusTraversalKeys"; + break; + case KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + name = "upCycleFocusTraversalKeys"; + break; + case KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS: + sa = getFocusTraversalKeys + (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + sb = getFocusTraversalKeys + (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + sc = getFocusTraversalKeys + (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + name = "downCycleFocusTraversalKeys"; + break; + default: + throw new IllegalArgumentException (); + } + + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); + + while (--i >= 0) + { + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) + || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) + throw new IllegalArgumentException (); + } + + if (focusTraversalKeys == null) + focusTraversalKeys = new Set[3]; + + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (name, focusTraversalKeys[id], keystrokes); + + focusTraversalKeys[id] = keystrokes; } /** @@ -1085,7 +1193,7 @@ public class Container extends Component * * @since 1.4 */ - public Set getFocusTraversalKeys(int id) + public Set getFocusTraversalKeys (int id) { if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && @@ -1093,9 +1201,18 @@ public class Container extends Component id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) throw new IllegalArgumentException (); - return null; + Set s = null; + + if (focusTraversalKeys != null) + s = focusTraversalKeys[id]; + + if (s == null && parent != null) + s = parent.getFocusTraversalKeys (id); + + return s == null ? (KeyboardFocusManager.getCurrentKeyboardFocusManager() + .getDefaultFocusTraversalKeys(id)) : s; } - + /** * Returns whether the Set of focus traversal keys for the given focus * traversal operation has been explicitly defined for this Container. @@ -1110,7 +1227,7 @@ public class Container extends Component * * @since 1.4 */ - public boolean areFocusTraversalKeysSet(int id) + public boolean areFocusTraversalKeysSet (int id) { if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && @@ -1118,43 +1235,148 @@ public class Container extends Component id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) throw new IllegalArgumentException (); - return false; + return focusTraversalKeys != null && focusTraversalKeys[id] != null; } - - public boolean isFocusCycleRoot(Container c) + + /** + * Check whether the given Container is the focus cycle root of this + * Container's focus traversal cycle. If this Container is a focus + * cycle root itself, then it will be in two different focus cycles + * -- it's own, and that of its ancestor focus cycle root's. In + * that case, if <code>c</code> is either of those containers, this + * method will return true. + * + * @param c the candidate Container + * + * @return true if c is the focus cycle root of the focus traversal + * cycle to which this Container belongs, false otherwise + * + * @since 1.4 + */ + public boolean isFocusCycleRoot (Container c) { + if (this == c + && isFocusCycleRoot ()) + return true; + + Container ancestor = getFocusCycleRootAncestor (); + + if (c == ancestor) + return true; + return false; } - - public void transferFocusBackward() - { - } - - public void setFocusTraversalPolicy(FocusTraversalPolicy policy) + + /** + * If this Container is a focus cycle root, set the focus traversal + * policy that determines the focus traversal order for its + * children. If non-null, this policy will be inherited by all + * inferior focus cycle roots. If <code>policy</code> is null, this + * Container will inherit its policy from the closest ancestor focus + * cycle root that's had its policy set. + * + * @param policy the new focus traversal policy for this Container or null + * + * @since 1.4 + */ + public void setFocusTraversalPolicy (FocusTraversalPolicy policy) { + focusTraversalPolicy = policy; } - - public FocusTraversalPolicy getFocusTraversalPolicy() + + /** + * Return the focus traversal policy that determines the focus + * traversal order for this Container's children. This method + * returns null if this Container is not a focus cycle root. If the + * focus traversal policy has not been set explicitly, then this + * method will return an ancestor focus cycle root's policy instead. + * + * @return this Container's focus traversal policy or null + * + * @since 1.4 + */ + public FocusTraversalPolicy getFocusTraversalPolicy () { - return null; + if (!isFocusCycleRoot ()) + return null; + + if (focusTraversalPolicy == null) + { + Container ancestor = getFocusCycleRootAncestor (); + + if (ancestor != this) + return ancestor.getFocusTraversalPolicy (); + else + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + return manager.getDefaultFocusTraversalPolicy (); + } + } + else + return focusTraversalPolicy; } - - public boolean isFocusTraversalPolicySet() + + /** + * Check whether this Container's focus traversal policy has been + * explicitly set. If it has not, then this Container will inherit + * its focus traversal policy from one of its ancestor focus cycle + * roots. + * + * @return true if focus traversal policy is set, false otherwise + */ + public boolean isFocusTraversalPolicySet () { - return false; + return focusTraversalPolicy == null; } - - public void setFocusCycleRoot(boolean focusCycleRoot) + + /** + * Set whether or not this Container is the root of a focus + * traversal cycle. This Container's focus traversal policy + * determines the order of focus traversal. Some policies prevent + * the focus from being transferred between two traversal cycles + * until an up or down traversal operation is performed. In that + * case, normal traversal (not up or down) is limited to this + * Container and all of this Container's descendents that are not + * descendents of inferior focus cycle roots. In the default case + * however, ContainerOrderFocusTraversalPolicy is in effect, and it + * supports implicit down-cycle traversal operations. + * + * @return true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public void setFocusCycleRoot (boolean focusCycleRoot) { + this.focusCycleRoot = focusCycleRoot; } - - public boolean isFocusCycleRoot() + + /** + * Check whether this Container is a focus cycle root. + * + * @return true if this is a focus cycle root, false otherwise + * + * @since 1.4 + */ + public boolean isFocusCycleRoot () { - return false; + return focusCycleRoot; } - - public void transferFocusDownCycle() + + /** + * Transfer focus down one focus traversal cycle. If this Container + * is a focus cycle root, then its default component becomes the + * focus owner, and this Container becomes the current focus cycle + * root. No traversal will occur if this Container is not a focus + * cycle root. + * + * @since 1.4 + */ + public void transferFocusDownCycle () { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + manager.downFocusCycle (this); } /** @@ -1371,6 +1593,61 @@ public class Container extends Component } } + /** + * Deserialize this Container: + * <ol> + * <li>Read from the stream the default serializable fields.</li> + * <li>Read a list of serializable ContainerListeners as optional + * data. If the list is null, no listeners will be registered.</li> + * <li>Read this Container's FocusTraversalPolicy as optional data. + * If this is null, then this Container will use a + * DefaultFocusTraversalPolicy.</li> + * </ol> + * + * @param s the stream to read from + * @throws ClassNotFoundException if deserialization fails + * @throws IOException if the stream fails + */ + private void readObject (ObjectInputStream s) + throws ClassNotFoundException, IOException + { + s.defaultReadObject (); + String key = (String) s.readObject (); + while (key != null) + { + Object object = s.readObject (); + if ("containerL".equals (key)) + addContainerListener((ContainerListener) object); + // FIXME: under what key is the focus traversal policy stored? + else if ("focusTraversalPolicy".equals (key)) + setFocusTraversalPolicy ((FocusTraversalPolicy) object); + + key = (String) s.readObject(); + } + } + + /** + * Serialize this Container: + * <ol> + * <li>Write to the stream the default serializable fields.</li> + * <li>Write the list of serializable ContainerListeners as optional + * data.</li> + * <li>Write this Container's FocusTraversalPolicy as optional data.</li> + * </ol> + * + * @param s the stream to write to + * @throws IOException if the stream fails + */ + private void writeObject (ObjectOutputStream s) throws IOException + { + s.defaultWriteObject (); + AWTEventMulticaster.save (s, "containerL", containerListener); + if (focusTraversalPolicy instanceof Serializable) + s.writeObject (focusTraversalPolicy); + else + s.writeObject (null); + } + // Nested classes. /* The following classes are used in concert with the diff --git a/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java b/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java index ce4bdf8..fa7ab4a 100644 --- a/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java +++ b/libjava/java/awt/ContainerOrderFocusTraversalPolicy.java @@ -41,7 +41,23 @@ package java.awt; import java.io.Serializable; /** + * ContainerOrderFocusTraversalPolicy defines a focus traversal order + * based on the order in which Components were packed in a Container. + * This policy performs a pre-order traversal of the Component + * hierarchy starting from a given focus cycle root. Portions of the + * hierarchy that are not visible and displayable are skipped. + * + * By default, this policy transfers focus down-cycle implicitly. + * That is, if a forward traversal is requested on a focus cycle root + * and the focus cycle root has focusable children, the focus will + * automatically be transfered down to the lower focus cycle. + * + * The default implementation of accept accepts only Components that + * are visible, displayable, enabled and focusable. Derived classes + * can override these acceptance criteria by overriding accept. + * * @author Michael Koch + * @author Thomas Fitzsimmons <fitzsim@redhat.com> * @since 1.4 */ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy @@ -52,12 +68,15 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy */ static final long serialVersionUID = 486933713763926351L; + /** + * True if implicit down cycling is enabled. + */ private boolean implicitDownCycleTraversal = true; /** * Creates the <code>ContainerOrderFocusTraversalPolicy</code> object. */ - public ContainerOrderFocusTraversalPolicy() + public ContainerOrderFocusTraversalPolicy () { // Nothing to do here } @@ -66,37 +85,196 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy * Returns the Component that should receive the focus after current. * root must be a focus cycle root of current. * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the next Component in the focus traversal order for root, + * or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is not a focus cycle * root of current, or if either root or current is null. */ - public Component getComponentAfter(Container root, Component current) + public Component getComponentAfter (Container root, Component current) { - if (root == null - || current == null) - throw new IllegalArgumentException (); - - return null; + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); + + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the first component in the + // focus traversal cycle. + if (current instanceof Window) + return getFirstComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search forward for the next acceptable component. + for (int i = componentIndex + 1; i < numComponents; i++) + { + if (accept (components[i])) + return components[i]; + + if (components[i] instanceof Container) + { + Component result = getFirstComponent ((Container) components[i]); + + if (result != null + && implicitDownCycleTraversal) + return result; + } + } + + // No focusable components after current in its Container. So go + // to the next Component after current's Container (parent). + Component result = getComponentAfter (root, parent); + + return result; + } } /** - * Returns the Component that should receive the focus before current. - * root must be a focus cycle root of current. + * Returns the Component that should receive the focus before + * <code>current</code>. <code>root</code> must be a focus cycle + * root of current. + * + * @param root a focus cycle root of current + * @param current a (possibly indirect) child of root, or root itself + * + * @return the previous Component in the focus traversal order for + * root, or null if no acceptable Component exists. * * @exception IllegalArgumentException If root is not a focus cycle * root of current, or if either root or current is null. */ - public Component getComponentBefore(Container root, Component current) + public Component getComponentBefore (Container root, Component current) { - if (root == null - || current == null) - throw new IllegalArgumentException (); + if (root == null) + throw new IllegalArgumentException ("focus cycle root is null"); + if (current == null) + throw new IllegalArgumentException ("current component is null"); - return null; + if (!root.isFocusCycleRoot ()) + throw new IllegalArgumentException ("root is not a focus cycle root"); + + Container ancestor = current.getFocusCycleRootAncestor (); + Container prevAncestor = ancestor; + while (ancestor != root) + { + ancestor = current.getFocusCycleRootAncestor (); + if (ancestor == prevAncestor) + { + // We've reached the top focus cycle root ancestor. Check + // if it is root. + if (ancestor != root) + throw new IllegalArgumentException ("the given container is not" + + " a focus cycle root of the" + + " current component"); + else + break; + } + prevAncestor = ancestor; + } + + // FIXME: is this the right thing to do here? It moves the context + // for traversal up one focus traversal cycle. We'll need a test + // for this. + if ((Component) root == current) + root = current.getFocusCycleRootAncestor (); + + // Check if we've reached the top of the component hierarchy. If + // so then we want to loop around to the last component in the + // focus traversal cycle. + if (current instanceof Window) + return getLastComponent ((Container) current); + + Container parent = current.getParent (); + + synchronized (parent.getTreeLock ()) + { + Component[] components = parent.getComponents (); + int componentIndex = 0; + int numComponents = parent.getComponentCount (); + + // Find component's index. + for (int i = 0; i < numComponents; i++) + { + if (components[i] == current) + componentIndex = i; + } + + // Search backward for the next acceptable component. + for (int i = componentIndex - 1; i >= 0; i--) + { + if (accept (components[i])) + return components[i]; + + if (components[i] instanceof Container) + { + Component result = getLastComponent ((Container) components[i]); + + if (result != null) + return result; + } + } + + // No focusable components before current in its Container. So go + // to the previous Component before current's Container (parent). + Component result = getComponentBefore (root, parent); + + return result; + } } /** * Returns the first Component of root that should receive the focus. * + * @param root a focus cycle root + * + * @return the first Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is null. */ public Component getFirstComponent(Container root) @@ -117,18 +295,16 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy { Component component = componentArray [i]; + if (accept (component)) + return component; + if (component instanceof Container) { - Component result = getLastComponent ((Container) component); + Component result = getFirstComponent ((Container) component); if (result != null) return result; } - else - { - if (accept (component)) - return component; - } } return null; @@ -137,9 +313,14 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy /** * Returns the last Component of root that should receive the focus. * + * @param root a focus cycle root + * + * @return the last Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is null. */ - public Component getLastComponent(Container root) + public Component getLastComponent (Container root) { if (root == null) throw new IllegalArgumentException (); @@ -153,10 +334,13 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy Component[] componentArray = root.getComponents (); - for (int i = componentArray.length - 1; i >= 0; i++) + for (int i = componentArray.length - 1; i >= 0; i--) { Component component = componentArray [i]; + if (accept (component)) + return component; + if (component instanceof Container) { Component result = getLastComponent ((Container) component); @@ -164,11 +348,6 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy if (result != null) return result; } - else - { - if (accept (component)) - return component; - } } return null; @@ -177,28 +356,58 @@ public class ContainerOrderFocusTraversalPolicy extends FocusTraversalPolicy /** * Returns the default Component of root that should receive the focus. * + * @param root a focus cycle root + * + * @return the default Component in the focus traversal order for + * root, or null if no acceptable Component exists. + * * @exception IllegalArgumentException If root is null. */ - public Component getDefaultComponent(Container root) + public Component getDefaultComponent (Container root) { return getFirstComponent (root); } - public void setImplicitDownCycleTraversal(boolean value) + /** + * Set whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @param value the setting for implicit down cycling + */ + public void setImplicitDownCycleTraversal (boolean value) { implicitDownCycleTraversal = value; } - public boolean getImplicitDownCycleTraversal() + /** + * Check whether or not implicit down cycling is enabled. If it is, + * then initiating a forward focus traversal operation onto a focus + * cycle root, the focus will be implicitly transferred into the + * root container's focus cycle. + * + * @return true if the focus will be transferred down-cycle + * implicitly + */ + public boolean getImplicitDownCycleTraversal () { return implicitDownCycleTraversal; } - protected boolean accept(Component current) + /** + * Check whether the given Component is an acceptable target for the + * keyboard input focus. + * + * @param current the Component to check + * + * @return true if current is acceptable, false otherwise + */ + protected boolean accept (Component current) { return (current.visible - && current.isDisplayable() + && current.isDisplayable () && current.enabled && current.focusable); } -} // class ContainerOrderFocusTraversalPolicy +} diff --git a/libjava/java/awt/DefaultFocusTraversalPolicy.java b/libjava/java/awt/DefaultFocusTraversalPolicy.java index ac3a178..73b1e95 100644 --- a/libjava/java/awt/DefaultFocusTraversalPolicy.java +++ b/libjava/java/awt/DefaultFocusTraversalPolicy.java @@ -39,17 +39,73 @@ exception statement from your version. */ package java.awt; /** - * STUB CLASS ONLY + * DefaultFocusTraversalPolicy is the default focus traversal policy + * used by Containers. + * + * This policy sharpens ContainerOrderFocusTraversalPolicy's + * acceptance criteria, to reject those Components that have + * unfocusable peers. Despite this extra strictness, this policy will + * always accept a Component that has explicitly been set focusable by + * any means. + * + * This AWT implementation assumes that the peers of the following + * Components are not focusable: Canvas, Panel, Label, ScrollPane, + * Scrollbar, Window, and any lightweight Component. + * + * A Component's focusability is independent of the focusability of + * its peer. + * + * @author Thomas Fitzsimmons <fitzsim@redhat.com> + * @since 1.4 */ public class DefaultFocusTraversalPolicy extends ContainerOrderFocusTraversalPolicy { - public DefaultFocusTraversalPolicy() + /** + * Construct a default focus traversal policy. + */ + public DefaultFocusTraversalPolicy () { } - protected boolean accept(Component comp) + /** + * Check whether a given Component would be acceptable as a focus + * owner. The Component must be displayable, visible and enabled to + * be acceptable. If the Component's focus traversability has been + * overridden, by overriding Component.isFocusTraversable or + * Component.isFocusable, or by calling Component.setFocusable, then + * the Component will be accepted if it is focusable. If the + * Component uses the default focus traversable behaviour, then + * <code>comp</code> will always be rejected if it is a Canvas, + * Panel, Label, ScrollPane, Scrollbar, Window or lightweight + * Component. + * + * @param comp the Component to check + * + * @return true if the Component is an acceptable target for + * keyboard input focus, false otherwise + */ + protected boolean accept (Component comp) { - throw new Error("not implemented"); + if (comp.visible + && comp.isDisplayable () + && comp.enabled) + { + if (comp.isFocusTraversableOverridden != 0 + && comp.isFocusTraversable ()) + return true; + else + { + if (!(comp instanceof Canvas + || comp instanceof Panel + || comp instanceof Label + || comp instanceof ScrollPane + || comp instanceof Scrollbar + || comp instanceof Window + || comp.isLightweight ())) + return true; + } + } + return false; } -} // class DefaultFocusTraversalPolicy +} diff --git a/libjava/java/awt/DefaultKeyboardFocusManager.java b/libjava/java/awt/DefaultKeyboardFocusManager.java index e2a2f68..79a9869 100644 --- a/libjava/java/awt/DefaultKeyboardFocusManager.java +++ b/libjava/java/awt/DefaultKeyboardFocusManager.java @@ -38,59 +38,423 @@ exception statement from your version. */ package java.awt; -import java.awt.event.KeyEvent; +import java.util.*; +import java.awt.event.*; -/** - * STUB CLASS ONLY - */ +// FIXME: finish documentation public class DefaultKeyboardFocusManager extends KeyboardFocusManager { - public DefaultKeyboardFocusManager() + /** + * This class models a request to delay the dispatch of events that + * arrive after a certain time, until a certain component becomes + * the focus owner. + */ + private class EventDelayRequest implements Comparable { + /** A {@link java.util.List} of {@link java.awt.event.KeyEvent}s + that are being delayed, pending this request's {@link + Component} receiving the keyboard focus. */ + private LinkedList enqueuedKeyEvents = new LinkedList (); + + /** An event timestamp. All events that arrive after this time + should be queued in the {@link #enqueuedKeyEvents} {@link + java.util.List}. */ + public long timestamp; + /** When this {@link Component} becomes focused, all events + between this EventDelayRequest and the next one in will be + dispatched from {@link #enqueuedKeyEvents}. */ + public Component focusedComp; + + /** + * Construct a new EventDelayRequest. + * + * @param timestamp events that arrive after this time will be + * delayed + * @param focusedComp the Component that needs to receive focus + * before events are dispatched + */ + public EventDelayRequest (long timestamp, Component focusedComp) + { + this.timestamp = timestamp; + this.focusedComp = focusedComp; + } + + public int compareTo (Object o) + { + if (!(o instanceof EventDelayRequest)) + throw new ClassCastException (); + + EventDelayRequest request = (EventDelayRequest) o; + + if (request.timestamp < timestamp) + return -1; + else if (request.timestamp == timestamp) + return 0; + else + return 1; + } + + public boolean equals (Object o) + { + if (!(o instanceof EventDelayRequest) || o == null) + return false; + + EventDelayRequest request = (EventDelayRequest) o; + + return (request.timestamp == timestamp + && request.focusedComp == focusedComp); + } + + public void enqueueEvent (KeyEvent e) + { + KeyEvent last = (KeyEvent) enqueuedKeyEvents.getLast (); + if (last != null && e.getWhen () < last.getWhen ()) + throw new RuntimeException ("KeyEvents enqueued out-of-order"); + + if (e.getWhen () <= timestamp) + throw new RuntimeException ("KeyEvents enqueued before starting timestamp"); + + enqueuedKeyEvents.add (e); + } + + public void dispatchEvents () + { + int size = enqueuedKeyEvents.size (); + for (int i = 0; i < size; i++) + { + KeyEvent e = (KeyEvent) enqueuedKeyEvents.remove (0); + dispatchKeyEvent (e); + } + } + + public void discardEvents () + { + enqueuedKeyEvents.clear (); + } } - public boolean dispatchEvent(AWTEvent e) + /** The {@link java.util.SortedSet} of current {@link + #EventDelayRequest}s. */ + private SortedSet delayRequests = new TreeSet (); + + public DefaultKeyboardFocusManager () { - throw new Error("not implemented"); } - public boolean dispatchKeyEvent(KeyEvent e) + + public boolean dispatchEvent (AWTEvent e) { - throw new Error("not implemented"); + if (e instanceof WindowEvent) + { + Window target = (Window) e.getSource (); + + if (e.id == WindowEvent.WINDOW_ACTIVATED) + setGlobalActiveWindow (target); + else if (e.id == WindowEvent.WINDOW_GAINED_FOCUS) + setGlobalFocusedWindow (target); + else if (e.id != WindowEvent.WINDOW_LOST_FOCUS + && e.id != WindowEvent.WINDOW_DEACTIVATED) + return false; + + target.dispatchEvent (e); + return true; + } + else if (e instanceof FocusEvent) + { + Component target = (Component) e.getSource (); + + if (e.id == FocusEvent.FOCUS_GAINED + && !(target instanceof Window)) + { + if (((FocusEvent) e).isTemporary ()) + setGlobalFocusOwner (target); + else + setGlobalPermanentFocusOwner (target); + } + + if (!(target instanceof Window)) + target.dispatchEvent (e); + + return true; + } + else if (e instanceof KeyEvent) + { + // Loop through all registered KeyEventDispatchers, giving + // each a chance to handle this event. + Iterator i = keyEventDispatchers.iterator (); + + while (i.hasNext ()) + { + KeyEventDispatcher dispatcher = (KeyEventDispatcher) i.next (); + if (dispatcher.dispatchKeyEvent ((KeyEvent) e)) + return true; + } + + // processKeyEvent checks if this event represents a focus + // traversal key stroke. + Component focusOwner = getGlobalPermanentFocusOwner (); + processKeyEvent (focusOwner, (KeyEvent) e); + + if (e.isConsumed ()) + return true; + + if (enqueueKeyEvent ((KeyEvent) e)) + // This event was enqueued for dispatch at a later time. + return true; + else + // This event wasn't handled by any of the registered + // KeyEventDispatchers, and wasn't enqueued for dispatch + // later, so send it to the default dispatcher. + return dispatchKeyEvent ((KeyEvent) e); + } + + return false; } - public boolean postProcessKeyEvent(KeyEvent e) + + private boolean enqueueKeyEvent (KeyEvent e) { - throw new Error("not implemented"); + Iterator i = delayRequests.iterator (); + boolean oneEnqueued = false; + while (i.hasNext ()) + { + EventDelayRequest request = (EventDelayRequest) i.next (); + if (e.getWhen () > request.timestamp) + { + request.enqueueEvent (e); + oneEnqueued = true; + } + } + return oneEnqueued; } - public void processKeyEvent(Component comp, KeyEvent e) + + public boolean dispatchKeyEvent (KeyEvent e) { - throw new Error("not implemented"); + Component focusOwner = getGlobalPermanentFocusOwner (); + + focusOwner.dispatchEvent (e); + + // Loop through all registered KeyEventPostProcessors, giving + // each a chance to process this event. + Iterator i = keyEventPostProcessors.iterator (); + + while (i.hasNext ()) + { + KeyEventPostProcessor processor = (KeyEventPostProcessor) i.next (); + if (processor.postProcessKeyEvent ((KeyEvent) e)) + return true; + } + + // The event hasn't been consumed yet. Check if it is an + // MenuShortcut. + if (postProcessKeyEvent (e)) + return true; + + // Always return true. + return true; } - protected void enqueueKeyEvents(long after, Component comp) + + public boolean postProcessKeyEvent (KeyEvent e) + { + // Check if this event represents a menu shortcut. + + // MenuShortcuts are activated by Ctrl- KeyEvents. + int modifiers = e.getModifiers (); + if ((modifiers & KeyEvent.CTRL_MASK) != 0 + || (modifiers & KeyEvent.CTRL_DOWN_MASK) != 0) + { + Window focusedWindow = getGlobalFocusedWindow (); + if (focusedWindow instanceof Frame) + { + MenuBar menubar = ((Frame) focusedWindow).getMenuBar (); + + if (menubar != null) + { + // If there's a menubar, loop through all menu items, + // checking whether each one has a shortcut, and if + // so, whether this key event should activate it. + int numMenus = menubar.getMenuCount (); + + for (int i = 0; i < numMenus; i++) + { + Menu menu = menubar.getMenu (i); + int numItems = menu.getItemCount (); + + for (int j = 0; j < numItems; j++) + { + MenuItem item = menu.getItem (j); + MenuShortcut shortcut = item.getShortcut (); + + if (shortcut != null) + { + // Dispatch a new ActionEvent if this is a + // Shift- KeyEvent and the shortcut requires + // the Shift modifier, or if the shortcut + // doesn't require the Shift modifier. + if ((shortcut.usesShiftModifier () + && ((modifiers & KeyEvent.SHIFT_MASK) != 0 + || (modifiers & KeyEvent.SHIFT_DOWN_MASK) != 0) + || !shortcut.usesShiftModifier ()) + && shortcut.getKey () == e.getKeyCode ()) + { + item.dispatchEvent (new ActionEvent (item, + ActionEvent.ACTION_PERFORMED, + item.getActionCommand (), + modifiers)); + // The event was dispatched. + return true; + } + } + } + } + } + } + } + return false; + } + + public void processKeyEvent (Component comp, KeyEvent e) + { + AWTKeyStroke eventKeystroke = AWTKeyStroke.getAWTKeyStrokeForEvent (e); + // For every focus traversal keystroke, we need to also consume + // the other two key event types for the same key (e.g. if + // KEY_PRESSED TAB is a focus traversal keystroke, we also need to + // consume KEY_RELEASED and KEY_TYPED TAB key events). + AWTKeyStroke oppositeKeystroke = AWTKeyStroke.getAWTKeyStroke (e.getKeyCode (), + e.getModifiers (), + !(e.id == KeyEvent.KEY_RELEASED)); + + Set forwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); + Set backwardKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); + Set upKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS); + Set downKeystrokes = null; + if (comp instanceof Container) + downKeystrokes = comp.getFocusTraversalKeys (KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS); + + if (forwardKeystrokes.contains (eventKeystroke)) + { + focusNextComponent (comp); + e.consume (); + } + else if (backwardKeystrokes.contains (eventKeystroke)) + { + focusPreviousComponent (comp); + e.consume (); + } + else if (upKeystrokes.contains (eventKeystroke)) + { + upFocusCycle (comp); + e.consume (); + } + else if (comp instanceof Container + && downKeystrokes.contains (eventKeystroke)) + { + downFocusCycle ((Container) comp); + e.consume (); + } + else if (forwardKeystrokes.contains (oppositeKeystroke) + || backwardKeystrokes.contains (oppositeKeystroke) + || upKeystrokes.contains (oppositeKeystroke) + || (comp instanceof Container && + downKeystrokes.contains (oppositeKeystroke))) + e.consume (); + } + + protected void enqueueKeyEvents (long after, Component untilFocused) { - throw new Error("not implemented"); + delayRequests.add (new EventDelayRequest (after, untilFocused)); } - protected void dequeueKeyEvents(long after, Component comp) + + protected void dequeueKeyEvents (long after, Component untilFocused) { - throw new Error("not implemented"); + // FIXME: need synchronization on delayRequests and enqueuedKeyEvents. + + // Remove the KeyEvent with the oldest timestamp, which should be + // the first element in the SortedSet. + if (after < 0) + { + int size = delayRequests.size (); + if (size > 0) + delayRequests.remove (delayRequests.first ()); + } + else + { + EventDelayRequest template = new EventDelayRequest (after, untilFocused); + if (delayRequests.contains (template)) + { + EventDelayRequest actual = (EventDelayRequest) delayRequests.tailSet (template).first (); + delayRequests.remove (actual); + actual.dispatchEvents (); + } + } } - protected void discardKeyEvents(Component comp) + + protected void discardKeyEvents (Component comp) { - throw new Error("not implemented"); + // FIXME: need synchronization on delayRequests and enqueuedKeyEvents. + + Iterator i = delayRequests.iterator (); + + while (i.hasNext ()) + { + EventDelayRequest request = (EventDelayRequest) i.next (); + + if (request.focusedComp == comp + || (comp instanceof Container + && ((Container) comp).isAncestorOf (request.focusedComp))) + request.discardEvents (); + } } - public void focusPreviousComponent(Component comp) + + public void focusPreviousComponent (Component comp) { - throw new Error("not implemented"); + Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; + Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); + FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); + + Component previous = policy.getComponentBefore (focusCycleRoot, focusComp); + previous.requestFocusInWindow (); } - public void focusNextComponent(Component comp) + + public void focusNextComponent (Component comp) { - throw new Error("not implemented"); + Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; + Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); + FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); + + Component next = policy.getComponentAfter (focusCycleRoot, focusComp); + next.requestFocusInWindow (); } - public void upFocusCycle(Component comp) + + public void upFocusCycle (Component comp) { - throw new Error("not implemented"); + Component focusComp = (comp == null) ? getGlobalFocusOwner () : comp; + Container focusCycleRoot = focusComp.getFocusCycleRootAncestor (); + + if (focusCycleRoot instanceof Window) + { + FocusTraversalPolicy policy = focusCycleRoot.getFocusTraversalPolicy (); + Component defaultComponent = policy.getDefaultComponent (focusCycleRoot); + defaultComponent.requestFocusInWindow (); + } + else + { + Container parentFocusCycleRoot = focusCycleRoot.getFocusCycleRootAncestor (); + + focusCycleRoot.requestFocusInWindow (); + setGlobalCurrentFocusCycleRoot (parentFocusCycleRoot); + } } - public void downFocusCycle(Container cont) + + public void downFocusCycle (Container cont) { - throw new Error("not implemented"); + if (cont == null) + return; + + if (cont.isFocusCycleRoot (cont)) + { + FocusTraversalPolicy policy = cont.getFocusTraversalPolicy (); + Component defaultComponent = policy.getDefaultComponent (cont); + defaultComponent.requestFocusInWindow (); + setGlobalCurrentFocusCycleRoot (cont); + } } } // class DefaultKeyboardFocusManager diff --git a/libjava/java/awt/EventDispatchThread.java b/libjava/java/awt/EventDispatchThread.java index 91145e1..89b6095 100644 --- a/libjava/java/awt/EventDispatchThread.java +++ b/libjava/java/awt/EventDispatchThread.java @@ -67,7 +67,17 @@ class EventDispatchThread extends Thread // We are interrupted when we should finish executing return; } - queue.dispatchEvent(evt); + + KeyboardFocusManager manager; + manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + // Try to dispatch this event to the current keyboard focus + // manager. It will dispatch all FocusEvents, all + // WindowEvents related to focus, and all KeyEvents, + // returning true. Otherwise, it returns false and we + // dispatch the event normally. + if (!manager.dispatchEvent (evt)) + queue.dispatchEvent(evt); } catch (InterruptedException ie) { diff --git a/libjava/java/awt/Image.java b/libjava/java/awt/Image.java index d4b75b8..451b092 100644 --- a/libjava/java/awt/Image.java +++ b/libjava/java/awt/Image.java @@ -39,6 +39,7 @@ exception statement from your version. */ package java.awt; import java.awt.image.AreaAveragingScaleFilter; +import java.awt.image.FilteredImageSource; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.ReplicateScaleFilter; @@ -179,7 +180,20 @@ public abstract class Image */ public Image getScaledInstance(int width, int height, int flags) { - throw new Error("not implemented"); + switch (flags) + { + case SCALE_DEFAULT: + case SCALE_FAST: + case SCALE_REPLICATE: + ImageProducer producer = + new FilteredImageSource(this.getSource(), + new ReplicateScaleFilter(width, height)); + return Toolkit.getDefaultToolkit().createImage(producer); + case SCALE_SMOOTH: + case SCALE_AREA_AVERAGING: + default: + throw new Error("not implemented"); + } } /** diff --git a/libjava/java/awt/KeyboardFocusManager.java b/libjava/java/awt/KeyboardFocusManager.java index 867316b..8ebd9e171 100644 --- a/libjava/java/awt/KeyboardFocusManager.java +++ b/libjava/java/awt/KeyboardFocusManager.java @@ -39,34 +39,66 @@ exception statement from your version. */ package java.awt; import java.awt.event.KeyEvent; +import java.awt.event.FocusEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyVetoException; import java.beans.VetoableChangeListener; import java.beans.VetoableChangeSupport; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; +// FIXME: finish documentation + /** * + * FIXME: discuss applet contexts and thread groups and codebases + * being insulated. + * + * FIXME: discuss where default focus traversal key sets apply + * (inherited by child Components etc.) + * * @author Eric Blake <ebb9@email.byu.edu> + * @author Thomas Fitzsimmons <fitzsim@redhat.com> * @since 1.4 * @status partially updated to 1.4, needs documentation. */ public abstract class KeyboardFocusManager implements KeyEventDispatcher, KeyEventPostProcessor { + /** Identifies {@link AWTKeyStroke}s that move the focus forward in + the focus cycle. */ public static final int FORWARD_TRAVERSAL_KEYS = 0; + + /** Identifies {@link AWTKeyStroke}s that move the focus backward in + the focus cycle. */ public static final int BACKWARD_TRAVERSAL_KEYS = 1; + + /** Identifies {@link AWTKeyStroke}s that move the focus up to the + parent focus cycle root. */ public static final int UP_CYCLE_TRAVERSAL_KEYS = 2; + + /** Identifies {@link AWTKeyStroke}s that move the focus down to the + child focus cycle root. */ public static final int DOWN_CYCLE_TRAVERSAL_KEYS = 3; + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the next focusable Component in the focus cycle. */ private static final Set DEFAULT_FORWARD_KEYS; + + /** The set of {@link AWTKeyStroke}s that cause focus to be moved to + the previous focusable Component in the focus cycle. */ private static final Set DEFAULT_BACKWARD_KEYS; + + /** Populate the DEFAULT_FORWARD_KEYS and DEFAULT_BACKWARD_KEYS + {@link java.util.Set}s. */ static { Set s = new HashSet(); @@ -83,232 +115,402 @@ public abstract class KeyboardFocusManager DEFAULT_BACKWARD_KEYS = Collections.unmodifiableSet(s); } - private static KeyboardFocusManager current - = new DefaultKeyboardFocusManager(); - - // XXX Not implemented correctly. I think a good implementation here may - // be to have permanentFocusOwner be null, and fall back to focusOwner, - // unless a temporary focus change is in effect. - private static Component focusOwner; - private static Component permanentFocusOwner; - - private static Window focusedWindow; - private static Window activeWindow; - private static Container focusCycleRoot; - + /** The global object {@link java.util.Map}s. */ + + /** For security reasons, {@link java.applet.Applet}s in different + codebases must be insulated from one another. Since {@link + KeyboardFocusManager}s have the ability to return {@link + Component}s from a given {@link java.applet.Applet}, each + codebase must have an independent {@link KeyboardFocusManager}. + Since each codebase has its own {@link ThreadGroup} in which its + {@link Applet}s run, it makes sense to partition {@link + KeyboardFocusManager}s according to {@link + java.lang.ThreadGroup}. Thus, currentKeyboardFocusManagers is a + {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}. */ + private static Map currentKeyboardFocusManagers = new HashMap (); + + /** {@link java.applet.Applet}s in one codebase must not be allowed + to access {@link Component}s in {@link java.applet.Applet}s in + other codebases. To enforce this restriction, we key the + following {@link java.util.Map}s on {@link java.lang.ThreadGroup}s (which + are per-codebase). For example, if {@link + java.lang.ThreadGroup} A calls {@link #setGlobalFocusOwner}, + passing {@link Component} C, currentFocusOwners[A] is assigned + C, and all other currentFocusOwners values are nullified. Then + if {@link java.lang.ThreadGroup} A subsequently calls {@link + #getGlobalFocusOwner}, it will return currentFocusOwners[A], + that is, {@link Component} C. If another {@link + java.lang.ThreadGroup} K calls {@link #getGlobalFocusOwner}, it + will return currentFocusOwners[K], that is, null. + + Since this is a static field, we ensure that there is only one + focused {@link Component} per class loader. */ + private static Map currentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the {@link Component} that owns the permanent + keyboard focus. @see currentFocusOwners */ + private static Map currentPermanentFocusOwners = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focused {@link Window}. @see + currentFocusOwners */ + private static Map currentFocusedWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the active {@link Window}. @see + currentFocusOwners */ + private static Map currentActiveWindows = new HashMap (); + + /** A {@link java.util.Map} keyed on {@link java.lang.ThreadGroup}s + that stores the focus cycle root {@link Container}. @see + currentFocusOwners */ + private static Map currentFocusCycleRoots = new HashMap (); + + /** The default {@link FocusTraveralPolicy} that focus-managing + {@link Container}s will use to define their initial focus + traversal policy. */ private FocusTraversalPolicy defaultPolicy; - private Set[] defaultFocusKeys = new Set[] { + + /** An array that stores the {@link #FORWARD_TRAVERSAL_KEYS}, {@link + #BACKWARD_TRAVERSAL_KEYS}, {@link #UP_CYCLE_TRAVERSAL_KEYS} and + {@link #DOWN_CYCLE_TRAVERSAL_KEYS} {@link AWTKeyStroke}s {@link + java.util.Set}s. */ + private Set[] defaultFocusKeys = new Set[] + { DEFAULT_FORWARD_KEYS, DEFAULT_BACKWARD_KEYS, Collections.EMPTY_SET, Collections.EMPTY_SET }; - private final PropertyChangeSupport propertyChangeSupport - = new PropertyChangeSupport(this); - private final VetoableChangeSupport vetoableChangeSupport - = new VetoableChangeSupport(this); + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (this); + private final VetoableChangeSupport vetoableChangeSupport = new VetoableChangeSupport (this); + + /** A list of {@link KeyEventDispatcher}s that process {@link + KeyEvent}s before they are processed the default keyboard focus + manager. */ private final ArrayList keyEventDispatchers = new ArrayList(); + + /** A list of {@link KeyEventPostProcessor}s that process unconsumed + {@link KeyEvent}s. */ private final ArrayList keyEventPostProcessors = new ArrayList(); - - public KeyboardFocusManager() + /** + * Construct a KeyboardFocusManager. + */ + public KeyboardFocusManager () { } - public static KeyboardFocusManager getCurrentKeyboardFocusManager() + /** + * Retrieve the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @return the keyboard focus manager associated with the current + * thread group + */ + public static KeyboardFocusManager getCurrentKeyboardFocusManager () { - // XXX Need a way to divide this into contexts. - return current; + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + return (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); } - public static void setCurrentKeyboardFocusManager(KeyboardFocusManager m) + /** + * Set the keyboard focus manager associated with the {@link + * java.lang.ThreadGroup} to which the calling thread belongs. + * + * @param m the keyboard focus manager for the current thread group + */ + public static void setCurrentKeyboardFocusManager (KeyboardFocusManager m) { - SecurityManager sm = System.getSecurityManager(); + SecurityManager sm = System.getSecurityManager (); if (sm != null) - sm.checkPermission(new AWTPermission("replaceKeyboardFocusManager")); - // XXX Need a way to divide this into contexts. - current = m == null ? new DefaultKeyboardFocusManager() : m; - } - - public Component getFocusOwner() + sm.checkPermission (new AWTPermission ("replaceKeyboardFocusManager")); + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager manager; + + if (m == null) + manager = new DefaultKeyboardFocusManager (); + else + manager = m; + + currentKeyboardFocusManagers.put (currentGroup, manager); + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, or + * null if the focus owner was not set by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getFocusOwner () + { + return (Component) getObject (currentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the keyboard focus, + * regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. If there is no temporary + * focus owner in effect then this method will return the same value + * as {@link #getGlobalPermanentFocusOwner}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalFocusOwner () + { + // Check if there is a temporary focus owner. + Component focusOwner = (Component) getGlobalObject (currentFocusOwners); + + return (focusOwner == null) ? getGlobalPermanentFocusOwner () : focusOwner; + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getFocusOwner} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusOwner}. This + * method does not actually transfer the keyboard focus. + * + * @param owner the Component to return from getFocusOwner and + * getGlobalFocusOwner + * + * @see Component.requestFocus () + * @see Component.requestFocusInWindow () + */ + protected void setGlobalFocusOwner (Component owner) { - // XXX Need an easy way to test if this thread is in the context of the - // global focus owner, to avoid creating the exception in the first place. - try - { - return getGlobalFocusOwner(); - } - catch (SecurityException e) - { - return null; - } - } - - protected Component getGlobalFocusOwner() - { - // XXX Need a way to test if this thread is in the context of the focus - // owner, and throw a SecurityException if that is the case. - // XXX Implement. - return focusOwner; - } - - protected void setGlobalFocusOwner(Component owner) - { - // XXX Should this send focus events to the components involved? if (owner == null || owner.focusable) - { - firePropertyChange("focusOwner", focusOwner, owner); - try - { - fireVetoableChange("focusOwner", focusOwner, owner); - focusOwner = owner; - } - catch (PropertyVetoException e) - { - } - } - } - - public void clearGlobalFocusOwner() - { - // XXX Is this enough? - setGlobalFocusOwner(null); + setGlobalObject (currentFocusOwners, owner, "focusOwner"); } - public Component getPermanentFocusOwner() + /** + * Clear the global focus owner and deliver a FOCUS_LOST event to + * the previously-focused {@link Component}. Until another {@link + * Component} becomes the keyboard focus owner, key events will be + * discarded by top-level windows. + */ + public void clearGlobalFocusOwner () { - // XXX Need an easy way to test if this thread is in the context of the - // global focus owner, to avoid creating the exception in the first place. - try + synchronized (currentFocusOwners) { - return getGlobalPermanentFocusOwner(); - } - catch (SecurityException e) - { - return null; - } - } + Component focusOwner = getGlobalFocusOwner (); + Component permanentFocusOwner = getGlobalPermanentFocusOwner (); - protected Component getGlobalPermanentFocusOwner() - { - // XXX Need a way to test if this thread is in the context of the focus - // owner, and throw a SecurityException if that is the case. - // XXX Implement. - return permanentFocusOwner == null ? focusOwner : permanentFocusOwner; - } + setGlobalFocusOwner (null); + setGlobalPermanentFocusOwner (null); - protected void setGlobalPermanentFocusOwner(Component focusOwner) - { - // XXX Should this send focus events to the components involved? - if (focusOwner == null || focusOwner.focusable) - { - firePropertyChange("permanentFocusOwner", permanentFocusOwner, - focusOwner); - try + // Inform the old focus owner that it has lost permanent + // focus. + if (focusOwner != null) { - fireVetoableChange("permanentFocusOwner", permanentFocusOwner, - focusOwner); - permanentFocusOwner = focusOwner; + // We can't cache the event queue, because of + // bootstrapping issues. We need to set the default + // KeyboardFocusManager in EventQueue before the event + // queue is started. + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + if (focusOwner != permanentFocusOwner) + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, true)); + else + q.postEvent (new FocusEvent (focusOwner, FocusEvent.FOCUS_LOST, false)); } - catch (PropertyVetoException e) + + if (focusOwner != permanentFocusOwner) { + EventQueue q = Toolkit.getDefaultToolkit ().getSystemEventQueue (); + q.postEvent (new FocusEvent (permanentFocusOwner, FocusEvent.FOCUS_LOST, false)); } } } - public Window getFocusedWindow() + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, or null if the focus owner was not set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner or null + */ + public Component getPermanentFocusOwner () + { + return (Component) getObject (currentPermanentFocusOwners); + } + + /** + * Retrieve the {@link Component} that has the permanent keyboard + * focus, regardless of whether or not it was set by a thread in the + * current {@link java.lang.ThreadGroup}. + * + * @return the keyboard focus owner + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Component getGlobalPermanentFocusOwner () + { + return (Component) getGlobalObject (currentPermanentFocusOwners); + } + + /** + * Set the {@link Component} that will be returned by {@link + * #getPermanentFocusOwner} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalPermanentFocusOwner}. This method does not actually + * transfer the keyboard focus. + * + * @param focusOwner the Component to return from + * getPermanentFocusOwner and getGlobalPermanentFocusOwner + * + * @see Component.requestFocus () + * @see Component.requestFocusInWindow () + */ + protected void setGlobalPermanentFocusOwner (Component focusOwner) { - // XXX Need an easy way to test if this thread is in the context of the - // global focus owner, to avoid creating the exception in the first place. - try - { - return getGlobalFocusedWindow(); - } - catch (SecurityException e) - { - return null; - } - } - - protected Window getGlobalFocusedWindow() - { - // XXX Need a way to test if this thread is in the context of the focus - // owner, and throw a SecurityException if that is the case. - // XXX Implement. - return focusedWindow; - } - - protected void setGlobalFocusedWindow(Window window) + if (focusOwner == null || focusOwner.focusable) + setGlobalObject (currentPermanentFocusOwners, focusOwner, + "permanentFocusOwner"); + } + + /** + * Retrieve the {@link Window} that is or contains the keyboard + * focus owner, or null if the focused window was not set by a + * thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window or null + */ + public Window getFocusedWindow () + { + return (Window) getObject (currentFocusedWindows); + } + + /** + * Retrieve the {@link Window} that is or contains the focus owner, + * regardless of whether or not the {@link Window} was set focused + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @return the focused window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Window getGlobalFocusedWindow () + { + return (Window) getGlobalObject (currentFocusedWindows); + } + + /** + * Set the {@link Window} that will be returned by {@link + * #getFocusedWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalFocusedWindow}. + * This method does not actually cause <code>window</code> to become + * the focused {@link Window}. + * + * @param window the Window to return from getFocusedWindow and + * getGlobalFocusedWindow + */ + protected void setGlobalFocusedWindow (Window window) { - // XXX Should this send focus events to the windows involved? if (window == null || window.focusable) - { - firePropertyChange("focusedWindow", focusedWindow, window); - try - { - fireVetoableChange("focusedWindow", focusedWindow, window); - focusedWindow = window; - } - catch (PropertyVetoException e) - { - } - } + setGlobalObject (currentFocusedWindows, window, "focusedWindow"); } + /** + * Retrieve the active {@link Window}, or null if the active window + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the active window or null + */ public Window getActiveWindow() { - // XXX Need an easy way to test if this thread is in the context of the - // global focus owner, to avoid creating the exception in the first place. - try - { - return getGlobalActiveWindow(); - } - catch (SecurityException e) - { - return null; - } + return (Window) getObject (currentActiveWindows); } + /** + * Retrieve the active {@link Window}, regardless of whether or not + * the {@link Window} was made active by a thread in the current + * {@link java.lang.ThreadGroup}. + * + * @return the active window + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ protected Window getGlobalActiveWindow() { - // XXX Need a way to test if this thread is in the context of the focus - // owner, and throw a SecurityException if that is the case. - // XXX Implement. - return activeWindow; + return (Window) getGlobalObject (currentActiveWindows); } + /** + * Set the {@link Window} that will be returned by {@link + * #getActiveWindow} (when it is called from the current {@link + * java.lang.ThreadGroup}) and {@link #getGlobalActiveWindow}. This + * method does not actually cause <code>window</code> to be made + * active. + * + * @param window the Window to return from getActiveWindow and + * getGlobalActiveWindow + */ protected void setGlobalActiveWindow(Window window) { - // XXX Should this send focus events to the windows involved? - firePropertyChange("activeWindow", activeWindow, window); - try - { - fireVetoableChange("activeWindow", activeWindow, window); - activeWindow = window; - } - catch (PropertyVetoException e) - { - } + setGlobalObject (currentActiveWindows, window, "activeWindow"); } - public FocusTraversalPolicy getDefaultFocusTraversalPolicy() + /** + * Retrieve the default {@link FocusTraversalPolicy}. + * Focus-managing {@link Container}s use the returned object to + * define their initial focus traversal policy. + * + * @return a non-null default FocusTraversalPolicy object + */ + public FocusTraversalPolicy getDefaultFocusTraversalPolicy () { if (defaultPolicy == null) - defaultPolicy = new DefaultFocusTraversalPolicy(); + defaultPolicy = new DefaultFocusTraversalPolicy (); return defaultPolicy; } - public void setDefaultFocusTraversalPolicy(FocusTraversalPolicy policy) + /** + * Set the {@link FocusTraversalPolicy} returned by {@link + * #getDefaultFocusTraversalPolicy}. Focus-managing {@link + * Container}s created after this call will use policy as their + * initial focus traversal policy. Existing {@link Container}s' + * focus traversal policies will not be affected by calls to this + * method. + * + * @param policy the FocusTraversalPolicy that will be returned by + * subsequent calls to getDefaultFocusTraversalPolicy + * @throws IllegalArgumentException if policy is null + */ + public void setDefaultFocusTraversalPolicy (FocusTraversalPolicy policy) { if (policy == null) - throw new IllegalArgumentException(); - firePropertyChange("defaultFocusTraversalPolicy", defaultPolicy, policy); + throw new IllegalArgumentException (); + firePropertyChange ("defaultFocusTraversalPolicy", defaultPolicy, policy); defaultPolicy = policy; } - public void setDefaultFocusTraversalKeys(int id, Set keystrokes) - { + /** + * Set the default {@link java.util.Set} of focus traversal keys for + * one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * @param keystrokes set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public void setDefaultFocusTraversalKeys (int id, Set keystrokes) + { + if (id != KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS && + id != KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS && + id != KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS) + throw new IllegalArgumentException (); + if (keystrokes == null) - throw new IllegalArgumentException(); + throw new IllegalArgumentException (); + Set sa; Set sb; Set sc; @@ -340,56 +542,82 @@ public abstract class KeyboardFocusManager type = "downCycleDefaultFocusTraversalKeys"; break; default: - throw new IllegalArgumentException(); + throw new IllegalArgumentException (); } - int i = keystrokes.size(); - Iterator iter = keystrokes.iterator(); + int i = keystrokes.size (); + Iterator iter = keystrokes.iterator (); while (--i >= 0) { - Object o = iter.next(); - if (! (o instanceof AWTKeyStroke) - || sa.contains(o) || sb.contains(o) || sc.contains(o) + Object o = iter.next (); + if (!(o instanceof AWTKeyStroke) + || sa.contains (o) || sb.contains (o) || sc.contains (o) || ((AWTKeyStroke) o).keyCode == KeyEvent.VK_UNDEFINED) - throw new IllegalArgumentException(); + throw new IllegalArgumentException (); } - keystrokes = Collections.unmodifiableSet(new HashSet(keystrokes)); - firePropertyChange(type, defaultFocusKeys[id], keystrokes); + keystrokes = Collections.unmodifiableSet (new HashSet (keystrokes)); + firePropertyChange (type, defaultFocusKeys[id], keystrokes); defaultFocusKeys[id] = keystrokes; } - public Set getDefaultFocusTraversalKeys(int id) + /** + * Retrieve the default {@link java.util.Set} of focus traversal + * keys for one of the focus traversal directions. + * + * @param id focus traversal direction identifier + * + * @return the default set of AWTKeyStrokes + * + * @see #FORWARD_TRAVERSAL_KEYS + * @see #BACKWARD_TRAVERSAL_KEYS + * @see #UP_CYCLE_TRAVERSAL_KEYS + * @see #DOWN_CYCLE_TRAVERSAL_KEYS + */ + public Set getDefaultFocusTraversalKeys (int id) { if (id < FORWARD_TRAVERSAL_KEYS || id > DOWN_CYCLE_TRAVERSAL_KEYS) - throw new IllegalArgumentException(); + throw new IllegalArgumentException (); return defaultFocusKeys[id]; } - public Container getCurrentFocusCycleRoot() + /** + * Retrieve the current focus cycle root, or null if the focus owner + * was not set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root or null + */ + public Container getCurrentFocusCycleRoot () { - // XXX Need an easy way to test if this thread is in the context of the - // global focus owner, to avoid creating the exception in the first place. - try - { - return getGlobalCurrentFocusCycleRoot(); - } - catch (SecurityException e) - { - return null; - } + return (Container) getObject (currentFocusCycleRoots); } - protected Container getGlobalCurrentFocusCycleRoot() + /** + * Retrieve the current focus cycle root, regardless of whether or + * not it was made set by a thread in the current {@link + * java.lang.ThreadGroup}. + * + * @return the current focus cycle root + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + */ + protected Container getGlobalCurrentFocusCycleRoot () { - // XXX Need a way to test if this thread is in the context of the focus - // owner, and throw a SecurityException if that is the case. - // XXX Implement. - return focusCycleRoot; + return (Container) getGlobalObject (currentFocusCycleRoots); } - public void setGlobalCurrentFocusCycleRoot(Container cycleRoot) + /** + * Set the {@link Container} that will be returned by {@link + * #getCurrentFocusCycleRoot} (when it is called from the current + * {@link java.lang.ThreadGroup}) and {@link + * #getGlobalCurrentFocusCycleRoot}. This method does not actually + * make <code>cycleRoot</code> the current focus cycle root. + * + * @param cycleRoot the focus cycle root to return from + * getCurrentFocusCycleRoot and getGlobalCurrentFocusCycleRoot + */ + public void setGlobalCurrentFocusCycleRoot (Container cycleRoot) { - firePropertyChange("currentFocusCycleRoot", focusCycleRoot, cycleRoot); - focusCycleRoot = cycleRoot; + setGlobalObject (currentFocusCycleRoots, cycleRoot, "currentFocusCycleRoot"); } public void addPropertyChangeListener(PropertyChangeListener l) @@ -484,73 +712,196 @@ public abstract class KeyboardFocusManager keyEventDispatchers.remove(dispatcher); } - protected List getKeyEventDispatchers() + protected List getKeyEventDispatchers () { - return (List) keyEventDispatchers.clone(); + return (List) keyEventDispatchers.clone (); } - public void addKeyEventPostProcessor(KeyEventPostProcessor postProcessor) + public void addKeyEventPostProcessor (KeyEventPostProcessor postProcessor) { if (postProcessor != null) - keyEventPostProcessors.add(postProcessor); + keyEventPostProcessors.add (postProcessor); } - public void removeKeyEventPostProcessor(KeyEventPostProcessor postProcessor) + public void removeKeyEventPostProcessor (KeyEventPostProcessor postProcessor) { - keyEventPostProcessors.remove(postProcessor); + keyEventPostProcessors.remove (postProcessor); } - protected List getKeyEventPostProcessors() + protected List getKeyEventPostProcessors () { - return (List) keyEventPostProcessors.clone(); + return (List) keyEventPostProcessors.clone (); } - public abstract boolean dispatchEvent(AWTEvent e); + public abstract boolean dispatchEvent (AWTEvent e); - public final void redispatchEvent(Component target, AWTEvent e) + public final void redispatchEvent (Component target, AWTEvent e) { - throw new Error("not implemented"); + e.setSource (target); + dispatchEvent (e); } - public abstract boolean dispatchKeyEvent(KeyEvent e); + public abstract boolean dispatchKeyEvent (KeyEvent e); - public abstract boolean postProcessKeyEvent(KeyEvent e); + public abstract boolean postProcessKeyEvent (KeyEvent e); - public abstract void processKeyEvent(Component focused, KeyEvent e); + public abstract void processKeyEvent (Component focused, KeyEvent e); - protected abstract void enqueueKeyEvents(long after, Component untilFocused); + protected abstract void enqueueKeyEvents (long after, Component untilFocused); - protected abstract void dequeueKeyEvents(long after, Component untilFocused); + protected abstract void dequeueKeyEvents (long after, Component untilFocused); - protected abstract void discardKeyEvents(Component comp); + protected abstract void discardKeyEvents (Component comp); - public abstract void focusNextComponent(Component comp); + public abstract void focusNextComponent (Component comp); - public abstract void focusPreviousComponent(Component comp); + public abstract void focusPreviousComponent (Component comp); - public abstract void upFocusCycle(Component comp); + public abstract void upFocusCycle (Component comp); - public abstract void downFocusCycle(Container cont); + public abstract void downFocusCycle (Container cont); - public final void focusNextComponent() + public final void focusNextComponent () { - focusNextComponent(focusOwner); + focusNextComponent (null); } - public final void focusPreviousComponent() + public final void focusPreviousComponent () { - focusPreviousComponent(focusOwner); + focusPreviousComponent (null); } - public final void upFocusCycle() + public final void upFocusCycle () { - upFocusCycle(focusOwner); + upFocusCycle (null); } - public final void downFocusCycle() + public final void downFocusCycle () { + Component focusOwner = getGlobalFocusOwner (); if (focusOwner instanceof Container - && ((Container) focusOwner).isFocusCycleRoot()) - downFocusCycle((Container) focusOwner); + && ((Container) focusOwner).isFocusCycleRoot ()) + downFocusCycle ((Container) focusOwner); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, if the object was set by the a thread in the + * current {@link java.lang.ThreadGroup}. Otherwise, return null. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @see getFocusOwner + * @see getPermanentFocusOwner + * @see getFocusedWindow + * @see getActiveWindow + * @see getCurrentFocusCycleRoot + */ + private Object getObject (Map globalMap) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + return globalMap.get (currentGroup); + } + + /** + * Retrieve an object from one of the global object {@link + * java.util.Map}s, regardless of whether or not the object was set + * by a thread in the current {@link java.lang.ThreadGroup}. + * + * @param globalMap one of the global object Maps + * + * @return a global object set by the current ThreadGroup, or null + * + * @throws SecurityException if this is not the keyboard focus + * manager associated with the current {@link java.lang.ThreadGroup} + * + * @see getGlobalFocusOwner + * @see getGlobalPermanentFocusOwner + * @see getGlobalFocusedWindow + * @see getGlobalActiveWindow + * @see getGlobalCurrentFocusCycleRoot + */ + private Object getGlobalObject (Map globalMap) + { + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + KeyboardFocusManager managerForCallingThread + = (KeyboardFocusManager) currentKeyboardFocusManagers.get (currentGroup); + + if (this != managerForCallingThread) + throw new SecurityException ("Attempted to retrieve an object from a " + + "keyboard focus manager that isn't " + + "associated with the current thread group."); + + synchronized (globalMap) + { + Collection globalObjects = globalMap.values (); + Iterator i = globalObjects.iterator (); + Component globalObject; + + while (i.hasNext ()) + { + globalObject = (Component) i.next (); + if (globalObject != null) + return globalObject; + } + } + + // No Object was found. + return null; + } + + /** + * Set an object in one of the global object {@link java.util.Map}s, + * that will be returned by subsequent calls to getGlobalObject on + * the same {@link java.util.Map}. + * + * @param globalMap one of the global object Maps + * @param newObject the object to set + * @param property the property that will change + * + * @see setGlobalFocusOwner + * @see setGlobalPermanentFocusOwner + * @see setGlobalFocusedWindow + * @see setGlobalActiveWindow + * @see setGlobalCurrentFocusCycleRoot + */ + private void setGlobalObject (Map globalMap, + Object newObject, + String property) + { + synchronized (globalMap) + { + // Save old object. + Object oldObject = getGlobalObject (globalMap); + + // Nullify old object. + Collection threadGroups = globalMap.keySet (); + Iterator i = threadGroups.iterator (); + while (i.hasNext ()) + { + ThreadGroup oldThreadGroup = (ThreadGroup) i.next (); + if (globalMap.get (oldThreadGroup) != null) + { + globalMap.put (oldThreadGroup, null); + // There should only be one object set at a time, so + // we can short circuit. + break; + } + } + + ThreadGroup currentGroup = Thread.currentThread ().getThreadGroup (); + firePropertyChange (property, oldObject, newObject); + try + { + fireVetoableChange (property, oldObject, newObject); + // Set new object. + globalMap.put (currentGroup, newObject); + } + catch (PropertyVetoException e) + { + } + } } -} // class KeyboardFocusManager +} diff --git a/libjava/java/awt/TextArea.java b/libjava/java/awt/TextArea.java index 6f60ee6..f27c296 100644 --- a/libjava/java/awt/TextArea.java +++ b/libjava/java/awt/TextArea.java @@ -39,6 +39,9 @@ package java.awt; import java.awt.peer.ComponentPeer; import java.awt.peer.TextAreaPeer; +import java.awt.event.KeyEvent; +import java.util.HashSet; +import java.util.Set; /** @@ -193,11 +196,19 @@ public class TextArea extends TextComponent implements java.io.Serializable this.rows = rows; this.columns = columns; this.scrollbarVisibility = scrollbarVisibility; - } - /* - * Instance Variables - */ + // TextAreas need to receive tab key events so we override the + // default forward and backward traversal key sets. + Set s = new HashSet (); + s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB, + KeyEvent.CTRL_DOWN_MASK)); + setFocusTraversalKeys (KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, s); + s = new HashSet (); + s.add (AWTKeyStroke.getAWTKeyStroke (KeyEvent.VK_TAB, + KeyEvent.SHIFT_DOWN_MASK + | KeyEvent.CTRL_DOWN_MASK)); + setFocusTraversalKeys (KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, s); + } /** * Retrieve the number of columns that this text area would prefer @@ -431,10 +442,8 @@ public class TextArea extends TextComponent implements java.io.Serializable */ public void addNotify () { - if (getPeer () != null) - return; - - setPeer ((ComponentPeer) getToolkit().createTextArea (this)); + if (getPeer () == null) + setPeer ((ComponentPeer) getToolkit().createTextArea (this)); } /** @@ -458,10 +467,9 @@ public class TextArea extends TextComponent implements java.io.Serializable public void appendText (String str) { TextAreaPeer peer = (TextAreaPeer) getPeer (); - if (peer == null) - return; - peer.insert (str, peer.getText().length ()); + if (peer != null) + peer.insert (str, peer.getText().length ()); } /** @@ -489,10 +497,9 @@ public class TextArea extends TextComponent implements java.io.Serializable public void insertText (String str, int pos) { TextAreaPeer peer = (TextAreaPeer) getPeer (); - if (peer == null) - return; - peer.insert (str, pos); + if (peer != null) + peer.insert (str, pos); } /** @@ -530,10 +537,9 @@ public class TextArea extends TextComponent implements java.io.Serializable public void replaceText (String str, int start, int end) { TextAreaPeer peer = (TextAreaPeer) getPeer (); - if (peer == null) - return; - peer.replaceRange (str, start, end); + if (peer != null) + peer.replaceRange (str, start, end); } /** diff --git a/libjava/java/awt/Window.java b/libjava/java/awt/Window.java index 81e37fc..51b00dc 100644 --- a/libjava/java/awt/Window.java +++ b/libjava/java/awt/Window.java @@ -83,6 +83,8 @@ public class Window extends Container implements Accessible private transient GraphicsConfiguration graphicsConfiguration; private transient AccessibleContext accessibleContext; + private transient boolean shown; + /** * This (package access) constructor is used by subclasses that want * to build windows that do not have parents. Eg. toplevel @@ -92,6 +94,9 @@ public class Window extends Container implements Accessible Window() { visible = false; + // Windows are the only Containers that default to being focus + // cycle roots. + focusCycleRoot = true; setLayout(new BorderLayout()); } @@ -242,6 +247,23 @@ public class Window extends Container implements Accessible validate(); super.show(); toFront(); + + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + manager.setGlobalFocusedWindow (this); + + if (!shown) + { + FocusTraversalPolicy policy = getFocusTraversalPolicy (); + Component initialFocusOwner = null; + + if (policy != null) + initialFocusOwner = policy.getInitialComponent (this); + + if (initialFocusOwner != null) + initialFocusOwner.requestFocusInWindow (false); + + shown = true; + } } public void hide() @@ -627,9 +649,16 @@ public class Window extends Container implements Accessible * @return The component that has focus, or <code>null</code> if no * component has focus. */ - public Component getFocusOwner() + public Component getFocusOwner () { - // FIXME + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + + Window activeWindow = manager.getActiveWindow (); + + // The currently-focused Component belongs to the active Window. + if (activeWindow == this) + return manager.getFocusOwner (); + return null; } diff --git a/libjava/java/awt/image/CropImageFilter.java b/libjava/java/awt/image/CropImageFilter.java index 8ffc148..c9a170b 100644 --- a/libjava/java/awt/image/CropImageFilter.java +++ b/libjava/java/awt/image/CropImageFilter.java @@ -39,6 +39,7 @@ exception statement from your version. */ package java.awt.image; import java.util.Hashtable; +import java.awt.Rectangle; /** * <br> @@ -92,7 +93,7 @@ public class CropImageFilter extends ImageFilter */ public void setProperties(Hashtable props) { -// props.put("filters", "ReplicateScaleFilter"); + props.put("filters", "CropImageFilter"); consumer.setProperties(props); } @@ -113,7 +114,27 @@ public class CropImageFilter extends ImageFilter public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int offset, int scansize) { - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + Rectangle filterBounds = new Rectangle(this.x, this.y, + this.width, this.height); + Rectangle pixelBounds = new Rectangle(x, y, w, h); + + if (filterBounds.intersects(pixelBounds)) + { + Rectangle bounds = filterBounds.intersection(pixelBounds); + + byte[] cropped = new byte[bounds.width * bounds.height]; + for (int i = 0; i < bounds.height; i++) + { + int start = (bounds.y - pixelBounds.y + i) * scansize + offset; + + for (int j = 0; j < bounds.width; j++) + cropped[i * bounds.width + j] = pixels[start + bounds.x + j]; + } + + consumer.setPixels(bounds.x, bounds.y, + bounds.width, bounds.height, + model, cropped, 0, bounds.width); + } } /** @@ -133,7 +154,27 @@ public class CropImageFilter extends ImageFilter public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int offset, int scansize) { - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + Rectangle filterBounds = new Rectangle(this.x, this.y, + this.width, this.height); + Rectangle pixelBounds = new Rectangle(x, y, w, h); + + if (filterBounds.intersects(pixelBounds)) + { + Rectangle bounds = filterBounds.intersection(pixelBounds); + + int[] cropped = new int[bounds.width * bounds.height]; + for (int i = 0; i < bounds.height; i++) + { + int start = (bounds.y - pixelBounds.y + i) * scansize + offset; + + for (int j = 0; j < bounds.width; j++) + cropped[i * bounds.width + j] = pixels[start + bounds.x + j]; + } + + consumer.setPixels(bounds.x, bounds.y, + bounds.width, bounds.height, + model, cropped, 0, bounds.width); + } } } diff --git a/libjava/java/awt/image/MemoryImageSource.java b/libjava/java/awt/image/MemoryImageSource.java index 5006afe..d861199 100644 --- a/libjava/java/awt/image/MemoryImageSource.java +++ b/libjava/java/awt/image/MemoryImageSource.java @@ -257,9 +257,15 @@ public class MemoryImageSource implements ImageProducer ic.setProperties( props ); } if( pixeli != null ) { - ic.setPixels( 0, 0, width, height, cm, pixeli, offset, scansize ); + int[] pixelbuf = new int[w * h]; + for (int row = y; row < h; row++) + System.arraycopy(pixeli, row * scansize + x + offset, pixelbuf, row * w, w); + ic.setPixels( x, y, w, h, cm, pixelbuf, 0, w ); } else { - ic.setPixels( 0, 0, width, height, cm, pixelb, offset, scansize ); + byte[] pixelbuf = new byte[w * h]; + for (int row = y; row < h; row++) + System.arraycopy(pixelb, row * scansize + x + offset, pixelbuf, row * w, w); + ic.setPixels( x, y, w, h, cm, pixelbuf, 0, w ); } ic.imageComplete( ImageConsumer.SINGLEFRAME ); } @@ -296,9 +302,15 @@ public class MemoryImageSource implements ImageProducer ic.setProperties( props ); } if( pixeli != null ) { - ic.setPixels( 0, 0, width, height, cm, pixeli, offset, scansize ); + int[] pixelbuf = new int[w * h]; + for (int row = y; row < h; row++) + System.arraycopy(pixeli, row * scansize + x + offset, pixelbuf, row * w, w); + ic.setPixels( x, y, w, h, cm, pixelbuf, 0, w ); } else { - ic.setPixels( 0, 0, width, height, cm, pixelb, offset, scansize ); + byte[] pixelbuf = new byte[w * h]; + for (int row = y; row < h; row++) + System.arraycopy(pixelb, row * scansize + x + offset, pixelbuf, row * w, w); + ic.setPixels( x, y, w, h, cm, pixelbuf, 0, w ); } if( framenotify == true ) ic.imageComplete( ImageConsumer.SINGLEFRAME ); @@ -313,9 +325,14 @@ public class MemoryImageSource implements ImageProducer int scansize) { + pixeli = null; + pixelb = newpix; + cm = newmodel; + this.offset = offset; + this.scansize = scansize; if( animated == true ) { - //FIXME + newPixels(); } } @@ -325,9 +342,14 @@ public class MemoryImageSource implements ImageProducer int scansize) { + pixelb = null; + pixeli = newpix; + cm = newmodel; + this.offset = offset; + this.scansize = scansize; if( animated == true ) { - //FIXME + newPixels(); } } diff --git a/libjava/java/awt/image/RGBImageFilter.java b/libjava/java/awt/image/RGBImageFilter.java index b15fe25..5718024 100644 --- a/libjava/java/awt/image/RGBImageFilter.java +++ b/libjava/java/awt/image/RGBImageFilter.java @@ -46,7 +46,7 @@ package java.awt.image; */ public abstract class RGBImageFilter extends ImageFilter { - protected ColorModel origmodel = ColorModel.getRGBdefault(); + protected ColorModel origmodel; protected ColorModel newmodel; @@ -126,7 +126,7 @@ public abstract class RGBImageFilter extends ImageFilter private int makeColor( byte a, byte r, byte g, byte b ) { - return ( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (b << 8) | 0xff & g ); + return ( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (g << 8) | 0xff & b ); } /** @@ -149,11 +149,15 @@ public abstract class RGBImageFilter extends ImageFilter int off, int scansize) { - int xp, yp; + int xp, yp, i; + i = 0; for( xp = x; xp < ( x + w); xp++ ) for( yp = y; yp < (y + h); yp++ ) - pixels[ off + yp * scansize + xp ] = filterRGB( xp, yp, pixels[ off + yp * scansize + xp ] ); + { + pixels[i] = filterRGB( xp, yp, pixels[i] ); + i++; + } } @@ -172,15 +176,19 @@ public abstract class RGBImageFilter extends ImageFilter * @param scansize the width to use in extracting pixels from the <code>pixels</code> array */ public void setPixels(int x, int y, int w, int h, - ColorModel model, byte[] pixels, int offset, int scansize) + ColorModel model, byte[] pixels, + int offset, int scansize) { - if( model == origmodel ) { + if(model == origmodel && (model instanceof IndexColorModel) && canFilterIndexColorModel) + { consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize); - } else { - //FIXME - //convert to proper CM - int pixelsi[] = new int[ pixels.length / 4 ]; - filterRGBPixels( x, y, w, h, pixelsi, offset, scansize ); + } + else + { + int intPixels[] = + convertColorModelToDefault( x, y, w, h, model, pixels, offset, scansize ); + filterRGBPixels( x, y, w, h, intPixels, offset, scansize ); + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), intPixels, offset, scansize); } } @@ -199,35 +207,53 @@ public abstract class RGBImageFilter extends ImageFilter * @param scansize the width to use in extracting pixels from the <code>pixels</code> array */ public void setPixels(int x, int y, int w, int h, - ColorModel model, int[] pixels, int offset, int scansize) + ColorModel model, int[] pixels, + int offset, int scansize) { - if( model == origmodel ) { + if(model == origmodel && (model instanceof IndexColorModel) && canFilterIndexColorModel) + { consumer.setPixels(x, y, w, h, newmodel, pixels, offset, scansize); - } else { + } + else + { + //FIXME: Store the filtered pixels in a separate temporary buffer? convertColorModelToDefault( x, y, w, h, model, pixels, offset, scansize ); filterRGBPixels( x, y, w, h, pixels, offset, scansize ); + consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(), pixels, offset, scansize); } } - private void convertColorModelToDefault( int x, int y, int w, int h, - ColorModel model, int pixels[], int offset, int scansize) - { - int xp, yp; + private int[] convertColorModelToDefault(int x, int y, int w, int h, + ColorModel model, byte pixels[], + int offset, int scansize) + { + int intPixels[] = new int[pixels.length]; + for (int i = 0; i < pixels.length; i++) + intPixels[i] = makeColorbyDefaultCM(model, pixels[i]); + return intPixels; + } - for( xp = x; xp < ( x + w); xp++ ) - for( yp = y; yp < (y + h); yp++ ) - pixels[ offset + yp * scansize + xp ] = makeColorbyDefaultCM( pixels[ offset + yp * scansize + xp ] ); - - } - private int makeColorbyDefaultCM( int rgb ) - { - return makeColor( origmodel.getRed( rgb ), origmodel.getGreen( rgb ), origmodel.getGreen( rgb ), origmodel.getBlue( rgb ) ); - } + private void convertColorModelToDefault(int x, int y, int w, int h, + ColorModel model, int pixels[], + int offset, int scansize) + { + for (int i = 0; i < pixels.length; i++) + pixels[i] = makeColorbyDefaultCM(model, pixels[i]); + } + private int makeColorbyDefaultCM(ColorModel model, byte rgb) + { + return makeColor( model.getAlpha( rgb ) * 4, model.getRed( rgb ) * 4, model.getGreen( rgb ) * 4, model.getBlue( rgb ) * 4 ); + } + + private int makeColorbyDefaultCM(ColorModel model, int rgb) + { + return makeColor( model.getAlpha( rgb ), model.getRed( rgb ), model.getGreen( rgb ), model.getBlue( rgb ) ); + } private int makeColor( int a, int r, int g, int b ) { - return (int)( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (b << 8) | 0xff & g ); + return (int)( 0xff000000 & (a << 24) | 0xff0000 & (r << 16) | 0xff00 & (g << 8) | 0xff & b ); } diff --git a/libjava/java/awt/image/ReplicateScaleFilter.java b/libjava/java/awt/image/ReplicateScaleFilter.java index 97992e8..a572da7 100644 --- a/libjava/java/awt/image/ReplicateScaleFilter.java +++ b/libjava/java/awt/image/ReplicateScaleFilter.java @@ -104,7 +104,27 @@ public class ReplicateScaleFilter extends ImageFilter */ public void setDimensions(int width, int height) { - consumer.setDimensions(width, height); + srcWidth = width; + srcHeight = height; + + /* If either destHeight or destWidth is < 0, the image should + maintain its original aspect ratio. When both are < 0, + just maintain the original width and height. */ + if (destWidth < 0 && destHeight < 0) + { + destWidth = width; + destHeight = height; + } + else if (destWidth < 0) + { + destWidth = (int) (width * ((double) destHeight / srcHeight)); + } + else if (destHeight < 0) + { + destHeight = (int) (height * ((double) destWidth / srcWidth)); + } + + consumer.setDimensions(destWidth, destHeight); } /** @@ -136,7 +156,18 @@ public class ReplicateScaleFilter extends ImageFilter public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int offset, int scansize) { - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + byte[] destPixels = replicatePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); } /** @@ -156,8 +187,58 @@ public class ReplicateScaleFilter extends ImageFilter public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int offset, int scansize) { - consumer.setPixels(x, y, w, h, model, pixels, offset, scansize); + double rx = ((double) srcWidth) / destWidth; + double ry = ((double) srcHeight) / destHeight; + + int destScansize = (int) Math.round(scansize / rx); + + int[] destPixels = replicatePixels(x, y, w, h, + model, pixels, offset, scansize, + rx, ry, destScansize); + + consumer.setPixels((int) Math.floor(x/rx), (int) Math.floor(y/ry), + (int) Math.ceil(w/rx), (int) Math.ceil(h/ry), + model, destPixels, 0, destScansize); } + protected byte[] replicatePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, byte[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + byte[] destPixels = + new byte[(int) Math.ceil(srcw/rx) * (int) Math.ceil(srch/ry)]; + + int a, b; + for (int i = 0; i < destPixels.length; i++) + { + a = (int) ((int) ( ((double) i) / destScansize) * ry) * srcScansize; + b = (int) ((i % destScansize) * rx); + if ((a + b + srcOffset) < srcPixels.length) + destPixels[i] = srcPixels[a + b + srcOffset]; + } + + return destPixels; + } + + protected int[] replicatePixels(int srcx, int srcy, int srcw, int srch, + ColorModel model, int[] srcPixels, + int srcOffset, int srcScansize, + double rx, double ry, int destScansize) + { + int[] destPixels = + new int[(int) Math.ceil(srcw/rx) * (int) Math.ceil(srch/ry)]; + + int a, b; + for (int i = 0; i < destPixels.length; i++) + { + a = (int) ((int) ( ((double) i) / destScansize) * ry) * srcScansize; + b = (int) ((i % destScansize) * rx); + if ((a + b + srcOffset) < srcPixels.length) + destPixels[i] = srcPixels[a + b + srcOffset]; + } + + return destPixels; + } } |