From 26e56d50901d27a67646c97e14b3e71cec89ec68 Mon Sep 17 00:00:00 2001 From: graydon Date: Wed, 17 Mar 2004 21:29:02 +0000 Subject: 2004-03-12 Graydon Hoare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gnu/java/awt/peer/gtk/GdkGraphics2D.java: Clipping fixes. * javax/swing/JComponent.java (paint): Use persistent double buffer. * javax/swing/JList.java (ListListener): Revalidate on changes. * javax/swing/JScrollPane.java: Reimplement. * javax/swing/JViewport.java: Reimplement. * javax/swing/ScrollPaneLayout.java: Reimplement. * javax/swing/ViewportLayout.java: Tidy up. * javax/swing/plaf/basic/BasicButtonListener.java: Remove printlns. * javax/swing/plaf/basic/BasicScrollPaneUI.java: Reimplement. * javax/swing/plaf/basic/BasicSliderUI.java: Handle missing labels. * javax/swing/plaf/basic/BasicViewportUI.java: Implement in terms of backing store only. 2004-03-11 Thomas Fitzsimmons * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c (window_wm_protocols_filter): New function. (window_focus_in_cb): Remove function. (window_focus_out_cb): Likewise. (window_focus_or_active_state_change_cb): New function. (create): Add filter that removes WM_TAKE_FOCUS client messages. (connectSignals): Don't attach handlers to focus-in-event or focus-out-event signals. Handle notify signal. 2004-03-11 David Jee * gnu/java/awt/peer/gtk/GtkCheckboxPeer.java (gtkSetLabel): New native method declaration. (setLabel): Use gtkSetLabel. * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c (Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkSetLabel): New method. 2004-03-10 Thomas Fitzsimmons * gnu/java/awt/peer/gtk/GdkGraphics.java (setColor): Default to black when color argument is null. 2004-03-10 Kim Ho * java/awt/Container.java: Remove check for drag events. 2004-03-10 Kim Ho * java/awt/Container.java: (visitChild): Remove candidate clip. Use the component clip to intersect. * gnu/java/awt/peer/gtk/GtkComponentPeer.java: (handleEvent): Use the PaintEvent's clip. 2004-03-10 Kim Ho * gnu/java/awt/peer/gtk/GtkComponentPeer.java: (handleEvent): Don't set the clip for the Graphics object. 2004-03-09 Graydon Hoare * jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGlyphVector.c: Fix double <-> fixed macros, reset font transform. * jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeerMetrics.c: Likewise. 2004-03-09�� Kim Ho * java/awt/Container.java: (visitChild): Move the x and y coordinate of the component rectangle to correct position. (handleEvent): Forward drag events to the pressed component. * javax/swing/plaf/basic/BasicScrollBarUI.java: Fix comments. (ArrowButtonListener::mousePressed): Stop the existing timer. (mouseDragged): Implement. (TrackListener::mousePressed): Only react if the press doesn't occur on the thumb, otherwise just set the offset. (TrackListener::mouseReleased): Unset the isAdjusting value. (createIncreaseIcon): Switch icon. (createDecreaseIcon): Switch icon. (calculatePreferredSize): Use width. (getThumbBounds): Use the top as the lower value. (layoutVScrollBar): Switch the button locations. (paintIncreaseHighlight): Paint correct side of thumb. (paintDecreaseHighlight): ditto. (valueForYPosition): Use top as the lower value. * javax/swing/plaf/basic/BasicSliderUI.java: Fix comments. (mouseDragged): Implement. (mousePressed): Only react when the thumb isn't pressed, otherwise just set offset. (mouseReleased): Handle a release of the thumb. (scrollDueToClickInTrack): Stop the timer first. * javax/swing/JProgressBar.java: (setString): Fix change condition. * javax/swing/JSeparator.java: Remove println's. 2004-03-08 David Jee * java/awt/image/AffineTransformOp.java: (filter): Use Graphics2D interface instead of directly using the GdkGraphics2D peer. 2004-03-05 David Jee * gnu/java/awt/peer/gtk/GtkButtonPeer.java (handleEvent): Action events are generated upon MOUSE_RELEASED. * java/awt/Container.java (acquireComponentForMouseEvent): Fixed. (handleEvent): Fixed. * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkEvents.c (state_to_awt_mods_with_button_states): New method. (pre_event_handler): Fixed mouse event generation. 2004-03-05 Olga Rodimina gnu/java/awt/peer/gtk/GdkGraphics2D.java (GdkGraphics2D (BufferedImage)): Initialize pixmap associated with specified BufferedImage. (setPaint): Changed implementation of Texture Paint to use AffineTransformOp. * java/awt/image/AffineTransformOp.java (createCompatibleDestRaster): Throw RasterFormatException if resulting width or height of raster is 0. 2004-03-04 Olga Rodimina * java/awt/image/AffineTransformOp.java: Removed unnecessary field interpolationType. Formatted some of the lines to be consistent with the GNU style. (AffineTransformOp): Create new RenderingHints containing specified interpolation type. (createCompatibleDestImage): Implemented. (createCompatibleDestRaster): Implemented. (filter): Implemented. (getBounds2D(BufferedImage)): Implemented. (getBounds2D(Raster)): Implemented. (getInterpolationType): Get interpolation value from rendering hints. 2004-03-04 David Jee * gnu/java/awt/peer/gtk/GtkContainerPeer.java (setFont): Check if child peers are null. 2004-03-04 Graydon Hoare * testsuite/lib/libjava.exp (libjava_find_lib): Don't include .libs in -L option. (libjava_arguments): Add new libraries to argument list. 2004-03-04 Tom Tromey * Makefile.in: Rebuilt. * Makefile.am (toolexeclib_LTLIBRARIES): Added lib-java-awt.la, lib-javax-swing.la, lib-java-applet.la, lib-java-beans.la. (misc_java_source_files): New macro. (swing_java_source_files): Likewise. (awt_java_source_files): Pruned. (applet_java_source_files): New macro. (beans_java_source_files): Likewise. (lib_java_applet_la_SOURCES): Likewise. (lib_java_awt_la_SOURCES): Likewise. (lib_javax_swing_la_SOURCES): Likewise. (lib_java_beans_la_SOURCES): Likewise. (all_java_object_files): Likewise. (%.lo: %.java): Use all_java_object_files. (all_java_source_files): Added new _SOURCES. (ordinary_java_source_files): Removed awt_java_source_files. 2004-03-02 Olga Rodimina * Makefile.am: Added java/awt/image/AffineTransformOp.java * Makefile.in: Re-generated. * java/awt/image/AffineTransformOp.java: New Class. 2004-03-01 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java (setPaint): Interpret correctly TexturePaint's anchor rectangle. (drawImage): Fixed scale factors of the affine transform. 2004-02-27 David Jee * gnu/java/awt/peer/gtk/GdkGraphics.java (GdkGraphics(Component)): Inherit font from component. (drawString): Use font style. * gnu/java/awt/peer/gtk/GtkCheckboxPeer.java (gtkSetFont): New native method declaration. (setFont): New method. * gnu/java/awt/peer/gtk/GtkComponentPeer.java (gtkSetFont): New native method declaration. (setFont): Call new native method gtkSetFont. * gnu/java/awt/peer/gtk/GtkContainerPeer.java (setFont): For all child components who do not their fonts set, set their peers' fonts with this container's font. * gnu/java/awt/peer/gtk/GtkLabelPeer.java: Move all native method declarations to the top for readability. (gtkSetFont): New native method declaration. (setFont): New method. * java/awt/Component.java (setFont): Invalidate after setting the font. * java/awt/Container.java (invalidateTree): New method. (setFont): Invalidate the container tree after setting the font. * jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics.c (Java_gnu_java_awt_peer_gtk_GdkGraphics_drawString): Use font style. * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkCheckboxPeer.c (Java_gnu_java_awt_peer_gtk_GtkCheckboxPeer_gtkSetFont): New method. * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c (Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkSetFont): New method. * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkLabelPeer.c (Java_gnu_java_awt_peer_gtk_GtkLabelPeer_gtkSetFont): New method. 2004-02-27 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java (updateBufferedImage): New helper function. Updates BufferedImage in memory if it was changed. (draw): changed to update BufferedImage in memory after this drawing operation (fill): Ditto. (draw3DRect): Ditto. (fill3DRect): Ditto. (clearRect): Ditto. (drawRaster): Ditto. (drawImage) : Ditto. Update only in case of GtkOffScreenImage with no affine transformation. (drawGlyphVector): Ditto. 2004-02-26 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java (isBufferedImageGraphics): New Helper function. Returns true if this graphics2d can be used to draw into buffered image and false otherwise. (updateImagePixels): New Helper function. Updates pixels in the BufferedImage. * jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c (getImagePixels): New function. Returns pixels of the buffered image associated with this Graphics2D. 2004-02-26 David Jee * java/awt/BorderLayout.java (layoutContainer): Fix width and height calculations to ensure that they're non-negative. * java/awt/Component.java (setBackground): If c is null, inherit from closest ancestor whose background color is set. 2004-02-26�� Kim Ho�� * Makefile.am: Add new files. * Makefile.in: Re-generate. * javax/swing/JProgressBar.java: (JProgressBar(int, int int)): Throw IllegalArgumentException if orientation is invalid. (JProgressBar(BoundedRangeModel)): Create ChangeListener and register it. UpdateUI. (getChangeListeners): Implement. (setModel): Reset ChangeListener. * javax/swing/JScrollBar.java: Implement. * javax/swing/JSeparator.java: Implement. * javax/swing/JSlider.java: (JSlider(int, int, int, int)): Throw IllegalArgumentException if orientation is invalid. (getChangeListeners): Fix method name. * javax/swing/SwingUtilities.java: (layoutCompoundLabel): If there is no text, set the text rectangle dimensions to 0. * javax/swing/plaf/basic/BasicButtonUI.java: (paint): If there is no text, don't paint it. * javax/swing/plaf/basic/BasicScrollBarUI.java: Implement. * javax/swing/plaf/basic/BasicSeparatorUI.java: Implement. * javax/swing/plaf/basic/BasicSliderUI.java: (propertyChange): If the model changes, change the listeners accordingly. 2004-02-25 Graydon Hoare * javax/swing/AbstractButton.java: Add "final" qualifiers. * javax/swing/JList.java: Reimplement. * javax/swing/DefaultListSelectionModel.java: Reimplement. * javax/swing/plaf/basic/BasicListUI.java: Reimplement. * javax/swing/plaf/basic/BasicLookAndFeel.java: Add "purple" values. * javax/swing/ListModel.java: Javadoc. * javax/swing/ListSelectionModel.java: Add missing methods. * javax/swing/AbstractListModel.java: Javadoc and corrections. * javax/swing/DefaultListModel.java: Javadoc and corrections. * javax/swing/ListModel.java: Javadoc and corrections. * javax/swing/DefaultListCellRenderer.java: Minor tidying. 2004-02-25 David Jee * gnu/java/awt/peer/gtk/GtkFontPeer.java (GtkFontPeer): Change default size to 12. * gnu/java/awt/peer/gtk/GtkToolkit.java (getFontPeer): Change default size to 12. (getClasspathFontPeer): Likewise. Set default name to "Default". * java/awt/Font.java (Font(Map)): Call Font(String,Map). (Font(String,Map)): If attrs is null, initialize it as an empty HashMap, which will ensure that the Font will get default attributes. 2004-02-25 David Jee * gnu/java/awt/peer/gtk/GtkFontPeer.java (GtkFontPeer(String,int)): Call the new constructor with size 1. (GtkFontPeer(String,int,int)): New constructor with size attribute. * gnu/java/awt/peer/gtk/GtkToolkit.java (getFontPeer(String,int)): Call the new overload method with size 1. (getFontPeer(String,int,int)): New method. Overloaded with size attribute. (getClasspathFontPeer): Set the size of the font. 2004-02-24 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java (bimage): New field. (GdkGraphics2D): New Constructor. Constructs Graphics object that can be used to draw into the Buffered Image. * gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java: (GdkGraphicsEnvironment): Fixed to include public keyword. (createGraphics): Implemented. * gnu/java/awt/peer/gtk/GtkToolkit.java (getLocalGraphicsEnvironment): Implemented. * java/awt/GraphicsEnvironment.java: (getLocalGraphicsEnvironment): Implemented. * java/awt/image/BufferedImage.java: (createGraphics): Implemented. 2004-02-24 David Jee * java/awt/Component.java (eventTypeEnabled): Add MOUSE_MOVED and MOUSE_DRAGGED event types. * java/awt/Container.java (addNotifyContainerChildren): Fix event enabling. 2004-02-23 Olga Rodimina * Makefile.am: Added gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java * Makefile.in: Re-generated. * gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java: New Class. 2004-02-19 Kim Ho * Makefile.am: Add BasicProgressBarUI * Makefile.in: Regenerate. * javax/swing/JProgressBar.java: Re-implement. * javax/swing/plaf/basic/BasicLookAndFeel.java Add constants for JProgressBar. * javax/swing/plaf/basic/BasicProgressBarUI.java Implement. * javax/swing/plaf/basic/BasicSliderUI.java Change comments. (calculateGeometry): New method (paint): Remove unnecessary size calculations. 2004-02-18 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java (drawRaster): Fixed small error that caused imageToUser transformation to be set incorrectly. (toString): Implemented. 2004-02-18 David Jee * java/awt/CardLayout.java (addLayoutComponent): Show the first component added as the default. (removeLayoutComponent): After removing, show the next component. (gotoComponent): If there is only one component, show it and return. 2004-02-18 Kim Ho * javax/swing/JSlider.java: Re-order modifiers. * javax/swing/JLabel.java: Re-order modifiers. * javax/swing/JComponent.java: (addPropertyChangeListener): Implement. (removePropertyChangeListener): ditto. (firePropertyChangeEvent): ditto. 2004-02-17 David Jee * java/awt/Component.java (show): Dispatch ComponentEvent via system event queue. (hide): Likewise. (move): Likewise. (resize): Likewise. (reshape): Likewise. * java/awt/Window.java (setBoundsCallback): Likewise. 2004-02-17 David Jee * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkComponentPeer.c (Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeBounds): Use gtk_widget_set_size_request() instead of the deprecated gtk_widget_set_usize(). 2004-02-17 Kim Ho * javax/swing/JSlider.java: Fix comments and make property strings constants. (createStandardLabels): Use the labels preferred size as bounds. * javax/swing/plaf/basic/BasicSliderUI.java Fix comments. (ScrollHandler::actionPerformed): Don't calculate the timer stop value. Let the MouseListeners find the stop location. (getPreferredHorizontalSize): Re-implement. (getPreferredVerticalSize): ditto. (getMinimumHorizontalSize): ditto. (getMinimumVerticalSize): ditto. (getPreferredSize): ditto. (getMinimumSize): ditto. (getMaximumSize): ditto. (paintTicks): Use doubles to find the tick location. (paintHorizontalLabel):�� Use preferredSize as initial width and height. (paintVerticalLabel): ditto. 2004-02-17 Kim Ho * javax/swing/JLabel.java: Changed property strings to constants. (DISPLAYED_MNEMONIC_INDEX_CHANGED_PROPERTY): New property. (setText): Change mnemonic index if text is too short. (setDisplayedMnemonicIndex): Fire property change event. (getDisplayedMnemonicIndex): Remove check against short text. 2004-02-17 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java: (drawImage(img,xform,obs)): Invert xform before passing the xform to cairo. (drawImage(img,x,y,bgcolor,obs)): Implemented. (drawImage (img,x,y,w,h,bgcolor,obs)): Partly implemented. (drawImage (img,x,y,w,h,obs)): Implemented. (drawImage (img,dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2, bgcolor,obs)): Partly implemented. (drawImage (img,dx1,dy1,dx2,dy2,sx1,sy1,sx2,sy2,obs)): Implemented. * java/awt/image/BufferedImage.java: (copyData): if dest is null, create raster with same dimensions as the current image. 2004-02-16 Graydon Hoare * javax/swing/plaf/basic/BasicLabelUI.java (getPreferredSize): Use layoutCL. * javax/swing/plaf/basic/BasicGraphicsUtils.java (getPreferredButtonSize): Start with empty view rect, layout using component's preferred alignment. * javax/swing/plaf/basic/BasicLookAndFeel.java: Add some Label and List defaults. 2004-02-16 David Jee * java/awt/Component.java (show): Dispatch COMPONENT_SHOWN ComponentEvent. (hide): Dispatch COMPONENT_HIDDEN ComponentEvent. (move): Erase old bounds and repaint new bounds. Dispatch COMPONENT_MOVED ComponentEvent. (resize): Erase old bounds and repaint new bounds. Dispatch COMPONENT_RESIZED ComponentEvent. (reshape): Dispatch COMPONENT_RESIZED and COMPONENT_MOVED ComponentEvents. * java/awt/Window.java (setBoundsCallback): Dispatch COMPONENT_RESIZED and COMPONENT_MOVED ComponentEvents. 2004-02-16 Olga Rodimina * gnu/java/awt/peer/gtk/GdkGraphics2D.java: (setRenderingHint): Added implementation of Interpolation rendering hints. (setRenderingHints): Ditto. * jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c: (drawPixels): fixed to allow user to choose type of filtering that should be used when displaying images. (cairoSurfaceSetFilter): New method. Sets filter type for interpolation of pixel values. 2004-02-16 David Jee * java/awt/GridBagLayout.java (calcCellSizes): Rows or columns with zero sizes should still be considered for extra space distribution. 2004-02-16 Kim Ho * javax/swing/JLabel.java: Re-implement. * javax/swing/plaf/basic/BasicLabelUI.java Re-implement. * javax/swing/plaf/basic/BasicLookAndFeel.java: Added constant. 2004-02-16�� Kim Ho�� * javax/swing/JSlider.java: Fix indentation and comments. (setModel): Remove null check to conform with Sun's. (setOrientation): Throw exception if not HORIZONTAL or VERTICAL. (getInverted): Use private variable instead of ComponentOrientation. (setInverted): ditto. * javax/swing/plaf/basic/BasicSliderUI.java: Fix indentation and comments. (propertyChange): Remove check for inverted slider, handle in main paint. (getMinimumSize): Return preferred size. (getMaximumSize): ditto. (calculateFocusRect): Don't relocate rectangle. (drawInverted): Return XOR of the slider's inversion and the component's orientation. (paint): Update leftToRightCache 2004-02-13 David Jee * java/awt/GridBagLayout.java (GetLayoutInfo): Fix weight and size distribution. Relocate repeated code to helper methods. (sortBySpan): New helper method. (distributeSizeAndWeight): Likewise. (calcCellWeights): Likewise. (calcCellSizes): Add comments. 2004-02-13 David Jee * java/awt/Component.java (show): Only do something if component is invisible at the moment. (hide): Only do something if component is visible at the moment. (reshape): If lightweight, erase old bounds and repaint new bounds. 2004-02-13�� Kim Ho�� * Makefile.am: Updated for new file. * Makefile.in: Regenerated. * javax/swing/JSlider.java: Reimplement. * javax/swing/SwingUtilities.java (layoutCompoundLabel): Use icon height instead of width. (paintComponent): Implement. * javax/swing/plaf/basic/BasicLookAndFeel.java: Add JSlider defaults. * javax/swing/plaf/basic/BasicSliderUI.java: Implement. New file. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@79607 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/javax/swing/AbstractListModel.java | 137 +- libjava/javax/swing/DefaultListCellRenderer.java | 270 +-- libjava/javax/swing/DefaultListModel.java | 944 ++++----- libjava/javax/swing/DefaultListSelectionModel.java | 629 ++++-- libjava/javax/swing/JComponent.java | 105 +- libjava/javax/swing/JLabel.java | 798 +++++-- libjava/javax/swing/JList.java | 1008 +++++++-- libjava/javax/swing/JProgressBar.java | 1054 ++++++---- libjava/javax/swing/JScrollBar.java | 702 ++++++- libjava/javax/swing/JScrollPane.java | 588 +++++- libjava/javax/swing/JSeparator.java | 334 ++- libjava/javax/swing/JSlider.java | 1534 ++++++++------ libjava/javax/swing/JViewport.java | 313 ++- libjava/javax/swing/ListModel.java | 38 +- libjava/javax/swing/ListSelectionModel.java | 53 +- libjava/javax/swing/ScrollPaneLayout.java | 622 +++--- libjava/javax/swing/SwingUtilities.java | 64 +- libjava/javax/swing/ViewportLayout.java | 72 +- .../swing/plaf/basic/BasicButtonListener.java | 3 - libjava/javax/swing/plaf/basic/BasicButtonUI.java | 3 +- .../javax/swing/plaf/basic/BasicGraphicsUtils.java | 11 +- libjava/javax/swing/plaf/basic/BasicLabelUI.java | 493 +++-- libjava/javax/swing/plaf/basic/BasicListUI.java | 710 ++++++- .../javax/swing/plaf/basic/BasicLookAndFeel.java | 67 +- .../javax/swing/plaf/basic/BasicProgressBarUI.java | 820 ++++++++ .../javax/swing/plaf/basic/BasicScrollBarUI.java | 1397 ++++++++++++ .../javax/swing/plaf/basic/BasicScrollPaneUI.java | 34 +- .../javax/swing/plaf/basic/BasicSeparatorUI.java | 266 +++ libjava/javax/swing/plaf/basic/BasicSliderUI.java | 2213 ++++++++++++++++++++ .../javax/swing/plaf/basic/BasicViewportUI.java | 108 +- 30 files changed, 12090 insertions(+), 3300 deletions(-) create mode 100644 libjava/javax/swing/plaf/basic/BasicProgressBarUI.java create mode 100644 libjava/javax/swing/plaf/basic/BasicScrollBarUI.java create mode 100644 libjava/javax/swing/plaf/basic/BasicSeparatorUI.java create mode 100644 libjava/javax/swing/plaf/basic/BasicSliderUI.java (limited to 'libjava/javax') diff --git a/libjava/javax/swing/AbstractListModel.java b/libjava/javax/swing/AbstractListModel.java index da85a4def95..4a5c14bed08 100644 --- a/libjava/javax/swing/AbstractListModel.java +++ b/libjava/javax/swing/AbstractListModel.java @@ -40,57 +40,64 @@ package javax.swing; import java.io.Serializable; import java.util.EventListener; import javax.swing.event.EventListenerList; -import javax.swing.event.ListDataListener; import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; + /** * AbstractListModel - * A2uthor Ronald Veldema - * @author Andrew Selkirk - * @version 1.0 + * + * @author Ronald Veldema + * @author Andrew Selkirk + * @version 1.0 */ -public abstract class AbstractListModel - implements ListModel, Serializable +public abstract class AbstractListModel implements ListModel, Serializable { static final long serialVersionUID = -3285184064379168730L; - /** - * listenerList - */ - protected EventListenerList listenerList = new EventListenerList (); - - /** - * Constructor AbstractListModel - */ - public AbstractListModel () + /** List of ListDataListeners called for each change to the list. */ + protected EventListenerList listenerList; + + public AbstractListModel() { + listenerList = new EventListenerList(); } /** - * addListDataListener - * @param listener TODO + * Add a listener object to this model. The listener will be called + * any time the set of elements in the model is changed. + * + * @param listener The listener to add */ - public void addListDataListener(ListDataListener listener) + public void addListDataListener(ListDataListener listener) { - listenerList.add (ListDataListener.class, listener); + listenerList.add(ListDataListener.class, listener); } /** - * removeListDataListener - * @param listener TODO + * Add a listener object to this model. The listener will no longer be + * called when the set of elements in the model is changed. + * + * @param listener The listener to remove */ public void removeListDataListener(ListDataListener listener) { - listenerList.remove (ListDataListener.class, listener); + listenerList.remove(ListDataListener.class, listener); } /** - * fireContentsChanged - * @param source TODO - * @param startIndex TODO - * @param endIndex TODO + * Call {@link ListDataListener#contentsChanged} on each element of the + * {@link listenerList} which is a {@link ListDataListener}. The event + * fired has type {@ListDataEvent.CONTENTS_CHANGED} and represents a + * change to the data elements in the range [startIndex, endIndex] + * inclusive. + * + * @param source The source of the change, typically this + * @param startIndex The index of the first element which changed + * @param endIndex The index of the last element which changed */ - protected void fireContentsChanged(Object source, int startIndex, int endIndex) + protected void fireContentsChanged(Object source, int startIndex, + int endIndex) { // Variables ListDataEvent event; @@ -100,10 +107,10 @@ public abstract class AbstractListModel // Create Event event = new ListDataEvent(source, ListDataEvent.CONTENTS_CHANGED, - startIndex, endIndex); + startIndex, endIndex); // Get Listeners - listeners = getListDataListeners (); + listeners = getListDataListeners(); // Process Listeners for (index = 0; index < listeners.length; index++) @@ -114,12 +121,17 @@ public abstract class AbstractListModel } /** - * fireIntervalAdded - * @param source TODO - * @param startIndex TODO - * @param endIndex TODO + * Call {@link ListDataListener#intervalAdded} on each element of the + * {@link listenerList} which is a {@link ListDataListener}. The event + * fired has type {@ListDataEvent.INTERVAL_ADDED} and represents an + * addition of the data elements in the range [startIndex, endIndex] + * inclusive. + * + * @param source The source of the change, typically this + * @param startIndex The index of the first new element + * @param endIndex The index of the last new element */ - protected void fireIntervalAdded (Object source, int startIndex, int endIndex) + protected void fireIntervalAdded(Object source, int startIndex, int endIndex) { // Variables ListDataEvent event; @@ -128,27 +140,32 @@ public abstract class AbstractListModel int index; // Create Event - event = new ListDataEvent (source, ListDataEvent.INTERVAL_ADDED, startIndex, - endIndex); + event = new ListDataEvent(source, ListDataEvent.INTERVAL_ADDED, + startIndex, endIndex); // Get Listeners - listeners = getListDataListeners (); + listeners = getListDataListeners(); // Process Listeners for (index = 0; index < listeners.length; index++) { - listener = listeners [index]; - listener.intervalAdded (event); + listener = listeners[index]; + listener.intervalAdded(event); } } /** - * fireIntervalRemoved - * @param source TODO - * @param startIndex TODO - * @param endIndex TODO + * Call {@link ListDataListener#intervalRemoved} on each element of the + * {@link listenerList} which is a {@link ListDataListener}. The event + * fired has type {@ListDataEvent.INTERVAL_REMOVED} and represents a + * removal of the data elements in the range [startIndex, endIndex] + * inclusive. + * + * @param source The source of the change, typically this + * @param startIndex The index of the first element removed + * @param endIndex The index of the last element removed */ - protected void fireIntervalRemoved (Object source, int startIndex, + protected void fireIntervalRemoved(Object source, int startIndex, int endIndex) { // Variables @@ -158,35 +175,41 @@ public abstract class AbstractListModel int index; // Create Event - event = new ListDataEvent (source, ListDataEvent.INTERVAL_REMOVED, - startIndex, endIndex); + event = new ListDataEvent(source, ListDataEvent.INTERVAL_REMOVED, + startIndex, endIndex); // Get Listeners - listeners = getListDataListeners (); + listeners = getListDataListeners(); // Process Listeners for (index = 0; index < listeners.length; index++) { - listener = listeners [index]; - listener.intervalRemoved (event); + listener = listeners[index]; + listener.intervalRemoved(event); } } /** - * getListeners - * @param listenerType TODO - * @returns EventListener[] + * Return the subset of {@link EventListener} objects found in this + * object's {@link listenerList} which are elements of the specified + * type. + * + * @param listenerType The type of listeners to select + * + * @return The set of listeners of the specified type */ - public EventListener[] getListeners (Class listenerType) + public EventListener[] getListeners(Class listenerType) { - return listenerList.getListeners (listenerType); + return listenerList.getListeners(listenerType); } /** - * getListDataListeners + * A synonym for getListeners(ListDataListener.class). + * + * @return The set of ListDataListeners found in the {@link listenerList} */ - public ListDataListener[] getListDataListeners () + public ListDataListener[] getListDataListeners() { - return (ListDataListener[]) getListeners (ListDataListener.class); + return (ListDataListener[]) getListeners(ListDataListener.class); } } diff --git a/libjava/javax/swing/DefaultListCellRenderer.java b/libjava/javax/swing/DefaultListCellRenderer.java index f3557719d50..cfb1f409dd7 100644 --- a/libjava/javax/swing/DefaultListCellRenderer.java +++ b/libjava/javax/swing/DefaultListCellRenderer.java @@ -42,213 +42,75 @@ import java.awt.Rectangle; import java.io.Serializable; import javax.swing.border.Border; + /** * DefaultListCellRenderer - * @author Andrew Selkirk - * @version 1.0 + * + * @author Andrew Selkirk + * @version 1.0 */ -public class DefaultListCellRenderer extends JLabel - implements ListCellRenderer, Serializable +public class DefaultListCellRenderer + extends JLabel implements ListCellRenderer, Serializable { static final long serialVersionUID = 7708947179685189462L; - //------------------------------------------------------------- - // Classes ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * UIResource - */ - public static class UIResource extends DefaultListCellRenderer - implements javax.swing.plaf.UIResource { - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor UIResource - */ - public UIResource() { - // TODO - } // UIResource() - - - } // UIResource - - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * noFocusBorder - */ - protected static Border noFocusBorder = null; // TODO - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor DefaultListCellRenderer - */ - public DefaultListCellRenderer() { - // TODO - } // DefaultListCellRenderer() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getListCellRendererComponent - * @param list TODO - * @param value TODO - * @param index TODO - * @param isSelected TODO - * @param cellHasFocus TODO - * @returns Component - */ - public Component getListCellRendererComponent(JList list, - Object value, int index, boolean isSelected, boolean cellHasFocus) { - return null; // TODO - } // getListCellRendererComponent() - - /** - * validate - */ - public void validate() { - // TODO - } // validate() - - /** - * revalidate - */ - public void revalidate() { - // TODO - } // revalidate() - - /** - * repaint - * @param tm TODO - * @param x TODO - * @param y TODO - * @param w TODO - * @param h TODO - */ - public void repaint(long tm, int x, int y, int w, int h) { - // TODO - } // repaint() - - /** - * repaint - * @param rect TODO - */ - public void repaint(Rectangle rect) { - // TODO - } // repaint() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - protected void firePropertyChange(String propertyName, - Object oldValue, Object newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - byte oldValue, byte newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - char oldValue, char newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - short oldValue, short newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - int oldValue, int newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - long oldValue, long newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - float oldValue, float newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - double oldValue, double newValue) { - // TODO - } // firePropertyChange() - - /** - * firePropertyChange - * @param propertyName TODO - * @param oldValue TODO - * @param newValue TODO - */ - public void firePropertyChange(String propertyName, - boolean oldValue, boolean newValue) { - // TODO - } // firePropertyChange() - - -} // DefaultListCellRenderer + public static class UIResource extends DefaultListCellRenderer + implements javax.swing.plaf.UIResource + { + public UIResource() + { + } + } + + /** noFocusBorder */ + protected static Border noFocusBorder = null; // TODO + + /** + * getListCellRendererComponent + * + * @param list TODO + * @param value TODO + * @param index TODO + * @param isSelected TODO + * @param cellHasFocus TODO + * + * @return Component + */ + public Component getListCellRendererComponent(JList list, Object value, + int index, boolean isSelected, + boolean cellHasFocus) + { + String s = value.toString(); + setText(s); + setOpaque(true); + + if (isSelected) + { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } + else + { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + + setEnabled(list.isEnabled()); + setFont(list.getFont()); + return this; + } + + public void validate() {} + public void revalidate() {} + public void repaint(long tm, int x, int y, int w, int h) {} + public void repaint(Rectangle rect) {} + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue){} + public void firePropertyChange(String propertyName, byte oldValue, byte newValue) {} + public void firePropertyChange(String propertyName, char oldValue, char newValue) {} + public void firePropertyChange(String propertyName, short oldValue, short newValue) {} + public void firePropertyChange(String propertyName, int oldValue, int newValue) {} + public void firePropertyChange(String propertyName, long oldValue, long newValue) {} + public void firePropertyChange(String propertyName, float oldValue, float newValue) {} + public void firePropertyChange(String propertyName, double oldValue, double newValue) {} + public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {} +} diff --git a/libjava/javax/swing/DefaultListModel.java b/libjava/javax/swing/DefaultListModel.java index 3ba13cdaf5d..23f135b2f6b 100644 --- a/libjava/javax/swing/DefaultListModel.java +++ b/libjava/javax/swing/DefaultListModel.java @@ -35,500 +35,474 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing; -import java.util.ArrayList; import java.util.Enumeration; import java.util.NoSuchElementException; import java.util.Vector; /** - * DefaultListModel - * @author Andrew Selkirk - * @version 1.0 + * This is a default subclass of the {@link AbstractListModel}, used by + * {@link javax.swing.JList} and similar objects as the model of a list of + * values. The implementation is based on an underlying {@link + * java.util.Vector}. + * + * @author Andrew Selkirk + * @author Graydon Hoare (graydon&064;redhat.com) */ + public class DefaultListModel extends AbstractListModel { private static final long serialVersionUID = 2315945659722172272L; - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * elements. Note: Sun obviously implemented the storage as a - * Vector according to the similar API on this class. I choose - * instead to implement the model with a proper collection object. - * Is this a good choice? Probably not (ya..I know there are - * sync issues by doing this) - */ - private ArrayList elements = new ArrayList(); - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor DefaultListModel - */ - public DefaultListModel() { - // TODO - } // DefaultListModel() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * elementAt - * @param index TODO - * @returns Object - */ - public Object elementAt(int index) { - return elements.get(index); - } // elementAt() - - /** - * toString - * @returns String - */ - public String toString() { - return elements.toString(); - } // toString() - - /** - * indexOf - * @param element TODO - * @returns int - */ - public int indexOf(Object element) { - return elements.indexOf(element); - } // indexOf() - - /** - * indexOf - * @param element TODO - * @param startIndex TODO - * @returns int - */ - public int indexOf(Object element, int startIndex) { - - // Variables - int index; - Object test; - - // Process Elements - for (index = startIndex; index < elements.size(); index++) { - test = elements.get(index); - if (test.equals(element) == true) { - return index; - } // if - } // for - return -1; - - } // indexOf() - - /** - * lastIndexOf - * @param element TODO - * @returns int - */ - public int lastIndexOf(Object element) { - return elements.lastIndexOf(element); - } // lastIndexOf() - - /** - * lastIndexOf - * @param element TODO - * @param endIndex TODO - * @returns int - */ - public int lastIndexOf(Object element, int endIndex) { - - // Variables - int index; - Object test; - - // Process Elements - for (index = endIndex; index >= 0; index--) { - test = elements.get(index); - if (test.equals(element) == true) { - return index; - } // if - } // for - return -1; - - } // lastIndexOf() - - /** - * get - * @param index TODO - * @returns Object - */ - public Object get(int index) { - return elements.get(index); - } // get() - - /** - * set - * @param index TODO - * @param element TODO - * @returns Object - */ - public Object set(int index, Object element) { - - // Variables - Object result; - - // Process Action - result = elements.set(index, element); - - // Send event - fireContentsChanged(this, index, index); - - return result; - - } // set() - - /** - * add - * @param index TODO - * @param element TODO - */ - public void add(int index, Object element) { - - // Process Action - elements.add(index, element); - - // Send event - fireContentsChanged(this, index, index); - - } // add() - - /** - * addElement - * @param element TODO - */ - public void addElement(Object element) { - - // Process Action - elements.add(element); - - // Send event - fireIntervalAdded(this, elements.size(), elements.size()); - - } // addElement() - - /** - * size - * @returns int - */ - public int size() { - return elements.size(); - } // size() - - /** - * toArray - * @returns Object[] - */ - public Object[] toArray() { - return elements.toArray(); - } // toArray() - - /** - * contains - * @param element TODO - * @returns boolean - */ - public boolean contains(Object element) { - return elements.contains(element); - } // contains() - - /** - * copyInto - * @param array TODO - */ - public void copyInto(Object[] array) { - - // Variables - int index; - int size; - Object[] srcArray; - - // Initialize - size = size(); - srcArray = toArray(); - - // Process Elements - for (index = 0; index < size; index++) { - array[index] = srcArray[index]; - } // for - - } // copyInto() - - /** - * clear - */ - public void clear() { - - // Process Action - elements.clear(); - - // Send event - fireIntervalRemoved(this, 0, elements.size()); - - } // clear() - - /** - * remove - * @param index TODO - * @returns Object - */ - public Object remove(int index) { - - // Variables - Object result; - - // Process Action - result = elements.remove(index); - - // Send event - fireIntervalRemoved(this, index, index); - - return result; - - } // remove() - - /** - * isEmpty - * @returns boolean - */ - public boolean isEmpty() { - return elements.isEmpty(); - } // isEmpty() - - /** - * elements - * @returns Enumeration - */ - public Enumeration elements() { - - // TODO - // Note: This is a pathetic implementation. If Vector - // was used for storage, this wouldn't be an issue. I'll - // have to implement an Enumeration inner class sometime. - - // Variables - Vector vector; - - // Get Enumeration - vector = new Vector(elements); - return vector.elements(); - - } // elements() - - /** - * trimToSize - */ - public void trimToSize() { - elements.trimToSize(); - } // trimToSize() - - /** - * ensureCapacity - * @param size TODO - */ - public void ensureCapacity(int size) { - elements.ensureCapacity(size); - } // ensureCapacity() - - /** - * setSize - * @param size TODO - */ - public void setSize(int size) { - elements.ensureCapacity(size); - } // setSize() - - /** - * capacity - * @returns int - */ - public int capacity() { - return elements.size(); - } // capacity() - - /** - * firstElement - * @returns Object - */ - public Object firstElement() { - - // Variables - Object element; - - try { - element = elements.get(0); - return element; - } catch (IndexOutOfBoundsException e) { - throw new NoSuchElementException(); - } // try - - } // firstElement() - - /** - * lastElement - * @returns Object - */ - public Object lastElement() { - - // Variables - Object element; - - try { - element = elements.get(elements.size() - 1); - return element; - } catch (ArrayIndexOutOfBoundsException e) { - throw new NoSuchElementException(); - } // try - - } // lastElement() - - /** - * setElementAt - * @param element TODO - * @param index TODO - */ - public void setElementAt(Object element, int index) { - - // Process Action - elements.set(index, element); - - // Send event - fireContentsChanged(this, index, index); - - } // setElementAt() - - /** - * removeElementAt - * @param index TODO - */ - public void removeElementAt(int index) { - - // Process Action - elements.remove(index); - - // Send event - fireIntervalRemoved(this, index, index); - - } // removeElementAt() - - /** - * insertElementAt - * @param element TODO - * @param index TODO - */ - public void insertElementAt(Object element, int index) { - - // Process Action - elements.add(index, element); - - // Send event - fireIntervalRemoved(this, index, index); - - } // insertElementAt() - - /** - * removeElement - * @param element TODO - * @returns boolean - */ - public boolean removeElement(Object element) { - - // Variables - int index; - - index = elements.indexOf(element); - if (index != -1) { - elements.remove(index); - - // Send event - fireIntervalRemoved(this, index, index); - - return true; - - } // if - - return false; - - } // removeElement() - - /** - * removeAllElements - */ - public void removeAllElements() { - - // Variables - int size; - - size = size(); - - if (size > 0) { - - // Process Action - elements.clear(); - - // Send event - fireIntervalRemoved(this, 0, size - 1); - - } // if - - } // removeAllElements() - - /** - * removeRange - * @param startIndex TODO - * @param endIndex TODO - */ - public void removeRange(int startIndex, int endIndex) { - - // Variables - int index; - - // Check Indices - if (startIndex > endIndex) { - throw new IllegalArgumentException(); - } // if - - // Process Elements - for (index = endIndex; index >= startIndex; index--) { - elements.remove(index); - } // for - - // Send event - fireIntervalRemoved(this, startIndex, endIndex); - - } // removeRange() - - /** - * getSize - * @returns int - */ - public int getSize() { - return elements.size(); - } // getSize() - - /** - * getElementAt - * @param index TODO - * @returns Object - */ - public Object getElementAt(int index) { - return elements.get(index); - } // getElementAt() - - -} // DefaultListModel + /** + * The vector of elements in this list model. + */ + private Vector elements = new Vector(); + + /** + * Gets an element of the list at the provided index. + * + * @param index The index of the element to get + * + * @return The object at the given index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public Object elementAt(int index) + { + return elements.elementAt(index); + } + + /** + * Convert the list to a string representation. + * + * @return A string representation of the list + */ + public String toString() + { + return elements.toString(); + } + + /** + * Gets the first index of a particular element in the list. + * + * @param element The element to search for + * + * @return The first index in the list at which an object + * obj exists such that obj.equals(element) is + * true; if no such object exists, the method returns + * -1 + */ + public int indexOf(Object element) + { + return elements.indexOf(element); + } + + /** + * Gets the first index of a particular element in a list which occurs + * at or after a particular index. + * + * @param element The element to search for + * @param startIndex The index to begin searching at + * + * @return The first index in the list, greater than or equal to + * startIndex, at which an object obj exists + * such that obj.equals(element) is true; if no + * such object exists, the method returns -1 + */ + public int indexOf(Object element, int startIndex) + { + return elements.indexOf(element, startIndex); + } + + /** + * Gets the last index of a particular element in the list. + * + * @param element The element to search for + * + * @return The last index in the list at which an object + * obj exists such that obj.equals(element) is + * true; if no such object exists, the method returns + * -1 + */ + public int lastIndexOf(Object element) + { + return elements.lastIndexOf(element); + } + + /** + * Gets the last index of a particular element in a list which occurs + * at or before a particular index. + * + * @param element The element to search for + * @param endIndex The index to finish searching at + * + * @return The last index in the list, less than to or equal to + * endIndexIndex, at which an object obj exists + * such that obj.equals(element) is true; if no + * such object exists, the method returns -1 + */ + public int lastIndexOf(Object element, int endIndex) + { + return elements.lastIndexOf(element, endIndex); + } + + /** + * Gets the list element at a particular index. + * + * @param index The index to get the list value at + * + * @return The list value at the provided index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public Object get(int index) + { + return elements.get(index); + } + + /** + * Sets the list element at a particular index. + * + * @param index The list index at which to set a value + * @param element The value to set at the specified index + * + * @return The value previously held at the specified index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public Object set(int index, Object element) + { + Object result; + result = elements.set(index, element); + fireContentsChanged(this, index, index); + return result; + } + + /** + * Inserts an element at a particular index in the list. Each element at + * index i >= index is shifted to position i+1. + * If index is equal to size(), this is + * equivalent to appending an element to the array. Any + * index greater than size() is illegal. + * + * @param index The index to insert the element at + * @param element The element to insert at the index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds [0, size()] + */ + public void add(int index, Object element) + { + elements.add(index, element); + fireContentsChanged(this, index, index); + } + + /** + * Inserts an element at the end of the list. This is equivalent to + * calling list.add(list.size(), element). + * + * @param element The element to add to the list + */ + public void addElement(Object element) + { + elements.add(element); + fireIntervalAdded(this, elements.size(), elements.size()); + } + + /** + * Gets the number of elements in the list. + * + * @return The number of elements in the list + */ + public int size() + { + return elements.size(); + } + + /** + * Gets an array containing the elements of the list. + * + * @return An array of the objects in the list, in the order they occur + * in the list + */ + public Object[] toArray() + { + return elements.toArray(); + } + + /** + * Determines whether a particular element is a member of the list. + * + * @param element The element to search for + * + * @return true if element is a member of the + * list, otherwise false + */ + public boolean contains(Object element) + { + return elements.contains(element); + } + + /** + * Copies the list into a provided array. The provided array must be at + * least as large as the list. + * + * @param array The array to copy the list into + * + * @throws IndexOutOfBoundsException if the array is too small to hold the + * elements of the list + */ + public void copyInto(Object[] array) + { + elements.copyInto(array); + } + + /** + * Erases all the elements of the list, setting the list's size to 0. + */ + public void clear() + { + elements.clear(); + fireIntervalRemoved(this, 0, elements.size()); + } + + /** + * Removes the element at a particular index from the list. + * + * @param index The index of the element to remove + * + * @return The value at the index, which has been removed from the list + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public Object remove(int index) + { + Object result; + result = elements.remove(index); + fireIntervalRemoved(this, index, index); + return result; + } + + /** + * Determines whether the list is empty. + * + * @return true if the list is empty, otherwise + * false + */ + public boolean isEmpty() + { + return elements.isEmpty(); + } + + /** + * Returns an {@link java.util.Enumeration} over the elements of the list. + * + * @return A new enumeration which iterates over the list + */ + public Enumeration elements() + { + return elements.elements(); + } + + /** + * Sets the capacity of the list to be equal to its size. The list's capacity + * is the number of elements it can hold before it needs to be reallocated. + * The list's size is the number of elements it currently holds. + */ + public void trimToSize() + { + elements.trimToSize(); + } + + /** + * Ensures that the list's capacity is at least equal to + * size. The list's capacity is the number of elements it + * can hold before it needs to be reallocated. + * + * @param size The capacity to ensure the list can hold + */ + public void ensureCapacity(int size) + { + elements.ensureCapacity(size); + } + + /** + * Sets the size of the list to a particular value. If the specified size + * is greater than the current size, the values at the excess list + * indices are set to null. If the specified size is less + * than the current size, the excess elements are removed from the list. + * + * @param size The new size to set the list to + */ + public void setSize(int size) + { + elements.setSize(size); + } + + /** + * Gets the capacity of the list. The list's capacity is the number of + * elements it can hold before it needs to be reallocated. + * + * @return The capacity of the list + */ + public int capacity() + { + return elements.capacity(); + } + + /** + * Gets the first element in the list. + * + * @return The first element in the list + */ + public Object firstElement() + { + return elements.firstElement(); + } + + /** + * Gets the last element in the list. + * + * @return The last element in the list + */ + public Object lastElement() + { + return elements.lastElement(); + } + + /** + * Sets the list element at a particular index. + * + * @param element The value to set at the specified index + * @param index The list index at which to set a value + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public void setElementAt(Object element, int index) + { + elements.setElementAt(element, index); + fireContentsChanged(this, index, index); + } + + /** + * Removes the element at a particular index from the list. + * + * @param index The index of the element to remove + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public void removeElementAt(int index) + { + elements.remove(index); + fireIntervalRemoved(this, index, index); + } + + /** + * Inserts an element at a particular index in the list. Each element at + * index i >= index is shifted to position i+1. + * If index is equal to size(), this is + * equivalent to appending an element to the array. Any + * index greater than size() is illegal. + * + * @param element The element to insert at the index + * @param index The index to insert the element at + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds [0, size()] + */ + public void insertElementAt(Object element, int index) + { + elements.insertElementAt(element, index); + fireIntervalAdded(this, index, index); + } + + /** + * Removes the first occurrence of a particular element in the list. If the + * element does not exist in the list, nothing happens. + * + * @param element The element to remove + * + * @return true if the element existed in the list (and was + * removed), false otherwise + */ + public boolean removeElement(Object element) + { + int index; + index = elements.indexOf(element); + if (index != -1) + { + elements.remove(index); + fireIntervalRemoved(this, index, index); + return true; + } + return false; + } + + /** + * Remove all elements in the list. + */ + public void removeAllElements() + { + int size; + size = size(); + if (size > 0) + { + elements.clear(); + fireIntervalRemoved(this, 0, size - 1); + } + } + + /** + * Remove all elements between startIndex and + * endIndex inclusive. + * + * @param startIndex The first index in the range to remove + * @param endIndex The last index in the range to remove + * + * @throws ArrayIndexOutOfBoundsException if either index is outside the + * valid range of indices for this list [0, size()) + * @throws IllegalArgumentException if startIndex > endIndex + */ + public void removeRange(int startIndex, int endIndex) + { + int index; + if (startIndex > endIndex) + throw new IllegalArgumentException(); + for (index = endIndex; index >= startIndex; index--) + elements.remove(index); + fireIntervalRemoved(this, startIndex, endIndex); + } + + /** + * Gets the size of the list. + * + * @return The number of elements currently in the list + */ + public int getSize() + { + return elements.size(); + } + + /** + * Gets the list element at a particular index. + * + * @param index The index to get the list value at + * + * @return The list value at the provided index + * + * @throws ArrayIndexOutOfBoundsException If the provided index is + * outside the bounds of the list [0, size()) + */ + public Object getElementAt(int index) + { + return elements.get(index); + } +} diff --git a/libjava/javax/swing/DefaultListSelectionModel.java b/libjava/javax/swing/DefaultListSelectionModel.java index 093e3e616af..fb60b85d42f 100644 --- a/libjava/javax/swing/DefaultListSelectionModel.java +++ b/libjava/javax/swing/DefaultListSelectionModel.java @@ -1,4 +1,4 @@ -/* DefaultListSelectionModel.java -- +/* DefaultListSelectionModel.java -- Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,190 +35,555 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing; import java.io.Serializable; import java.util.EventListener; -import java.util.Vector; +import java.util.BitSet; import javax.swing.event.EventListenerList; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -public class DefaultListSelectionModel implements Cloneable, ListSelectionModel, Serializable + +/** + *

This class provides a default implementation of {@link + * ListSelectioModel}, which is used by {@link javax.swing.JList} and + * similar classes to manage the selection status of a number of data + * elements.

+ * + *

The class is organized abstractly as a set of intervals of + * integers. Each interval indicates an inclusive range of indices in a + * list -- held by some other object and unknown to this class -- which is + * considered "selected". There are various accessors for querying and + * modifying the set of intervals, with simplified forms accepting a single + * index, representing an interval with only one element.

+ */ +public class DefaultListSelectionModel implements Cloneable, + ListSelectionModel, + Serializable { + + /** The list of ListSelectionListeners subscribed to this selection model. */ protected EventListenerList listenerList = new EventListenerList(); + + + /** + * The current list selection mode. Must be one of the numeric constants + * SINGLE_SELECTION, SINGLE_INTERVAL_SELECTION + * or MULTIPLE_INTERVAL_SELECTION from {@link + * ListSelectionModel}. The default value is + * MULTIPLE_INTERVAL_SELECTION. + */ + int selectionMode = MULTIPLE_INTERVAL_SELECTION; + + + /** + * The index of the "lead" of the most recent selection. The lead is the + * second argument in any call to {@link #setSelectionInterval}, {@link + * #addSelectionInterval} or {@link #removeSelectionInterval}. Generally + * the lead refers to the most recent position a user dragged their mouse + * over. + */ + int leadSelectionIndex = -1; + + + /** + * The index of the "anchor" of the most recent selection. The anchor is + * the first argument in any call to {@link #setSelectionInterval}, + * {@link #addSelectionInterval} or {@link + * #removeSelectionInterval}. Generally the anchor refers to the first + * recent position a user clicks when they begin to drag their mouse over + * a list. + * + * @see #getAnchorSelectionIndex + * @see #setAnchorSelectionIndex + */ + int anchorSelectionIndex = -1; + + + /** + * controls the range of indices provided in any {@link + * ListSelectionEvent} fired by the selectionModel. Let + * [A,L] be the range of indices between {@link + * anchorSelectionIndex} and {@link leadSelectionIndex} inclusive, and + * let [i0,i1] be the range of indices changed in a given + * call which generates a {@link ListSelectionEvent}. Then when this + * property is true, the {@link ListSelectionEvent} contains + * the range [A,L] union [i0,i1]; when false it + * will contain only [i0,i1]. The default is + * true. + * + * @see #isLeadAnchorNotificationEnabled + * @see #setLeadAnchorNotificationEnabled + */ + boolean leadAnchorNotificationEnabled = true; + + + /** + * Whether the selection is currently "adjusting". Any {@link + * ListSelectionEvent} events constructed in response to changes in this + * list selection model will have their {@link + * ListSelectionEvent#isAdjusting} field set to this value. + * + * @see #getValueIsAdjusting + * @see #setValueIsAdjusting + */ + boolean valueIsAdjusting = false; + + + /** + * The current set of "intervals", represented simply by a {@link + * java.util.BitSet}. A set bit indicates a selected index, whereas a + * cleared bit indicates a non-selected index. + */ + BitSet sel = new BitSet(); + + + /** + * Gets the value of the {@link #selectionMode} property. + * + * @return The current value of the property + */ + public int getSelectionMode() + { + return selectionMode; + } + + /** + * Sets the value of the {@link #selectionMode} property. + * + * @param a The new value of the property + */ + public void setSelectionMode(int a) + { + selectionMode = a; + } + + /** + * Gets the value of the {@link #anchorSelectionIndex} property. + * + * @return The current property value + * + * @see #setAnchorSelectionIndex + */ + public int getAnchorSelectionIndex() + { + return anchorSelectionIndex; + } + + /** + * Sets the value of the {@link #anchorSelectionIndex} property. + * + * @param anchorIndex The new property value + * + * @see #getAnchorSelectionIndex + */ + public void setAnchorSelectionIndex(int anchorIndex) + { + anchorSelectionIndex = anchorIndex; + } - int mode = SINGLE_SELECTION; - - Vector sel = new Vector(); - - class Range - { - int i0, i1; - - Range(int a, int b) - { - if (a > b) - { - i0 = b; - i1 = a; - } - else - { - i0 = a; - i1 = b; - } - } - } + /** + * Gets the value of the {@link #leadSelectionIndex} property. + * + * @return The current property value + * + * @see #setLeadSelectionIndex + */ + public int getLeadSelectionIndex() + { + return leadSelectionIndex; + } + + /** + *

Sets the value of the {@link #anchorSelectionIndex} property. As a + * side effect, alters the selection status of two ranges of indices. Let + * OL be the old lead selection index, NL be + * the new lead selection index, and A be the anchor + * selection index. Then if A is a valid selection index, + * one of two things happens depending on the seleciton status of + * A:

+ * + *
    + * + *
  • isSelectedIndex(A) == true: set [A,OL] + * to deselected, then set [A,NL] to + * selected.
  • + * + *
  • isSelectedIndex(A) == false: set [A,OL] + * to selected, then set [A,NL] to + * deselected.
  • + * + *
+ * + *

This method generates at most a single {@link ListSelectionEvent} + * despite changing multiple ranges. The range of values provided to the + * {@link ListSelectionEvent} includes only the minimum range of values + * which changed selection status between the beginning and end of the + * method.

+ * + * @param anchorIndex The new property value + * + * @see #getAnchorSelectionIndex + */ + public void setLeadSelectionIndex(int leadIndex) + { + int oldLeadIndex = leadSelectionIndex; + leadSelectionIndex = leadIndex; + + if (anchorSelectionIndex == -1) + return; + + int R1 = Math.min(anchorSelectionIndex, oldLeadIndex); + int R2 = Math.max(anchorSelectionIndex, oldLeadIndex); + int S1 = Math.min(anchorSelectionIndex, leadIndex); + int S2 = Math.max(anchorSelectionIndex, leadIndex); + + int lo = Math.min(R1, S1); + int hi = Math.max(R2, S2); + + BitSet oldRange = sel.get(lo, hi+1); + + if (isSelectedIndex(anchorSelectionIndex)) + { + sel.clear(R1, R2+1); + sel.set(S1, S2+1); + } + else + { + sel.set(R1, R2+1); + sel.clear(S1, S2+1); + } + + BitSet newRange = sel.get(lo, hi+1); + newRange.xor(oldRange); + + int beg = sel.nextSetBit(0), end = -1; + for(int i=beg; i >= 0; i=sel.nextSetBit(i+1)) + { + end = i; + } + fireSelectionValueChanged(beg, end, valueIsAdjusting); + } + + /** + * Gets the value of the {@link #leadAnchorNotificationEnabled} property. + * + * @return The current property value + * + * @see #setLeadAnchorNotificationEnabled + */ + public boolean isLeadAnchorNotificationEnabled() + { + return leadAnchorNotificationEnabled; + } + + /** + * Sets the value of the {@link #leadAnchorNotificationEnabled} property. + * + * @param flag The new property value + * + * @see #getLeadAnchorNotificationEnabled + */ + public void setLeadAnchorNotificationEnabled(boolean l) + { + leadAnchorNotificationEnabled = l; + } + + + /** + * Gets the value of the {@link #valueIsAdjusting} property. + * + * @return The current property value + * + * @see #setValueIsAdjusting + */ + public boolean getValueIsAdjusting() + { + return valueIsAdjusting; + } + + /** + * Sets the value of the {@link #valueIsAdjusting} property. + * + * @param v The new property value + * + * @see #getValueIsAdjusting + */ + public void setValueIsAdjusting(boolean v) + { + valueIsAdjusting = v; + } + + /** + * Determines whether the selection is empty. + * + * @return true if the selection is empty, otherwise + * false + */ + public boolean isSelectionEmpty() + { + return sel.isEmpty(); + } + + + /** + * Gets the smallest index which is currently a member of a selection + * interval. + * + * @return The least integer i such that i >= + * 0 and i is a member of a selected interval, or + * -1 if there are no selected intervals + * + * @see #getMaxSelectionIndex + */ + public int getMinSelectionIndex() + { + if (isSelectionEmpty()) + return -1; + + return sel.nextSetBit(0); + } + /** + * Gets the largest index which is currently a member of a selection + * interval. + * + * @return The greatest integer i such that i >= + * 0 and i is a member of a selected interval, or + * -1 if there are no selected intervals + * + * @see #getMinSelectionIndex + */ + public int getMaxSelectionIndex() + { + if (isSelectionEmpty()) + return -1; + + int mx = -1; + for(int i=sel.nextSetBit(0); i >= 0; i=sel.nextSetBit(i+1)) + { + mx = i; + } + return mx; + } + + /** + * Determines whether a particular index is a member of a selection + * interval. + * + * @param a The index to search for + * + * @return true if the index is a member of a selection interval, + * otherwise false + */ + public boolean isSelectedIndex(int a) + { + return sel.get(a); + } + + /** + * If the {@link #selectionMode} property is equal to + * SINGLE_SELECTION or + * SINGLE_INTERVAL_SELECTION, equivalent to calling + * setSelectionInterval(index1, index2); otherwise adds the + * range [index0, index1] to the selection interval set. + * + * @param index0 The beginning of the range of indices to select + * @param index1 The end of the range of indices to select + * + * @see #setSelectionInterval + * @see #removeSelectionInterval + */ + public void addSelectionInterval(int index0, int index1) + { + if (selectionMode == SINGLE_SELECTION + || selectionMode == SINGLE_INTERVAL_SELECTION) + sel.clear(); - public int getMinSelectionIndex() - { - if (isSelectionEmpty()) - return -1; - - boolean first = true; - int min = -1; - for (int i=0;i min) - { - min = r.i0; - } - } - } - return min; - } - - public int getMaxSelectionIndex() - { - if (isSelectionEmpty()) - return -1; - - boolean first = true; - int max = -1; - for (int i=1;i max) - { - max = r.i1; - } - } - } - return max; - } - - public boolean isSelectedIndex(int a) - { - for (int i=0;i= a) - { - return true; - } - } - return false; - } - - - public int getSelectionMode() - { return mode; } - public void setSelectionMode(int a) - { mode = a; } - - boolean isSelectionEmpty() - { - return sel.size() == 0; - } - - public void clearSelection() - { - sel.removeAllElements(); - } - - public void setSelectionInterval(int index0, int index1) - { - if (mode == SINGLE_SELECTION) - { - sel.removeAllElements(); - } - - sel.addElement(new Range(index0, index1)); - } + if (selectionMode == SINGLE_SELECTION) + index0 = index1; + + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + + sel.set(lo, hi+1); + fireSelectionValueChanged(lo, hi, valueIsAdjusting); + } + + + /** + * Deselects all indices in the inclusive range + * [index0,index1]. + * + * @param index0 The beginning of the range of indices to deselect + * @param index1 The end of the range of indices to deselect + * + * @see #addSelectionInterval + * @see #setSelectionInterval + */ + public void removeSelectionInterval(int index0, + int index1) + { + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + sel.clear(lo, hi+1); + fireSelectionValueChanged(lo, hi, valueIsAdjusting); + } + + /** + * Removes all intervals in the selection set. + */ + public void clearSelection() + { + int sz = sel.size(); + sel.clear(); + fireSelectionValueChanged(0, sz, valueIsAdjusting); + } + + /** + * Clears the current selection and marks a given interval as + * "selected". If the current selection mode is + * SINGLE_SELECTION only the index index2 is + * selected. + * + * @param index0 The low end of the new selection + * @param index1 The high end of the new selection + */ + public void setSelectionInterval(int index0, int index1) + { + sel.clear(); + if (selectionMode == SINGLE_SELECTION) + index0 = index1; + + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + sel.set(lo, hi+1); + fireSelectionValueChanged(lo, hi, valueIsAdjusting); + } + + /** + * Inserts a number of indices either before or after a particular + * position in the set of indices. Renumbers all indices after the + * inserted range. The new indices in the inserted range are not + * selected. This method is typically called to synchronize the selection + * model with an inserted range of elements in a {@link ListModel}. + * + * @param index The position to insert indices at + * @param length The number of indices to insert + * @param before Indicates whether to insert the indices before the index + * or after it + */ + public void insertIndexInterval(int index, + int length, + boolean before) + { + if (!before) + { + index++; + length--; + } + BitSet tmp = sel.get(index, sel.size()); + sel.clear(index, sel.size()); + int n = tmp.size(); + for (int i = 0; i < n; ++i) + sel.set(index + length + i, tmp.get(i)); + } + + /** + * Removes a range from the set of indices. Renumbers all indices after + * the removed range. This method is typically called to synchronize the + * selection model with a deleted range of elements in a {@link + * ListModel}. + * + * @param index0 The first index to remove (inclusive) + * @param index1 The last index to remove (inclusive) + */ + public void removeIndexInterval(int index0, + int index1) + { + int lo = Math.min(index0, index1); + int hi = Math.max(index0, index1); + + BitSet tmp = sel.get(hi, sel.size()); + sel.clear(lo, sel.size()); + int n = tmp.size(); + for (int i = 0; i < n; ++i) + sel.set(lo + i, tmp.get(i)); + } + + /** + * Fires a {@link ListSelectionEvent} to all the listeners of type {@link + * ListSelectionListener} registered with this selection model. + * + * @param firstIndex The low index of the changed range + * @param lastIndex The high index of the changed range + * @param isAdjusting Whether this change is part of a seqence of adjustments + * made to the selection, such as during interactive scrolling + */ + public void fireSelectionValueChanged(int firstIndex, int lastIndex, + boolean isAdjusting) + { + ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, + lastIndex, isAdjusting); + ListSelectionListener[] listeners = getListSelectionListeners(); + for (int i = 0; i < listeners.length; ++i) + listeners[i].valueChanged(evt); + } /** * Adds a listener. * - * @param listener the listener to add + * @param listener The listener to add * * @see removeListSelectionListener * @see getListSelectionListeners */ public void addListSelectionListener(ListSelectionListener listener) { - listenerList.add (ListSelectionListener.class, listener); + listenerList.add(ListSelectionListener.class, listener); } /** * Removes a registered listener. * - * @param listener the listener to remove + * @param listener The listener to remove * * @see addListSelectionListener * @see getListSelectionListeners */ public void removeListSelectionListener(ListSelectionListener listener) { - listenerList.remove (ListSelectionListener.class, listener); + listenerList.remove(ListSelectionListener.class, listener); } - + /** * Returns an array of all registerers listeners. - * - * @return the array - * - * @since 1.3 + * + * @param listenerType The type of listener to retrieve + * + * @return The array * * @see getListSelectionListener + * @since 1.3 */ - public EventListener[] getListeners (Class listenerType) + public EventListener[] getListeners(Class listenerType) { - return listenerList.getListeners (listenerType); + return listenerList.getListeners(listenerType); } /** * Returns an array of all registerd list selection listeners. * * @return the array - * - * @since 1.4 * * @see addListSelectionListener * @see removeListSelectionListener * @see getListeners + * @since 1.4 */ public ListSelectionListener[] getListSelectionListeners() { - return (ListSelectionListener[]) getListeners (ListSelectionListener.class); + return (ListSelectionListener[]) getListeners(ListSelectionListener.class); } } diff --git a/libjava/javax/swing/JComponent.java b/libjava/javax/swing/JComponent.java index afe5700d13e..fdc5dbcc8a9 100644 --- a/libjava/javax/swing/JComponent.java +++ b/libjava/javax/swing/JComponent.java @@ -75,6 +75,7 @@ import javax.swing.event.AncestorListener; import javax.swing.event.EventListenerList; import javax.swing.border.Border; import javax.swing.plaf.ComponentUI; +import javax.swing.event.SwingPropertyChangeSupport; /** * Every component in swing inherits from this class (JLabel, JButton, etc). @@ -88,21 +89,26 @@ public abstract class JComponent extends Container implements Serializable { static final long serialVersionUID = -5242478962609715464L; - protected EventListenerList listenerList = new EventListenerList(); - - /** - * accessibleContext - */ - protected AccessibleContext accessibleContext; - - Dimension pref,min,max; - Border border; - JToolTip tooltip; - String tool_tip_text; - boolean use_double_buffer, opaque; - protected ComponentUI ui; - - Hashtable prop_hash; + EventListenerList listenerList = new EventListenerList(); + + /** + * accessibleContext + */ + AccessibleContext accessibleContext; + + Dimension pref,min,max; + Border border; + JToolTip tooltip; + String tool_tip_text; + boolean use_double_buffer, opaque; + Image doubleBuffer; + int doubleBufferWidth = -1; + int doubleBufferHeight = -1; + ComponentUI ui; + private SwingPropertyChangeSupport changeSupport; + + Hashtable prop_hash; + /** * AccessibleJComponent @@ -195,7 +201,7 @@ public abstract class JComponent extends Container implements Serializable * addPropertyChangeListener * @param listener TODO */ - public void addPropertyChangeListener(PropertyChangeListener listener) { + public void addPropertyChangeListener(PropertyChangeListener listener) { // TODO } // addPropertyChangeListener() @@ -318,7 +324,8 @@ public abstract class JComponent extends Container implements Serializable */ public void removePropertyChangeListener(PropertyChangeListener listener) { - listenerList.remove(PropertyChangeListener.class, listener); + if (changeSupport != null) + changeSupport.removePropertyChangeListener(listener); } /** @@ -350,7 +357,9 @@ public abstract class JComponent extends Container implements Serializable */ public void addPropertyChangeListener(PropertyChangeListener listener) { - listenerList.add(PropertyChangeListener.class, listener); + if (changeSupport == null) + changeSupport = new SwingPropertyChangeSupport(this); + changeSupport.addPropertyChangeListener(listener); } /** @@ -404,45 +413,68 @@ public abstract class JComponent extends Container implements Serializable //Returns the Component's "visible rect rectangle" - the intersection of the visible rectangles for this component and all of its ancestors. //super.computeVisibleRect(rect); } + + public PropertyChangeListener[] getPropertyChangeListeners(String property) + { + return changeSupport == null ? new PropertyChangeListener[0] + : changeSupport.getPropertyChangeListeners(property); + } public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { - //Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Boolean(oldValue), + new Boolean(newValue)); } public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { - // Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Byte(oldValue), + new Byte(newValue)); } public void firePropertyChange(String propertyName, char oldValue, char newValue) { - //Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Character(oldValue), + new Character(newValue)); } public void firePropertyChange(String propertyName, double oldValue, double newValue) { - //Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Double(oldValue), + new Double(newValue)); } public void firePropertyChange(String propertyName, float oldValue, float newValue) { - // Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Float(oldValue), + new Float(newValue)); } public void firePropertyChange(String propertyName, int oldValue, int newValue) { - // Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Integer(oldValue), + new Integer(newValue)); } public void firePropertyChange(String propertyName, long oldValue, long newValue) { - //Reports a bound property change. protected + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Long(oldValue), + new Long(newValue)); } - protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) + protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { - // Support for reporting bound property changes. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, oldValue, newValue); } public void firePropertyChange(String propertyName, short oldValue, short newValue) { - // Reports a bound property change. + if (changeSupport != null) + changeSupport.firePropertyChange(propertyName, new Short(oldValue), + new Short(newValue)); } protected void fireVetoableChange(String propertyName, Object oldValue, Object newValue) @@ -757,14 +789,21 @@ public abstract class JComponent extends Container implements Serializable public void paint(Graphics g) { Graphics g2 = g; - Image im = null; Rectangle r = getBounds (); - // System.err.println(this + ".paint(...), bounds = " + r); if (use_double_buffer) { - im = createImage (r.width, r.height); - g2 = im.getGraphics (); + + if (doubleBuffer == null + || doubleBufferWidth != r.width + || doubleBufferHeight != r.height) + { + doubleBuffer = createImage(r.width, r.height); + doubleBufferWidth = r.width; + doubleBufferHeight = r.height; + } + + g2 = doubleBuffer.getGraphics (); if (this.getBackground() != null) { Color save = g2.getColor(); @@ -785,7 +824,7 @@ public abstract class JComponent extends Container implements Serializable // always draw at 0,0, because regardless of your current bounds, // the graphics object you were passed was positioned so the origin // was at the upper left corner of your bounds. - g.drawImage (im, 0, 0, (ImageObserver)null); + g.drawImage (doubleBuffer, 0, 0, (ImageObserver)null); } } diff --git a/libjava/javax/swing/JLabel.java b/libjava/javax/swing/JLabel.java index 2d1c440ca2c..19f992c2f7f 100644 --- a/libjava/javax/swing/JLabel.java +++ b/libjava/javax/swing/JLabel.java @@ -1,5 +1,5 @@ -/* JLabel.java -- - Copyright (C) 2002 Free Software Foundation, Inc. +/* JLabel.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,205 +35,661 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing; import java.awt.Component; import java.awt.Image; +import java.awt.Font; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; +import javax.swing.Icon; import javax.swing.plaf.LabelUI; + +/** + *

+ * A swing widget that displays a text message and/or an icon. + *

+ */ public class JLabel extends JComponent implements Accessible, SwingConstants { + /** DOCUMENT ME! */ private static final long serialVersionUID = 5496508283662221534L; + + /** + * The Component the label will give focus to when its mnemonic is + * activated. + */ + protected Component labelFor; + + /** The label's text. */ + private transient String labelText; + + /** Where the label will be positioned horizontally. */ + private transient int horizontalAlignment = CENTER; + + /** Where the label text will be placed horizontally relative to the icon. */ + private transient int horizontalTextPosition = TRAILING; + + /** Where the label will be positioned vertically. */ + private transient int verticalAlignment = CENTER; + + /** Where the label text will be place vertically relative to the icon. */ + private transient int verticalTextPosition = CENTER; + + /** The icon painted when the label is enabled. */ + private transient Icon activeIcon; + + /** The icon painted when the label is disabled. */ + private transient Icon disabledIcon; + + /** The label's mnemnonic key. */ + private transient char mnemonicKey; + + /** The index of the menemonic character in the text. */ + private transient int underlinedChar = -1; + + /** The gap between the icon and the text. */ + private transient int iconTextGap = 4; + + /** + * Fired in a PropertyChangeEvent when the "disabledIcon" property changes. + */ + public static final String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon"; + + /** + * Fired in a PropertyChangeEvent when the "displayedMnemonic" property + * changes. + */ + public static final String DISPLAYED_MNEMONIC_CHANGED_PROPERTY = "displayedMnemonic"; - String text; - Icon icon; - int gap; - int align; + /** + * Fired in a PropertyChangeEvent when the "displayedMnemonicIndex" + * property changes. */ + public static final String DISPLAYED_MNEMONIC_INDEX_CHANGED_PROPERTY = "displayedMnemonicIndex"; - int hor_align; - int hor_text_pos; + /** + * Fired in a PropertyChangeEvent when the "horizontalAlignment" property + * changes. + */ + public static final String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment"; - int vert_align; - int vert_text_pos; + /** + * Fired in a PropertyChangeEvent when the "horizontalTextPosition" property + * changes. + */ + public static final String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition"; - public JLabel() - { - this("", null, 0); - } + /** Fired in a PropertyChangeEvent when the "icon" property changes. */ + public static final String ICON_CHANGED_PROPERTY = "icon"; - public JLabel(Icon image) - { - this("", image, 0); - } + /** Fired in a PropertyChangeEvent when the "iconTextGap" property changes. */ + public static final String ICON_TEXT_GAP_CHANGED_PROPERTY = "iconTextGap"; - public JLabel(Icon image, int horizontalAlignment) - { - this("", image, horizontalAlignment); - } + /** Fired in a PropertyChangeEvent when the "labelFor" property changes. */ + public static final String LABEL_FOR_CHANGED_PROPERTY = "labelFor"; - public JLabel(String text) - { - this(text, null, 0); - } + /** Fired in a PropertyChangeEvent when the "text" property changes. */ + public static final String TEXT_CHANGED_PROPERTY = "text"; - public JLabel(String text, int horizontalAlignment) - { - this(text, null, horizontalAlignment); - } + /** + * Fired in a PropertyChangeEvent when the "verticalAlignment" property + * changes. + */ + public static final String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment"; - public JLabel(String text, Icon icon, int horizontalAlignment) - { - // do the work..... - this.text = text; - setIcon(icon); - this.align = horizontalAlignment; + /** + * Fired in a PropertyChangeEvent when the "verticalTextPosition" property + * changes. + */ + public static final String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition"; - updateUI(); // get a proper ui - } + /** + * Creates a new horizontally and vertically centered JLabel object with no text and no + * icon. + */ + public JLabel() + { + this(null, null, CENTER); + } + /** + * Creates a new horizontally and vertically centered JLabel object with no text and the + * given icon. + * + * @param image The icon to use with the label. + */ + public JLabel(Icon image) + { + this(null, image, CENTER); + } - protected int checkHorizontalKey(int key, String message) - { - // Verify that key is a legal value for the horizontalAlignment properties. - return 0; - } - protected int checkVerticalKey(int key, String message) - { - // Verify that key is a legal value for the verticalAlignment or verticalTextPosition properties. - return 0; - } - public AccessibleContext getAccessibleContext() - { - // Get the AccessibleContext of this object - return null; - } - public Icon getDisabledIcon() - { - // Returns the value of the disabledIcon property if it's been set, If it hasn't been set and the value of the icon property is an ImageIcon, we compute a "grayed out" version of the icon and update the disabledIcon property with that. - return null; - } - public int getDisplayedMnemonic() - { - // Return the keycode that indicates a mnemonic key. - return 0; - } - public int getHorizontalAlignment() - { - // Returns the alignment of the label's contents along the X axis. - return hor_align; - } - public int getHorizontalTextPosition() - { - // Returns the horizontal position of the label's text, relative to its image. - return hor_text_pos; - } + /** + * Creates a new vertically centered JLabel object with no text and the given icon and + * horizontal alignment. By default, the text is TRAILING the image. + * + * @param image The icon to use with the label. + * @param horizontalAlignment The horizontal alignment of the label. + */ + public JLabel(Icon image, int horizontalAlignment) + { + this(null, image, horizontalAlignment); + } - public Icon getIcon() - { return icon; } + /** + * Creates a new horizontally and vertically centered JLabel object with no icon and the + * given text. + * + * @param text The text to use with the label. + */ + public JLabel(String text) + { + this(text, null, CENTER); + } - public int getIconTextGap() - { - // Returns the amount of space between the text and the icon displayed in this label. - return 0; - } - public Component getLabelFor() - { - // Get the component this is labelling. - return null; - } - public String getText() - { return text; } + /** + * Creates a new vertically centered JLabel object with no icon and the given text and + * horizontal alignment. + * + * @param text The text to use with the label. + * @param horizontalAlignment The horizontal alignment of the label. + */ + public JLabel(String text, int horizontalAlignment) + { + this(text, null, horizontalAlignment); + } - public String getUIClassID() - { return "LabelUI"; } + /** + * Creates a new vertically centered JLabel object with the given text, icon, and horizontal + * alignment. + * + * @param text The text to use with the label. + * @param icon The icon to use with the label. + * @param horizontalAlignment The horizontal alignment of the label. + */ + public JLabel(String text, Icon icon, int horizontalAlignment) + { + labelText = text; + activeIcon = icon; + this.horizontalAlignment = horizontalAlignment; + updateUI(); + } - public int getVerticalAlignment() - { - // Returns the alignment of the label's contents along the Y axis. - return vert_align; - } - public int getVerticalTextPosition() - { - // Returns the vertical position of the label's text, relative to its image. - return vert_text_pos; - } + /** + * This method returns the label's UI delegate. + * + * @return The label's UI delegate. + */ + public LabelUI getUI() + { + return (LabelUI) ui; + } - public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) - { - // This is overriden to return false if the current Icon's Image is not equal to the passed in Image img. - return (img == icon); - } - protected String paramString() - { - // Returns a string representation of this JLabel. - return "JLabel"; - } - public void setDisabledIcon(Icon disabledIcon) - { - // Set the icon to be displayed if this JLabel is "disabled" (JLabel.setEnabled(false)). - } - public void setDisplayedMnemonic(char aChar) - { - // Specifies the displayedMnemonic as a char value. - } - public void setDisplayedMnemonic(int key) - { - // Specify a keycode that indicates a mnemonic key. - } - public void setHorizontalAlignment(int alignment) - { - // Sets the alignment of the label's contents along the X axis. - hor_align = alignment; - } - public void setHorizontalTextPosition(int textPosition) - { - // Sets the horizontal position of the label's text, relative to its image. - hor_text_pos = textPosition; - } - public void setIcon(Icon icon) - { - this.icon = icon; - if (icon != null) - { - // XXX FIXME - icons do not know their parent -// icon.setParent(this); - } - revalidate(); - repaint(); - } + /** + * This method sets the label's UI delegate. + * + * @param ui The label's UI delegate. + */ + public void setUI(LabelUI ui) + { + super.setUI(ui); + } - public void setIconTextGap(int iconTextGap) - { - gap = iconTextGap; - } - - public void setLabelFor(Component c) - { - // Set the component this is labelling. - } - public void setText(String text) + /** + * This method resets the label's UI delegate to the default UI for the + * current look and feel. + */ + public void updateUI() + { + setUI((LabelUI) UIManager.getUI(this)); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for this label. + * + * @return The UIClass identifier. "LabelUI" + */ + public String getUIClassID() + { + return "LabelUI"; + } + + /** + * This method is used primarily for debugging purposes and returns a string + * that can be used to represent this label. + * + * @return A string to represent this label. + */ + protected String paramString() + { + return "JLabel"; + } + + /** + * This method returns the label text. + * + * @return The label text. + */ + public String getText() + { + return labelText; + } + + /** + * This method changes the "text" property. The given text will be painted + * in the label. + * + * @param text The label's text. + */ + public void setText(String text) + { + if (text != labelText) + { + String oldText = labelText; + labelText = text; + firePropertyChange(TEXT_CHANGED_PROPERTY, oldText, labelText); + if (labelText.length() <= underlinedChar) + setDisplayedMnemonicIndex(labelText.length() - 1); + } + } + + /** + * This method returns the active icon. The active icon is painted when the + * label is enabled. + * + * @return The active icon. + */ + public Icon getIcon() + { + return activeIcon; + } + + /** + * This method changes the "icon" property. This icon (the active icon) will + * be the one displayed when the label is enabled. + * + * @param icon The active icon. + */ + public void setIcon(Icon icon) + { + if (icon != activeIcon) + { + Icon oldIcon = activeIcon; + activeIcon = icon; + firePropertyChange(ICON_CHANGED_PROPERTY, oldIcon, activeIcon); + } + } + + /** + * This method returns the disabled icon. The disabled icon is painted when + * the label is disabled. If the disabled icon is null and the active icon is + * an ImageIcon, this method returns a grayed version of the icon. The grayed + * version of the icon becomes the disabledIcon. + * + * @return The disabled icon. + */ + public Icon getDisabledIcon() + { + //FIXME: We should be gray-scaling the active icon and then returning it + if (disabledIcon == null && activeIcon instanceof ImageIcon) + setDisabledIcon(activeIcon); + return disabledIcon; + } + + /** + * This method changes the "disabledIcon" property. This icon (the disabled + * icon) will be the one displayed when the label is disabled. + * + * @param disabledIcon The disabled icon. + */ + public void setDisabledIcon(Icon disabledIcon) + { + if (disabledIcon != this.disabledIcon) + { + Icon oldDisabledIcon = this.disabledIcon; + this.disabledIcon = disabledIcon; + firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, oldDisabledIcon, + this.disabledIcon); + } + } + + /** + * This method sets the keycode that will be the label's mnemonic. If the + * label is used as a label for another component, the label will give + * focus to that component when the mnemonic is activated. + * + * @param key The keycode to use for the mnemonic. + */ + public void setDisplayedMnemonic(int key) + { + setDisplayedMnemonic((char) key); + } + + /** + * This method sets the character that will be the mnemonic used. If the + * label is used as a label for another component, the label will give + * focus to that component when the mnemonic is activated. + * + * @param aChar The character to use for the mnemonic. + */ + public void setDisplayedMnemonic(char aChar) + { + if (aChar != mnemonicKey) + { + char oldKey = mnemonicKey; + mnemonicKey = aChar; + firePropertyChange(DISPLAYED_MNEMONIC_CHANGED_PROPERTY, oldKey, + mnemonicKey); + if (labelText != null) + setDisplayedMnemonicIndex(labelText.indexOf(mnemonicKey)); + } + } + + /** + * This method returns the keycode that is used for the label's mnemonic. + * + * @return The keycode that is used for the label's mnemonic. + */ + public int getDisplayedMnemonic() + { + return (int) mnemonicKey; + } + + /** + * This method sets which character in the text will be the underlined + * character. If the given index is -1, then this indicates that there is + * no mnemonic. If the index is less than -1 or if the index is equal to + * the length, this method will throw an IllegalArgumentException. + * + * @param index The index of the character to underline. + * + * @throws IllegalArgumentException If index less than -1 or index equals + * length. + */ + public void setDisplayedMnemonicIndex(int index) + throws IllegalArgumentException + { + if (index < -1 || labelText != null && index >= labelText.length()) + throw new IllegalArgumentException(); + + if (labelText == null || labelText.charAt(index) != mnemonicKey) + index = -1; + + if (index != underlinedChar) { - this.text = text; - revalidate(); - repaint(); + int oldIndex = underlinedChar; + underlinedChar = index; + firePropertyChange(DISPLAYED_MNEMONIC_INDEX_CHANGED_PROPERTY, + oldIndex, underlinedChar); } + } + + /** + * This method returns which character in the text will be the underlined + * character. + * + * @return The index of the character that will be underlined. + */ + public int getDisplayedMnemonicIndex() + { + return underlinedChar; + } + + /** + * This method ensures that the key is valid as a horizontal alignment. + * Valid keys are: LEFT, CENTER, RIGHT, LEADING, TRAILING + * + * @param key The key to check. + * @param message The message of the exception to be thrown if the key is + * invalid. + * + * @return The key if it's valid. + * + * @throws IllegalArgumentException If the key is invalid. + */ + protected int checkHorizontalKey(int key, String message) + { + if (key != LEFT && key != CENTER && key != RIGHT && key != LEADING + && key != TRAILING) + throw new IllegalArgumentException(message); + else + return key; + } + + /** + * This method ensures that the key is valid as a vertical alignment. Valid + * keys are: TOP, CENTER, and BOTTOM. + * + * @param key The key to check. + * @param message The message of the exception to be thrown if the key is + * invalid. + * + * @return The key if it's valid. + * + * @throws IllegalArgumentException If the key is invalid. + */ + protected int checkVerticalKey(int key, String message) + { + if (key != TOP && key != BOTTOM && key != CENTER) + throw new IllegalArgumentException(message); + else + return key; + } + + /** + * This method returns the gap between the icon and the text. + * + * @return The gap between the icon and the text. + */ + public int getIconTextGap() + { + return iconTextGap; + } + + /** + * This method changes the "iconTextGap" property. The iconTextGap + * determines how much space there is between the icon and the text. + * + * @param iconTextGap The gap between the icon and the text. + */ + public void setIconTextGap(int iconTextGap) + { + if (iconTextGap != this.iconTextGap) + { + int oldIconTextGap = this.iconTextGap; + this.iconTextGap = iconTextGap; + firePropertyChange(ICON_TEXT_GAP_CHANGED_PROPERTY, oldIconTextGap, + iconTextGap); + } + } + + /** + * This method returns the vertical alignment of the label. + * + * @return The vertical alignment of the label. + */ + public int getVerticalAlignment() + { + return verticalAlignment; + } + + /** + * This method changes the "verticalAlignment" property of the label. The + * vertical alignment determines how where the label will be placed + * vertically. If the alignment is not valid, it will default to the + * center. + * + * @param alignment The vertical alignment of the label. + */ + public void setVerticalAlignment(int alignment) + { + if (alignment != verticalAlignment) + { + int oldAlignment = verticalAlignment; + verticalAlignment = checkVerticalKey(alignment, "verticalAlignment"); + firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, oldAlignment, + verticalAlignment); + } + } + + /** + * This method returns the horziontal alignment of the label. + * + * @return The horizontal alignment of the label. + */ + public int getHorizontalAlignment() + { + return horizontalAlignment; + } + + /** + * This method changes the "horizontalAlignment" property. The horizontal + * alignment determines where the label will be placed horizontally. + * + * @param alignment The horizontal alignment of the label. + */ + public void setHorizontalAlignment(int alignment) + { + int oldAlignment = horizontalAlignment; + horizontalAlignment = checkHorizontalKey(alignment, "horizontalAlignment"); + firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, oldAlignment, + horizontalAlignment); + } + + /** + * This method returns the vertical text position of the label. + * + * @return The vertical text position of the label. + */ + public int getVerticalTextPosition() + { + return verticalTextPosition; + } + + /** + * This method changes the "verticalTextPosition" property of the label. The + * vertical text position determines where the text will be placed + * vertically relative to the icon. + * + * @param textPosition The vertical text position. + */ + public void setVerticalTextPosition(int textPosition) + { + if (textPosition != verticalTextPosition) + { + int oldPos = verticalTextPosition; + verticalTextPosition = checkVerticalKey(textPosition, + "verticalTextPosition"); + firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, oldPos, + verticalTextPosition); + } + } + + /** + * This method returns the horizontal text position of the label. + * + * @return The horizontal text position. + */ + public int getHorizontalTextPosition() + { + return horizontalTextPosition; + } + + /** + * This method changes the "horizontalTextPosition" property of the label. + * The horizontal text position determines where the text will be placed + * horizontally relative to the icon. + * + * @param textPosition The horizontal text position. + */ + public void setHorizontalTextPosition(int textPosition) + { + if (textPosition != horizontalTextPosition) + { + int oldPos = horizontalTextPosition; + horizontalTextPosition = checkHorizontalKey(textPosition, + "horizontalTextPosition"); + firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, oldPos, + horizontalTextPosition); + } + } + + /** + * This method simply returns false if the current icon image (current icon + * will depend on whether the label is enabled) is not equal to the passed + * in image. + * + * @param img The image to check. + * @param infoflags The bitwise inclusive OR of ABORT, ALLBITS, ERROR, + * FRAMEBITS, HEIGHT, PROPERTIES, SOMEBITS, and WIDTH + * @param x The x position + * @param y The y position + * @param w The width + * @param h The height + * + * @return Whether the current icon image is equal to the image given. + */ + public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, + int h) + { + Icon currIcon = (isEnabled()) ? activeIcon : disabledIcon; + + //Is this the correct way to check for image equality? + if (currIcon != null && currIcon instanceof ImageIcon) + return (((ImageIcon) currIcon).getImage() == img); + return false; + } + + /** + * This method returns the component that the label gives focus to when the + * mnemonic is activated. + * + * @return The component that gets focus when the label's mnemonic is + * activated. + */ + public Component getLabelFor() + { + return labelFor; + } + + /** + * This method changes the "labelFor" property. The component that the label + * is acting as a label for will request focus when the label's mnemonic + * is activated. + * + * @param c The component that gets focus when the label's mnemonic is + * activated. + */ + public void setLabelFor(Component c) + { + if (c != labelFor) + { + Component oldLabelFor = labelFor; + labelFor = c; + firePropertyChange(LABEL_FOR_CHANGED_PROPERTY, oldLabelFor, labelFor); + } + } - public void setVerticalAlignment(int alignment) - { - // Sets the alignment of the label's contents along the Y axis. - vert_align = alignment; - } - public void setVerticalTextPosition(int textPosition) - { - // Sets the vertical position of the label's text, relative to its image. - vert_text_pos = textPosition; - } - public void updateUI() - { - LabelUI b = (LabelUI)UIManager.getUI(this); - setUI(b); - } + /** + * This method overrides setFont so that we can call for a repaint + * after the font is changed. + * + * @param f The font for this label. + */ + public void setFont(Font f) + { + super.setFont(f); + repaint(); + } + + /** + * DOCUMENT ME! + * + * @return + */ + public AccessibleContext getAccessibleContext() + { + return null; + } } diff --git a/libjava/javax/swing/JList.java b/libjava/javax/swing/JList.java index f87ce6201a9..92cce2240c1 100644 --- a/libjava/javax/swing/JList.java +++ b/libjava/javax/swing/JList.java @@ -1,4 +1,4 @@ -/* JList.java -- +/* JList.java -- Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,10 +35,10 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing; import java.awt.Color; +import java.awt.Component; import java.awt.Dimension; import java.awt.Rectangle; import java.util.Vector; @@ -46,208 +46,890 @@ import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; +import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.plaf.ListUI; + +/** + *

This class is a facade over three separate objects: {@link + * javax.swing.ListModel}, {@link javax.swing.ListSelectionModel} and + * {@link javax.swing.plaf.ListUI}. The facade represents a unified "list" + * concept, with independently replacable (possibly client-provided) models + * for its contents and its current selection. In addition, each element in + * the list is rendered via a strategy class {@link + * javax.swing.ListCellRenderer}.

+ * + *

Lists have many properties, some of which are stored in this class + * while others are delegated to the list's model or selection. The + * following properties are available:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Property Stored inBound?
accessibleContext list no
anchorSelectionIndex selectionno
cellRenderer list yes
dragEnabled list no
firstVisibleIndex list no
fixedCellHeight list yes
fixedCellWidth list yes
lastVisibleIndex list no
layoutOrientation list yes
leadSelectionIndex selectionno
maxSelectionIndex selectionno
minSelectionIndex selectionno
model list yes
opaque list no
preferredScrollableViewportSizelist no
prototypeCellValue list yes
scrollableTracksViewportHeight list no
scrollableTracksViewportWidth list no
selectedIndex selectionno
selectedIndices selectionno
selectedValue model no
selectedValues model no
selectionBackground list yes
selectionEmpty selectionno
selectionForeground list yes
selectionMode selectionno
selectionModel list yes
UI list yes
UIClassID list no
valueIsAdjusting list no
visibleRowCount list no
+ * + * @author Graydon Hoare (graydon&064;redhat.com) + */ + public class JList extends JComponent implements Accessible, Scrollable { private static final long serialVersionUID = 4406629526391098046L; - Color select_back, select_fore; - ListCellRenderer render; - int visibles = 8; - - ListModel model; - ListSelectionModel sel_model; + /** + * Constant value used in "layoutOrientation" property. This value means + * that cells are laid out in multiple columns "newspaper style", + * filling horizontally first, then vertically. + */ + public static int HORIZONTAL_WRAP = 1; - public JList() - { - init(); - } + /** + * Constant value used in "layoutOrientation" property. This value means + * that cells are laid out in a single vertical column. This is the default. + */ + public static int VERTICAL = 2; - public JList(Object[] listData) - { - init(); - setListData(listData); - } + /** + * Constant value used in "layoutOrientation" property. This value means + * that cells are laid out in multiple columns "newspaper style", filling + * vertically first, then horizontally. + */ + public static int VERTICAL_WRAP = 3; + + /** Fired in a PropertyChangeEvent when the "cellRenderer" property changes. */ + public static final String CELL_RENDERER_PROPERTY_CHANGED = "cellRenderer"; + /** Fired in a PropertyChangeEvent when the "fixedCellHeight" property changes. */ + public static final String FIXED_CELL_HEIGHT_PROPERTY_CHANGED = "fixedCellHeight"; - public JList(Vector listData) - { - init(); - setListData(listData); - } + /** Fired in a PropertyChangeEvent when the "fixedCellWidth" property changes. */ + public static final String FIXED_CELL_WIDTH_PROPERTY_CHANGED = "fixedCellWidth"; + /** Fired in a PropertyChangeEvent when the "layoutOrientation" property changes. */ + public static final String LAYOUT_ORIENTATION_PROPERTY_CHANGED = "layoutOrientation"; - public JList(ListModel listData) - { - init(); - setModel(listData); - } - void init() - { - render = new DefaultCellRenderer(); - - sel_model = new DefaultListSelectionModel(); - setModel(new DefaultListModel()); + /** Fired in a PropertyChangeEvent when the "model" property changes. */ + public static final String MODEL_PROPERTY_CHANGED = "model"; - select_back = new Color(0,0,255); - select_fore = new Color(255,255,255); + /** Fired in a PropertyChangeEvent when the "prototypeCellValue" property changes. */ + public static final String PROTOTYPE_CELL_VALUE_PROPERTY_CHANGED = "prototypeCellValue"; - updateUI(); - } + /** Fired in a PropertyChangeEvent when the "selectionBackground" property changes. */ + public static final String SELECTION_BACKGROUND_PROPERTY_CHANGED = "selectionBackground"; - - public int getVisibleRowCount() - { return visibles; } - public void setVisibleRowCount(int visibleRowCount) - { - visibles = visibleRowCount; - invalidate(); - repaint(); - } + /** Fired in a PropertyChangeEvent when the "selectionForeground" property changes. */ + public static final String SELECTION_FOREGROUND_PROPERTY_CHANGED = "selectionForeground"; - public void addListSelectionListener (ListSelectionListener listener) - { - sel_model.addListSelectionListener (listener); - } + /** Fired in a PropertyChangeEvent when the "selectionModel" property changes. */ + public static final String SELECTION_MODEL_PROPERTY_CHANGED = "selectionModel"; + + + /** + * This property indicates whether "drag and drop" functions are enabled + * on the list. + */ + boolean dragEnabled; + + /** This property provides a strategy for rendering cells in the list. */ + ListCellRenderer cellRenderer; + + /** + * This property indicates an fixed width to assign to all cells in the + * list. If its value is -1, no width has been + * assigned. This value can be set explicitly, or implicitly by setting + * the {@link #prototypeCellValue} property. + */ + int fixedCellWidth; - public void removeListSelectionListener (ListSelectionListener listener) - { - sel_model.removeListSelectionListener (listener); - } + /** + * This property indicates an fixed height to assign to all cells in the + * list. If its value is -1, no height has been + * assigned. This value can be set explicitly, or implicitly by setting + * the {@link #prototypeCellValue} property. + */ + int fixedCellHeight; + + /** + * This property holds the current layout orientation of the list, which + * is one of the integer constants {@link #VERTICAL}, {@link + * #VERTICAL_WRAP}, or {@link #HORIZONTAL_WRAP}. + */ + + int layoutOrientation; + + /** This property holds the data elements displayed by the list. */ + ListModel model; /** - * @since 1.4 + *

This property holds a reference to a "prototype" data value -- + * typically a String -- which is used to calculate the {@link + * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the + * {@link #cellRenderer} property to acquire a component to render the + * prototype.

+ * + *

It is important that you not set this value to a + * component. It has to be a data value such as the objects you + * would find in the list's model. Setting it to a component will have + * undefined (and undesirable) affects.

*/ - public ListSelectionListener[] getListSelectionListeners() - { - throw new Error ("not implemented"); - } - - void setSelectionMode(int a) - { sel_model.setSelectionMode(a); } - void setSelectedIndex(int a) - { sel_model.setSelectionInterval(a,a); } - int getSelectedIndex() - { return sel_model.getMinSelectionIndex(); } - Object getSelectedValue() - { - int index = getSelectedIndex(); - if (index == -1) - return null; - return getModel().getElementAt(index); - } + Object prototypeCellValue; + + /** + * This property specifies a foreground color for the selected cells in + * the list. When {@link ListCellRenderer.getListCellRendererComponent} + * is called with a selected cell object, the component returned will + * have its "foreground" set to this color. + */ + Color selectionBackground; + + /** + * This property specifies a background color for the selected cells in + * the list. When {@link ListCellRenderer.getListCellRendererComponent} + * is called with a selected cell object, the component returned will + * have its "background" property set to this color. + */ + Color selectionForeground; + + /** + * This property holds a description of which data elements in the {@link + * #model} property should be considered "selected", when displaying and + * interacting with the list. + */ + ListSelectionModel selectionModel; + - Color getSelectionBackground() - { return select_back; } - Color getSelectionForeground() - { return select_fore; } + /** + * This property indicates that the list's selection is currently + * "adjusting" -- perhaps due to a user actively dragging the mouse over + * multiple list elements -- and is therefore likely to change again in + * the near future. A {@link ListSelectionListener} might choose to delay + * updating its view of the list's selection until this property is + * false, meaning that the adjustment has completed. + */ + boolean valueIsAdjusting; + + /** + * This property indicates a preference for the number of rows + * displayed in the list, and will scale the + * {@link #preferredScrollableViewportSize} property accordingly. The actual + * number of displayed rows, when the list is placed in a real {@link + * Viewport} or other component, may be greater or less than this number. + */ + int visibleRowCount; + + + + /** + * Fire a {@link ListSelectionEvent} to all the registered ListSelectionListeners. + */ + void fireSelectionValueChanged(int firstIndex, int lastIndex, boolean isAdjusting) + { + ListSelectionEvent evt = new ListSelectionEvent(this, firstIndex, lastIndex, isAdjusting); + ListSelectionListener listeners[] = getListSelectionListeners(); + for (int i = 0; i < listeners.length; ++i) + { + listeners[i].valueChanged(evt); + } + } - public void setListData(final Object[] listData) + /** + * This private listener propagates {@link ListSelectionEvent} events + * from the list's "selectionModel" property to the list's {@link + * ListSelectionListener} listeners. It also listens to {@link + * ListDataEvent} events from the list's {@link #model} property. If this + * class receives either type of event, it triggers repainting of the + * list. + */ + private class ListListener + implements ListSelectionListener, ListDataListener + { + // ListDataListener events + public void contentsChanged(ListDataEvent event) { - class AL extends AbstractListModel - { - public int getSize() { return listData.length; } - public Object getElementAt(int i) { return listData[i]; } - }; - - setModel (new AL()); + JList.this.revalidate(); + JList.this.repaint(); } - - public void setListData(final Vector listData) + public void intervalAdded(ListDataEvent event) { - class AL extends AbstractListModel - { - public int getSize() { return listData.size(); } - public Object getElementAt(int i) { return listData.elementAt(i); } - }; - - setModel (new AL()); + JList.this.revalidate(); + JList.this.repaint(); } - - - public ListCellRenderer getCellRenderer() - { return render; } - public void setCellRenderer(ListCellRenderer cellRenderer) + public void intervalRemoved(ListDataEvent event) { - render = cellRenderer; - invalidate(); - repaint(); + JList.this.revalidate(); + JList.this.repaint(); } - - public void setModel(ListModel model) + // ListSelectionListener events + public void valueChanged(ListSelectionEvent event) { - ListDataListener l = new ListDataListener() - { - public void intervalAdded(ListDataEvent e) { - repaint(); - } - public void intervalRemoved(ListDataEvent e) { - repaint(); - } - public void contentsChanged(ListDataEvent e) { - repaint(); - } - }; - - this.model = model; - model.addListDataListener(l); + JList.this.fireSelectionValueChanged(event.firstIndex, + event.lastIndex, + event.isAdjusting); + JList.this.repaint(); } + }; - public ListModel getModel() - { return model; } - - - public ListUI getUI() - { return (ListUI) ui; } - public void setUI(ListUI ui) - { super.setUI(ui); } + /** + * Shared ListListener instance, subscribed to both the current {@link + * #model} and {@link #selectionModel} properties of the list. + */ + ListListener listListener; - public void updateUI() - { - setUI((ListUI)UIManager.getUI(this)); - } - public String getUIClassID() - { - return "ListUI"; - } + /** + * Creates a new JList object. + */ + public JList() + { + init(); + } + + /** + * Creates a new JList object. + * + * @param listData Initial data to populate the list with + */ + public JList(Object[] listData) + { + init(); + setListData(listData); + } + /** + * Creates a new JList object. + * + * @param listData Initial data to populate the list with + */ + public JList(Vector listData) + { + init(); + setListData(listData); + } - public AccessibleContext getAccessibleContext() - { + /** + * Creates a new JList object. + * + * @param listData Initial data to populate the list with + */ + public JList(ListModel listData) + { + init(); + setModel(listData); + } + + void init() + { + dragEnabled = false; + fixedCellHeight = -1; + fixedCellWidth = -1; + layoutOrientation = VERTICAL; + opaque = true; + valueIsAdjusting = false; + visibleRowCount = 8; + + cellRenderer = new DefaultListCellRenderer(); + listListener = new ListListener(); + + setModel(new DefaultListModel()); + setSelectionModel(new DefaultListSelectionModel()); + + updateUI(); + } + + /** + * Gets the value of the {@link #fixedCellHeight} property. This property + * may be -1 to indicate that no cell height has been + * set. This property is also set implicitly when the + * {@link #prototypeCellValue} property is set. + * + * @return The current value of the property + * + * @see #fixedCellHeight + * @see #setFixedCellHeight + * @see #setPrototypeCellValue + */ + public int getFixedCellHeight() + { + return fixedCellHeight; + } + + /** + * Sets the value of the {@link #fixedCellHeight} property. This property + * may be -1 to indicate that no cell height has been + * set. This property is also set implicitly when the {@link + * #prototypeCellValue} property is set, but setting it explicitly + * overrides the height computed from {@link #prototypeCellValue}. + * + * @see #getFixedCellHeight + * @see #getPrototypeCellValue + */ + public void setFixedCellHeight(int h) + { + int old = fixedCellHeight; + fixedCellHeight = h; + firePropertyChange(FIXED_CELL_WIDTH_PROPERTY_CHANGED, old, h); + } + + + /** + * Gets the value of the {@link #fixedCellWidth} property. This property + * may be -1 to indicate that no cell width has been + * set. This property is also set implicitly when the {@link + * #prototypeCellValue} property is set. + * + * @return The current value of the property + * + * @see #setFixedCellWidth + * @see #setPrototypeCellValue + */ + public int getFixedCellWidth() + { + return fixedCellWidth; + } + + /** + * Sets the value of the {@link #fixedCellWidth} property. This property + * may be -1 to indicate that no cell width has been + * set. This property is also set implicitly when the {@link + * #prototypeCellValue} property is set, but setting it explicitly + * overrides the width computed from {@link #prototypeCellValue}. + * + * @see #getFixedCellWidth + * @see #getPrototypeCellValue + */ + public void setFixedCellWidth(int h) + { + int old = fixedCellHeight; + fixedCellHeight = h; + firePropertyChange(FIXED_CELL_HEIGHT_PROPERTY_CHANGED, old, h); + } + + + /** + * Gets the value of the {@link #visibleRowCount} property. + * + * @return the current value of the property. + */ + + public int getVisibleRowCount() + { + return visibleRowCount; + } + + /** + * Sets the value of the {@link #visibleRowCount} property. + * + * @param visibleRowCount The new property value + */ + public void setVisibleRowCount(int vc) + { + visibleRowCount = vc; + revalidate(); + repaint(); + } + + /** + * Adds a {@link ListSelectionListener} to the listener list for this + * list. The listener will be called back with a {@link + * ListSelectionEvent} any time the list's {@link #selectionModel} + * property changes. The source of such events will be the JList, + * not the selection model. + * + * @param listener The new listener to add + */ + public void addListSelectionListener(ListSelectionListener listener) + { + listenerList.add (ListSelectionListener.class, listener); + } + + /** + * Removes a {@link ListSelectionListener} from the listener list for + * this list. The listener will no longer be called when the list's + * {@link #selectionModel} changes. + * + * @param listener The listener to remove + */ + public void removeListSelectionListener(ListSelectionListener listener) + { + listenerList.remove(ListSelectionListener.class, listener); + } + + /** + * Returns an array of all ListSelectionListeners subscribed to this + * list. + * + * @return The current subscribed listeners + * + * @since 1.4 + */ + public ListSelectionListener[] getListSelectionListeners() + { + return (ListSelectionListener[]) getListeners(ListSelectionListener.class); + } + + /** + * Sets the list's "selectionMode" property, which simply mirrors the + * same property on the list's {@link #selectionModel} property. This + * property should be one of the integer constants + * SINGLE_SELECTION, SINGLE_INTERVAL_SELECTION, + * or MULTIPLE_INTERVAL_SELECTION from the {@link + * ListSelectionModel} interface. + * + * @param a The new selection mode + */ + public void setSelectionMode(int a) + { + selectionModel.setSelectionMode(a); + } + + /** + * Adds the interval [a,a] to the set of selections managed + * by this list's {@link #selectionModel} property. Depending on the + * selection mode, this may cause existing selections to become invalid, + * or may simply expand the set of selections. + * + * @param a A number in the half-open range [0, x) where + * x = getModel.getSize(), indicating the index of an + * element in the list to select. + * + * @see #setSelectionMode + * @see #selectionModel + */ + public void setSelectedIndex(int a) + { + selectionModel.setSelectionInterval(a, a); + } + + /** + * Returns the minimum index of an element in the list which is currently + * selected. + * + * @return A number in the half-open range [0, x) where + * x = getModel.getSize(), indicating the minimum index of + * an element in the list for which the element is selected, or + * -1 if no elements are selected + */ + public int getSelectedIndex() + { + return selectionModel.getMinSelectionIndex(); + } + + /** + * Indicates whether the list element at a given index value is + * currently selected. + * + * @param a The index to check + * @return true if a is the index of a selected + * list element + */ + public boolean isSelectedIndex(int a) + { + return selectionModel.isSelectedIndex(a); + } + + /** + * Returns the first value in the list's {@link #model} property which is + * selected, according to the list's {@link #selectionModel} property. + * This is equivalent to calling + * getModel()getElementAt(getSelectedIndex()), with a check + * for the special index value of -1 which returns null + * null. + * + * @return The first selected element, or null if no element + * is selected. + */ + public Object getSelectedValue() + { + int index = getSelectedIndex(); + if (index == -1) return null; - } + return getModel().getElementAt(index); + } - public Dimension getPreferredScrollableViewportSize() - { - return null; - } + /** + * Gets the value of the {@link #selectionBackground} property. + * + * @return The current value of the property + */ + public Color getSelectionBackground() + { + return selectionBackground; + } - public int getScrollableUnitIncrement(Rectangle visibleRect, - int orientation, - int direction) - { - return 1; - } + /** + * Sets the value of the {@link #selectionBackground} property. + * + * @param c The new value of the property + */ + public void setSelectionBackground(Color c) + { + Color old = selectionBackground; + selectionBackground = c; + firePropertyChange(SELECTION_BACKGROUND_PROPERTY_CHANGED, old, c); + repaint(); + } - public int getScrollableBlockIncrement(Rectangle visibleRect, - int orientation, - int direction) - { - return 1; - } + /** + * Gets the value of the {@link #selectionForeground} property. + * + * @return The current value of the property + */ + public Color getSelectionForeground() + { + return selectionForeground; + } + + /** + * Sets the value of the {@link #selectionForeground} property. + * + * @param c The new value of the property + */ + public void setSelectionForeground(Color c) + { + Color old = selectionForeground; + selectionForeground = c; + firePropertyChange(SELECTION_FOREGROUND_PROPERTY_CHANGED, old, c); + } - public boolean getScrollableTracksViewportWidth() - { - return false; - } + /** + * Sets the {@link #model} property of the list to a new anonymous + * {@link AbstractListModel} subclass which accesses the provided Object + * array directly. + * + * @param listData The object array to build a new list model on + * @see #setModel + */ + public void setListData(final Object[] listData) + { + setModel(new AbstractListModel() + { + public int getSize() + { + return listData.length; + } + + public Object getElementAt(int i) + { + return listData[i]; + } + }); + } - public boolean getScrollableTracksViewportHeight() - { - return false; - } - + /** + * Sets the {@link #model} property of the list to a new anonymous {@link + * AbstractListModel} subclass which accesses the provided vector + * directly. + * + * @param listData The object array to build a new list model on + * @see #setModel + */ + public void setListData(final Vector listData) + { + setModel(new AbstractListModel() + { + public int getSize() + { + return listData.size(); + } + + public Object getElementAt(int i) + { + return listData.elementAt(i); + } + }); + } + + /** + * Gets the value of the {@link #cellRenderer} property. + * + * @return The current value of the property + */ + public ListCellRenderer getCellRenderer() + { + return cellRenderer; + } + + /** + * Sets the value of the {@link #celLRenderer} property. + * + * @param cellRenderer The new property value + */ + public void setCellRenderer(ListCellRenderer cr) + { + ListCellRenderer old = cellRenderer; + cellRenderer = cr; + firePropertyChange(CELL_RENDERER_PROPERTY_CHANGED, old, cr); + revalidate(); + repaint(); + } + + /** + * Gets the value of the {@link #model} property. + * + * @return The current value of the property + */ + public ListModel getModel() + { + return model; + } + + /** + * Sets the value of the {@link #model} property. The list's {@link + * #listListener} is unsubscribed from the existing model, if it exists, + * and re-subscribed to the new model. + * + * @param model The new property value + */ + public void setModel(ListModel m) + { + ListModel old = model; + if (old != null) + old.removeListDataListener(listListener); + model = m; + if (model != null) + model.addListDataListener(listListener); + firePropertyChange(MODEL_PROPERTY_CHANGED, old, m); + } + + + public ListSelectionModel getSelectionModel() + { + return selectionModel; + } + + /** + * Sets the value of the {@link #selectionModel} property. The list's + * {@link #listListener} is unsubscribed from the existing selection + * model, if it exists, and re-subscribed to the new selection model. + * + * @param l The new property value + */ + public void setSelectionModel(ListSelectionModel l) + { + ListSelectionModel old = selectionModel; + if (old != null) + old.removeListSelectionListener(listListener); + selectionModel = l; + if (selectionModel != null) + selectionModel.addListSelectionListener(listListener); + firePropertyChange(SELECTION_MODEL_PROPERTY_CHANGED, old, l); + } + + /** + * Gets the value of the UI property. + * + * @return The current property value + */ + public ListUI getUI() + { + return (ListUI) ui; + } + + /** + * Sets the value of the UI property. + * + * @param ui The new property value + */ + public void setUI(ListUI ui) + { + super.setUI(ui); + } + + /** + * Calls {@link #setUI} with the {@link ListUI} subclass + * returned from calling {@link UIManager#getUI}. + */ + public void updateUI() + { + setUI((ListUI) UIManager.getUI(this)); + } + + /** + * Return the class identifier for the list's UI property. This should + * be the constant string "ListUI", and map to an + * appropriate UI class in the {@link UIManager}. + * + * @return The class identifier + */ + public String getUIClassID() + { + return "ListUI"; + } + + + /** + * Returns the current value of the {@link #prototypeCellValue} + * property. This property holds a reference to a "prototype" data value + * -- typically a String -- which is used to calculate the {@link + * #fixedCellWidth} and {@link #fixedCellHeight} properties, using the + * {@link #cellRenderer} property to acquire a component to render the + * prototype. + * + * @return The current prototype cell value + * @see #setPrototypeCellValue + */ + public Object getPrototypeCellValue() + { + return prototypeCellValue; + } + + /** + *

Set the {@link #prototypeCellValue} property. This property holds a + * reference to a "prototype" data value -- typically a String -- which + * is used to calculate the {@link #fixedCellWidth} and {@link + * #fixedCellHeight} properties, using the {@link #cellRenderer} property + * to acquire a component to render the prototype.

+ * + *

It is important that you not set this value to a + * component. It has to be a data value such as the objects you + * would find in the list's model. Setting it to a component will have + * undefined (and undesirable) affects.

+ * + * @param obj The new prototype cell value + * @see #getPrototypeCellValue + */ + public void setPrototypeCellValue(Object obj) + { + Object old = prototypeCellValue; + Component comp = getCellRenderer() + .getListCellRendererComponent(this, obj, 0, false, false); + Dimension d = comp.getPreferredSize(); + fixedCellWidth = d.width; + fixedCellHeight = d.height; + prototypeCellValue = obj; + firePropertyChange(PROTOTYPE_CELL_VALUE_PROPERTY_CHANGED, old, obj); + } + + public AccessibleContext getAccessibleContext() + { + return null; + } + + /** + * Returns a size indicating how much space this list would like to + * consume, when contained in a scrollable viewport. This is part of the + * {@link Scrollable} interface, which interacts with {@link + * ScrollPaneLayout} and {@link Viewport} to define scrollable objects. + * + * @return The preferred size, or null + */ + public Dimension getPreferredScrollableViewportSize() + { + return null; + } + + /** + *

Return the number of pixels the list must scroll in order to move a + * "unit" of the list into the provided visible rectangle. When the + * provided direction is positive, the call describes a "downwards" + * scroll, which will be exposing a cell at a greater index in + * the list than those elements currently showing. Then the provided + * direction is negative, the call describes an "upwards" scroll, which + * will be exposing a cell at a lesser index in the list than + * those elements currently showing.

+ * + *

If the provided orientation is HORIZONTAL, the above + * comments refer to "rightwards" for positive direction, and "leftwards" + * for negative.

+ * + * + * @param visibleRect The rectangle to scroll an element into + * @param orientation One of the numeric consants VERTICAL + * or HORIZONTAL + * @param direction An integer indicating the scroll direction: positive means + * forwards (down, right), negative means backwards (up, left) + * + * @return The scrollable unit increment, in pixels + */ + public int getScrollableUnitIncrement(Rectangle visibleRect, + int orientation, int direction) + { + return 1; + } + + /** + *

Return the number of pixels the list must scroll in order to move a + * "block" of the list into the provided visible rectangle. When the + * provided direction is positive, the call describes a "downwards" + * scroll, which will be exposing a cell at a greater index in + * the list than those elements currently showing. Then the provided + * direction is negative, the call describes an "upwards" scroll, which + * will be exposing a cell at a lesser index in the list than + * those elements currently showing.

+ * + *

If the provided orientation is HORIZONTAL, the above + * comments refer to "rightwards" for positive direction, and "leftwards" + * for negative.

+ * + * + * @param visibleRect The rectangle to scroll an element into + * @param orientation One of the numeric consants VERTICAL + * or HORIZONTAL + * @param direction An integer indicating the scroll direction: positive means + * forwards (down, right), negative means backwards (up, left) + * + * @return The scrollable unit increment, in pixels + */ + public int getScrollableBlockIncrement(Rectangle visibleRect, + int orientation, int direction) + { + return 1; + } + + /** + * Gets the value of the {@link #scrollableTracksViewportWidth} property. + * + * @return true if the viewport is larger (horizontally) + * than the list and the list should be expanded to fit the viewport; + * false if the viewport is smaller than the list and the + * list should scroll (horizontally) within the viewport + */ + public boolean getScrollableTracksViewportWidth() + { + return false; + } + + /** + * Gets the value of the {@link #scrollableTracksViewportWidth} property. + * + * @return true if the viewport is larger (vertically) + * than the list and the list should be expanded to fit the viewport; + * false if the viewport is smaller than the list and the + * list should scroll (vertically) within the viewport + */ + public boolean getScrollableTracksViewportHeight() + { + return false; + } } diff --git a/libjava/javax/swing/JProgressBar.java b/libjava/javax/swing/JProgressBar.java index 3e65c3873fa..f8bb4a5235b 100644 --- a/libjava/javax/swing/JProgressBar.java +++ b/libjava/javax/swing/JProgressBar.java @@ -47,442 +47,628 @@ import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; import javax.swing.plaf.ProgressBarUI; + /** - * JProgressBar - * @author Andrew Selkirk - * @version 1.0 + *

+ * The ProgressBar is a widget that displays in two modes. In + * determinate mode, it displays fills a percentage of its bar + * based on its current value. In indeterminate mode, it creates + * box and bounces it between its bounds. + *

+ * + *

+ * JProgressBars have the following properties: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Property Stored in Bound?
borderPainted progressBar yes
changeListeners progressBar no
indeterminate progressBar yes
maximum model no
minimum model no
model progressBar no
orientation progressBar yes
percentComplete progressBar no
string progressBar yes
stringPainted progressBar yes
value model no
*/ -public class JProgressBar extends JComponent implements SwingConstants, Accessible +public class JProgressBar extends JComponent implements SwingConstants, + Accessible { - - //------------------------------------------------------------- - // Classes ---------------------------------------------------- - //------------------------------------------------------------- - - - /** - * AccessibleJProgressBar - */ - protected class AccessibleJProgressBar extends AccessibleJComponent - implements AccessibleValue { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor AccessibleJProgressBar - * @param component TODO - */ - protected AccessibleJProgressBar(JProgressBar component) { - super(component); - // TODO - } // AccessibleJProgressBar() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getAccessibleStateSet - * @returns AccessibleStateSet - */ - public AccessibleStateSet getAccessibleStateSet() { - return null; // TODO - } // getAccessibleStateSet() - - /** - * getAccessibleRole - * @returns AccessibleRole - */ - public AccessibleRole getAccessibleRole() { - return AccessibleRole.PROGRESS_BAR; - } // getAccessibleRole() - - /** - * getAccessibleValue - * @returns AccessibleValue - */ - public AccessibleValue getAccessibleValue() { - return null; // TODO - } // getAccessibleValue() - - /** - * getCurrentAccessibleValue - * @returns Number - */ - public Number getCurrentAccessibleValue() { - return null; // TODO - } // getCurrentAccessibleValue() - - /** - * setCurrentAccessibleValue - * @param value0 TODO - * @returns boolean - */ - public boolean setCurrentAccessibleValue(Number value0) { - return false; // TODO - } // setCurrentAccessibleValue() - - /** - * getMinimumAccessibleValue - * @returns Number - */ - public Number getMinimumAccessibleValue() { - return null; // TODO - } // getMinimumAccessibleValue() - - /** - * getMaximumAccessibleValue - * @returns Number - */ - public Number getMaximumAccessibleValue() { - return null; // TODO - } // getMaximumAccessibleValue() - - - } // AccessibleJProgressBar - - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * uiClassID - */ - private static final String uiClassID = "ProgressBarUI"; - - /** - * orientation - */ - protected int orientation; - - /** - * paintBorder - */ - protected boolean paintBorder; - - /** - * model - */ - protected BoundedRangeModel model; - - /** - * progressString - */ - protected String progressString; - - /** - * paintString - */ - protected boolean paintString; - - /** - * changeEvent - */ - protected transient ChangeEvent changeEvent; - - /** - * changeListener - */ - protected ChangeListener changeListener; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor JProgressBar - */ - public JProgressBar() { - // TODO - } // JProgressBar() - - /** - * Constructor JProgressBar - * @param orientation TODO - */ - public JProgressBar(int orientation) { - // TODO - } // JProgressBar() - - /** - * Constructor JProgressBar - * @param minimum TODO - * @param maximum TODO - */ - public JProgressBar(int minimum, int maximum) { - // TODO - } // JProgressBar() - - /** - * Constructor JProgressBar - * @param minimum TODO - * @param maximum TODO - * @param orientation TODO - */ - public JProgressBar(int minimum, int maximum, int orientation) { - // TODO - } // JProgressBar() - - /** - * Constructor JProgressBar - * @param model TODO - */ - public JProgressBar(BoundedRangeModel model) { - // TODO - } // JProgressBar() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * writeObject - * @param stream TODO - * @exception IOException TODO - */ - private void writeObject(ObjectOutputStream stream) throws IOException { - // TODO - } // writeObject() - - /** - * getValue - * @returns int - */ - public int getValue() { - return 0; // TODO - } // getValue() - - /** - * setValue - * @param value TODO - */ - public void setValue(int value) { - // TODO - } // setValue() - - /** - * paintBorder - * @param graphics TODO - */ - protected void paintBorder(Graphics graphics) { - // TODO - } // paintBorder() - - /** - * getOrientation - * @returns int - */ - public int getOrientation() { - return 0; // TODO - } // getOrientation() - - /** - * setOrientation - * @param orientation TODO - */ - public void setOrientation(int orientation) { - // TODO - } // setOrientation() - - /** - * isStringPainted - * @returns boolean - */ - public boolean isStringPainted() { - return false; // TODO - } // isStringPainted() - - /** - * setStringPainted - * @param painted TODO - */ - public void setStringPainted(boolean painted) { - // TODO - } // setStringPainted() - - /** - * getString - * @returns String - */ - public String getString() { - return null; // TODO - } // getString() - - /** - * setString - * @param string TODO - */ - public void setString(String string) { - // TODO - } // setString() - - /** - * getPercentComplete - * @returns double - */ - public double getPercentComplete() { - return 0.0; // TODO - } // getPercentComplete() - - /** - * isBorderPainted - * @returns boolean - */ - public boolean isBorderPainted() { - return false; // TODO - } // isBorderPainted() - - /** - * setBorderPainted - * @param painted TODO - */ - public void setBorderPainted(boolean painted) { - // TODO - } // setBorderPainted() - - /** - * getUI - * @returns ProgressBarUI - */ - public ProgressBarUI getUI() { - return (ProgressBarUI) ui; - } // getUI() - - /** - * setUI - * @param ui TODO - */ - public void setUI(ProgressBarUI ui) { - super.setUI(ui); - // TODO - } // setUI() - - /** - * updateUI - */ - public void updateUI() { - setUI((ProgressBarUI) UIManager.get(this)); - invalidate(); - } // updateUI() - - /** - * getUIClassID - * @returns String - */ - public String getUIClassID() { - return uiClassID; - } // getUIClassID() - - /** - * createChangeListener - * @returns ChangeListener - */ - protected ChangeListener createChangeListener() { - return null; // TODO - } // createChangeListener() - - /** - * addChangeListener - * @param listener TODO - */ - public void addChangeListener(ChangeListener listener) { - // TODO - } // addChangeListener() - - /** - * removeChangeListener - * @param listener TODO - */ - public void removeChangeListener(ChangeListener valulistener) { - // TODO - } // removeChangeListener() - - /** - * fireStateChanged - */ - protected void fireStateChanged() { - // TODO - } // fireStateChanged() - - /** - * getModel - * @returns BoundedRangeModel - */ - public BoundedRangeModel getModel() { - return null; // TODO - } // getModel() - - /** - * setModel - * @param model TODO - */ - public void setModel(BoundedRangeModel model) { - // TODO - } // setModel() - - /** - * getMinimum - * @returns int - */ - public int getMinimum() { - return 0; // TODO - } // getMinimum() - - /** - * setMinimum - * @param minimum TODO - */ - public void setMinimum(int minimum) { - // TODO - } // setMinimum() - - /** - * getMaximum - * @returns int - */ - public int getMaximum() { - return 0; // TODO - } // getMaximum() - - /** - * setMaximum - * @param maximum TODO - */ - public void setMaximum(int maximum) { - // TODO - } // setMaximum() - - /** - * paramString - * @returns String - */ - protected String paramString() { - return null; // TODO - } // paramString() - - /** - * getAccessibleContext - * @returns AccessibleContext - */ - public AccessibleContext getAccessibleContext() { - if (accessibleContext == null) { - accessibleContext = new AccessibleJProgressBar(this); - } // if - return accessibleContext; - } // getAccessibleContext() - - -} // JProgressBar + /** + * AccessibleJProgressBar + */ + protected class AccessibleJProgressBar extends AccessibleJComponent + implements AccessibleValue + { + /** + * Constructor AccessibleJProgressBar + * + * @param component TODO + */ + protected AccessibleJProgressBar(JProgressBar component) + { + super(component); + } + + /** + * getAccessibleStateSet + * + * @return AccessibleStateSet + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.PROGRESS_BAR; + } + + /** + * getAccessibleValue + * + * @return AccessibleValue + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * getCurrentAccessibleValue + * + * @return Number + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * setCurrentAccessibleValue + * + * @param value0 TODO + * + * @return boolean + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * getMinimumAccessibleValue + * + * @return Number + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * getMaximumAccessibleValue + * + * @return Number + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + /** Fired in a PropertyChangeEvent when the "borderPainted" property changes. */ + public static final String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted"; + + /** Fired in a PropertyChangeEvent when the "orientation" property changes. */ + public static final String ORIENTATION_CHANGED_PROPERTY = "orientation"; + + /** Fired in a PropertyChangeEvent when the "string" property changes. */ + public static final String STRING_CHANGED_PROPERTY = "string"; + + /** Fired in a PropertyChangeEvent when the "stringPainted" property changes. */ + public static final String STRING_PAINTED_CHANGED_PROPERTY = "stringPainted"; + + /** Fired in a PropertyChangeEvent when the "indeterminate" property changes. */ + public static final String INDETERMINATE_CHANGED_PROPERTY = "indeterminate"; + + /** A list of ChangeListeners registered with this ProgressBar. */ + private transient EventListenerList changeListenerList; + + /** Whether the ProgressBar is determinate. */ + private transient boolean indeterminate = false; + + /** The orientation of the ProgressBar */ + protected int orientation = HORIZONTAL; + + /** Whether borders should be painted. */ + protected boolean paintBorder = true; + + /** The model describing this ProgressBar. */ + protected BoundedRangeModel model; + + /** The string that is displayed by the ProgressBar. */ + protected String progressString; + + /** Whether the string should be painted. */ + protected boolean paintString = false; + + /** The static changeEvent passed to all ChangeListeners. */ + protected transient ChangeEvent changeEvent; + + /** The ChangeListener that listens to the model. */ + protected ChangeListener changeListener; + + /** + * Creates a new horizontally oriented JProgressBar object + * with a minimum of 0 and a maximum of 100. + */ + public JProgressBar() + { + this(0, 100, HORIZONTAL); + } + + /** + * Creates a new JProgressBar object with a minimum of 0, + * a maximum of 100, and the given orientation. + * + * @param orientation The orientation of the JProgressBar. + */ + public JProgressBar(int orientation) + { + this(0, 100, orientation); + } + + /** + * Creates a new horizontally oriented JProgressBar object + * with the given minimum and maximum. + * + * @param minimum The minimum of the JProgressBar. + * @param maximum The maximum of the JProgressBar. + */ + public JProgressBar(int minimum, int maximum) + { + this(minimum, maximum, HORIZONTAL); + } + + /** + * Creates a new JProgressBar object with the given minimum, + * maximum, and orientation. + * + * @param minimum The minimum of the JProgressBar. + * @param maximum The maximum of the JProgressBar. + * @param orientation The orientation of the JProgressBar. + */ + public JProgressBar(int minimum, int maximum, int orientation) + { + model = new DefaultBoundedRangeModel(minimum, 0, minimum, maximum); + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + " is not a legal orientation"); + this.orientation = orientation; + changeListener = createChangeListener(); + model.addChangeListener(changeListener); + changeListenerList = new EventListenerList(); + updateUI(); + } + + /** + * Creates a new horizontally oriented JProgressBar object + * with the given model. + * + * @param model The model to be used with the JProgressBar. + */ + public JProgressBar(BoundedRangeModel model) + { + this.model = model; + changeListener = createChangeListener(); + model.addChangeListener(changeListener); + changeListenerList = new EventListenerList(); + updateUI(); + } + + /** + * This method returns the current value of the JProgressBar. + * + * @return The current value of the JProgressBar. + */ + public int getValue() + { + return model.getValue(); + } + + /** + * This method sets the value of the JProgressBar. + * + * @param value The value of the JProgressBar. + */ + public void setValue(int value) + { + model.setValue(value); + } + + /** + * This method paints the border of the JProgressBar + * + * @param graphics The graphics object to paint with. + */ + protected void paintBorder(Graphics graphics) + { + getBorder().paintBorder(this, graphics, 0, 0, + getWidth(), + getHeight()); + } + + /** + * This method returns the orientation of the JProgressBar. + * + * @return The orientation of the JProgressBar. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method changes the orientation property. The orientation of the + * JProgressBar can be either horizontal or vertical. + * + * @param orientation The orientation of the JProgressBar. + */ + public void setOrientation(int orientation) + { + if (orientation != VERTICAL && orientation != HORIZONTAL) + throw new IllegalArgumentException("orientation must be one of VERTICAL or HORIZONTAL"); + if (this.orientation != orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange(ORIENTATION_CHANGED_PROPERTY, oldOrientation, + this.orientation); + } + } + + /** + * This method returns whether the progressString will be painted. + * + * @return Whether the string is painted. + */ + public boolean isStringPainted() + { + return paintString; + } + + /** + * This method changes the stringPainted property. + * + * @param painted Whether the string is painted. + */ + public void setStringPainted(boolean painted) + { + if (paintString != painted) + { + boolean oldPainted = paintString; + paintString = painted; + firePropertyChange(STRING_PAINTED_CHANGED_PROPERTY, oldPainted, + paintString); + } + } + + /** + * This method returns the string that is painted if the + * stringPainted property is set to true. If there is no + * string set, it will return a string containing the + * JProgressBar's value as a percent. + * + * @return The string that is painted. + */ + public String getString() + { + if (progressString != null) + return progressString; + else + return (int) (getPercentComplete() * 100) + "%"; + } + + /** + * This method changes the string property. The string + * given will be the one painted. If you want to + * revert to the default string given, set the + * string to null. + * + * @param string The string to be painted. + */ + public void setString(String string) + { + if (((string == null || progressString == null) && + string != progressString) || (string != null && + ! string.equals(progressString))) + { + String oldString = progressString; + progressString = string; + firePropertyChange(STRING_CHANGED_PROPERTY, oldString, progressString); + } + } + + /** + * This method returns the percent of the bar + * that is "complete". (This is the amount value / (max - min)). + * + * @return DOCUMENT ME! + */ + public double getPercentComplete() + { + if (getMaximum() == getMinimum()) + return 1.0; + else + return (double) (model.getValue() - model.getMinimum()) / (model + .getMaximum() + - model.getMinimum()); + } + + /** + * This method returns whether the border is painted. + * + * @return Whether the border is painted. + */ + public boolean isBorderPainted() + { + return paintBorder; + } + + /** + * This method changes the borderPainted property. + * + * @param painted Whether the border is painted. + */ + public void setBorderPainted(boolean painted) + { + if (painted != paintBorder) + { + boolean oldPainted = paintBorder; + paintBorder = painted; + firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, oldPainted, + paintBorder); + } + } + + /** + * This method returns the JProgressBar's UI delegate. + * + * @return This JProgressBar's UI delegate. + */ + public ProgressBarUI getUI() + { + return (ProgressBarUI) ui; + } + + /** + * This method changes the UI property for this JProgressBar. + * + * @param ui The new UI delegate. + */ + public void setUI(ProgressBarUI ui) + { + super.setUI(ui); + } + + /** + * This method reverts the UI delegate for this JProgressBar + * to the default for this Look and Feel. + */ + public void updateUI() + { + setUI((ProgressBarUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns the identifier to allow the UIManager + * to pick the correct class to act as the UI for + * this JProgressBar. + * + * @return The UIClassID: "ProgressBarUI". + */ + public String getUIClassID() + { + return "ProgressBarUI"; + } + + /** + * This method returns a ChangeListener that gets registered + * model. By default, the ChangeListener, propagates the + * ChangeEvents to the ChangeListeners of the JProgressBar. + * + * @return A new ChangeListener. + */ + protected ChangeListener createChangeListener() + { + return new ChangeListener() + { + public void stateChanged(ChangeEvent ce) + { + fireStateChanged(); + } + }; + } + + /** + * This method adds a ChangeListener to this JProgressBar. + * + * @param listener The ChangeListener to add to this JProgressBar. + */ + public void addChangeListener(ChangeListener listener) + { + changeListenerList.add(ChangeListener.class, listener); + } + + /** + * This method removes a ChangeListener from this JProgressBar. + * + * @param listener The ChangeListener to remove from this JProgressBar. + */ + public void removeChangeListener(ChangeListener listener) + { + changeListenerList.remove(ChangeListener.class, listener); + } + + /** + * This method returns an array of all ChangeListeners listening to this + * progress bar. + * + * @return An array of ChangeListeners listening to this progress bar. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) changeListenerList.getListenerList(); + } + + /** + * This method is called when the JProgressBar receives a ChangeEvent + * from its model. This simply propagates the event (changing the source + * to the JProgressBar) to the JProgressBar's listeners. + */ + protected void fireStateChanged() + { + Object[] changeListeners = changeListenerList.getListenerList(); + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + for (int i = changeListeners.length - 2; i >= 0; i -= 2) + { + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + } + } + + /** + * This method returns the model used with this JProgressBar. + * + * @return The model used with this JProgressBar. + */ + public BoundedRangeModel getModel() + { + return model; + } + + /** + * This method changes the model property for this JProgressBar. + * + * @param model The model to use with this JProgressBar. + */ + public void setModel(BoundedRangeModel model) + { + if (model != this.model) + { + this.model.removeChangeListener(changeListener); + this.model = model; + this.model.addChangeListener(changeListener); + fireStateChanged(); + } + } + + /** + * This method returns the minimum value of this JProgressBar. + * + * @return The minimum value of this JProgressBar. + */ + public int getMinimum() + { + return model.getMinimum(); + } + + /** + * This method sets the minimum value of this JProgressBar. + * + * @param minimum The minimum value of this JProgressBar. + */ + public void setMinimum(int minimum) + { + model.setMinimum(minimum); + } + + /** + * This method returns the maximum value of this JProgressBar. + * + * @return The maximum value of this JProgressBar. + */ + public int getMaximum() + { + return model.getMaximum(); + } + + /** + * This method sets the maximum value of this JProgressBar. + * + * @param maximum The maximum value of this JProgressBar. + */ + public void setMaximum(int maximum) + { + model.setMaximum(maximum); + } + + /** + * This method returns a string that can be used to + * describe this JProgressBar. This method is usually + * only used for debugging purposes. + * + * @return A string that describes this JProgressBar. + */ + protected String paramString() + { + return "JProgressBar"; + } + + /** + * This method changes the indeterminate property. If the + * JProgressBar is determinate, it paints a percentage + * of the bar described by its value. If it is indeterminate, + * it simply bounces a box between the ends of the bar; the + * value of the JProgressBar is ignored. + * + * @param newValue Whether the JProgressBar is indeterminate. + */ + public void setIndeterminate(boolean newValue) + { + if (indeterminate != newValue) + { + boolean olddeter = indeterminate; + indeterminate = newValue; + firePropertyChange(INDETERMINATE_CHANGED_PROPERTY, olddeter, + indeterminate); + } + } + + /** + * This method returns whether the JProgressBar is indeterminate. + * + * @return Whether this JProgressBar is indeterminate. + */ + public boolean isIndeterminate() + { + return indeterminate; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJProgressBar(this); + return accessibleContext; + } +} diff --git a/libjava/javax/swing/JScrollBar.java b/libjava/javax/swing/JScrollBar.java index 1cf6667d483..7ee0510fdc9 100644 --- a/libjava/javax/swing/JScrollBar.java +++ b/libjava/javax/swing/JScrollBar.java @@ -1,5 +1,5 @@ -/* JScrollBar.java -- - Copyright (C) 2002 Free Software Foundation, Inc. +/* JScrollBar.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,13 +35,707 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing; import java.awt.Adjustable; +import java.awt.Dimension; +import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import javax.accessibility.Accessible; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.accessibility.AccessibleStateSet; +import javax.accessibility.AccessibleValue; +import javax.swing.SwingConstants; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; +import javax.swing.plaf.ProgressBarUI; +import javax.swing.plaf.ScrollBarUI; + -public class JScrollBar extends JComponent +/** + * The JScrollBar. Two buttons control how the values that the + * scroll bar can take. You can also drag the thumb or click the track + * to move the scroll bar. Typically, the JScrollBar is used with + * other components to translate the value of the bar to the viewable + * contents of the other components. + */ +public class JScrollBar extends JComponent implements Adjustable, Accessible { + /** + * DOCUMENT ME! + */ + protected class AccessibleJScrollBar extends JComponent.AccessibleJComponent + implements AccessibleValue + { + /** + * Creates a new AccessibleJSlider object. + * + * @param value0 DOCUMENT ME! + */ + protected AccessibleJScrollBar(JScrollBar value0) + { + super(value0); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * setCurrentAccessibleValue + * + * @param value0 TODO + * + * @return boolean + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * getMinimumAccessibleValue + * + * @return Number + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * getMaximumAccessibleValue + * + * @return Number + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + /** Fired in a PropertyChangeEvent when the "blockIncrement" changes. */ + public static final String BLOCK_INCREMENT_CHANGED_PROPERTY = "blockIncrement"; + + /** Fired in a PropertyChangeEvent when the "model" changes. */ + public static final String MODEL_CHANGED_PROPERTY = "model"; + + /** Fired in a PropertyChangeEvent when the "orientation" changes. */ + public static final String ORIENTATION_CHANGED_PROPERTY = "orientation"; + + /** Fired in a PropertyChangeEvent when the "unitIncrement" changes. */ + public static final String UNIT_INCREMENT_CHANGED_PROPERTY = "unitIncrement"; + + /** How much the thumb moves when moving in a block. */ + protected int blockIncrement = 10; + + /** The model that holds the scroll bar's data. */ + protected BoundedRangeModel model; + + /** The orientation of the scroll bar. */ + protected int orientation = SwingConstants.HORIZONTAL; + + /** How much the thumb moves when moving in a unit. */ + protected int unitIncrement = 1; + + /** A list of all ChangeListeners attached to the scroll bar. */ + private transient EventListenerList changeListenerList; + + /** A list of all AdjustmentListeners attached to the scroll bar. */ + private transient EventListenerList adjustmentListenerList; + + /** The ChangeListener that listens to the model. */ + private transient ChangeListener changeListener; + + /** The ChangeEvent that's fired. */ + private transient ChangeEvent changeEvent; + + /** + * Creates a new horizontal JScrollBar object with a minimum + * of 0, a maxmium of 100, a value of 0 and an extent of 10. + */ + public JScrollBar() + { + this(SwingConstants.HORIZONTAL, 0, 10, 0, 100); + } + + /** + * Creates a new JScrollBar object with a minimum of 0, a + * maximum of 100, a value of 0, an extent of 10 and the given + * orientation. + * + * @param orientation The orientation of the JScrollBar. + */ + public JScrollBar(int orientation) + { + this(orientation, 0, 10, 0, 100); + } + + /** + * Creates a new JScrollBar object with the given orientation, + * value, min, max, and extent. + * + * @param orientation The orientation to use. + * @param value The value to use. + * @param extent The extent to use. + * @param min The minimum value of the scrollbar. + * @param max The maximum value of the scrollbar. + */ + public JScrollBar(int orientation, int value, int extent, int min, int max) + { + model = new DefaultBoundedRangeModel(value, extent, min, max); + if (orientation != SwingConstants.HORIZONTAL + && orientation != SwingConstants.VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a legal orientation"); + this.orientation = orientation; + changeListener = createChangeListener(); + changeListenerList = new EventListenerList(); + adjustmentListenerList = new EventListenerList(); + model.addChangeListener(changeListener); + updateUI(); + } + + /** + * This method sets the UI of this scrollbar to + * the given UI. + * + * @param ui The UI to use with this scrollbar. + */ + public void setUI(ScrollBarUI ui) + { + super.setUI(ui); + } + + /** + * This method returns the UI that is being used + * with this scrollbar. + * + * @return The scrollbar's current UI. + */ + public ScrollBarUI getUI() + { + return (ScrollBarUI) ui; + } + + /** + * This method changes the UI to be the + * default for the current look and feel. + */ + public void updateUI() + { + setUI((ScrollBarUI) UIManager.getUI(this)); + invalidate(); + repaint(); + } + + /** + * This method returns an identifier to + * choose the correct UI delegate for the + * scrollbar. + * + * @return The identifer to choose the UI delegate; "ScrollBarUI" + */ + public String getUIClassID() + { + return "ScrollBarUI"; + } + + /** + * This method returns the orientation of the scrollbar. + * + * @return The orientation of the scrollbar. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method sets the orientation of the scrollbar. + * + * @param orientation The orientation of the scrollbar. + */ + public void setOrientation(int orientation) + { + if (orientation != SwingConstants.HORIZONTAL + && orientation != SwingConstants.VERTICAL) + throw new IllegalArgumentException("orientation must be one of HORIZONTAL or VERTICAL"); + if (orientation != this.orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange(ORIENTATION_CHANGED_PROPERTY, oldOrientation, + this.orientation); + } + } + + /** + * This method returns the model being used with + * the scrollbar. + * + * @return The scrollbar's model. + */ + public BoundedRangeModel getModel() + { + return model; + } + + /** + * This method sets the model to use with + * the scrollbar. + * + * @param newModel The new model to use with the scrollbar. + */ + public void setModel(BoundedRangeModel newModel) + { + if (model != newModel) + { + BoundedRangeModel oldModel = model; + model = newModel; + oldModel.removeChangeListener(changeListener); + model.addChangeListener(changeListener); + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, model); + } + } + + /** + * This method returns how much the scrollbar's value + * should change for a unit increment depending on the + * given direction. + * + * @param direction The direction to scroll in. + * + * @return The amount the scrollbar's value will change given the direction. + */ + public int getUnitIncrement(int direction) + { + return direction * unitIncrement; + } + + /** + * This method sets the unitIncrement property. + * + * @param unitIncrement The new unitIncrement. + */ + public void setUnitIncrement(int unitIncrement) + { + if (unitIncrement != this.unitIncrement) + { + int oldInc = this.unitIncrement; + this.unitIncrement = unitIncrement; + firePropertyChange(UNIT_INCREMENT_CHANGED_PROPERTY, oldInc, + this.unitIncrement); + } + } + + /** + * The method returns how much the scrollbar's value + * should change for a block increment depending on + * the given direction. + * + * @param direction The direction to scroll in. + * + * @return The amount the scrollbar's value will change given the direction. + */ + public int getBlockIncrement(int direction) + { + return direction * blockIncrement; + } + + /** + * This method sets the blockIncrement property. + * + * @param blockIncrement The new blockIncrement. + */ + public void setBlockIncrement(int blockIncrement) + { + if (blockIncrement != this.blockIncrement) + { + int oldInc = this.blockIncrement; + this.blockIncrement = blockIncrement; + firePropertyChange(BLOCK_INCREMENT_CHANGED_PROPERTY, oldInc, + this.blockIncrement); + } + } + + /** + * This method returns the unitIncrement. + * + * @return The unitIncrement. + */ + public int getUnitIncrement() + { + return unitIncrement; + } + + /** + * This method returns the blockIncrement. + * + * @return The blockIncrement. + */ + public int getBlockIncrement() + { + return blockIncrement; + } + + /** + * This method returns the value of the scrollbar. + * + * @return The value of the scrollbar. + */ + public int getValue() + { + return model.getValue(); + } + + /** + * This method changes the value of the scrollbar. + * + * @param value The new value of the scrollbar. + */ + public void setValue(int value) + { + if (isEnabled() && value != getValue()) + { + model.setValue(value); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, value); + } + } + + /** + * This method returns the visible amount (AKA extent). + * The visible amount can be used by UI delegates to + * determine the size of the thumb. + * + * @return The visible amount (AKA extent). + */ + public int getVisibleAmount() + { + return model.getExtent(); + } + + /** + * This method sets the visible amount (AKA extent). + * + * @param extent The visible amount (AKA extent). + */ + public void setVisibleAmount(int extent) + { + if (extent != getVisibleAmount()) + { + model.setExtent(extent); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, extent); + } + } + + /** + * This method returns the minimum value of the scrollbar. + * + * @return The minimum value of the scrollbar. + */ + public int getMinimum() + { + return model.getMinimum(); + } + + /** + * This method sets the minimum value of the scrollbar. + * + * @param minimum The minimum value of the scrollbar. + */ + public void setMinimum(int minimum) + { + if (minimum != getMinimum()) + { + model.setMinimum(minimum); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, minimum); + } + } + + /** + * This method returns the maximum value of the scrollbar. + * + * @return The maximum value of the scrollbar. + */ + public int getMaximum() + { + return model.getMaximum(); + } + + /** + * This method sets the maximum value of the scrollbar. + * + * @param maximum The maximum value of the scrollbar. + */ + public void setMaximum(int maximum) + { + if (maximum != getMaximum()) + { + model.setMaximum(maximum); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, maximum); + } + } + + /** + * This method returns the model's isAjusting value. + * + * @return The model's isAdjusting value. + */ + public boolean getValueIsAdjusting() + { + return model.getValueIsAdjusting(); + } + + /** + * This method sets the model's isAdjusting value. + * + * @param b The new isAdjusting value. + */ + public void setValueIsAdjusting(boolean b) + { + model.setValueIsAdjusting(b); + } + + /** + * This method sets the value, extent, minimum and + * maximum. + * + * @param newValue The new value. + * @param newExtent The new extent. + * @param newMin The new minimum. + * @param newMax The new maximum. + */ + public void setValue(int newValue, int newExtent, int newMin, int newMax) + { + if (!isEnabled()) + newValue = model.getValue(); + // It seems to be that on any change the value is fired. + if (newValue != getValue() || newExtent != getVisibleAmount() || + newMin != getMinimum() || newMax != getMaximum()) + { + model.setRangeProperties(newValue, newExtent, newMin, newMax, + model.getValueIsAdjusting()); + fireAdjustmentValueChanged(AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, newValue); + } + } + + /** + * This method creates a new ChangeListener. + * + * @return A new ChangeListener. + */ + private ChangeListener createChangeListener() + { + return new ChangeListener() + { + public void stateChanged(ChangeEvent e) + { + fireStateChanged(); + } + }; + } + + /** + * This method is called whenever the model fires a ChangeEvent. It should + * propagate the ChangeEvent to its listeners with a new ChangeEvent that + * identifies the scroll bar as the source. + */ + private void fireStateChanged() + { + Object[] changeListeners = changeListenerList.getListenerList(); + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + for (int i = changeListeners.length - 2; i >= 0; i -= 2) + { + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + } + } + + /** + * This method adds a ChangeListener to the scroll bar. + * + * @param listener The listener to add. + */ + public void addChangeListener(ChangeListener listener) + { + changeListenerList.add(ChangeListener.class, listener); + } + + /** + * This method removes a ChangeListener from the scroll bar. + * + * @param listener The listener to remove. + */ + public void removeChangeListener(ChangeListener listener) + { + changeListenerList.remove(ChangeListener.class, listener); + } + + /** + * This method returns an array of all ChangeListeners listening to this + * scroll bar. + * + * @return An array of ChangeListeners listening to this scroll bar. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) changeListenerList.getListenerList(); + } + + /** + * This method adds an AdjustmentListener to the scroll bar. + * + * @param listener The listener to add. + */ + public void addAdjustmentListener(AdjustmentListener listener) + { + adjustmentListenerList.add(AdjustmentListener.class, listener); + } + + /** + * This method removes an AdjustmentListener from the scroll bar. + * + * @param listener The listener to remove. + */ + public void removeAdjustmentListener(AdjustmentListener listener) + { + adjustmentListenerList.remove(AdjustmentListener.class, listener); + } + + /** + * This method returns an arry of all AdjustmentListeners listening to + * this scroll bar. + * + * @return An array of AdjustmentListeners listening to this scroll bar. + */ + public AdjustmentListener[] getAdjustmentListeners() + { + return (AdjustmentListener[]) adjustmentListenerList.getListenerList(); + } + + /** + * This method is called to fired AdjustmentEvents to the listeners + * of this scroll bar. All AdjustmentEvents that are fired + * will have an ID of ADJUSTMENT_VALUE_CHANGED and a type of + * TRACK. + * + * @param id The ID of the adjustment event. + * @param type The Type of change. + * @param value The new value for the property that was changed.. + */ + protected void fireAdjustmentValueChanged(int id, int type, int value) + { + Object[] adjustmentListeners = adjustmentListenerList.getListenerList(); + AdjustmentEvent adjustmentEvent = new AdjustmentEvent(this, + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + AdjustmentEvent.TRACK, + value); + for (int i = adjustmentListeners.length - 2; i >= 0; i -= 2) + { + if (adjustmentListeners[i] == AdjustmentListener.class) + ((AdjustmentListener) adjustmentListeners[i + 1]).adjustmentValueChanged(adjustmentEvent); + } + } + + /** + * This method returns the minimum size for this scroll bar. + * + * @return The minimum size. + */ + public Dimension getMinimumSize() + { + return ui.getMinimumSize(this); + } + + /** + * This method returns the maximum size for this scroll bar. + * + * @return The maximum size. + */ + public Dimension getMaximumSize() + { + return ui.getMaximumSize(this); + } + + /** + * This method overrides the setEnabled in JComponent. + * When the scroll bar is disabled, the knob cannot + * be moved. + * + * @param x Whether the scrollbar is enabled. + */ + public void setEnabled(boolean x) + { + // nothing special needs to be done here since we + // just check the enabled setting before changing the value. + super.setEnabled(x); + } + + /** + * A string that describes this JScrollBar. Normally only used + * for debugging. + * + * @return A string describing this JScrollBar. + */ + protected String paramString() + { + return "JScrollBar"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJScrollBar(this); + return accessibleContext; + } } diff --git a/libjava/javax/swing/JScrollPane.java b/libjava/javax/swing/JScrollPane.java index 6a63be5f2e7..f31da048abf 100644 --- a/libjava/javax/swing/JScrollPane.java +++ b/libjava/javax/swing/JScrollPane.java @@ -1,5 +1,5 @@ /* JScrollPane.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,96 +39,540 @@ exception statement from your version. */ package javax.swing; import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.LayoutManager; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; + +import javax.swing.border.Border; import javax.accessibility.Accessible; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.plaf.ScrollPaneUI; +import javax.swing.plaf.UIResource; -public class JScrollPane extends JComponent implements Accessible, ScrollPaneConstants +/** + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Property Stored in Bound?
columnHeader scrollPane yes
columnHeaderView columnHeader no
componentOrientation scrollPane yes
horizontalScrollBar scrollPane yes
horizontalScrollBarPolicy scrollPane yes
layout scrollPane yes
rowHeader scrollPane yes
rowHeaderView rowHeader no
validateRoot scrollPane no
verticalScrollBar scrollPane yes
verticalScrollBarPolicy scrollPane yes
viewport scrollPane yes
viewportBorder scrollPane yes
viewportBorderBounds scrollPane no
viewportView viewport no
wheelScrollingEnabled scrollPane yes
+ */ +public class JScrollPane + extends JComponent + implements Accessible, ScrollPaneConstants { - protected JViewport columnHeader; - protected JViewport rowHeader; + JViewport columnHeader; + JViewport rowHeader; - protected Component lowerLeft; - protected Component lowerRight; - protected Component upperLeft; - protected Component upperRight; + Component lowerLeft; + Component lowerRight; + Component upperLeft; + Component upperRight; - protected JScrollBar horizontalScrollBar; - protected int horizontalScrollBarPolicy; - protected JScrollBar verticalScrollBar; - protected int verticalScrollBarPolicy; + JScrollBar horizontalScrollBar; + int horizontalScrollBarPolicy; + JScrollBar verticalScrollBar; + int verticalScrollBarPolicy; - protected JViewport viewport; + JViewport viewport; + Border viewportBorder; + boolean wheelScrollingEnabled; + ChangeListener scrollListener; + public static final String COLUMN_HEADER_CHANGED_PROPERTY = "columnHeader"; + public static final String COMPONENT_ORIENTATION_CHANGED_PROPERTY = "componentOrientation"; + public static final String HORIZONTAL_SCROLLBAR_CHANGED_PROPERTY = "horizontalScrollBar"; + public static final String HORIZONTAL_SCROLLBAR_POLICY_CHANGED_PROPERTY = "horizontalScrollBarPolicy"; + public static final String LAYOUT_CHANGED_PROPERTY = "layout"; + public static final String ROW_HEADER_CHANGED_PROPERTY = "rowHeader"; + public static final String VERTICAL_SCROLLBAR_CHANGED_PROPERTY = "verticalScrollBar"; + public static final String VERTICAL_SCROLLBAR_POLICY_CHANGED_PROPERTY = "verticalScrollBarPolicy"; + public static final String VIEWPORT_CHANGED_PROPERTY = "viewport"; + public static final String VIEWPORT_BORDER_CHANGED_PROPERTY = "viewportBorder"; + public static final String WHEEL_SCROLLING_ENABLED_CHANGED_PROPERTY = "wheelScrollingEnabled"; - public JScrollPane() - { - this(null, 0, 0); - } - - public JScrollPane(Component view) - { - this(view, 0, 0); - } - + public JViewport getColumnHeader() + { + return columnHeader; + } + + public Component getCorner(String key) { + if (getComponentOrientation() + == ComponentOrientation.LEFT_TO_RIGHT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_LEFT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_RIGHT_CORNER; + } + else if (getComponentOrientation() + == ComponentOrientation.RIGHT_TO_LEFT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_RIGHT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_LEFT_CORNER; + } + + if (key == LOWER_RIGHT_CORNER) + return lowerRight; + else if (key == UPPER_RIGHT_CORNER) + return upperRight; + else if (key == LOWER_LEFT_CORNER) + return lowerLeft; + else if (key == UPPER_LEFT_CORNER) + return upperLeft; + return null; + } + + public JScrollBar getHorizontalScrollBar() + { + return horizontalScrollBar; + } + + public int getHorizontalScrollBarPolicy() + { + return horizontalScrollBarPolicy; + } + + public JViewport getRowHeader() + { + return rowHeader; + } + + public JScrollBar getVerticalScrollBar() + { + return verticalScrollBar; + } + + public int getVerticalScrollBarPolicy() + { + return verticalScrollBarPolicy; + } + + public JViewport getViewport() + { + return viewport; + } + + public Border getViewportBorder() + { + return viewportBorder; + } + + public Rectangle getViewportBorderBounds() + { + if (viewportBorder == null) + { + if (getViewport() == null) + return new Rectangle(0,0,0,0); + else + return getViewport().getBounds(); + } + else + { + Insets i = viewportBorder.getBorderInsets(getViewport()); + if (getViewport() == null) + return new Rectangle(0,0, + i.left+i.right, i.top+i.bottom); + else + { + Rectangle b = getViewport().getBounds(); + return new Rectangle(b.x - i.left, + b.y - i.top, + b.width + i.left + i.right, + b.height + i.top + i.bottom); + } + } + } + + public boolean isWheelScrollingEnabled() + { + return wheelScrollingEnabled; + } + + + + private void sync() + { + LayoutManager m = super.getLayout(); + if (m != null && m instanceof ScrollPaneLayout) + { + ScrollPaneLayout sl = (ScrollPaneLayout) m; + sl.syncWithScrollPane(this); + } + } + + private void removeNonNull(Component c) + { + if (c != null) + remove(c); + } + + private void addNonNull(Component c) + { + if (c != null) + add(c); + } + + public void setComponentOrientation(ComponentOrientation co) + { + ComponentOrientation old = super.getComponentOrientation(); + super.setComponentOrientation(co); + firePropertyChange(COMPONENT_ORIENTATION_CHANGED_PROPERTY, old, co); + sync(); + } + + public void setColumnHeader(JViewport h) + { + JViewport old = columnHeader; + removeNonNull(old); + columnHeader = h; + addNonNull(h); + firePropertyChange(COLUMN_HEADER_CHANGED_PROPERTY, old, h); + sync(); + } + + public void setColumnHeaderView(Component c) + { + if (columnHeader == null) + setColumnHeader(createViewport()); + columnHeader.setView(c); + sync(); + } + + public void setCorner(String key, Component c) + { + if (getComponentOrientation() + == ComponentOrientation.LEFT_TO_RIGHT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_LEFT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_RIGHT_CORNER; + } + else if (getComponentOrientation() + == ComponentOrientation.RIGHT_TO_LEFT) + { + if (key == LOWER_LEADING_CORNER) + key = LOWER_RIGHT_CORNER; + else if (key == LOWER_TRAILING_CORNER) + key = LOWER_LEFT_CORNER; + else if (key == UPPER_LEADING_CORNER) + key = UPPER_RIGHT_CORNER; + else if (key == UPPER_TRAILING_CORNER) + key = UPPER_LEFT_CORNER; + } + + if (key == LOWER_RIGHT_CORNER) + { + removeNonNull(lowerRight); + lowerRight = c; + addNonNull(c); + } + else if (key == UPPER_RIGHT_CORNER) + { + removeNonNull(upperRight); + upperRight = c; + addNonNull(c); + } + else if (key == LOWER_LEFT_CORNER) + { + removeNonNull(lowerLeft); + lowerLeft = c; + addNonNull(c); + } + else if (key == UPPER_LEFT_CORNER) + { + removeNonNull(upperLeft); + upperLeft = c; + addNonNull(c); + } + else + throw new IllegalArgumentException("unknown corner " + key); + sync(); + } + + public void setHorizontalScrollBar(JScrollBar h) + { + JScrollBar old = horizontalScrollBar; + removeNonNull(old); + horizontalScrollBar = h; + addNonNull(h); + firePropertyChange(HORIZONTAL_SCROLLBAR_CHANGED_PROPERTY, old, h); + sync(); + + if (old != null) + { + BoundedRangeModel model = old.getModel(); + if (model != null) + model.removeChangeListener(scrollListener); + } + if (h != null) + { + BoundedRangeModel model = h.getModel(); + if (model != null) + model.addChangeListener(scrollListener); + } + } + + public void setHorizontalScrollBarPolicy(int h) + { + if (h != HORIZONTAL_SCROLLBAR_AS_NEEDED + && h != HORIZONTAL_SCROLLBAR_NEVER + && h != HORIZONTAL_SCROLLBAR_ALWAYS) + throw new IllegalArgumentException("unknown horizontal scrollbar policy"); + int old = horizontalScrollBarPolicy; + horizontalScrollBarPolicy = h; + firePropertyChange(HORIZONTAL_SCROLLBAR_POLICY_CHANGED_PROPERTY, old, h); + sync(); + } + + public void setLayout(LayoutManager l) + { + LayoutManager old = super.getLayout(); + ScrollPaneLayout tmp = (ScrollPaneLayout) l; + super.setLayout(l); + tmp.syncWithScrollPane(this); + firePropertyChange(LAYOUT_CHANGED_PROPERTY, old, l); + sync(); + } + + public void setRowHeader(JViewport v) + { + JViewport old = rowHeader; + removeNonNull(old); + rowHeader = v; + addNonNull(v); + firePropertyChange(ROW_HEADER_CHANGED_PROPERTY, old, v); + sync(); + } + + public void setRowHeaderView(Component c) + { + if (rowHeader == null) + setRowHeader(createViewport()); + rowHeader.setView(c); + sync(); + } + + public void setVerticalScrollBar(JScrollBar v) + { + JScrollBar old = verticalScrollBar; + removeNonNull(old); + verticalScrollBar = v; + addNonNull(v); + firePropertyChange(VERTICAL_SCROLLBAR_CHANGED_PROPERTY, old, v); + sync(); + + if (old != null) + { + BoundedRangeModel model = old.getModel(); + if (model != null) + model.removeChangeListener(scrollListener); + } + if (v != null) + { + BoundedRangeModel model = v.getModel(); + if (model != null) + model.addChangeListener(scrollListener); + } + } + + public void setVerticalScrollBarPolicy(int v) + { + if (v != VERTICAL_SCROLLBAR_AS_NEEDED + && v != VERTICAL_SCROLLBAR_NEVER + && v != VERTICAL_SCROLLBAR_ALWAYS) + throw new IllegalArgumentException("unknown vertical scrollbar policy"); + int old = verticalScrollBarPolicy; + verticalScrollBarPolicy = v; + firePropertyChange(VERTICAL_SCROLLBAR_POLICY_CHANGED_PROPERTY, old, v); + sync(); + } + + public void setWheelScrollingEnabled(boolean b) + { + boolean old = wheelScrollingEnabled; + wheelScrollingEnabled = b; + firePropertyChange(WHEEL_SCROLLING_ENABLED_CHANGED_PROPERTY, old, b); + sync(); + } + + public void setViewport(JViewport v) + { + JViewport old = viewport; + removeNonNull(old); + viewport = v; + addNonNull(v); + revalidate(); + repaint(); + firePropertyChange(VIEWPORT_CHANGED_PROPERTY, old, v); + sync(); + } + + public void setViewportBorder(Border b) + { + Border old = viewportBorder; + viewportBorder = b; + firePropertyChange(VIEWPORT_BORDER_CHANGED_PROPERTY, old, b); + sync(); + } - public JScrollPane(int vsbPolicy, int hsbPolicy) - { - this(null, 0, 0); - } + public void setViewportView(Component view) + { + if (getViewport() == null) + { + setViewport(createViewport()); + } + + if (view != null) + { + getViewport().setView(view); + } + sync(); + } - public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) - { - setViewportView(view); - setOpaque(true); - updateUI(); - } + public boolean isValidateRoot() + { + return true; + } - public String getUIClassID() - { - //Returns a string that specifies the name of the L&F class that renders this component. - return "ScrollPaneUI"; - } + ChangeListener createScrollListener() + { + return new ChangeListener() { + public void stateChanged(ChangeEvent event) + { + int xpos = 0; + int ypos = 0; + JScrollBar vsb = JScrollPane.this.getVerticalScrollBar(); + JScrollBar hsb = JScrollPane.this.getHorizontalScrollBar(); + + if (vsb != null) + { + BoundedRangeModel vmod = vsb.getModel(); + if (vmod != null) + ypos = vmod.getValue(); + } - public JViewport getViewport() - { - return viewport; - } + if (hsb != null) + { + BoundedRangeModel hmod = hsb.getModel(); + if (hmod != null) + xpos = hmod.getValue(); + } + if (JScrollPane.this.viewport != null) + JScrollPane.this.viewport.setViewPosition(new Point(xpos, ypos)); + } + }; + } - public JViewport createViewport() - { - return new JViewport(); - } + + public JScrollPane() + { + this(null); + } - public void setViewport(JViewport v) - { - if (viewport != null) - remove(viewport); + public JScrollPane(Component view) + { + this(view, + VERTICAL_SCROLLBAR_AS_NEEDED, + HORIZONTAL_SCROLLBAR_AS_NEEDED); + } - viewport = v; - - add(v); - - revalidate(); - repaint(); - } + public JScrollPane(int vsbPolicy, int hsbPolicy) + { + this(null, vsbPolicy, hsbPolicy); + } + + public JScrollPane(Component view, int vsbPolicy, int hsbPolicy) + { + scrollListener = createScrollListener(); + setVerticalScrollBarPolicy(vsbPolicy); + setVerticalScrollBar(createVerticalScrollBar()); + setHorizontalScrollBarPolicy(hsbPolicy); + setHorizontalScrollBar(createHorizontalScrollBar()); + setViewportView(view); + setLayout(new ScrollPaneLayout()); + setOpaque(false); + updateUI(); + } + + + public JScrollBar createHorizontalScrollBar() + { + return new JScrollBar(SwingConstants.HORIZONTAL); + } + + public JScrollBar createVerticalScrollBar() + { + return new JScrollBar(SwingConstants.VERTICAL); + } - public void updateUI() - { - ScrollPaneUI b = (ScrollPaneUI)UIManager.getUI(this); - setUI(b); - } + public JViewport createViewport() + { + return new JViewport(); + } - public void setViewportView(Component view) + public String getUIClassID() + { + return "ScrollPaneUI"; + } + + public void updateUI() + { + ScrollPaneUI b = (ScrollPaneUI)UIManager.getUI(this); + setUI(b); + } + + /* + class ScrollBar + extends JScrollBar + implements UIResource + { + public ScrollBar(int orientation) { - if (getViewport() == null) - { - setViewport(createViewport()); - } - - if (view != null) - { - getViewport().setView(view); - } + super(orientation); + Component view = this.JScrollPane.getViewportView(); + if (view == null) + return; + if (! view instanceof Scrollable) + { + Scrollable s = (Scrollable) view; + s. + } } + + } + */ + } diff --git a/libjava/javax/swing/JSeparator.java b/libjava/javax/swing/JSeparator.java index a38d1a50a5e..224280b35a6 100644 --- a/libjava/javax/swing/JSeparator.java +++ b/libjava/javax/swing/JSeparator.java @@ -44,183 +44,163 @@ import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.swing.plaf.SeparatorUI; + /** - * JSeparator - * @author Andrew Selkirk - * @version 1.0 + * The JSeparator. It is mostly used to divide/space out + * components. */ -public class JSeparator extends JComponent - implements SwingConstants, Accessible +public class JSeparator extends JComponent implements SwingConstants, + Accessible { - - //------------------------------------------------------------- - // Classes ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * AccessibleJSeparator - */ - protected class AccessibleJSeparator extends AccessibleJComponent { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor AccessibleJSeparator - * @param component TODO - */ - protected AccessibleJSeparator(JSeparator component) { - super(component); - // TODO - } // AccessibleJSeparator() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getAccessibleRole - * @returns AccessibleRole - */ - public AccessibleRole getAccessibleRole() { - return AccessibleRole.SEPARATOR; - } // getAccessibleRole() - - - } // AccessibleJSeparator - - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * uiClassID - */ - private static final String uiClassID = "SeparatorUI"; - - /** - * orientation - */ - private int orientation; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor JSeparator - */ - public JSeparator() { - this(HORIZONTAL); - } // JSeparator() - - /** - * Constructor JSeparator - * @param value0 TODO - */ - public JSeparator(int orientation) { - this.orientation = orientation; - // TODO - } // JSeparator() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * writeObject - * @param stream TODO - * @exception IOException TODO - */ - private void writeObject(ObjectOutputStream stream) throws IOException { - // TODO - } // writeObject() - - /** - * getUI - * @returns SeparatorUI - */ - public SeparatorUI getUI() { - return (SeparatorUI) ui; - } // getUI() - - /** - * setUI - * @param ui TODO - */ - public void setUI(SeparatorUI ui) { - super.setUI(ui); - } // setUI() - - /** - * updateUI - */ - public void updateUI() { - setUI((SeparatorUI) UIManager.get(this)); - invalidate(); - } // updateUI() - - /** - * getUIClassID - * @returns String - */ - public String getUIClassID() { - return uiClassID; - } // getUIClassID() - - /** - * getOrientation - * @returns int - */ - public int getOrientation() { - return orientation; - } // getOrientation() - - /** - * setOrientation - * @param orientation TODO - */ - public void setOrientation(int orientation) { - this.orientation = orientation; - // TODO - } // setOrientation() - - /** - * paramString - * @returns String - */ - protected String paramString() { - return null; // TODO - } // paramString() - - /** - * isFocusTraversable - * @returns boolean - */ - public boolean isFocusTraversable() { - return false; - } // isFocusTraversable() - - /** - * getAccessibleContext - * @returns AccessibleContext - */ - public AccessibleContext getAccessibleContext() { - if (accessibleContext == null) { - accessibleContext = new AccessibleJSeparator(this); - } // if - return accessibleContext; - } // getAccessibleContext() - - -} // JSeparator + /** + * AccessibleJSeparator + */ + protected class AccessibleJSeparator extends AccessibleJComponent + { + /** + * Constructor AccessibleJSeparator + * + * @param component TODO + */ + protected AccessibleJSeparator(JSeparator component) + { + super(component); + } + + /** + * getAccessibleRole + * + * @return AccessibleRole + */ + public AccessibleRole getAccessibleRole() + { + return AccessibleRole.SEPARATOR; + } + } + + /** The orientation of the JSeparator. */ + private transient int orientation = HORIZONTAL; + + /** + * Creates a new horizontal JSeparator object. + */ + public JSeparator() + { + this(HORIZONTAL); + } + + /** + * Creates a new JSeparator object with the given orientation. + * + * @param orientation The orientation of the JSeparator. + */ + public JSeparator(int orientation) + { + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a valid orientation."); + this.orientation = orientation; + updateUI(); + } + + /** + * This method returns the UI delegate being + * used with the JSeparator. + * + * @return SeparatorUI The JSeparator's UI delegate. + */ + public SeparatorUI getUI() + { + return (SeparatorUI) ui; + } + + /** + * This method sets the UI delegate to use + * with the JSeparator. + * + * @param ui The UI delegate to use. + */ + public void setUI(SeparatorUI ui) + { + super.setUI(ui); + } + + /** + * This method resets the UI delegate to the + * default for the current look and feel. + */ + public void updateUI() + { + setUI((SeparatorUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * This method returns the identifier string + * that is used to determine the UI delegate + * from the current look and feel. + * + * @return String The identifier string for the UI. + */ + public String getUIClassID() + { + return "SeparatorUI"; + } + + /** + * This method returns the JSeparator's orientation. + * + * @return int The JSeparator's orientation. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method changes the JSeparator's orientation. + * + * @param orientation The JSeparator's orientation. + */ + public void setOrientation(int orientation) + { + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + + " is not a valid orientation."); + this.orientation = orientation; + } + + /** + * This method returns a string desribing the JSeparator. + * Normally only used in debugging. + * + * @return String A string describing the JSeparator. + */ + protected String paramString() + { + return "JSeparator"; + } + + /** + * This method overrides the isFocusTraversable method from + * Component to false. JSeparator cannot be focused on. + * + * @return boolean False. + */ + public boolean isFocusTraversable() + { + return false; + } + + /** + * getAccessibleContext + * + * @return AccessibleContext + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJSeparator(this); + return accessibleContext; + } +} diff --git a/libjava/javax/swing/JSlider.java b/libjava/javax/swing/JSlider.java index c9fc022fa6a..203dc4a6197 100644 --- a/libjava/javax/swing/JSlider.java +++ b/libjava/javax/swing/JSlider.java @@ -1,5 +1,5 @@ /* JSlider.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,13 +35,17 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing; +import java.awt.ComponentOrientation; +import java.awt.MenuContainer; +import java.awt.Dimension; +import java.awt.image.ImageObserver; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Dictionary; +import java.util.Enumeration; import java.util.Hashtable; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; @@ -50,652 +54,894 @@ import javax.accessibility.AccessibleStateSet; import javax.accessibility.AccessibleValue; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; import javax.swing.plaf.SliderUI; + /** - * JSlider - * @author Andrew Selkirk - * @version 1.0 + *

+ * The JSlider is a Swing component that allows selection of a value within a + * range by adjusting a thumb in a track. The values for the minimum, + * maximum, extent and value are stored in a {@link + * DefaultBoundedRangeModel}. + *

+ * + *

+ * JSliders have the following properties: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Property Stored in Bound?
extent model no
inverted slider yes
labelTable slider yes
majorTickSpacing slider yes
maximum model no
minimum model no
minorTickSpacing slider yes
model slider yes
orientation slider yes
paintLabels slider yes
paintTicks slider yes
snapToTicks slider no
value model no
valueIsAdjusting model no
+ * + *

+ * The various behavioral aspects of these properties follows: + *

+ * + *
    + *
  • + * When non-bound properties stored in the slider change, the slider fires + * ChangeEvents to its ChangeListeners. + *
  • + *
  • + * When bound properties stored in the slider change, the slider fires + * PropertyChangeEvents to its PropertyChangeListeners + *
  • + *
  • + * If any of the model's properties change, it fires a ChangeEvent to its + * ChangeListeners, which include the slider. + *
  • + *
  • + * If the slider receives a ChangeEvent from its model, it will propagate the + * ChangeEvent to its ChangeListeners, with the ChangeEvent's "source" + * property set to refer to the slider, rather than the model. + *
  • + *
*/ -public class JSlider - extends JComponent - implements SwingConstants, Accessible +public class JSlider extends JComponent implements SwingConstants, Accessible, + ImageObserver, + MenuContainer, Serializable { + /** DOCUMENT ME! */ static final long serialVersionUID = -1441275936141218479L; - //------------------------------------------------------------- - // Classes ---------------------------------------------------- - //------------------------------------------------------------- - - - /** - * AccessibleJSlider - */ - protected class AccessibleJSlider extends JComponent.AccessibleJComponent implements AccessibleValue { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor AccessibleJSlider - * @param value0 TODO - */ - protected AccessibleJSlider(JSlider value0) { - super(value0); - // TODO - } // AccessibleJSlider() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * getAccessibleStateSet - * @returns AccessibleStateSet - */ - public AccessibleStateSet getAccessibleStateSet() { - return null; // TODO - } // getAccessibleStateSet() - - /** - * getAccessibleRole - * @returns AccessibleRole - */ - public AccessibleRole getAccessibleRole() { - return null; // TODO - } // getAccessibleRole() - - /** - * getAccessibleValue - * @returns AccessibleValue - */ - public AccessibleValue getAccessibleValue() { - return null; // TODO - } // getAccessibleValue() - - /** - * getCurrentAccessibleValue - * @returns Number - */ - public Number getCurrentAccessibleValue() { - return null; // TODO - } // getCurrentAccessibleValue() - - /** - * setCurrentAccessibleValue - * @param value0 TODO - * @returns boolean - */ - public boolean setCurrentAccessibleValue(Number value0) { - return false; // TODO - } // setCurrentAccessibleValue() - - /** - * getMinimumAccessibleValue - * @returns Number - */ - public Number getMinimumAccessibleValue() { - return null; // TODO - } // getMinimumAccessibleValue() - - /** - * getMaximumAccessibleValue - * @returns Number - */ - public Number getMaximumAccessibleValue() { - return null; // TODO - } // getMaximumAccessibleValue() - - - } // AccessibleJSlider - - /** - * ModelListener - */ - private class ModelListener implements ChangeListener, Serializable { - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor ModelListener - * @param value0 TODO - */ - private ModelListener(JSlider value0) { - // TODO - } // ModelListener() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * stateChanged - * @param value0 TODO - */ - public void stateChanged(ChangeEvent value0) { - // TODO - } // stateChanged() - - - } // ModelListener - - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * uiClassID - */ - private static final String uiClassID = "SliderUI"; - - /** - * paintTicks - */ - private boolean paintTicks; - - /** - * paintTrack - */ - private boolean paintTrack; - - /** - * paintLabels - */ - private boolean paintLabels; - - /** - * isInverted - */ - private boolean isInverted; - - /** - * sliderModel - */ - protected BoundedRangeModel sliderModel; - - /** - * majorTickSpacing - */ - protected int majorTickSpacing; - - /** - * minorTickSpacing - */ - protected int minorTickSpacing; - - /** - * snapToTicks - */ - protected boolean snapToTicks; - - /** - * snapToValue - */ - boolean snapToValue; - - /** - * orientation - */ - protected int orientation; - - /** - * labelTable - */ - private Dictionary labelTable; - - /** - * changeListener - */ - protected ChangeListener changeListener; - - /** - * changeEvent - */ - protected transient ChangeEvent changeEvent; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor JSlider - */ - public JSlider() { - // TODO - } // JSlider() - - /** - * Constructor JSlider - * @param value0 TODO - */ - public JSlider(int orientation) { - // TODO - } // JSlider() - - /** - * Constructor JSlider - * @param minimum TODO - * @param maximum TODO - */ - public JSlider(int minimum, int maximum) { - // TODO - } // JSlider() - - /** - * Constructor JSlider - * @param minimum TODO - * @param maximum TODO - * @param value TODO - */ - public JSlider(int minimum, int maximum, int value) { - // TODO - } // JSlider() - - /** - * Constructor JSlider - * @param orientation TODO - * @param minimum TODO - * @param maximum TODO - * @param value TODO - */ - public JSlider(int orientation, int minimum, int maximum, int value) { - // TODO - } // JSlider() - - /** - * Constructor JSlider - * @param value0 TODO - */ - public JSlider(BoundedRangeModel model) { - // TODO - } // JSlider() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * writeObject - * @param stream TODO - * @exception IOException TODO - */ - private void writeObject(ObjectOutputStream stream) throws IOException { - // TODO - } // writeObject() - - /** - * getValue - * @returns int - */ - public int getValue() { - return 0; // TODO - } // getValue() - - /** - * setValue - * @param value0 TODO - */ - public void setValue(int value) { - // TODO - } // setValue() - - /** - * getUI - * @returns SliderUI - */ - public SliderUI getUI() { - return (SliderUI) ui; - } // getUI() - - /** - * setUI - * @param ui TODO - */ - public void setUI(SliderUI ui) { - super.setUI(ui); - } // setUI() - - /** - * updateUI - */ - public void updateUI() { - setUI((SliderUI) UIManager.get(this)); - invalidate(); - } // updateUI() - - /** - * getUIClassID - * @returns String - */ - public String getUIClassID() { - return uiClassID; - } // getUIClassID() - - /** - * createChangeListener - * @returns ChangeListener - */ - protected ChangeListener createChangeListener() { - return null; // TODO - } // createChangeListener() - - /** - * addChangeListener - * @param listener TODO - */ - public void addChangeListener(ChangeListener listener) { - // TODO - } // addChangeListener() - - /** - * removeChangeListener - * @param listener TODO - */ - public void removeChangeListener(ChangeListener listener) { - // TODO - } // removeChangeListener() - - /** - * fireStateChanged - */ - protected void fireStateChanged() { - // TODO - } // fireStateChanged() - - /** - * getModel - * @returns BoundedRangeModel - */ - public BoundedRangeModel getModel() { - return null; // TODO - } // getModel() - - /** - * setModel - * @param model TODO - */ - public void setModel(BoundedRangeModel model) { - // TODO - } // setModel() - - /** - * getMinimum - * @returns int - */ - public int getMinimum() { - return 0; // TODO - } // getMinimum() - - /** - * setMinimum - * @param minimum TODO - */ - public void setMinimum(int minimum) { - // TODO - } // setMinimum() - - /** - * getMaximum - * @returns int - */ - public int getMaximum() { - return 0; // TODO - } // getMaximum() - - /** - * setMaximum - * @param maximum TODO - */ - public void setMaximum(int maximum) { - // TODO - } // setMaximum() - - /** - * getValueIsAdjusting - * @returns boolean - */ - public boolean getValueIsAdjusting() { - return false; // TODO - } // getValueIsAdjusting() - - /** - * setValueIsAdjusting - * @param adjusting TODO - */ - public void setValueIsAdjusting(boolean adjusting) { - // TODO - } // setValueIsAdjusting() - - /** - * getExtent - * @returns int - */ - public int getExtent() { - return 0; // TODO - } // getExtent() - - /** - * setExtent - * @param vextent TODO - */ - public void setExtent(int extent) { - // TODO - } // setExtent() - - /** - * getOrientation - * @returns int - */ - public int getOrientation() { - return 0; // TODO - } // getOrientation() - - /** - * setOrientation - * @param orientation TODO - */ - public void setOrientation(int orientation) { - // TODO - } // setOrientation() - - /** - * getLabelTable - * @returns Dictionary - */ - public Dictionary getLabelTable() { - return null; // TODO - } // getLabelTable() - - /** - * setLabelTable - * @param table TODO - */ - public void setLabelTable(Dictionary table) { - // TODO - } // setLabelTable() - - /** - * updateLabelUIs - */ - protected void updateLabelUIs() { - // TODO - } // updateLabelUIs() - - /** - * createStandardLabels - * @param increment TODO - * @returns Hashtable - */ - public Hashtable createStandardLabels(int increment) { - return null; // TODO - } // createStandardLabels() - - /** - * createStandardLabels - * @param increment TODO - * @param start TODO - * @returns Hashtable - */ - public Hashtable createStandardLabels(int increment, int start) { - return null; // TODO - } // createStandardLabels() - - /** - * getInverted - * @returns boolean - */ - public boolean getInverted() { - return false; // TODO - } // getInverted() - - /** - * setInverted - * @param inverted TODO - */ - public void setInverted(boolean inverted) { - // TODO - } // setInverted() - - /** - * getMajorTickSpacing - * @returns int - */ - public int getMajorTickSpacing() { - return 0; // TODO - } // getMajorTickSpacing() - - /** - * setMajorTickSpacing - * @param spacing TODO - */ - public void setMajorTickSpacing(int spacing) { - // TODO - } // setMajorTickSpacing() - - /** - * getMinorTickSpacing - * @returns int - */ - public int getMinorTickSpacing() { - return 0; // TODO - } // getMinorTickSpacing() - - /** - * setMinorTickSpacing - * @param spacing TODO - */ - public void setMinorTickSpacing(int spacing) { - // TODO - } // setMinorTickSpacing() - - /** - * getSnapToTicks - * @returns boolean - */ - public boolean getSnapToTicks() { - return false; // TODO - } // getSnapToTicks() - - /** - * getSnapToValue - * @returns boolean - */ - boolean getSnapToValue() { - return false; // TODO - } // getSnapToValue() - - /** - * setSnapToTicks - * @param snap TODO - */ - public void setSnapToTicks(boolean snap) { - // TODO - } // setSnapToTicks() - - /** - * getPaintTicks - * @returns boolean - */ - public boolean getPaintTicks() { - return false; // TODO - } // getPaintTicks() - - /** - * setPaintTicks - * @param paint TODO - */ - public void setPaintTicks(boolean paint) { - // TODO - } // setPaintTicks() - - /** - * getPaintTrack - * @returns boolean - */ - public boolean getPaintTrack() { - return false; // TODO - } // getPaintTrack() - - /** - * setPaintTrack - * @param paint TODO - */ - public void setPaintTrack(boolean paint) { - // TODO - } // setPaintTrack() - - /** - * getPaintLabels - * @returns boolean - */ - public boolean getPaintLabels() { - return false; // TODO - } // getPaintLabels() - - /** - * setPaintLabels - * @param paint TODO - */ - public void setPaintLabels(boolean paint) { - // TODO - } // setPaintLabels() - - /** - * paramString - * @returns String - */ - protected String paramString() { - return null; // TODO - } // paramString() - - /** - * getAccessibleContext - * @returns AccessibleContext - */ - public AccessibleContext getAccessibleContext() { - if (accessibleContext == null) { - accessibleContext = new AccessibleJSlider(this); - } // if - return accessibleContext; - } // getAccessibleContext() - - -} // JSlider + /** + * DOCUMENT ME! + */ + protected class AccessibleJSlider extends JComponent.AccessibleJComponent + implements AccessibleValue + { + /** + * Creates a new AccessibleJSlider object. + * + * @param value0 DOCUMENT ME! + */ + protected AccessibleJSlider(JSlider value0) + { + super(value0); + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleStateSet getAccessibleStateSet() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleRole getAccessibleRole() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleValue getAccessibleValue() + { + return null; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public Number getCurrentAccessibleValue() + { + return null; + } + + /** + * setCurrentAccessibleValue + * + * @param value0 TODO + * + * @return boolean + */ + public boolean setCurrentAccessibleValue(Number value0) + { + return false; + } + + /** + * getMinimumAccessibleValue + * + * @return Number + */ + public Number getMinimumAccessibleValue() + { + return null; + } + + /** + * getMaximumAccessibleValue + * + * @return Number + */ + public Number getMaximumAccessibleValue() + { + return null; + } + } + + /** Fired in a PropertyChangeEvent when the "inverted" property changes. */ + public static final String INVERTED_CHANGED_PROPERTY = "inverted"; + + /** Fired in a PropertyChangeEvent when the "labelTable" property changes. */ + public static final String LABEL_TABLE_CHANGED_PROPERTY = "labelTable"; + + /** + * Fired in a PropertyChangeEvent when the "majorTickSpacing" property + * changes. + */ + public static final String MAJOR_TICK_SPACING_CHANGED_PROPERTY = "majorTickSpacing"; + + /** + * Fired in a PropertyChangeEvent when the "minorTickSpacing" property + * changes. + */ + public static final String MINOR_TICK_SPACING_CHANGED_PROPERTY = "minorTickSpacing"; + + /** Fired in a PropertyChangeEvent when the "model" property changes. */ + public static final String MODEL_CHANGED_PROPERTY = "model"; + + /** Fired in a PropertyChangeEvent when the "orientation" property changes. */ + public static final String ORIENTATION_CHANGED_PROPERTY = "orientation"; + + /** Fired in a PropertyChangeEvent when the "paintLabels" property changes. */ + public static final String PAINT_LABELS_CHANGED_PROPERTY = "paintLabels"; + + /** Fired in a PropertyChangeEvent when the "paintTicks" property changes. */ + public static final String PAINT_TICKS_CHANGED_PROPERTY = "paintTicks"; + + /** Whether or not this slider paints its ticks. */ + private transient boolean paintTicks = false; + + /** Whether or not this slider paints its track. */ + private transient boolean paintTrack = true; + + /** Whether or not this slider paints its labels. */ + private transient boolean paintLabels = false; + + /** + * A dictionary of (Integer, Component) pairs where each Component is a + * JLabel and the Integer determines where the label will be painted. + */ + private transient Dictionary labelTable; + + /** A list of all ChangeListeners listening to this slider. */ + private transient EventListenerList changeListenerList; + + /** The model used to describe the slider. */ + protected BoundedRangeModel sliderModel; + + /** The space between major ticks. */ + protected int majorTickSpacing; + + /** The space between minor ticks. */ + protected int minorTickSpacing; + + /** Whether the slider snaps its values to ticks. */ + protected boolean snapToTicks = true; + + /** The orientation of the slider. */ + protected int orientation = HORIZONTAL; + + /** Whether the slider is inverted. */ + private transient boolean isInverted; + + /** The ChangeListener that listens to the model. */ + protected ChangeListener changeListener; + + /** The ChangeEvent that is passed to all listeners of this slider. */ + protected transient ChangeEvent changeEvent; + + /** + * Creates a new horizontal JSlider object with a minimum of 0, a maximum of + * 100, and a value of 50. + */ + public JSlider() + { + this(HORIZONTAL, 0, 100, 50); + } + + /** + * Creates a new JSlider object with the given orientation and a minimum of + * 0, a maximum of 100, and a value of 50. + * + * @param orientation The orientation of the slider. + */ + public JSlider(int orientation) + { + this(orientation, 0, 100, 50); + } + + /** + * Creates a new horizontal JSlider object with the given maximum and + * minimum and a value that is halfway between the minimum and the + * maximum. + * + * @param minimum The minimum value of the JSlider. + * @param maximum The maximum value of the JSlider. + */ + public JSlider(int minimum, int maximum) + { + this(HORIZONTAL, minimum, maximum, (maximum - minimum) / 2); + } + + /** + * Creates a new horizontal JSlider object with the given minimum, maximum, + * and value. + * + * @param minimum The minimum value of the JSlider. + * @param maximum The maximum value of the JSlider. + * @param value The initial value of the JSlider. + */ + public JSlider(int minimum, int maximum, int value) + { + this(HORIZONTAL, minimum, maximum, value); + } + + /** + * Creates a new JSlider object with the given orientation, minimum, + * maximum, and value. + * + * @param orientation The orientation of the JSlider. + * @param minimum The minimum value of the JSlider. + * @param maximum The maximum value of the JSlider. + * @param value The initial value of the JSlider. + */ + public JSlider(int orientation, int minimum, int maximum, int value) + { + sliderModel = new DefaultBoundedRangeModel(value, 0, minimum, maximum); + if (orientation != HORIZONTAL && orientation != VERTICAL) + throw new IllegalArgumentException(orientation + " is not a legal orientation"); + this.orientation = orientation; + changeListener = createChangeListener(); + changeListenerList = new EventListenerList(); + sliderModel.addChangeListener(changeListener); + updateUI(); + } + + /** + * Creates a new horizontal JSlider object with the given model. + * + * @param model The model the slider will be created with. + */ + public JSlider(BoundedRangeModel model) + { + if (model == null) + sliderModel = new DefaultBoundedRangeModel(50, 0, 0, 100); + else + sliderModel = model; + changeListener = createChangeListener(); + changeListenerList = new EventListenerList(); + sliderModel.addChangeListener(changeListener); + updateUI(); + } + + /** + * This method returns the current value of the slider. + * + * @return The value of the slider stored in the model. + */ + public int getValue() + { + return sliderModel.getValue(); + } + + /** + * This method sets the value of the slider. + * + * @param value The slider's new value. + */ + public void setValue(int value) + { + sliderModel.setValue(value); + } + + /** + * This method returns the slider's UI delegate. + * + * @return The slider's UI delegate. + */ + public SliderUI getUI() + { + return (SliderUI) ui; + } + + /** + * This method sets the slider's UI delegate. + * + * @param ui A SliderUI object to use with this slider. + */ + public void setUI(SliderUI ui) + { + super.setUI(ui); + } + + /** + * This method sets this slider's UI to the UIManager's default for the + * current look and feel. + */ + public void updateUI() + { + setUI((SliderUI) UIManager.getUI(this)); + invalidate(); + repaint(); + } + + /** + * This method returns a name to identify which look and feel class will be + * the UI delegate for the slider. + * + * @return The L&F classID. "SliderUI" + */ + public String getUIClassID() + { + return "SliderUI"; + } + + /** + * Creates a ChangeListener for this Slider. + * + * @return A new ChangeListener. + */ + protected ChangeListener createChangeListener() + { + return new ChangeListener() + { + public void stateChanged(ChangeEvent ce) + { + // No need to trigger a repaint since the UI listens to the model + // as well. All we need to do is pass on the stateChanged event + // to our listeners. + fireStateChanged(); + } + }; + } + + /** + * This method registers a listener to this slider. The listener will be + * informed of new ChangeEvents. + * + * @param listener The listener to register. + */ + public void addChangeListener(ChangeListener listener) + { + changeListenerList.add(ChangeListener.class, listener); + } + + /** + * This method removes a listener from this slider. + * + * @param listener The listener to remove. + */ + public void removeChangeListener(ChangeListener listener) + { + changeListenerList.remove(ChangeListener.class, listener); + } + + /** + * This method is called whenever the model fires a ChangeEvent. It should + * propagate the ChangeEvent to its listeners with a new ChangeEvent that + * identifies the slider as the source. + */ + protected void fireStateChanged() + { + Object[] changeListeners = changeListenerList.getListenerList(); + if (changeEvent == null) + changeEvent = new ChangeEvent(this); + for (int i = changeListeners.length - 2; i >= 0; i -= 2) + { + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + } + } + + /** + * This method returns an array of all ChangeListeners listening to this + * slider. + * + * @return An array of ChangeListeners listening to this slider. + */ + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) changeListenerList.getListenerList(); + } + + /** + * This method returns the model of the slider. + * + * @return The slider's model. + */ + public BoundedRangeModel getModel() + { + return sliderModel; + } + + /** + * This method changes the "model" property. It also needs to unregister + * any listeners to the old model and register any listeners to the new + * model. + * + * @param model The model to use with the slider. + */ + public void setModel(BoundedRangeModel model) + { + // I didn't do the null pointer check on purpose. + // If you try it with Sun's, it'll go ahead and set it to null + // and bork the next time it tries to access the model. + if (model != sliderModel) + { + BoundedRangeModel oldModel = sliderModel; + sliderModel = model; + oldModel.removeChangeListener(changeListener); + sliderModel.addChangeListener(changeListener); + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, sliderModel); + } + } + + /** + * This method returns the minimum value of the slider. + * + * @return The minimum value of the slider. + */ + public int getMinimum() + { + return sliderModel.getMinimum(); + } + + /** + * This method sets the minimum value of the slider. + * + * @param minimum The minimum value of the slider. + */ + public void setMinimum(int minimum) + { + sliderModel.setMinimum(minimum); + } + + /** + * This method returns the maximum value of the slider. + * + * @return The maximum value of the slider. + */ + public int getMaximum() + { + return sliderModel.getMaximum(); + } + + /** + * This method sets the maximum value of the slider. + * + * @param maximum The maximum value of the slider. + */ + public void setMaximum(int maximum) + { + sliderModel.setMaximum(maximum); + } + + /** + * This method returns this slider's isAdjusting value which is true if the + * thumb is being dragged. + * + * @return The slider's isAdjusting value. + */ + public boolean getValueIsAdjusting() + { + return sliderModel.getValueIsAdjusting(); + } + + /** + * This method sets the isAdjusting value for the slider. + * + * @param adjusting The slider's isAdjusting value. + */ + public void setValueIsAdjusting(boolean adjusting) + { + sliderModel.setValueIsAdjusting(adjusting); + } + + /** + * This method returns the extent value for this slider. + * + * @return The extent value for this slider. + */ + public int getExtent() + { + return sliderModel.getExtent(); + } + + /** + * This method sets the extent value for this slider. + * + * @param extent The extent value for this slider. + */ + public void setExtent(int extent) + { + sliderModel.setExtent(extent); + } + + /** + * This method returns the slider orientation. + * + * @return The orientation of the slider. + */ + public int getOrientation() + { + return orientation; + } + + /** + * This method changes the "orientation" property of this slider. If the + * orientation is not VERTICAL or HORIZONTAL, this method does nothing. + * + * @param orientation The orientation of this slider. + */ + public void setOrientation(int orientation) + { + if (orientation != VERTICAL && orientation != HORIZONTAL) + throw new IllegalArgumentException("orientation must be one of: VERTICAL, HORIZONTAL"); + if (orientation != this.orientation) + { + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange(ORIENTATION_CHANGED_PROPERTY, oldOrientation, + this.orientation); + } + } + + /** + * This method returns the label table for this slider. + * + * @return The label table for this slider. + */ + public Dictionary getLabelTable() + { + return labelTable; + } + + /** + * This method changes the "labelTable" property of this slider. + * + * @param table The label table for this slider. + */ + public void setLabelTable(Dictionary table) + { + if (table != labelTable) + { + Dictionary oldTable = labelTable; + labelTable = table; + firePropertyChange(LABEL_TABLE_CHANGED_PROPERTY, oldTable, labelTable); + } + } + + /** + * This method is called to reset UI delegates for the labels in the + * labelTable to a default for the current look and feel. + */ + protected void updateLabelUIs() + { + if (labelTable == null) + return; + for (Enumeration list = labelTable.elements(); list.hasMoreElements();) + { + JLabel label = (JLabel) list.nextElement(); + label.updateUI(); + } + } + + /** + * Creates a hashtable of (Integer, JLabel) pairs that can be used as a + * label table for this slider. The labels will start from the sliders + * minimum and increase by the increment. Each label will have a text + * string indicating their integer value. + * + * @param increment The increment to between labels. + * + * @return A hashtable with the labels and their keys. + */ + public Hashtable createStandardLabels(int increment) + { + return createStandardLabels(increment, sliderModel.getMinimum()); + } + + /** + * Creates a hashtable of (Integer, JLabel) pairs that can be used as a + * label table for this slider. The labels will start from the given start + * value and increase by the increment. Each label will have a text string + * indicating their integer value. + * + * @param increment The increment to between labels. + * @param start The value to start from. + * + * @return A hashtable with the labels and their keys. + */ + public Hashtable createStandardLabels(int increment, int start) + { + Hashtable table = new Hashtable(); + JLabel label; + Dimension dim; + + int max = sliderModel.getMaximum(); + + for (int i = start; i <= max; i += increment) + { + label = new JLabel(String.valueOf(i)); + label.setVerticalAlignment(CENTER); + label.setHorizontalAlignment(CENTER); + + // Make sure these labels have the width and height + // they want. + dim = label.getPreferredSize(); + label.setBounds(label.getX(), label.getY(), + (int) dim.getWidth(), + (int) dim.getHeight()); + table.put(new Integer(i), label); + } + return table; + } + + /** + * This method returns whether the slider is inverted. Horizontal sliders + * that are not inverted will have the minimums on the left. If they are + * inverted, the minimums will be on the right. Vertical sliders that are + * not inverted will have the minimums at the bottom. If they are inverted, + * the minimums will be at the top. + * + * @return Whether this slider is inverted. + */ + public boolean getInverted() + { + return isInverted; + } + + /** + * This method changes the "inverted" property for this slider.Horizontal + * sliders that are not inverted will have the minimums on the left. If + * they are inverted, the minimums will be on the right. Vertical sliders + * that are not inverted will have the minimums at the bottom. If they are + * inverted, the minimums will be at the top. However, if the slider's + * componentOrientation is set to RIGHT_TO_LEFT, then everything gets + * reversed again. + * + * @param inverted Whether the slider should be inverted. + */ + public void setInverted(boolean inverted) + { + if (isInverted != inverted) + { + boolean oldInverted = isInverted; + isInverted = inverted; + firePropertyChange(INVERTED_CHANGED_PROPERTY, oldInverted, isInverted); + } + } + + /** + * This method returns the amount of units between each major tick mark. + * + * @return The amount of units between each major tick mark. + */ + public int getMajorTickSpacing() + { + return majorTickSpacing; + } + + /** + * This method changes the "majorTickSpacing" property for this slider. The + * major tick spacing is the amount of units between each major tick mark. + * + * @param spacing The amount of units between each major tick mark. + */ + public void setMajorTickSpacing(int spacing) + { + if (majorTickSpacing != spacing) + { + int oldSpacing = majorTickSpacing; + majorTickSpacing = spacing; + firePropertyChange(MAJOR_TICK_SPACING_CHANGED_PROPERTY, oldSpacing, + majorTickSpacing); + } + } + + /** + * This method returns the amount of units between each minor tick mark. + * + * @return The amount of units between each minor tick mark. + */ + public int getMinorTickSpacing() + { + return minorTickSpacing; + } + + /** + * This method changes the "minorTickSpacing" property for this slider. The + * minor tick spacing is the amount of units between each minor tick mark. + * + * @param spacing The amount of units between each minor tick mark. + */ + public void setMinorTickSpacing(int spacing) + { + if (minorTickSpacing != spacing) + { + int oldSpacing = minorTickSpacing; + minorTickSpacing = spacing; + firePropertyChange(MINOR_TICK_SPACING_CHANGED_PROPERTY, oldSpacing, + minorTickSpacing); + } + } + + /** + * This method returns whether this slider is snapping to ticks. Sliders + * that snap to ticks will automatically move the thumb to the nearest tick + * mark. + * + * @return Whether this slider snaps to ticks. + */ + public boolean getSnapToTicks() + { + return snapToTicks; + } + + /** + * This method sets whether this slider will snap to ticks. Sliders that + * snap to ticks will automatically move the thumb to the nearest tick + * mark. + * + * @param snap Whether this slider snaps to ticks. + */ + public void setSnapToTicks(boolean snap) + { + if (snap != snapToTicks) + { + snapToTicks = snap; + fireStateChanged(); + } + } + + /** + * This method returns whether the slider will paint its tick marks. In + * addition to setting this property to true, one of minor tick spacing or + * major tick spacing must be set to a value greater than 0 in order for + * ticks to be painted. + * + * @return Whether ticks will be painted. + */ + public boolean getPaintTicks() + { + return paintTicks; + } + + /** + * This method changes the "paintTicks" property for this slider. In + * addition to setting this property to true, one of minor tick spacing or + * major tick spacing must be set to a value greater than 0 in order for + * ticks to be painted. + * + * @param paint Whether ticks will be painted. + */ + public void setPaintTicks(boolean paint) + { + if (paint != paintTicks) + { + boolean oldPaintTicks = paintTicks; + paintTicks = paint; + firePropertyChange(PAINT_TICKS_CHANGED_PROPERTY, oldPaintTicks, + paintTicks); + } + } + + /** + * This method returns whether the track will be painted. + * + * @return Whether the track will be painted. + */ + public boolean getPaintTrack() + { + return paintTrack; + } + + /** + * This method sets whether the track will be painted. + * + * @param paint Whether the track will be painted. + */ + public void setPaintTrack(boolean paint) + { + paintTrack = paint; + } + + /** + * This method returns whether labels will be painted. + * + * @return Whether labels will be painted. + */ + public boolean getPaintLabels() + { + return paintLabels; + } + + /** + * This method changes the "paintLabels" property. + * + * @param paint Whether labels will be painted. + */ + public void setPaintLabels(boolean paint) + { + if (paint != paintLabels) + { + boolean oldPaintLabels = paintLabels; + paintLabels = paint; + firePropertyChange(PAINT_LABELS_CHANGED_PROPERTY, oldPaintLabels, + paintLabels); + } + } + + /** + * This method is used primarily for debugging purposes and returns a string + * that can be used to represent this slider. + * + * @return A string representing this slider. + */ + protected String paramString() + { + return "JSlider"; + } + + /** + * DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public AccessibleContext getAccessibleContext() + { + if (accessibleContext == null) + accessibleContext = new AccessibleJSlider(this); + return accessibleContext; + } +} diff --git a/libjava/javax/swing/JViewport.java b/libjava/javax/swing/JViewport.java index 18365bcf9ec..9174a833b70 100644 --- a/libjava/javax/swing/JViewport.java +++ b/libjava/javax/swing/JViewport.java @@ -40,103 +40,240 @@ package javax.swing; import java.awt.Component; import java.awt.Container; +import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; +import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; +import java.awt.image.ImageObserver; import javax.accessibility.Accessible; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.plaf.ViewportUI; + +/** + * + *
+ *                                                     _
+ *   +-------------------------------+    ...........Y1 \
+ *   |  view                         |                .  \
+ *   |  (this component's child)     |                .   > VY
+ *   |                               |                .  / = Y2-Y1
+ *   |         +------------------------------+  ....Y2_/
+ *   |         | viewport            |        |       .
+ *   |         | (this component)    |        |       .
+ *   |         |                     |        |       .
+ *   |         |                     |        |       .
+ *   |         |                     |        |       .
+ *   |         |                     |        |       .
+ *   |         +------------------------------+  ....Y3
+ *   |                               |                .
+ *   |         .                     |        .       .
+ *   |         .                     |        .       .
+ *   +---------.---------------------+    ...........Y4
+ *   .         .                     .        .
+ *   .         .                     .        .
+ *   .         .                     .        .
+ *   X1.......X2.....................X3.......X4
+ *   \____  ___/
+ *        \/
+ *        VX = X2-X1
+ *
+ * + *

A viewport is, like all swing components, located at some position in + * the swing component tree; that location is exactly the same as any other + * components: the viewport's "bounds".

+ * + *

But in terms of drawing its child, the viewport thinks of itself as + * covering a particular position of the view's coordinate space. + * For example, the {@link javax.JViewPort.getViewPosition} method returns + * the position (VX,VY) shown above, which is an position in + * "view space", even though this is implemented by positioning + * the underlying child at position (-VX,-VY)

+ * + */ + public class JViewport extends JComponent { - Component c; - - JViewport() - { - setOpaque(true); - updateUI(); - } - - void setView(Component c) - { - if (this.c != null) - remove(c); - - this.c = c; - - add(c); - } - - public String getUIClassID() - { - return "ViewportUI"; - } - - public void updateUI() - { - ViewportUI vp = (ViewportUI) UIManager.getUI(this); - setUI(vp); - } - - Container GetHeavy(Container parent) - { - if (parent == null) - return null; - - while (isLightweightComponent(parent)) - { - Container p = parent.getParent(); - - if (p == null) - { - System.out.println("GetHeavy FAILED, no heavy weight component found"); - return parent; - } - - parent = p; - } - return parent; - } + public static int BACKINGSTORE_SCROLL_MODE = 1; + public static int BLIT_SCROLL_MODE = 2; + public static int SIMPLE_SCROLL_MODE = 3; + + ChangeEvent changeEvent = new ChangeEvent(this); + + int scrollMode; + + boolean scrollUnderway; + boolean isViewSizeSet; + + /** + * The width and height of the Viewport's area in terms of view + * coordinates. Typically this will be the same as the width and height + * of the viewport's bounds, unless the viewport transforms units of + * width and height, which it may do, for example if it magnifies or + * rotates its view. + * + * @see #toViewCoordinates + */ + Dimension viewExtent; + + Point lastPaintPosition; + + JViewport() + { + setOpaque(true); + updateUI(); + } + + public Dimension getViewSize() + { + if (viewExtent == null) + return getPreferredSize(); + else + return viewExtent; + } + + public void setViewSize(Dimension newSize) + { + viewExtent = newSize; + fireStateChanged(); + } + + public Point getViewPosition() + { + Component view = getView(); + if (view == null) + return new Point(0,0); + else + { + Point p = view.getLocation(); + p.x = -p.x; + p.y = -p.y; + return p; + } + } + + public void setViewPosition(Point p) + { + Component view = getView(); + if (view != null) + { + Point q = new Point(-p.x, -p.y); + view.setLocation(q); + fireStateChanged(); + } + } + + public Rectangle getViewRect() + { + return new Rectangle(getViewPosition(), + getViewSize()); + } + + public boolean isBackingStoreEnabled() + { + return scrollMode == BACKINGSTORE_SCROLL_MODE; + } + + public void setBackingStoreEnabled(boolean b) + { + if (b && scrollMode != BACKINGSTORE_SCROLL_MODE) + { + scrollMode = BACKINGSTORE_SCROLL_MODE; + fireStateChanged(); + } + } + + public void setScrollMode(int mode) + { + scrollMode = mode; + fireStateChanged(); + } + + public int getScrollMode() + { + return scrollMode; + } + + public Component getView() + { + if (ncomponents > 0) + return component[0]; + else + return null; + } + + public void setView(Component v) + { + add(v); + fireStateChanged(); + } - public void paint(Graphics g) - { - paintChildren(g); - - System.out.println("XXXXXXXXXXXXXXXXXXXXXXXXXXXX JViewport -----> paint()"); - - Container parent = GetHeavy(getParent()); - - System.out.println("parent = " + parent + ", " + getParent()); - - //parent.paint(); - - Graphics wg = parent.getGraphics(); - - int x = 0; - int y = 0; - int w = getWidth(); - int h = getHeight(); - - Rectangle r = new Rectangle(x, y, w, h); - - int ox = 0; - int oy = 0; - - wg.copyArea(r.x, - r.y, - r.width, - r.height, - ox, - oy); - - wg.dispose(); - } + public void addImpl(Component comp, Object constraints, int index) + { + if (ncomponents > 0) + remove(component[0]); + super.addImpl(comp, constraints, index); + } + + public final Insets getInsets() + { + return new Insets(0,0,0,0); + } + + public final Insets getInsets(Insets insets) + { + if (insets == null) + return getInsets(); + insets.top = 0; + insets.bottom = 0; + insets.left = 0; + insets.right = 0; + return insets; + } + + public boolean isOptimizedDrawingEnabled() + { + return false; + } + + public ChangeListener[] getChangeListeners() + { + return (ChangeListener[]) getListeners(ChangeListener.class); + } + + public void paint(Graphics g) + { + paintComponent(g); + } + + void fireStateChanged() + { + ChangeListener[] listeners = getChangeListeners(); + for (int i = 0; i < listeners.length; ++i) + listeners[i].stateChanged(changeEvent); + } + + public void addChangeListener(ChangeListener listener) + { + listenerList.add(ChangeListener.class, listener); + } + + public void removeChangeListener(ChangeListener listener) + { + listenerList.remove(ChangeListener.class, listener); + } + + public String getUIClassID() + { + return "ViewportUI"; + } + + public void updateUI() + { + setUI((ViewportUI) UIManager.getUI(this)); + } } - - - - - - - diff --git a/libjava/javax/swing/ListModel.java b/libjava/javax/swing/ListModel.java index ef92d744198..e11fc633c0e 100644 --- a/libjava/javax/swing/ListModel.java +++ b/libjava/javax/swing/ListModel.java @@ -1,4 +1,4 @@ -/* ListModel.java -- +/* ListModel.java -- Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -36,13 +36,45 @@ obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ package javax.swing; - import javax.swing.event.ListDataListener; +/** + * This is an interface to general list-like data, typically used as the + * model object of a {@link JList} component. + * + * @author Graydon Hoare (graydon&064;redhat.com) + */ public interface ListModel -{ +{ + /** + * Return the number of data elements in the list. + * + * @return The number of data elements in the list + */ int getSize(); + + /** + * Retrieves a data element at a specified index. + * + * @param index The index of the element to retrieve + * + * @return The data element at the specified index + */ Object getElementAt(int index); + + /** + * Add a listener object to this model. The listener will be called + * any time the set of elements in the model is changed. + * + * @param l The listener to add + */ void addListDataListener(ListDataListener l); + + /** + * Add a listener object to this model. The listener will no longer be + * called when the set of elements in the model is changed. + * + * @param l The listener to remove + */ void removeListDataListener(ListDataListener l); } diff --git a/libjava/javax/swing/ListSelectionModel.java b/libjava/javax/swing/ListSelectionModel.java index 4314667880f..c2e9648acd7 100644 --- a/libjava/javax/swing/ListSelectionModel.java +++ b/libjava/javax/swing/ListSelectionModel.java @@ -42,24 +42,41 @@ import javax.swing.event.ListSelectionListener; public interface ListSelectionModel { - int SINGLE_SELECTION = 0; - int SINGLE_INTERVAL_SELECTION = 1; - int MULTIPLE_INTERVAL_SELECTION = 1; - - void setSelectionMode(int a); - int getSelectionMode(); - - void clearSelection(); - - int getMinSelectionIndex(); - int getMaxSelectionIndex(); - boolean isSelectedIndex(int a); - - void setSelectionInterval(int index0, int index1); - + int SINGLE_SELECTION = 0; + int SINGLE_INTERVAL_SELECTION = 1; + int MULTIPLE_INTERVAL_SELECTION = 2; + + void setSelectionMode(int a); + int getSelectionMode(); + + void clearSelection(); - - void addListSelectionListener(ListSelectionListener listener); - void removeListSelectionListener(ListSelectionListener listener); + int getMinSelectionIndex(); + int getMaxSelectionIndex(); + + boolean isSelectedIndex(int a); + + boolean isSelectionEmpty(); + void setSelectionInterval(int index0, int index1); + void addSelectionInterval(int index0, + int index1); + void removeSelectionInterval(int index0, + int index1); + void insertIndexInterval(int index, + int length, + boolean before); + void removeIndexInterval(int index0, + int index1); + + int getAnchorSelectionIndex(); + void setAnchorSelectionIndex(int index); + int getLeadSelectionIndex(); + void setLeadSelectionIndex(int index); + + void setValueIsAdjusting(boolean valueIsAdjusting); + boolean getValueIsAdjusting(); + + void addListSelectionListener(ListSelectionListener listener); + void removeListSelectionListener(ListSelectionListener listener); } diff --git a/libjava/javax/swing/ScrollPaneLayout.java b/libjava/javax/swing/ScrollPaneLayout.java index d6cc479de0b..c8573589f29 100644 --- a/libjava/javax/swing/ScrollPaneLayout.java +++ b/libjava/javax/swing/ScrollPaneLayout.java @@ -41,9 +41,11 @@ package javax.swing; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Rectangle; import java.io.Serializable; +import javax.swing.border.Border; /** * ScrollPaneLayout @@ -55,258 +57,368 @@ public class ScrollPaneLayout { static final long serialVersionUID = -4480022884523193743L; - //------------------------------------------------------------- - // Classes ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * UIResource - */ - public static class UIResource extends ScrollPaneLayout - implements javax.swing.plaf.UIResource { - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor UIResource - */ - public UIResource() { - // TODO - } // UIResource() - - - } // UIResource - - - //------------------------------------------------------------- - // Variables -------------------------------------------------- - //------------------------------------------------------------- - - /** - * viewport - */ - protected JViewport viewport; - - /** - * vsb - */ - protected JScrollBar vsb; - - /** - * hsb - */ - protected JScrollBar hsb; - - /** - * rowHead - */ - protected JViewport rowHead; - - /** - * colHead - */ - protected JViewport colHead; - - /** - * lowerLeft - */ - protected Component lowerLeft; - - /** - * lowerRight - */ - protected Component lowerRight; - - /** - * upperLeft - */ - protected Component upperLeft; - - /** - * upperRight - */ - protected Component upperRight; - - /** - * vsbPolicy - */ - protected int vsbPolicy; - - /** - * hsbPolicy - */ - protected int hsbPolicy; - - - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor ScrollPaneLayout - */ - public ScrollPaneLayout() { - // TODO - } // ScrollPaneLayout() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * syncWithScrollPane - * @param scrollPane TODO - */ - public void syncWithScrollPane(JScrollPane scrollPane) { - // TODO - } // syncWithScrollPane() - - /** - * addSingletonComponent - * @param oldComponent TODO - * @param newComponent TODO - * @returns Component - */ - protected Component addSingletonComponent(Component oldComponent, - Component newComponent) { - return null; // TODO - } // addSingletonComponent() - - /** - * addLayoutComponent - * @param string TODO - * @param component TODO - */ - public void addLayoutComponent(String string, Component component) { - // TODO - } // addLayoutComponent() - - /** - * removeLayoutComponent - * @param component TODO - */ - public void removeLayoutComponent(Component component) { - // TODO - } // removeLayoutComponent() - - /** - * getVerticalScrollBarPolicy - * @returns int - */ - public int getVerticalScrollBarPolicy() { - return 0; // TODO - } // getVerticalScrollBarPolicy() - - /** - * setVerticalScrollBarPolicy - * @param policy TODO - */ - public void setVerticalScrollBarPolicy(int policy) { - // TODO - } // setVerticalScrollBarPolicy() - - /** - * getHorizontalScrollBarPolicy - * @returns int - */ - public int getHorizontalScrollBarPolicy() { - return 0; // TODO - } // getHorizontalScrollBarPolicy() - - /** - * setHorizontalScrollBarPolicy - * @param policy TODO - */ - public void setHorizontalScrollBarPolicy(int policy) { - // TODO - } // setHorizontalScrollBarPolicy() - - /** - * getViewport - * @returns JViewport - */ - public JViewport getViewport() { - return null; // TODO - } // getViewport() - - /** - * getHorizontalScrollBar - * @returns JScrollBar - */ - public JScrollBar getHorizontalScrollBar() { - return null; // TODO - } // getHorizontalScrollBar() - - /** - * getVerticalScrollBar - * @returns JScrollBar - */ - public JScrollBar getVerticalScrollBar() { - return null; // TODO - } // getVerticalScrollBar() - - /** - * getRowHeader - * @returns JViewport - */ - public JViewport getRowHeader() { - return null; // TODO - } // getRowHeader() - - /** - * getColumnHeader - * @returns JViewport - */ - public JViewport getColumnHeader() { - return null; // TODO - } // getColumnHeader() - - /** - * getCorner - * @param key TODO - * @returns Component - */ - public Component getCorner(String key) { - return null; // TODO - } // getCorner() - - /** - * preferredLayoutSize - * @param parent TODO - * @returns Dimension - */ - public Dimension preferredLayoutSize(Container parent) { - return null; // TODO - } // preferredLayoutSize() - - /** - * minimumLayoutSize - * @param parent TODO - * @returns Dimension - */ - public Dimension minimumLayoutSize(Container parent) { - return null; // TODO - } // minimumLayoutSize() - - /** - * layoutContainer - * @param parent TODO - */ - public void layoutContainer(Container parent) { - // TODO - } // layoutContainer() - - /** - * getViewportBorderBounds - * @param value0 TODO - * @returns Rectangle - */ - public Rectangle getViewportBorderBounds(JScrollPane scrollPane) { - return null; // TODO - } // getViewportBorderBounds() - - -} // ScrollPaneLayout + public static class UIResource extends ScrollPaneLayout + implements javax.swing.plaf.UIResource { + public UIResource() { + } + } + + JViewport viewport; + JScrollBar verticalScrollBar; + JScrollBar horizontalScrollBar; + JViewport rowHeader; + JViewport columnHeader; + Component lowerLeft; + Component lowerRight; + Component upperLeft; + Component upperRight; + int verticalScrollBarPolicy; + int horizontalScrollBarPolicy; + + public ScrollPaneLayout() { + + } + + public void syncWithScrollPane(JScrollPane scrollPane) { + viewport = scrollPane.getViewport(); + verticalScrollBar = scrollPane.getVerticalScrollBar(); + horizontalScrollBar = scrollPane.getHorizontalScrollBar(); + verticalScrollBarPolicy = scrollPane.getVerticalScrollBarPolicy(); + horizontalScrollBarPolicy = scrollPane.getHorizontalScrollBarPolicy(); + lowerLeft = scrollPane.getCorner(LOWER_LEFT_CORNER); + lowerRight = scrollPane.getCorner(LOWER_RIGHT_CORNER); + upperLeft = scrollPane.getCorner(UPPER_LEFT_CORNER); + upperRight = scrollPane.getCorner(UPPER_RIGHT_CORNER); + } + + protected Component addSingletonComponent(Component oldComponent, + Component newComponent) { + return null; + } + + public void addLayoutComponent(String key, Component component) + { + if (key == VIEWPORT) + viewport = (JViewport) component; + else if (key == VERTICAL_SCROLLBAR) + verticalScrollBar = (JScrollBar) component; + else if (key == HORIZONTAL_SCROLLBAR) + horizontalScrollBar = (JScrollBar) component; + else if (key == ROW_HEADER) + rowHeader = (JViewport) component; + else if (key == COLUMN_HEADER) + columnHeader = (JViewport) component; + else if (key == LOWER_RIGHT_CORNER) + lowerRight = component; + else if (key == UPPER_RIGHT_CORNER) + upperRight = component; + else if (key == LOWER_LEFT_CORNER) + lowerLeft = component; + else if (key == UPPER_LEFT_CORNER) + upperLeft = component; + } + + public void removeLayoutComponent(Component component) { + if (component == viewport) + viewport = null; + else if (component == verticalScrollBar) + verticalScrollBar = null; + else if (component == horizontalScrollBar) + horizontalScrollBar = null; + else if (component == rowHeader) + rowHeader = null; + else if (component == columnHeader) + columnHeader = null; + else if (component == lowerRight) + lowerRight = null; + else if (component == upperRight) + upperRight = null; + else if (component == lowerLeft) + lowerLeft = null; + else if (component == upperLeft) + upperLeft = null; + } + + public int getVerticalScrollBarPolicy() { + return verticalScrollBarPolicy; + } + + public void setVerticalScrollBarPolicy(int policy) { + verticalScrollBarPolicy = policy; + } + + public int getHorizontalScrollBarPolicy() { + return horizontalScrollBarPolicy; + } + + public void setHorizontalScrollBarPolicy(int policy) { + horizontalScrollBarPolicy = policy; + } + + public JViewport getViewport() { + return viewport; + } + + public JScrollBar getHorizontalScrollBar() { + return horizontalScrollBar; + } + + public JScrollBar getVerticalScrollBar() { + return verticalScrollBar; + } + + public JViewport getRowHeader() { + return rowHeader; + } + + public JViewport getColumnHeader() { + return columnHeader; + } + + public Component getCorner(String key) { + if (key == LOWER_RIGHT_CORNER) + return lowerRight; + else if (key == UPPER_RIGHT_CORNER) + return upperRight; + else if (key == LOWER_LEFT_CORNER) + return lowerLeft; + else if (key == UPPER_LEFT_CORNER) + return upperLeft; + return null; + } + + public Dimension preferredLayoutSize(Container parent) + { + if (parent instanceof JScrollPane) + { + JScrollPane sc = (JScrollPane) parent; + synchronized (sc.getTreeLock ()) + { + Dimension insetsSize = new Dimension(0,0); + Dimension viewportSize = new Dimension(0,0); + Dimension viewportInsetsSize = new Dimension(0,0); + Dimension columnHeaderSize = new Dimension(0,0); + Dimension rowHeaderSize = new Dimension(0,0); + Dimension verticalScrollBarSize = new Dimension(0,0); + Dimension horizontalScrollBarSize = new Dimension(0,0); + + Insets insets = sc.getInsets(); + Border viewportBorder = sc.getViewportBorder(); + Insets viewportInsets = null; + + if (viewportBorder != null) + viewportInsets = viewportBorder.getBorderInsets(parent); + + if (insets != null) + insetsSize.setSize(insets.left + insets.right, + insets.top + insets.bottom); + + if (viewport != null) + viewportSize.setSize(viewport.getPreferredSize()); + + if (columnHeader != null) + columnHeaderSize.setSize(columnHeader.getPreferredSize()); + + if (rowHeader != null) + rowHeaderSize.setSize(rowHeader.getPreferredSize()); + + if (verticalScrollBar != null) + verticalScrollBarSize.setSize(verticalScrollBar.getPreferredSize()); + + if (horizontalScrollBar != null) + horizontalScrollBarSize.setSize(horizontalScrollBar.getPreferredSize()); + + return new Dimension(insetsSize.width + + viewportSize.width + + viewportInsetsSize.width + + rowHeaderSize.width + + verticalScrollBarSize.width, + insetsSize.height + + viewportSize.height + + viewportInsetsSize.height + + columnHeaderSize.height + + horizontalScrollBarSize.height); + } + } + else + { + return new Dimension(0,0); + } + } + + public Dimension minimumLayoutSize(Container parent) + { + if (parent instanceof JScrollPane) + { + JScrollPane sc = (JScrollPane) parent; + synchronized (sc.getTreeLock ()) + { + Dimension insetsSize = new Dimension(0,0); + Dimension viewportSize = new Dimension(0,0); + Dimension viewportInsetsSize = new Dimension(0,0); + Dimension columnHeaderSize = new Dimension(0,0); + Dimension rowHeaderSize = new Dimension(0,0); + Dimension verticalScrollBarSize = new Dimension(0,0); + Dimension horizontalScrollBarSize = new Dimension(0,0); + + Insets insets = sc.getInsets(); + Border viewportBorder = sc.getViewportBorder(); + Insets viewportInsets = null; + + if (viewportBorder != null) + viewportInsets = viewportBorder.getBorderInsets(parent); + + if (insets != null) + insetsSize.setSize(insets.left + insets.right, + insets.top + insets.bottom); + + if (viewport != null) + viewportSize.setSize(viewport.getMinimumSize()); + + if (columnHeader != null) + columnHeaderSize.setSize(columnHeader.getMinimumSize()); + + if (rowHeader != null) + rowHeaderSize.setSize(rowHeader.getMinimumSize()); + + if (verticalScrollBar != null + && verticalScrollBarPolicy != VERTICAL_SCROLLBAR_NEVER) + verticalScrollBarSize.setSize(verticalScrollBar.getMinimumSize()); + + if (horizontalScrollBar != null + && horizontalScrollBarPolicy != HORIZONTAL_SCROLLBAR_NEVER) + horizontalScrollBarSize.setSize(horizontalScrollBar.getMinimumSize()); + + return new Dimension(insetsSize.width + + viewportSize.width + + viewportInsetsSize.width + + rowHeaderSize.width + + verticalScrollBarSize.width, + insetsSize.height + + viewportSize.height + + viewportInsetsSize.height + + columnHeaderSize.height + + horizontalScrollBarSize.height); + } + } + else + { + return new Dimension(0,0); + } + } + + /** + * + * +----+--------------------+----+ y1 + * | c1 | column header | c2 | + * +----+--------------------+----+ y2 + * | r | | v | + * | o | | | + * | w | | s | + * | | | r | + * | h | | o | + * | e | viewport | l | + * | a | | l | + * | d | | b | + * | e | | a | + * | r | | r | + * +----+--------------------+----+ y3 + * | c3 | h scrollbar | c4 | + * +----+--------------------+----+ y4 + * x1 x2 x3 x4 + * + */ + + public void layoutContainer(Container parent) { + if (parent instanceof JScrollPane) + { + JScrollPane sc = (JScrollPane) parent; + synchronized (sc.getTreeLock ()) + { + Rectangle scrollPaneBounds = sc.getBounds(); + Dimension viewportSize = new Dimension(0,0); + Dimension viewSize = new Dimension(0,0); + JViewport viewport = sc.getViewport(); + + int x1 = 0, x2 = 0, x3 = 0, x4 = 0; + int y1 = 0, y2 = 0, y3 = 0, y4 = 0; + + x1 = scrollPaneBounds.x; + y1 = scrollPaneBounds.y; + x4 = scrollPaneBounds.x + scrollPaneBounds.width; + y4 = scrollPaneBounds.y + scrollPaneBounds.height; + + if (columnHeader != null) + y2 = columnHeader.getPreferredSize().height; + else + y2 = y1; + + if (rowHeader != null) + x2 = rowHeader.getPreferredSize().width; + else + x2 = x1; + + int vsbPolicy = sc.getVerticalScrollBarPolicy(); + int hsbPolicy = sc.getHorizontalScrollBarPolicy(); + + boolean showVsb = + (verticalScrollBar != null) + && ((vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) + || (vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED + && viewSize.height > viewportSize.height)); + + boolean showHsb = + (horizontalScrollBar != null) + && ((hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) + || (hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED + && viewSize.width > viewportSize.width)); + + if (showVsb) + x3 = x4 - verticalScrollBar.getPreferredSize().width; + else + x3 = x4; + + if (showHsb) + y3 = y4 - horizontalScrollBar.getPreferredSize().height; + else + y3 = y4; + + // now set the layout + + if (viewport != null) + viewport.setBounds(new Rectangle(x2, y2, x3-x2, y3-y2)); + + if (columnHeader != null) + columnHeader.setBounds(new Rectangle(x2, y1, x3-x2, y2-y1)); + + if (rowHeader != null) + rowHeader.setBounds(new Rectangle(x1, y2, x2-x1, y3-y2)); + + if (showVsb) + verticalScrollBar.setBounds(new Rectangle(x3, y2, x4-x3, y3-y2)); + + if (showHsb) + horizontalScrollBar.setBounds(new Rectangle(x2, y3, x3-x2, y4-y3)); + + if (upperLeft != null) + upperLeft.setBounds(new Rectangle(x1, y1, x2-x1, y2-y1)); + + if (upperRight != null) + upperRight.setBounds(new Rectangle(x3, y1, x4-x3, y2-y1)); + + if (lowerLeft != null) + lowerLeft.setBounds(new Rectangle(x1, y3, x2-x1, y4-y3)); + + if (lowerRight != null) + lowerRight.setBounds(new Rectangle(x3, y3, x4-x3, y4-y3)); + + } + } + } + + public Rectangle getViewportBorderBounds(JScrollPane scrollPane) { + return null; + } + + +} diff --git a/libjava/javax/swing/SwingUtilities.java b/libjava/javax/swing/SwingUtilities.java index 590c3032fb7..36fe017c1ca 100644 --- a/libjava/javax/swing/SwingUtilities.java +++ b/libjava/javax/swing/SwingUtilities.java @@ -48,6 +48,7 @@ import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; +import java.awt.Shape; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.KeyEvent; @@ -667,10 +668,19 @@ public class SwingUtilities implements SwingConstants else { iconR.width = icon.getIconWidth(); - iconR.height = icon.getIconWidth(); + iconR.height = icon.getIconHeight(); + } + if (text == null) + { + textIconGap = 0; + textR.width = 0; + textR.height = 0; + } + else + { + textR.width = fm.stringWidth(text); + textR.height = fm.getHeight(); } - textR.width = fm.stringWidth(text); - textR.height = fm.getHeight(); // Work out the position of text and icon, assuming the top-left coord // starts at (0,0). We will fix that up momentarily, after these @@ -776,5 +786,53 @@ public class SwingUtilities implements SwingConstants { return java.awt.EventQueue.isDispatchThread(); } + + /** + * This method paints the given component at the given position and size. + * The component will be reparented to the container given. + * + * @param g The Graphics object to draw with. + * @param c The Component to draw + * @param p The Container to reparent to. + * @param x The x coordinate to draw at. + * @param y The y coordinate to draw at. + * @param w The width of the drawing area. + * @param h The height of the drawing area. + */ + public static void paintComponent(Graphics g, Component c, Container p, + int x, int y, int w, int h) + { + Container parent = c.getParent(); + if (parent != null) + parent.remove(c); + if (p != null) + p.add(c); + + Shape savedClip = g.getClip(); + + g.setClip(x, y, w, h); + g.translate(x, y); + + c.paint(g); + + g.translate(-x, -y); + g.setClip(savedClip); + } + + /** + * This method paints the given component in the given rectangle. + * The component will be reparented to the container given. + * + * @param g The Graphics object to draw with. + * @param c The Component to draw + * @param p The Container to reparent to. + * @param r The rectangle that describes the drawing area. + */ + public static void paintComponent(Graphics g, Component c, + Container p, Rectangle r) + { + paintComponent(g, c, p, r.x, r.y, r.width, r.height); + } + } diff --git a/libjava/javax/swing/ViewportLayout.java b/libjava/javax/swing/ViewportLayout.java index c984321495b..4c774d59f40 100644 --- a/libjava/javax/swing/ViewportLayout.java +++ b/libjava/javax/swing/ViewportLayout.java @@ -52,64 +52,26 @@ public class ViewportLayout implements LayoutManager, Serializable { static final long serialVersionUID = -788225906076097229L; - //------------------------------------------------------------- - // Initialization --------------------------------------------- - //------------------------------------------------------------- - - /** - * Constructor ViewportLayout - */ public ViewportLayout() { - // TODO - } // ViewportLayout() - - - //------------------------------------------------------------- - // Methods ---------------------------------------------------- - //------------------------------------------------------------- - - /** - * addLayoutComponent - * @param name TODO - * @param c TODO - */ + } public void addLayoutComponent(String name, Component c) { - // TODO - } // addLayoutComponent() - - /** - * removeLayoutComponent - * @param c TODO - */ + // ignore + } public void removeLayoutComponent(Component c) { - // TODO - } // removeLayoutComponent() - - /** - * preferredLayoutSize - * @param parent TODO - * @returns Dimension - */ + // ignore + } public Dimension preferredLayoutSize(Container parent) { - return null; // TODO - } // preferredLayoutSize() - - /** - * minimumLayoutSize - * @param parent TODO - * @returns Dimension - */ + return null; + } public Dimension minimumLayoutSize(Container parent) { - return null; // TODO - } // minimumLayoutSize() - - /** - * layoutContainer - * @param parent TODO - */ + return null; + } public void layoutContainer(Container parent) { - // TODO - } // layoutContainer() - - -} // ViewportLayout + if (parent.countComponents() == 1) + { + // This should usually be true, but if it's not it is + // probably nicer if we do not panic. + Component c = parent.getComponent(0); + } + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicButtonListener.java b/libjava/javax/swing/plaf/basic/BasicButtonListener.java index 393ba3727bb..98b4c8b3c53 100644 --- a/libjava/javax/swing/plaf/basic/BasicButtonListener.java +++ b/libjava/javax/swing/plaf/basic/BasicButtonListener.java @@ -87,15 +87,12 @@ public class BasicButtonListener } public void mouseMoved(MouseEvent e) { - System.err.println("button got mouse move"); } public void mouseDragged(MouseEvent e) { - System.err.println("button got mouse drag"); } public void mouseClicked(MouseEvent e) { - System.err.println("button got mouse click"); } /** diff --git a/libjava/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/javax/swing/plaf/basic/BasicButtonUI.java index 7d59fc2467d..5dbd17ecfa8 100644 --- a/libjava/javax/swing/plaf/basic/BasicButtonUI.java +++ b/libjava/javax/swing/plaf/basic/BasicButtonUI.java @@ -250,7 +250,8 @@ public class BasicButtonUI extends ButtonUI paintButtonNormal(g, br, c); paintIcon(g, c, ir); - paintText(g, c, tr, b.getText()); + if (text != null) + paintText(g, c, tr, b.getText()); paintFocus(g, c, vr, tr, ir); } diff --git a/libjava/javax/swing/plaf/basic/BasicGraphicsUtils.java b/libjava/javax/swing/plaf/basic/BasicGraphicsUtils.java index 65cc7b9f038..1f2f7444db1 100644 --- a/libjava/javax/swing/plaf/basic/BasicGraphicsUtils.java +++ b/libjava/javax/swing/plaf/basic/BasicGraphicsUtils.java @@ -597,10 +597,7 @@ public class BasicGraphicsUtils Insets insets = b.getInsets(); Insets margin = b.getMargin(); - /* For determining the ideal size, do not assume a size restriction. */ - viewRect = new Rectangle(0, 0, - /* width */ Integer.MAX_VALUE, - /* height */ Integer.MAX_VALUE); + viewRect = new Rectangle(); /* java.awt.Toolkit.getFontMetrics is deprecated. However, it * seems not obvious how to get to the correct FontMetrics object @@ -614,14 +611,13 @@ public class BasicGraphicsUtils b.getToolkit().getFontMetrics(b.getFont()), // see comment above b.getText(), b.getIcon(), - SwingUtilities.TOP, // important: - SwingUtilities.LEFT, // large vrect, stick to the top left + b.getVerticalAlignment(), + b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, textIconGap); - /* +------------------------+ +------------------------+ * | | | | * | ICON | | CONTENTCONTENTCONTENT | @@ -629,6 +625,7 @@ public class BasicGraphicsUtils * | TEXTTEXTTEXT | | CONTENTCONTENTCONTENT | * +------------------------+ +------------------------+ */ + contentRect = textRect.union(iconRect); return new Dimension(insets.left + margin.left diff --git a/libjava/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/javax/swing/plaf/basic/BasicLabelUI.java index 51c694a7331..219c6fab02e 100644 --- a/libjava/javax/swing/plaf/basic/BasicLabelUI.java +++ b/libjava/javax/swing/plaf/basic/BasicLabelUI.java @@ -1,5 +1,5 @@ /* BasicLabelUI.java - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -35,7 +35,6 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing.plaf.basic; import java.awt.Color; @@ -47,156 +46,384 @@ import java.awt.Insets; import java.awt.Rectangle; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.SwingConstants; import javax.swing.SwingUtilities; +import javax.swing.UIDefaults; +import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.LabelUI; -public class BasicLabelUI extends LabelUI - implements PropertyChangeListener + +/** + * This is the Basic Look and Feel class for the JLabel. One BasicLabelUI + * object is used to paint all JLabels that utilize the Basic L&F. + */ +public class BasicLabelUI extends LabelUI implements PropertyChangeListener { - int gap = 3; - Color foreground; + /** The labelUI that is shared by all labels. */ + protected static BasicLabelUI labelUI; - - public static ComponentUI createUI(final JComponent c) { - return new BasicLabelUI(); - } - - - public void installUI(final JComponent c) { - super.installUI(c); - - foreground = new Color(0,0,250); - } - + /** + * Creates a new BasicLabelUI object. + */ + public BasicLabelUI() + { + super(); + } - public Dimension getPreferredSize(JComponent c) - { - JLabel b = (JLabel)c; - /* - We cannot use this method because it is not part of the - official Swing API. - - Dimension d = BasicGraphicsUtils.getPreferredSize(b, - gap, - b.getText(), - b.getIcon(), - b.getVerticalAlignment(), - b.getHorizontalAlignment(), - b.getHorizontalTextPosition(), - b.getVerticalTextPosition()); - System.out.println("JLABEL->^^^^^^^^^^^^^^^^^^^^^^ BASIC-PREF="+d + ",T="+b.getText()); - */ - return new Dimension(100, 30); - } + /** + * Creates and returns a UI for the label. Since one UI is shared by all + * labels, this means creating only if necessary and returning the shared + * UI. + * + * @param c The {@link JComponent} that a UI is being created for. + * + * @return A label UI for the Basic L&F. + */ + public static ComponentUI createUI(JComponent c) + { + if (labelUI == null) + labelUI = new BasicLabelUI(); + return labelUI; + } + + /** + * Returns the preferred size of this component as calculated by the + * {@link layoutCL} method. + * + * @param c This {@link JComponent} to get a preferred size for. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + JLabel lab = (JLabel)c; + Rectangle vr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle tr = new Rectangle(); + Insets insets = lab.getInsets(); + FontMetrics fm = lab.getToolkit().getFontMetrics(lab.getFont()); + layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr); + Rectangle cr = tr.union(ir); + return new Dimension(insets.left + cr.width + insets.right, + insets.top + cr.height + insets.bottom); + } - public void paint(Graphics g, JComponent c) - { - JLabel b = (JLabel) c; - - Rectangle tr = new Rectangle(); - Rectangle ir = new Rectangle(); - Rectangle vr = new Rectangle(); - - Font f = c.getFont(); - - g.setFont(f); - - FontMetrics fm = g.getFontMetrics(f); - - Insets i = c.getInsets(); - - Rectangle bound = c.getBounds(); - - System.out.println("BOUND=" + bound + ", insets = " + i + ", " + b.getText()); - - if (bound == null) - { - vr.x = i.left; - vr.y = i.top; - vr.width = b.getWidth() - (i.right + i.left); - vr.height = b.getHeight() - (i.bottom + i.top); - } - else - { - vr.x = bound.x + i.left; - vr.y = bound.y + i.top; - vr.width = bound.width - (i.right + i.left); - vr.height = bound.height - (i.bottom + i.top); - } - - System.out.println(" VIEW-RECT-JLABEL="+vr+", insets="+i+", FONTM="+fm); - - String text = SwingUtilities.layoutCompoundLabel(c, - fm, - b.getText(), - b.getIcon(), - b.getVerticalAlignment(), - b.getHorizontalAlignment(), - b.getVerticalTextPosition(), - b.getHorizontalTextPosition(), - vr, - ir, - tr, - gap); - - paintIcon(g, c, ir); - paintText(g, c, tr, b.getText()); - paintFocus(g, c, vr, tr, ir); - } + /** + * This method returns the minimum size of the {@link JComponent} given. If + * this method returns null, then it is up to the Layout Manager to give + * this component a minimum size. + * + * @param c The {@link JComponent} to get a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum size of the {@link JComponent} given. If + * this method returns null, then it is up to the Layout Manager to give + * this component a maximum size. + * + * @param c The {@link JComponent} to get a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + /** + * The method that paints the label according to its current state. + * + * @param g The {@link Graphics} object to paint with. + * @param c The {@link JComponent} to paint. + */ + public void paint(Graphics g, JComponent c) + { + JLabel b = (JLabel) c; - protected void paintFocus(Graphics g, - JComponent c, - Rectangle vr, - Rectangle tr, - Rectangle ir) - { - } + Font saved_font = g.getFont(); - protected void paintIcon(Graphics g, - JComponent c, - Rectangle iconRect) - { - JLabel b = (JLabel) c; - if (b.getIcon() != null) - { - int x = iconRect.x; - int y = iconRect.y; - - System.out.println("WE HAVE AN ICON: " + b.getIcon()); - - b.getIcon().paintIcon(c, g, x, y); - } - else - { - //System.out.println("NO ICON FOR BUTTON:" + b.text); - } - } + Rectangle tr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle vr = new Rectangle(); + + Font f = c.getFont(); + + g.setFont(f); + FontMetrics fm = g.getFontMetrics(f); + + vr = SwingUtilities.calculateInnerArea(c, vr); + + if (vr.width < 0) + vr.width = 0; + if (vr.height < 0) + vr.height = 0; + + Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon(); + String text = layoutCL(b, fm, b.getText(), icon, vr, ir, tr); - protected void paintText(Graphics g, - JComponent c, - Rectangle textRect, - String text) + if (b.isOpaque()) { - // AbstractLabel b = (AbstractLabel) c; - - System.out.println("JLabel: drawing string: " + text + ", at:" + textRect); - - g.setColor(foreground); - //g.setBackColor(new Color(190,190,190)); - - g.drawLine(0,0,100,100); - - BasicGraphicsUtils.drawString(g, text, 0, 0 /*textRect.x*/, 0 /*textRect.y*/); + g.setColor(b.getBackground()); + g.fillRect(vr.x, vr.y, vr.width, vr.height); } - public void propertyChange (PropertyChangeEvent event) + if (icon != null) + icon.paintIcon(b, g, ir.x, ir.y); + if (b.isEnabled()) + paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + else + paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + g.setFont(saved_font); + } + + /** + * This method is simply calls SwingUtilities's layoutCompoundLabel. + * + * @param label The label to lay out. + * @param fontMetrics The FontMetrics for the font used. + * @param text The text to paint. + * @param icon The icon to draw. + * @param viewR The entire viewable rectangle. + * @param iconR The icon bounds rectangle. + * @param textR The text bounds rectangle. + * + * @return A possibly clipped version of the text. + */ + protected String layoutCL(JLabel label, FontMetrics fontMetrics, + String text, Icon icon, Rectangle viewR, + Rectangle iconR, Rectangle textR) + { + return SwingUtilities.layoutCompoundLabel(label, fontMetrics, text, icon, + label.getVerticalAlignment(), + label.getHorizontalAlignment(), + label.getVerticalTextPosition(), + label.getHorizontalTextPosition(), + viewR, iconR, textR, + label.getIconTextGap()); + } + + /** + * Paints the text if the label is disabled. By default, this paints the + * clipped text returned by layoutCompoundLabel using the + * background.brighter() color. It also paints the same text using the + * background.darker() color one pixel to the right and one pixel down. + * + * @param l The {@link JLabel} being painted. + * @param g The {@link Graphics} object to paint with. + * @param s The String to paint. + * @param textX The x coordinate of the start of the baseline. + * @param textY The y coordinate of the start of the baseline. + */ + protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, + int textY) + { + Color saved_color = g.getColor(); + + g.setColor(l.getBackground().brighter()); + + int mnemIndex = l.getDisplayedMnemonicIndex(); + + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, + textY); + else + g.drawString(s, textX, textY); + + g.setColor(l.getBackground().darker()); + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX + 1, + textY + 1); + else + g.drawString(s, textX + 1, textY + 1); + + g.setColor(saved_color); + } + + /** + * Paints the text if the label is enabled. The text is painted using the + * foreground color. + * + * @param l The {@link JLabel} being painted. + * @param g The {@link Graphics} object to paint with. + * @param s The String to paint. + * @param textX The x coordinate of the start of the baseline. + * @param textY The y coordinate of the start of the baseline. + */ + protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, + int textY) + { + Color saved_color = g.getColor(); + g.setColor(l.getForeground()); + + int mnemIndex = l.getDisplayedMnemonicIndex(); + + if (mnemIndex != -1) + BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, + textY); + else + g.drawString(s, textX, textY); + + g.setColor(saved_color); + } + + /** + * This method installs the UI for the given {@link JComponent}. This + * method will install the component, defaults, listeners, and keyboard + * actions. + * + * @param c The {@link JComponent} that this UI is being installed on. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JLabel) + { + JLabel l = (JLabel) c; + + installComponents(l); + installDefaults(l); + installListeners(l); + installKeyboardActions(l); + } + } + + /** + * This method uninstalls the UI for the given {@link JComponent}. This + * method will uninstall the component, defaults, listeners, and keyboard + * actions. + * + * @param c The {@link JComponent} that this UI is being installed on. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + if (c instanceof JLabel) + { + JLabel l = (JLabel) c; + + uninstallKeyboardActions(l); + uninstallListeners(l); + uninstallDefaults(l); + uninstallComponents(l); + } + } + + /** + * This method installs the components for this {@link JLabel}. + * + * @param c The {@link JLabel} to install components for. + */ + protected void installComponents(JLabel c) + { + //FIXME: fix javadoc + implement. + } + + /** + * This method uninstalls the components for this {@link JLabel}. + * + * @param c The {@link JLabel} to uninstall components for. + */ + protected void uninstallComponents(JLabel c) + { + //FIXME: fix javadoc + implement. + } + + /** + * This method installs the defaults that are defined in the Basic look and + * feel for this {@link JLabel}. + * + * @param c The {@link JLabel} to install defaults for. + */ + protected void installDefaults(JLabel c) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + c.setForeground(defaults.getColor("Label.foreground")); + c.setBackground(defaults.getColor("Label.background")); + c.setFont(defaults.getFont("Label.font")); + c.setBorder(defaults.getBorder("Label.border")); + //XXX: There are properties we don't use called disabledForeground + //and disabledShadow. + } + + /** + * This method uninstalls the defaults that are defined in the Basic look + * and feel for this {@link JLabel}. + * + * @param c The {@link JLabel} to uninstall defaults for. + */ + protected void uninstallDefaults(JLabel c) + { + c.setForeground(null); + c.setBackground(null); + c.setFont(null); + c.setBorder(null); + } + + /** + * This method installs the keyboard actions for the given {@link JLabel}. + * + * @param l The {@link JLabel} to install keyboard actions for. + */ + protected void installKeyboardActions(JLabel l) + { + //FIXME: implement. + } + + /** + * This method uninstalls the keyboard actions for the given {@link JLabel}. + * + * @param l The {@link JLabel} to uninstall keyboard actions for. + */ + protected void uninstallKeyboardActions(JLabel l) + { + //FIXME: implement. + } + + /** + * This method installs the listeners for the given {@link JLabel}. The UI + * delegate only listens to the label. + * + * @param c The {@link JLabel} to install listeners for. + */ + protected void installListeners(JLabel c) + { + c.addPropertyChangeListener(this); + } + + /** + * This method uninstalls the listeners for the given {@link JLabel}. The UI + * delegate only listens to the label. + * + * @param c The {@link JLabel} to uninstall listeners for. + */ + protected void uninstallListeners(JLabel c) + { + c.removePropertyChangeListener(this); + } + + /** + * This method is called whenever any JLabel's that use this UI has one of + * their properties change. + * + * @param e The {@link PropertyChangeEvent} that describes the change. + */ + public void propertyChange(PropertyChangeEvent e) { - throw new Error ("Not implemented"); + JLabel c = (JLabel) e.getSource(); + c.revalidate(); + c.repaint(); } } diff --git a/libjava/javax/swing/plaf/basic/BasicListUI.java b/libjava/javax/swing/plaf/basic/BasicListUI.java index 6b83a910672..7a1f5a4a820 100644 --- a/libjava/javax/swing/plaf/basic/BasicListUI.java +++ b/libjava/javax/swing/plaf/basic/BasicListUI.java @@ -35,7 +35,6 @@ this exception to your version of the library, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. */ - package javax.swing.plaf.basic; import java.awt.Color; @@ -44,141 +43,664 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; +import javax.swing.ListModel; +import javax.swing.ListSelectionModel; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ListUI; + +/** + * The Basic Look and Feel UI delegate for the + * JList. + */ public class BasicListUI extends ListUI { - int gap_between_cells; - Color textColor, disabledTextColor, pressedBackgroundColor, normalBackgroundColor; - + /** + * A helper class which listens for {@link FocusEvents} + * from the JList. + */ + class FocusHandler implements FocusListener + { + /** + * Called when the JList acquires focus. + * + * @param e The FocusEvent representing focus acquisition + */ + public void focusGained(FocusEvent e) + { + repaintCellFocus(); + } - public static ComponentUI createUI(final JComponent c) + /** + * Called when the JList loses focus. + * + * @param e The FocusEvent representing focus loss + */ + public void focusLost(FocusEvent e) { - return new BasicButtonUI(); + repaintCellFocus(); } - - public void installUI(final JComponent c) + /** + * Helper method to repaint the focused cell's + * lost or acquired focus state. + */ + void repaintCellFocus() { - super.installUI(c); + } + } - textColor = new Color(0,0,0); - disabledTextColor = new Color(130, 130, 130); - pressedBackgroundColor = new Color(150,150,150); - normalBackgroundColor = new Color(192,192,192); + /** + * A helper class which listens for {@link ListDataEvent}s generated by + * the {@link JList}'s {@link ListModel}. + * + * @see javax.swing.JList#model + */ + class ListDataHandler implements ListDataListener + { + /** + * Called when a general change has happened in the model which cannot + * be represented in terms of a simple addition or deletion. + * + * @param e The event representing the change + */ + public void contentsChanged(ListDataEvent e) + { + // System.err.println(this + ".contentsChanged(" + e + ")"); + BasicListUI.this.damageLayout(); } - public Dimension getPreferredSize(JComponent c) + /** + * Called when an interval of objects has been added to the model. + * + * @param e The event representing the addition + */ + public void intervalAdded(ListDataEvent e) { - JList l = (JList) c; - - System.out.println("XXXXXXXXXXXXXXXxx getPreferredSize------------> " + l); - - - int rows = l.getVisibleRowCount(); - - ListCellRenderer render = l.getCellRenderer(); - - int width = 200; - int height = rows * 16; - - if (l.getModel().getSize() == 0) - { - return new Dimension(width, height); - } - - System.out.println("BASIC_LIST_UI ====-> " + l.getModel().getElementAt(0)); - - Component elt = render.getListCellRendererComponent(l, - l.getModel().getElementAt(0), - 0, - false, - false); - Dimension a = elt.getPreferredSize(); - if (a == null) - { - return new Dimension(width, height); - } - - return new Dimension(a.width, - a.height * rows); + // System.err.println(this + ".intervalAdded(" + e + ")"); + BasicListUI.this.damageLayout(); } - public void paintBackground(Graphics g, - JComponent c) + /** + * Called when an inteval of objects has been removed from the model. + * + * @param e The event representing the removal + */ + public void intervalRemoved(ListDataEvent e) { - Dimension size = getPreferredSize(c); + // System.err.println(this + ".intervalRemoved(" + e + ")"); + BasicListUI.this.damageLayout(); + } + } - g.setColor(normalBackgroundColor); - g.fillRect(0,0,size.width, size.height); + /** + * A helper class which listens for {@link ListSelectionEvent}s + * from the {@link JList}'s {@link ListSelectionModel}. + */ + class ListSelectionHandler implements ListSelectionListener + { + /** + * Called when the list selection changes. + * + * @param e The event representing the change + */ + public void valueChanged(ListSelectionEvent e) + { + // System.err.println(this + ".valueChanged(" + e + ")"); } + } - public void paint(Graphics g, - JComponent c) - { - JList l = (JList) c; + /** + * A helper class which listens for {@link MouseEvent}s + * from the {@link JList}. + */ + class MouseInputHandler implements MouseInputListener + { + /** + * Called when a mouse button press/release cycle completes + * on the {@link JList} + * + * @param event The event representing the mouse click + */ + public void mouseClicked(MouseEvent event) + { + } - int rows = l.getVisibleRowCount(); + /** + * Called when a mouse button is pressed down on the + * {@link JList}. + * + * @param event The event representing the mouse press + */ + public void mousePressed(MouseEvent event) + { + // System.err.println("got mouse click event " + event); + int row = BasicListUI.this.convertYToRow(event.y); + if (row == -1) + return; - ListCellRenderer render = l.getCellRenderer(); + // System.err.println("clicked on row " + row); + BasicListUI.this.list.setSelectedIndex(row); + } - System.out.println("RENDER-JLIST: " + rows + ", " + l.getModel().getSize()); + /** + * Called when a mouse button is released on + * the {@link JList} + * + * @param event The event representing the mouse press + */ + public void mouseReleased(MouseEvent event) + { + } - paintBackground(g, c); + /** + * Called when the mouse pointer enters the area bounded + * by the {@link JList} + * + * @param event The event representing the mouse entry + */ + public void mouseEntered(MouseEvent event) + { + } - if (l.getModel().getSize() == 0) - return; + /** + * Called when the mouse pointer leaves the area bounded + * by the {@link JList} + * + * @param event The event representing the mouse exit + */ + public void mouseExited(MouseEvent event) + { + } - // use element 0 to figure out how big we are: - Component elt = render.getListCellRendererComponent(l, - l.getModel().getElementAt(0), - 0, - false, - false); - Dimension dim = elt.getPreferredSize(); - - Rectangle a = new Rectangle(0, - 0, - dim.width, - dim.height); + /** + * Called when the mouse pointer moves over the area bounded + * by the {@link JList} while a button is held down. + * + * @param event The event representing the mouse drag + */ + public void mouseDragged(MouseEvent event) + { + } + + /** + * Called when the mouse pointer moves over the area bounded + * by the {@link JList}. + * + * @param event The event representing the mouse move + */ + public void mouseMoved(MouseEvent event) + { + } + } - for (int i=0;i " + a + ", " + comp + ", index = " + i); + /** The current focus listener. */ + FocusHandler focusListener; + + /** The data listener listening to the model. */ + ListDataHandler listDataListener; + + /** The selection listener listening to the selection model. */ + ListSelectionHandler listSelectionListener; + + /** The mouse listener listening to the list. */ + MouseInputHandler mouseInputListener; + + /** The property change listener listening to the list. */ + PropertyChangeHandler propertyChangeListener; + + /** Saved reference to the list this UI was created for. */ + JList list; + + /** The height of a single cell in the list. */ + int cellHeight; + + /** The width of a single cell in the list. */ + int cellWidth; + + /** + * An array of varying heights of cells in the list, in cases where each + * cell might have a different height. + */ + int[] cellHeights; + + /** + * A simple counter. When nonzero, indicates that the UI class is out of + * date with respect to the underlying list, and must recalculate the + * list layout before painting or performing size calculations. + */ + int updateLayoutStateNeeded; + + /** + * Calculate the height of a particular row. If there is a fixed {@link + * #cellHeight}, return it; otherwise return the specific row height + * requested from the {@link #cellHeights} array. If the requested row + * is invalid, return -1. + * + * @param row The row to get the height of + * + * @return The height, in pixels, of the specified row + */ + int getRowHeight(int row) + { + if (row < 0 || row >= cellHeights.length) + return -1; + else if (cellHeight != -1) + return cellHeight; + else + return cellHeights[row]; + } - comp.setBounds(a); + /** + * Calculate the bounds of a particular cell, considering the upper left + * corner of the list as the origin position (0,0). + * + * @param l Ignored; calculates over this.list + * @param index1 The first row to include in the bounds + * @param index2 The last row to incude in the bounds + * + * @return A rectangle encompassing the range of rows between + * index1 and index2 inclusive + */ + public Rectangle getCellBounds(JList l, int index1, int index2) + { + if (l != list || cellWidth == -1) + return null; + + int lo = Math.min(index1, index2); + int hi = Math.max(index1, index2); + Rectangle lobounds = new Rectangle(0, convertRowToY(lo), cellWidth, + getRowHeight(lo)); + Rectangle hibounds = new Rectangle(0, convertRowToY(hi), cellWidth, + getRowHeight(hi)); + return lobounds.union(hibounds); + } - comp.paint(g); + /** + * Calculate the Y coordinate of the upper edge of a particular row, + * considering the Y coordinate 0 to occur at the top of the + * list. + * + * @param row The row to calculate the Y coordinate of + * + * @return The Y coordinate of the specified row, or -1 if + * the specified row number is invalid + */ + int convertRowToY(int row) + { + int y = 0; + for (int i = 0; i < row; ++i) + { + int h = getRowHeight(i); + if (h == -1) + return -1; + y += h; + } + return y; + } - a.y += dim.height + gap_between_cells; - } - } + /** + * Calculate the row number containing a particular Y coordinate, + * considering the Y coodrinate 0 to occur at the top of the + * list. + * + * @param y0 The Y coordinate to calculate the row number for + * + * @return The row number containing the specified Y value, or -1 + * if the specified Y coordinate is invalid + */ + int convertYToRow(int y0) + { + for (int row = 0; row < cellHeights.length; ++row) + { + int h = getRowHeight(row); + + // System.err.println("convertYToRow(" + y0 + ") vs. " + h); + if (y0 < h) + return row; + y0 -= h; + } + return -1; + } - public int locationToIndex(JList list, Point location) + /** + * Recomputes the {@link #cellHeights}, {@link #cellHeight}, and {@link + * #cellWidth} properties by examining the variouis properties of the + * {@link JList}. + */ + void updateLayoutState() { - throw new Error ("Not implemented"); + int nrows = list.getModel().getSize(); + cellHeight = -1; + cellWidth = -1; + if (cellHeights == null || cellHeights.length != nrows) + cellHeights = new int[nrows]; + if (list.getFixedCellHeight() == -1 || list.getFixedCellWidth() == -1) + { + ListCellRenderer rend = list.getCellRenderer(); + for (int i = 0; i < nrows; ++i) + { + Component flyweight = rend.getListCellRendererComponent(list, + list.getModel() + .getElementAt(i), + 0, false, + false); + Dimension dim = flyweight.getPreferredSize(); + cellHeights[i] = dim.height; + cellWidth = Math.max(cellWidth, dim.width); + } + } + else + { + cellHeight = list.getFixedCellHeight(); + cellWidth = list.getFixedCellWidth(); + } } - public Point indexToLocation(JList list, int index) + /** + * Marks the current layout as damaged and requests revalidation from the + * JList. + * + * @see #updateLayoutStateNeeded + */ + void damageLayout() + { + updateLayoutStateNeeded = 1; + list.revalidate(); + } + + /** + * Calls {@link #updateLayoutState} if {@link #updateLayoutStateNeeded} + * is nonzero, then resets {@link #updateLayoutStateNeeded} to zero. + */ + void maybeUpdateLayoutState() { - throw new Error ("Not implemented"); + // System.err.println(this + ".maybeUpdateLayoutState()"); + if (updateLayoutStateNeeded != 0) + { + updateLayoutState(); + updateLayoutStateNeeded = 0; + } } - public Rectangle getCellBounds(JList list, int index1, int index2) + /** + * Creates a new BasicListUI object. + */ + public BasicListUI() + { + focusListener = new FocusHandler(); + listDataListener = new ListDataHandler(); + listSelectionListener = new ListSelectionHandler(); + mouseInputListener = new MouseInputHandler(); + propertyChangeListener = new PropertyChangeHandler(); + updateLayoutStateNeeded = 1; + } + + /** + * Installs various default settings (mostly colors) from the {@link + * UIDefaults} into the {@link JList} + * + * @see #uninstallDefaults + */ + void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + list.setForeground(defaults.getColor("List.foreground")); + list.setBackground(defaults.getColor("List.background")); + list.setSelectionForeground(defaults.getColor("List.selectionForeground")); + list.setSelectionBackground(defaults.getColor("List.selectionBackground")); + } + + /** + * Resets to null those defaults which were installed in + * {@link #installDefaults} + */ + void uninstallDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + list.setForeground(null); + list.setBackground(null); + list.setSelectionForeground(null); + list.setSelectionBackground(null); + } + + /** + * Attaches all the listeners we have in the UI class to the {@link + * JList}, its model and its selection model. + * + * @see #uninstallListeners + */ + void installListeners() + { + list.addFocusListener(focusListener); + list.getModel().addListDataListener(listDataListener); + list.addListSelectionListener(listSelectionListener); + list.addMouseListener(mouseInputListener); + list.addMouseMotionListener(mouseInputListener); + list.addPropertyChangeListener(propertyChangeListener); + } + + /** + * Detaches all the listeners we attached in {@link #installListeners}. + */ + void uninstallListeners() + { + list.removeFocusListener(focusListener); + list.getModel().removeListDataListener(listDataListener); + list.removeListSelectionListener(listSelectionListener); + list.removeMouseListener(mouseInputListener); + list.removeMouseMotionListener(mouseInputListener); + list.removePropertyChangeListener(propertyChangeListener); + } + + /** + * Installs keyboard actions for this UI in the {@link JList}. + */ + void installKeyboardActions() + { + } + + /** + * Uninstalls keyboard actions for this UI in the {@link JList}. + */ + void uninstallKeyboardActions() + { + } + + /** + * Installs the various aspects of the UI in the {@link JList}. In + * particular, calls {@link #installDefaults}, {@link #installListeners} + * and {@link #installKeyboardActions}. Also saves a reference to the + * provided component, cast to a {@link JList}. + * + * @param c The {@link JList} to install the UI into + */ + public void installUI(final JComponent c) + { + super.installUI(c); + list = (JList) c; + installDefaults(); + installListeners(); + installKeyboardActions(); + // System.err.println(this + ".installUI()"); + maybeUpdateLayoutState(); + } + + /** + * Uninstalls all the aspects of the UI which were installed in {@link + * #installUI}. When finished uninstalling, drops the saved reference to + * the {@link JList}. + * + * @param c Ignored; the UI is uninstalled from the {@link JList} + * reference saved during the call to {@link #installUI} + */ + public void uninstallUI(final JComponent c) + { + uninstallKeyboardActions(); + uninstallListeners(); + uninstallDefaults(); + list = null; + } + + /** + * Gets the maximum size this list can assume. + * + * @param c The component to measure the size of + * + * @return A new Dimension representing the component's maximum size + */ + public Dimension getMaximumSize(JComponent c) + { + return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); + } + + /** + * Gets the size this list would prefer to assume. This is calculated by + * calling {@link #getCellBounds} over the entire list. + * + * @param c Ignored; uses the saved {@link JList} reference + * + * @return DOCUMENT ME! + */ + public Dimension getPreferredSize(JComponent c) + { + maybeUpdateLayoutState(); + if (list.getModel().getSize() == 0) + return new Dimension(0, 0); + Rectangle bounds = getCellBounds(list, 0, list.getModel().getSize() - 1); + return bounds.getSize(); + } + + /** + * Paints the packground of the list using the background color + * of the specified component. + * + * @param g The graphics context to paint in + * @param c The component to paint the background of + */ + public void paintBackground(Graphics g, JComponent c) + { + Dimension size = getPreferredSize(c); + Color save = g.getColor(); + g.setColor(c.getBackground()); + g.fillRect(0, 0, size.width, size.height); + g.setColor(save); + } + + /** + * Paints a single cell in the list. + * + * @param g The graphics context to paint in + * @param row The row number to paint + * @param bounds The bounds of the cell to paint, assuming a coordinate + * system beginning at (0,0) in the upper left corner of the + * list + * @param rend A cell renderer to paint with + * @param data The data to provide to the cell renderer + * @param sel A selection model to provide to the cell renderer + * @param lead The lead selection index of the list + */ + void paintCell(Graphics g, int row, Rectangle bounds, ListCellRenderer rend, + ListModel data, ListSelectionModel sel, int lead) + { + boolean is_sel = list.isSelectedIndex(row); + boolean has_focus = false; + Component comp = rend.getListCellRendererComponent(list, + data.getElementAt(row), + 0, is_sel, has_focus); + g.translate(bounds.x, bounds.y); + comp.setBounds(new Rectangle(0, 0, bounds.width, bounds.height)); + comp.paint(g); + g.translate(-bounds.x, -bounds.y); + } + + /** + * Paints the list by calling {@link #paintBackground} and then repeatedly + * calling {@link #paintCell} for each visible cell in the list. + * + * @param g The graphics context to paint with + * @param c Ignored; uses the saved {@link JList} reference + */ + public void paint(Graphics g, JComponent c) + { + int nrows = Math.min(list.getVisibleRowCount(), list.getModel().getSize()); + if (nrows == 0) + return; + + maybeUpdateLayoutState(); + ListCellRenderer render = list.getCellRenderer(); + ListModel model = list.getModel(); + ListSelectionModel sel = list.getSelectionModel(); + int lead = sel.getLeadSelectionIndex(); + paintBackground(g, list); + + for (int row = 0; row < nrows; ++row) + { + Rectangle bounds = getCellBounds(list, row, row); + paintCell(g, row, bounds, render, model, sel, lead); + } + } + + public int locationToIndex(JList list, Point location) + { + throw new Error("Not implemented"); + } + + public Point indexToLocation(JList list, int index) { - throw new Error ("Not implemented"); + throw new Error("Not implemented"); } } diff --git a/libjava/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/javax/swing/plaf/basic/BasicLookAndFeel.java index 901ea516e95..c4d3d80a77c 100644 --- a/libjava/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/libjava/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -226,6 +226,13 @@ public abstract class BasicLookAndFeel extends LookAndFeel protected void initComponentDefaults(UIDefaults defaults) { Object[] uiDefaults; + + // The JDK's default L&F happens to use these three purple shades + // extensively. + Color lightPurple = new Color(0xCC, 0xCC, 0xFF); + Color midPurple = new Color(0x99, 0x99, 0xCC); + Color darkPurple = new Color(0x66, 0x66, 0x99); + uiDefaults = new Object[] { "AbstractUndoableEdit.undoText", "Undo", @@ -275,8 +282,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "CheckBoxMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), "CheckBoxMenuItem.foreground", new ColorUIResource(Color.black), "CheckBoxMenuItem.margin", new InsetsUIResource(2, 2, 2, 2), - "CheckBoxMenuItem.selectionBackground", new ColorUIResource(0, 0, 128), - "CheckBoxMenuItem.selectionForeground", new ColorUIResource(Color.white), + "CheckBoxMenuItem.selectionBackground", new ColorUIResource(lightPurple), + "CheckBoxMenuItem.selectionForeground", new ColorUIResource(Color.black), "ColorChooser.background", new ColorUIResource(Color.lightGray), "ColorChooser.cancelText", "Cancel", "ColorChooser.font", new FontUIResource("Dialog", Font.PLAIN, 12), @@ -316,8 +323,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "ComboBox.disabledForeground", new ColorUIResource(Color.gray), "ComboBox.font", new FontUIResource("SansSerif", Font.PLAIN, 12), "ComboBox.foreground", new ColorUIResource(Color.black), - "ComboBox.selectionBackground", new ColorUIResource(0, 0, 128), - "ComboBox.selectionForeground", new ColorUIResource(Color.white), + "ComboBox.selectionBackground", new ColorUIResource(lightPurple), + "ComboBox.selectionForeground", new ColorUIResource(Color.black), "Desktop.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { "KP_LEFT", "left", "KP_RIGHT", "right", @@ -412,8 +419,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "FocusManagerClassName", "TODO", "FormView.resetButtonText", "Reset", "FormView.submitButtonText", "Submit Query", - "InternalFrame.activeTitleBackground", new ColorUIResource(0, 0, 128), - "InternalFrame.activeTitleForeground", new ColorUIResource(Color.white), + "InternalFrame.activeTitleBackground", new ColorUIResource(lightPurple), + "InternalFrame.activeTitleForeground", new ColorUIResource(Color.black), "InternalFrame.border", new BorderUIResource.CompoundBorderUIResource(null, null), "InternalFrame.closeIcon", BasicIconFactory.createEmptyFrameIcon(), @@ -434,6 +441,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Label.disabledForeground", new ColorUIResource(Color.white), "Label.disabledShadow", new ColorUIResource(Color.gray), "Label.font", new FontUIResource("Dialog", Font.PLAIN, 12), + "Label.foreground", new ColorUIResource(Color.black), + "List.background", new ColorUIResource(Color.white), + "List.border", new BasicBorders.MarginBorder(), "List.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { "PAGE_UP", "scrollUp", "ctrl \\", "clearSelection", @@ -455,8 +465,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "KP_DOWN", "selectNextRow" }), "List.foreground", new ColorUIResource(Color.black), - "List.selectionBackground", new ColorUIResource(0, 0, 128), - "List.selectionForeground", new ColorUIResource(Color.white), + "List.selectionBackground", new ColorUIResource(0xCC, 0xCC, 0xFF), + "List.selectionForeground", new ColorUIResource(Color.black), "Menu.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12), "Menu.acceleratorForeground", new ColorUIResource(Color.black), "Menu.acceleratorSelectionForeground", new ColorUIResource(Color.white), @@ -482,8 +492,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "ENTER", "return", "SPACE", "return" }, - "Menutext.selectionBackground", new ColorUIResource(0, 0, 128), - "Menu.selectionForeground", new ColorUIResource(Color.white), + "Menutext.selectionBackground", new ColorUIResource(lightPurple), + "Menu.selectionForeground", new ColorUIResource(Color.black), "MenuBar.background", new ColorUIResource(Color.lightGray), "MenuBar.border", new BasicBorders.MenuBarBorder(null, null), "MenuBar.font", new FontUIResource("Dialog", Font.PLAIN, 12), @@ -503,8 +513,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "MenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), "MenuItem.foreground", new ColorUIResource(Color.black), "MenuItem.margin", new InsetsUIResource(2, 2, 2, 2), - "MenuItem.selectionBackground", new ColorUIResource(0, 0, 128), - "MenuItem.selectionForeground", new ColorUIResource(Color.white), + "MenuItem.selectionBackground", new ColorUIResource(lightPurple), + "MenuItem.selectionForeground", new ColorUIResource(Color.black), "OptionPane.background", new ColorUIResource(Color.lightGray), "OptionPane.border", new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0), "OptionPane.buttonAreaBorder", new BorderUIResource.EmptyBorderUIResource(0, 0, 0, 0), @@ -544,8 +554,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel 0), "notify-field-accept")}, "PasswordField.margin", new InsetsUIResource(0, 0, 0, 0), - "PasswordField.selectionBackground", new ColorUIResource(0, 0, 128), - "PasswordField.selectionForeground", new ColorUIResource(Color.white), + "PasswordField.selectionBackground", new ColorUIResource(lightPurple), + "PasswordField.selectionForeground", new ColorUIResource(Color.black), "PopupMenu.background", new ColorUIResource(Color.lightGray), "PopupMenu.border", new BorderUIResource.BevelBorderUIResource(0), "PopupMenu.font", new FontUIResource("Dialog", Font.PLAIN, 12), @@ -555,9 +565,11 @@ public abstract class BasicLookAndFeel extends LookAndFeel "ProgressBar.cellLength", new Integer(1), "ProgressBar.cellSpacing", new Integer(0), "ProgressBar.font", new FontUIResource("Dialog", Font.PLAIN, 12), - "ProgressBar.foreground", new ColorUIResource(0, 0, 128), - "ProgressBar.selectionBackground", new ColorUIResource(0, 0, 128), + "ProgressBar.foreground", new ColorUIResource(midPurple), + "ProgressBar.selectionBackground", new ColorUIResource(lightPurple), "ProgressBar.selectionForeground", new ColorUIResource(Color.lightGray), + "ProgressBar.repaintInterval", new Integer(250), + "ProgressBar.cycleTime", new Integer(6000), "RadioButton.background", new ColorUIResource(Color.lightGray), "RadioButton.border", new BorderUIResource.CompoundBorderUIResource(null, null), @@ -587,8 +599,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "RadioButtonMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), "RadioButtonMenuItem.foreground", new ColorUIResource(Color.black), "RadioButtonMenuItem.margin", new InsetsUIResource(2, 2, 2, 2), - "RadioButtonMenuItem.selectionBackground", new ColorUIResource(0, 0, 128), - "RadioButtonMenuItem.selectionForeground", new ColorUIResource(Color.white), + "RadioButtonMenuItem.selectionBackground", new ColorUIResource(lightPurple), + "RadioButtonMenuItem.selectionForeground", new ColorUIResource(Color.black), "RootPane.defaultButtonWindowKeyBindings", new Object[] { "ENTER", "press", "released ENTER", "release", @@ -663,6 +675,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Slider.foreground", new ColorUIResource(Color.lightGray), "Slider.highlight", new ColorUIResource(Color.white), "Slider.shadow", new ColorUIResource(Color.gray), + "Slider.thumbHeight", new Integer(20), + "Slider.thumbWidth", new Integer(10), + "Slider.tickHeight", new Integer(12), "SplitPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { "F6", "toggleFocus", "F8", "startResize", @@ -762,8 +777,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Table.foreground", new ColorUIResource(Color.black), "Table.gridColor", new ColorUIResource(Color.gray), "Table.scrollPaneBorder", new BorderUIResource.BevelBorderUIResource(0), - "Table.selectionBackground", new ColorUIResource(0, 0, 128), - "Table.selectionForeground", new ColorUIResource(Color.white), + "Table.selectionBackground", new ColorUIResource(lightPurple), + "Table.selectionForeground", new ColorUIResource(Color.black), "TableHeader.background", new ColorUIResource(Color.lightGray), "TableHeader.cellBorder", new BorderUIResource.BevelBorderUIResource(0), "TableHeader.font", new FontUIResource("Dialog", Font.PLAIN, 12), @@ -790,8 +805,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel 0), "insert-tab") }, "TextArea.margin", new InsetsUIResource(0, 0, 0, 0), - "TextArea.selectionBackground", new ColorUIResource(0, 0, 128), - "TextArea.selectionForeground", new ColorUIResource(Color.white), + "TextArea.selectionBackground", new ColorUIResource(lightPurple), + "TextArea.selectionForeground", new ColorUIResource(Color.black), "TextField.background", new ColorUIResource(Color.white), "TextField.border", new BasicBorders.FieldBorder(null, null, null, null), "TextField.caretBlinkRate", new Integer(500), @@ -804,8 +819,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel 0), "notify-field-accept")}, "TextField.margin", new InsetsUIResource(0, 0, 0, 0), - "TextField.selectionBackground", new ColorUIResource(0, 0, 128), - "TextField.selectionForeground", new ColorUIResource(Color.white), + "TextField.selectionBackground", new ColorUIResource(lightPurple), + "TextField.selectionForeground", new ColorUIResource(Color.black), "TextPane.background", new ColorUIResource(Color.white), "TextPane.border", new BasicBorders.MarginBorder(), "TextPane.caretBlinkRate", new Integer(500), @@ -931,9 +946,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Tree.rightChildIndent", new Integer(13), "Tree.rowHeight", new Integer(16), "Tree.scrollsOnExpand", Boolean.TRUE, - "Tree.selectionBackground", new ColorUIResource(0, 0, 128), + "Tree.selectionBackground", new ColorUIResource(lightPurple), "Tree.selectionBorderColor", new ColorUIResource(Color.black), - "Tree.selectionForeground", new ColorUIResource(Color.white), + "Tree.selectionForeground", new ColorUIResource(Color.black), "Tree.textBackground", new ColorUIResource(Color.lightGray), "Tree.textForeground", new ColorUIResource(Color.black), "Viewport.background", new ColorUIResource(Color.lightGray), diff --git a/libjava/javax/swing/plaf/basic/BasicProgressBarUI.java b/libjava/javax/swing/plaf/basic/BasicProgressBarUI.java new file mode 100644 index 00000000000..bf5cd0a7aa9 --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicProgressBarUI.java @@ -0,0 +1,820 @@ +/* BasicProgressBarUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.JComponent; +import javax.swing.JProgressBar; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ProgressBarUI; + + +/** + * The Basic Look and Feel UI delegate for the + * JProgressBar. + */ +public class BasicProgressBarUI extends ProgressBarUI +{ + /** + * A helper class that listens for ChangeEvents + * from the progressBar's model. + */ + protected class ChangeHandler implements ChangeListener + { + /** + * Called every time the state of the model changes. + * + * @param e The ChangeEvent given by the model. + */ + public void stateChanged(ChangeEvent e) + { + // Nothing to do but repaint. + progressBar.repaint(); + } + } + + /** + * This helper class is used to listen for + * PropertyChangeEvents from the progressBar. + */ + private class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called every time the properties of the + * progressBar change. + * + * @param e The PropertyChangeEvent given by the progressBar. + */ + public void propertyChange(PropertyChangeEvent e) + { + // Only need to listen for indeterminate changes. + // All other things are done on a repaint. + if (e.getPropertyName().equals(JProgressBar.INDETERMINATE_CHANGED_PROPERTY)) + if (((Boolean) e.getNewValue()).booleanValue()) + startAnimationTimer(); + else + stopAnimationTimer(); + else + progressBar.repaint(); + } + } + + /** + * This helper class is used to listen for + * the animationTimer's intervals. On every interval, + * the bouncing box should move. + */ + private class Animator implements ActionListener + { + /** + * Called every time the animationTimer reaches + * its interval. + * + * @param e The ActionEvent given by the timer. + */ + public void actionPerformed(ActionEvent e) + { + // Incrementing the animation index will cause + // a repaint. + incrementAnimationIndex(); + } + } + + /** The timer used to move the bouncing box. */ + private transient Timer animationTimer = new Timer(); + + + // The total number of frames must be an even number. + // The total number of frames is calculated from + // the cycleTime and repaintInterval given by + // the basic L&F's defaults. + // + // +-----------------------------------------------+ + // | frame0 | frame1 | frame2 | frame 3 | frame 4 | + // | | frame7 | frame6 | frame 5 | | + // +-----------------------------------------------+ + + /** The current animation index. */ + private transient int animationIndex; + + /** The total number of frames.*/ + private transient int numFrames; + + /** The helper that moves the bouncing box. */ + private transient Animator animation; + + /** The helper that listens for property change events. */ + private transient PropertyChangeHandler propertyListener; + + /** The Listener for the model. */ + protected ChangeListener changeListener; + + /** The progressBar for this UI. */ + protected JProgressBar progressBar; + + /** The length of the cell. The cell is the painted part. */ + private transient int cellLength; + + /** The gap between cells. */ + private transient int cellSpacing; + + /** The color of the text when the bar is not over it.*/ + private transient Color selectionBackground; + + /** The color of the text when the bar is over it. */ + private transient Color selectionForeground; + + /** + * Creates a new BasicProgressBarUI object. + */ + public BasicProgressBarUI() + { + super(); + } + + /** + * Creates a new BasicProgressBarUI for the component. + * + * @param x The JComponent to create the UI for. + * + * @return A new BasicProgressBarUI. + */ + public static ComponentUI createUI(JComponent x) + { + return new BasicProgressBarUI(); + } + + /** + * This method returns the length of the bar (from the minimum) + * in pixels (or units that the Graphics object draws in) based + * on the progressBar's getPercentComplete() value. + * + * @param b The insets of the progressBar. + * @param width The width of the progressBar. + * @param height The height of the progressBar. + * + * @return The length of the bar that should be painted in pixels. + */ + protected int getAmountFull(Insets b, int width, int height) + { + double percentDone = progressBar.getPercentComplete(); + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + return (int) (percentDone * (width - b.left - b.right)); + else + return (int) (percentDone * (height - b.top - b.bottom)); + } + + /** + * The current animation index. + * + * @return The current animation index. + */ + protected int getAnimationIndex() + { + return animationIndex; + } + + /** + * This method returns the size and position of the bouncing box + * for the current animation index. It stores the values in the + * given rectangle and returns it. It returns null if no box should + * be drawn. + * + * @param r The bouncing box rectangle. + * + * @return The bouncing box rectangle. + */ + protected Rectangle getBox(Rectangle r) + { + if (!progressBar.isIndeterminate()) + return null; + //numFrames has to be an even number as defined by spec. + int iterations = numFrames / 2 + 1; + + double boxDependent; + double boxIndependent; + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + Dimension dims = getPreferredInnerHorizontal(); + boxDependent = (double) dims.width / iterations; + boxIndependent = dims.height; + } + else + { + Dimension dims = getPreferredInnerVertical(); + boxDependent = (double) dims.height / iterations; + boxIndependent = dims.width; + } + + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(progressBar, vr); + + int index = getAnimationIndex(); + if (animationIndex > (numFrames + 1) / 2) + index = numFrames - getAnimationIndex(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + r.x = vr.x + (int) (index * boxDependent); + r.y = vr.y; + r.width = (int) boxDependent; + r.height = (int) boxIndependent; + } + else + { + index++; + r.x = vr.x; + r.y = vr.height - (int) (index * boxDependent) + vr.y; + r.width = (int) boxIndependent; + r.height = (int) boxDependent; + } + + return r; + } + + /** + * This method returns the length of the cells. + * + * @return The cell length. + */ + protected int getCellLength() + { + return cellLength; + } + + /** + * This method returns the spacing between cells. + * + * @return The cell gap. + */ + protected int getCellSpacing() + { + return cellSpacing; + } + + /** + * This method returns the maximum size of the JComponent. + * If it returns null, it is up to the LayoutManager + * to give it a size. + * + * @param c The component to find a maximum size for. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum size of the JComponent. + * If it returns null, it is up to the LayoutManager to + * give it a size. + * + * @param c The component to find a minimum size for. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the preferred size of the inner + * rectangle (the bounds without the insets) if the + * progressBar is horizontal. + * + * @return The preferred size of the progressBar minus + * insets if it's horizontal. + */ + protected Dimension getPreferredInnerHorizontal() + { + Rectangle vr = new Rectangle(); + + SwingUtilities.calculateInnerArea(progressBar, vr); + + return new Dimension(vr.width, vr.height); + } + + /** + * This method returns the preferred size of the inner + * rectangle (the bounds without insets) if the + * progressBar is vertical. + * + * @return The preferred size of the progressBar minus + * insets if it's vertical. + */ + protected Dimension getPreferredInnerVertical() + { + Rectangle vr = new Rectangle(); + + SwingUtilities.calculateInnerArea(progressBar, vr); + + return new Dimension(vr.width, vr.height); + } + + /** + * This method returns the preferred size of the + * given JComponent. If it returns null, then it + * is up to the LayoutManager to give it a size. + * + * @param c The component to find the preferred size for. + * + * @return The preferred size of the component. + */ + public Dimension getPreferredSize(JComponent c) + { + // The only thing we need to worry about is + // the text size. + Graphics g = progressBar.getGraphics(); + + Insets insets = c.getInsets(); + + FontMetrics fm = g.getFontMetrics(c.getFont()); + + int textW = fm.stringWidth(progressBar.getString()); + int textH = fm.getHeight(); + + g.dispose(); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + if (textH < 20) + textH = 20; + if (textW < 200) + textW = 200; + } + else + { + if (textH < 200) + textH = 200; + if (textW < 20) + textW = 20; + } + textW += insets.left + insets.right; + textH += insets.top + insets.bottom; + return new Dimension(textW, textH); + } + + /** + * This method returns the Color that the text is shown in when the bar is + * not over the text. + * + * @return The color of the text when the bar is not over it. + */ + protected Color getSelectionBackground() + { + return selectionBackground; + } + + /** + * This method returns the Color that the text is shown in when the bar is + * over the text. + * + * @return The color of the text when the bar is over it. + */ + protected Color getSelectionForeground() + { + return selectionForeground; + } + + /** + * This method returns the point (the top left of the bounding box) + * where the text should be painted. + * + * @param g The Graphics object to measure FontMetrics with. + * @param progressString The string to paint. + * @param x The x coordinate of the overall bounds box. + * @param y The y coordinate of the overall bounds box. + * @param width The width of the overall bounds box. + * @param height The height of the overall bounds box. + * + * @return The top left of the bounding box where text should be painted. + */ + protected Point getStringPlacement(Graphics g, String progressString, int x, + int y, int width, int height) + { + Rectangle tr = new Rectangle(); + Rectangle vr = new Rectangle(x, y, width, height); + Rectangle ir = new Rectangle(); + + Font f = g.getFont(); + FontMetrics fm = g.getFontMetrics(f); + + SwingUtilities.layoutCompoundLabel(progressBar, fm, progressString, null, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, + SwingConstants.CENTER, vr, ir, tr, 0); + return new Point(tr.x, tr.y); + } + + /** + * This method increments the animation index. + */ + public void incrementAnimationIndex() + { + animationIndex++; + //numFrames is like string length, it should be named numFrames or something + if (animationIndex >= numFrames) + animationIndex = 0; + progressBar.repaint(); + } + + /** + * This method paints the progressBar. It delegates its responsibilities + * to paintDeterminate and paintIndeterminate. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + if (! progressBar.isIndeterminate()) + paintDeterminate(g, c); + else + paintIndeterminate(g, c); + + if (progressBar.isBorderPainted()) + progressBar.getBorder().paintBorder(progressBar, g, 0, 0, + progressBar.getWidth(), + progressBar.getHeight()); + } + + /** + * This method is called if the painting to be done is + * for a determinate progressBar. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + protected void paintDeterminate(Graphics g, JComponent c) + { + Color saved = g.getColor(); + int space = getCellSpacing(); + int len = getCellLength(); + int max = progressBar.getMaximum(); + int min = progressBar.getMinimum(); + int value = progressBar.getValue(); + + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(c, vr); + + Rectangle or = c.getBounds(); + + Insets insets = c.getInsets(); + + int amountFull = getAmountFull(insets, or.width, or.height); + + g.setColor(c.getBackground()); + g.fill3DRect(vr.x, vr.y, vr.width, vr.height, false); + + if (max != min && len != 0 && value > min) + { + int iterations = value / (space + len); + + if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) + { + double spaceInUnits = space * (double) vr.width / (max - min); + double lenInUnits = len * (double) vr.width / (max - min); + double currX = vr.x; + + g.setColor(c.getForeground()); + g.fill3DRect(vr.x, vr.y, amountFull, vr.height, true); + + g.setColor(c.getBackground()); + if (spaceInUnits != 0) + { + for (int i = 0; i < iterations; i++) + { + currX += lenInUnits; + g.fill3DRect((int) currX, vr.y, (int) spaceInUnits, + vr.height, true); + currX += spaceInUnits; + } + } + } + else + { + double currY = vr.y; + double spaceInUnits = space * (double) vr.height / (max - min); + double lenInUnits = len * (double) vr.height / (max - min); + + g.setColor(c.getForeground()); + g.fill3DRect(vr.x, vr.y + vr.height - amountFull, vr.width, + amountFull, true); + + g.setColor(c.getBackground()); + + if (spaceInUnits != 0) + { + for (int i = 0; i < iterations; i++) + { + currY -= lenInUnits + spaceInUnits; + g.fill3DRect(vr.x, (int) currY, vr.width, + (int) spaceInUnits, true); + } + } + } + } + + if (progressBar.isStringPainted()) + paintString(g, 0, 0, or.width, or.height, amountFull, insets); + g.setColor(saved); + } + + /** + * This method is called if the painting to be done is for + * an indeterminate progressBar. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + protected void paintIndeterminate(Graphics g, JComponent c) + { + //need to paint the box at it's current position. no text is painted since + //all we're doing is bouncing back and forth + Color saved = g.getColor(); + Insets insets = c.getInsets(); + + Rectangle or = c.getBounds(); + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(c, vr); + + g.setColor(c.getBackground()); + g.fill3DRect(vr.x, vr.y, vr.width, vr.height, false); + + Rectangle box = new Rectangle(); + getBox(box); + + g.setColor(c.getForeground()); + g.fill3DRect(box.x, box.y, box.width, box.height, true); + + if (progressBar.isStringPainted()) + paintString(g, 0, 0, or.width, or.height, + getAmountFull(insets, or.width, or.height), insets); + + g.setColor(saved); + } + + /** + * This method paints the string for the progressBar. + * + * @param g The Graphics object to paint with. + * @param x The x coordinate of the progressBar. + * @param y The y coordinate of the progressBar. + * @param width The width of the progressBar. + * @param height The height of the progressBar. + * @param amountFull The amount of the progressBar that has its bar filled. + * @param b The insets of the progressBar. + */ + protected void paintString(Graphics g, int x, int y, int width, int height, + int amountFull, Insets b) + { + // We want to place in the exact center of the bar. + Point placement = getStringPlacement(g, progressBar.getString(), + x + b.left, y + b.top, + width - b.left - b.right, + height - b.top - b.bottom); + Color saved = g.getColor(); + + // FIXME: The Color of the text should use selectionForeground and selectionBackground + // but that can't be done right now, so we'll use white in the mean time. + g.setColor(Color.WHITE); + + FontMetrics fm = g.getFontMetrics(progressBar.getFont()); + + g.drawString(progressBar.getString(), placement.x, + placement.y + fm.getAscent()); + + g.setColor(saved); + } + + /** + * This method sets the current animation index. If the index + * is greater than the number of frames, it resets to 0. + * + * @param newValue The new animation index. + */ + protected void setAnimationIndex(int newValue) + { + animationIndex = (newValue <= numFrames) ? newValue : 0; + progressBar.repaint(); + } + + /** + * This method sets the cell length. + * + * @param cellLen The cell length. + */ + protected void setCellLength(int cellLen) + { + cellLength = cellLen; + } + + /** + * This method sets the cell spacing. + * + * @param cellSpace The cell spacing. + */ + protected void setCellSpacing(int cellSpace) + { + cellSpacing = cellSpace; + } + + /** + * This method starts the animation timer. It is called + * when the propertyChangeListener detects that the progressBar + * has changed to indeterminate mode. + */ + protected void startAnimationTimer() + { + if (animationTimer != null) + animationTimer.start(); + } + + /** + * This method stops the animation timer. It is called when + * the propertyChangeListener detects that the progressBar + * has changed to determinate mode. + */ + protected void stopAnimationTimer() + { + if (animationTimer != null) + animationTimer.stop(); + setAnimationIndex(0); + } + + /** + * This method changes the settings for the progressBar to + * the defaults provided by the current Look and Feel. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + progressBar.setFont(defaults.getFont("ProgressBar.font")); + progressBar.setForeground(defaults.getColor("ProgressBar.foreground")); + progressBar.setBackground(defaults.getColor("ProgressBar.background")); + progressBar.setBorder(defaults.getBorder("ProgressBar.border")); + + selectionForeground = defaults.getColor("ProgressBar.selectionForeground"); + selectionBackground = defaults.getColor("ProgressBar.selectionBackground"); + cellLength = defaults.getInt("ProgressBar.cellLength"); + cellSpacing = defaults.getInt("ProgressBar.cellSpacing"); + + int repaintInterval = defaults.getInt("ProgressBar.repaintInterval"); + int cycleTime = defaults.getInt("ProgressBar.cycleTime"); + + if (cycleTime % repaintInterval != 0 + && (cycleTime / repaintInterval) % 2 != 0) + { + int div = (cycleTime / repaintInterval) + 2; + div /= 2; + div *= 2; + cycleTime = div * repaintInterval; + } + setAnimationIndex(0); + numFrames = cycleTime / repaintInterval; + animationTimer.setDelay(repaintInterval); + } + + /** + * The method uninstalls any defaults that were + * set by the current Look and Feel. + */ + protected void uninstallDefaults() + { + progressBar.setFont(null); + progressBar.setForeground(null); + progressBar.setBackground(null); + + selectionForeground = null; + selectionBackground = null; + } + + /** + * This method registers listeners to all the + * components that this UI delegate needs to listen to. + */ + protected void installListeners() + { + changeListener = new ChangeHandler(); + propertyListener = new PropertyChangeHandler(); + animation = new Animator(); + + progressBar.addChangeListener(changeListener); + progressBar.addPropertyChangeListener(propertyListener); + animationTimer.addActionListener(animation); + } + + /** + * This method unregisters listeners to all the + * components that were listened to. + */ + protected void uninstallListeners() + { + progressBar.removeChangeListener(changeListener); + progressBar.removePropertyChangeListener(propertyListener); + animationTimer.removeActionListener(animation); + + changeListener = null; + propertyListener = null; + animation = null; + } + + /** + * This method installs the UI for the given JComponent. + * This includes setting up defaults and listeners as + * well as initializing any values or objects that + * the UI may need. + * + * @param c The JComponent that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JProgressBar) + { + progressBar = (JProgressBar) c; + + animationTimer = new Timer(); + animationTimer.setRepeats(true); + + installDefaults(); + installListeners(); + } + } + + /** + * This method removes the UI for the given JComponent. + * This includes removing any listeners or defaults + * that the installUI may have set up. + * + * @param c The JComponent that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + uninstallListeners(); + uninstallDefaults(); + + animationTimer = null; + progressBar = null; + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/javax/swing/plaf/basic/BasicScrollBarUI.java new file mode 100644 index 00000000000..2e9f76d2e5f --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -0,0 +1,1397 @@ +/* BasicScrollBarUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.LayoutManager; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.swing.BoundedRangeModel; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.ScrollBarUI; + + +/** + * The Basic Look and Feel UI delegate for JScrollBar. + */ +public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, + SwingConstants +{ + /** + * A helper class that listens to the two JButtons on each end + * of the JScrollBar. + */ + protected class ArrowButtonListener extends MouseAdapter + { + /** + * Move the thumb in the direction specified by the + * button's arrow. If this button is held down, then + * it should keep moving the thumb. + * + * @param e The MouseEvent fired by the JButton. + */ + public void mousePressed(MouseEvent e) + { + scrollTimer.stop(); + scrollListener.setScrollByBlock(false); + if (e.getSource() == incrButton) + scrollListener.setDirection(POSITIVE_SCROLL); + else + scrollListener.setDirection(NEGATIVE_SCROLL); + scrollTimer.start(); + } + + /** + * Stops the thumb when the JButton is released. + * + * @param e The MouseEvent fired by the JButton. + */ + public void mouseReleased(MouseEvent e) + { + scrollTimer.stop(); + } + } + + /** + * A helper class that listens to the ScrollBar's model + * for ChangeEvents. + */ + protected class ModelListener implements ChangeListener + { + /** + * Called when the model changes. + * + * @param e The ChangeEvent fired by the model. + */ + public void stateChanged(ChangeEvent e) + { + getThumbBounds(); + scrollbar.repaint(); + } + } + + /** + * A helper class that listens to the ScrollBar's properties. + */ + public class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called when one of the ScrollBar's properties change. + * + * @param e The PropertyChangeEvent fired by the ScrollBar. + */ + public void propertyChange(PropertyChangeEvent e) + { + if (e.getPropertyName().equals(JScrollBar.MODEL_CHANGED_PROPERTY)) + { + ((BoundedRangeModel) e.getOldValue()).removeChangeListener(modelListener); + scrollbar.getModel().addChangeListener(modelListener); + getThumbBounds(); + } + else if (e.getPropertyName().equals(JScrollBar.ORIENTATION_CHANGED_PROPERTY)) + { + incrButton.removeMouseListener(buttonListener); + decrButton.removeMouseListener(buttonListener); + incrButton = createIncreaseButton(scrollbar.getOrientation()); + decrButton = createDecreaseButton(scrollbar.getOrientation()); + incrButton.addMouseListener(buttonListener); + decrButton.addMouseListener(buttonListener); + calculatePreferredSize(); + layoutContainer(scrollbar); + } + layoutContainer(scrollbar); + scrollbar.repaint(); + } + } + + /** + * A helper class that listens for events from + * the timer that is used to move the thumb. + */ + protected class ScrollListener implements ActionListener + { + /** The direction the thumb moves in. */ + private transient int direction; + + /** Whether movement will be in blocks. */ + private transient boolean block; + + /** + * Creates a new ScrollListener object. + * The default is scrolling positively with block movement. + */ + public ScrollListener() + { + direction = POSITIVE_SCROLL; + block = true; + } + + /** + * Creates a new ScrollListener object using + * the given direction and block. + * + * @param dir The direction to move in. + * @param block Whether movement will be in blocks. + */ + public ScrollListener(int dir, boolean block) + { + direction = dir; + this.block = block; + } + + /** + * Sets the direction to scroll in. + * + * @param direction The direction to scroll in. + */ + public void setDirection(int direction) + { + this.direction = direction; + } + + /** + * Sets whether scrolling will be done in blocks. + * + * @param block Whether scrolling will be in blocks. + */ + public void setScrollByBlock(boolean block) + { + this.block = block; + } + + /** + * Called every time the timer reaches its interval. + * + * @param e The ActionEvent fired by the timer. + */ + public void actionPerformed(ActionEvent e) + { + if (block) + { + // Only need to check it if it's block scrolling + // We only block scroll if the click occurs + // in the track. + + if (!trackListener.shouldScroll(direction)) + { + trackHighlight = NO_HIGHLIGHT; + scrollbar.repaint(); + return; + } + scrollByBlock(direction); + } + else + scrollByUnit(direction); + } + } + + /** + * Helper class that listens for movement on the track. + */ + protected class TrackListener extends MouseAdapter + implements MouseMotionListener + { + /** The current X coordinate of the mouse. */ + protected int currentMouseX; + + /** The current Y coordinate of the mouse. */ + protected int currentMouseY; + + /** The offset between the current mouse cursor and the + current value of the scrollbar. */ + protected int offset; + + /** + * This method is called when the mouse is being + * dragged. + * + * @param e The MouseEvent given. + */ + public void mouseDragged(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (scrollbar.getValueIsAdjusting()) + { + int value; + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + scrollbar.setValue(value); + } + } + + /** + * This method is called when the mouse is moved. + * + * @param e The MouseEvent given. + */ + public void mouseMoved(MouseEvent e) + { + // Not interested in where the mouse + // is unless it is being dragged. + } + + /** + * This method is called when the mouse is + * pressed. When it is pressed, the thumb should + * move in blocks towards the cursor. + * + * @param e The MouseEvent given. + */ + public void mousePressed(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (value == scrollbar.getValue()) + return; + + if (!thumbRect.contains(e.getPoint())) + { + scrollTimer.stop(); + scrollListener.setScrollByBlock(true); + if (value > scrollbar.getValue()) + { + trackHighlight = INCREASE_HIGHLIGHT; + scrollListener.setDirection(POSITIVE_SCROLL); + } + else + { + trackHighlight = DECREASE_HIGHLIGHT; + scrollListener.setDirection(NEGATIVE_SCROLL); + } + scrollTimer.start(); + } + else + { + // We'd like to keep track of where the cursor + // is inside the thumb. + // This works because the scrollbar's value represents + // "lower" edge of the thumb. The value at which + // the cursor is at must be greater or equal + // to that value. + scrollbar.setValueIsAdjusting(true); + offset = value - scrollbar.getValue(); + } + scrollbar.repaint(); + } + + /** + * This method is called when the mouse is released. + * It should stop movement on the thumb + * + * @param e The MouseEvent given. + */ + public void mouseReleased(MouseEvent e) + { + trackHighlight = NO_HIGHLIGHT; + scrollTimer.stop(); + + if (scrollbar.getValueIsAdjusting()) + scrollbar.setValueIsAdjusting(false); + scrollbar.repaint(); + } + + /** + * A helper method that decides whether we should + * keep scrolling in the given direction. + * + * @param direction The direction to check for. + * + * @return Whether the thumb should keep scrolling. + */ + public boolean shouldScroll (int direction) + { + int value; + if (scrollbar.getOrientation() == HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (direction == POSITIVE_SCROLL) + return (value > scrollbar.getValue()); + else + return (value < scrollbar.getValue()); + } + } + + /** The listener that listens to the JButtons. */ + protected ArrowButtonListener buttonListener; + + /** The listener that listens to the model. */ + protected ModelListener modelListener; + + /** The listener that listens to the scrollbar for property + changes. */ + protected PropertyChangeListener propertyChangeListener; + + /** The listener that listens to the timer. */ + protected ScrollListener scrollListener; + + /** The listener that listens for MouseEvents on the track. */ + protected TrackListener trackListener; + + /** The JButton that decrements the scrollbar's value. */ + protected JButton decrButton; + + /** The JButton that increments the scrollbar's value. */ + protected JButton incrButton; + + /** The dimensions of the maximum thumb size. */ + protected static Dimension maximumThumbSize; + + /** The dimensions of the minimum thumb size. */ + protected static Dimension minimumThumbSize; + + /** The color of the thumb. */ + protected Color thumbColor; + + /** The outer shadow of the thumb. */ + protected Color thumbDarkShadowColor; + + /** The top and left edge color for the thumb. */ + protected Color thumbHighlightColor; + + /** The outer light shadow for the thumb. */ + protected Color thumbLightShadowColor; + + /** The color that is used when the mouse press + occurs in the track. */ + protected Color trackHighlightColor; + + /** The color of the track. */ + protected Color trackColor; + + /** The size and position of the track. */ + protected Rectangle trackRect; + + /** The size and position of the thumb. */ + protected Rectangle thumbRect; + + /** Indicates that the decrease highlight should be painted. */ + protected static int DECREASE_HIGHLIGHT = 1; + + /** Indicates that the increase highlight should be painted. */ + protected static int INCREASE_HIGHLIGHT = 2; + + /** Indicates that no highlight should be painted. */ + protected static int NO_HIGHLIGHT = 0; + + /** Indicates that the scrolling direction is positive. */ + private static int POSITIVE_SCROLL = 1; + + /** Indicates that the scrolling direction is negative. */ + private static int NEGATIVE_SCROLL = -1; + + /** The cached preferred size for the scrollbar. */ + private transient Dimension preferredSize; + + /** The current highlight status. */ + protected int trackHighlight; + + /** FIXME: Use this for something (presumably mouseDragged) */ + protected boolean isDragging; + + /** The timer used to move the thumb when the mouse is held. */ + protected Timer scrollTimer; + + /** The scrollbar this UI is acting for. */ + protected JScrollBar scrollbar; + + /** + * A helper class that allows us to draw icons for + * the JButton. + */ + private class arrowIcon implements Icon + { + /** The polygon that describes the icon. */ + private Polygon arrow; + + /** + * Creates a new arrowIcon object. + * + * @param arrow The polygon that describes the arrow. + */ + public arrowIcon(Polygon arrow) + { + this.arrow = arrow; + } + + /** + * Returns the height of the icon. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 10; + } + + /** + * Returns the width of the icon. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 10; + } + + /** + * Paints the icon. + * + * @param c The Component to paint for. + * @param g The Graphics object to draw with. + * @param x The X coordinate to draw at. + * @param y The Y coordinate to draw at. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + g.translate(x, y); + + Color saved = g.getColor(); + + g.setColor(Color.BLACK); + + g.fillPolygon(arrow); + + g.setColor(saved); + g.translate(-x, -y); + } + } + + /** The Icon that points up. */ + private static Icon upIcon = new arrowIcon(new Polygon(new int[] { 2, 5, 8 }, + new int[] { 7, 3, 7 }, + 3)); + + /** The Icon that points down. */ + private static Icon downIcon = new arrowIcon(new Polygon(new int[] { 2, 5, 8 }, + new int[] { 3, 7, 3 }, + 3)); + + /** The Icon that points left. */ + private static Icon leftIcon = new arrowIcon(new Polygon(new int[] { 7, 3, 7 }, + new int[] { 2, 5, 8 }, + 3)); + + /** The Icon that points right. */ + private static Icon rightIcon = new arrowIcon(new Polygon(new int[] + { + 3, 7, 3 + }, + new int[] + { + 2, 5, 8 + }, 3)); + + /** + * This method adds a component to the layout. + * + * @param name The name to associate with the component that is added. + * @param child The Component to add. + */ + public void addLayoutComponent(String name, Component child) + { + // You should not be adding stuff to this component. + // The contents are fixed. + } + + /** + * This method configures the scrollbar's colors. This can be + * done by looking up the standard colors from the L&F defaults. + */ + protected void configureScrollBarColors() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + trackColor = defaults.getColor("ScrollBar.track"); + trackHighlightColor = defaults.getColor("ScrollBar.trackHighlight"); + thumbColor = defaults.getColor("ScrollBar.thumb"); + thumbHighlightColor = defaults.getColor("ScrollBar.thumbHighlight"); + thumbDarkShadowColor = defaults.getColor("ScrollBar.thumbDarkShadow"); + thumbLightShadowColor = defaults.getColor("ScrollBar.thumbLightShadow"); + } + + /** + * This method creates an ArrowButtonListener. + * + * @return A new ArrowButtonListener. + */ + protected ArrowButtonListener createArrowButtonListener() + { + return new ArrowButtonListener(); + } + + /** + * This method creates a new JButton with the appropriate + * icon for the orientation. + * + * @param orientation The orientation this JButton uses. + * + * @return The increase JButton. + */ + protected JButton createIncreaseButton(int orientation) + { + if (incrButton == null) + incrButton = new JButton(); + if (orientation == SwingConstants.HORIZONTAL) + incrButton.setIcon(rightIcon); + else + incrButton.setIcon(downIcon); + + return incrButton; + } + + /** + * This method creates a new JButton with the appropriate + * icon for the orientation. + * + * @param orientation The orientation this JButton uses. + * + * @return The decrease JButton. + */ + protected JButton createDecreaseButton(int orientation) + { + if (decrButton == null) + decrButton = new JButton(); + if (orientation == SwingConstants.HORIZONTAL) + decrButton.setIcon(leftIcon); + else + decrButton.setIcon(upIcon); + + return decrButton; + } + + /** + * This method creates a new ModelListener. + * + * @return A new ModelListener. + */ + protected ModelListener createModelListener() + { + return new ModelListener(); + } + + /** + * This method creates a new PropertyChangeListener. + * + * @return A new PropertyChangeListener. + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * This method creates a new ScrollListener. + * + * @return A new ScrollListener. + */ + protected ScrollListener createScrollListener() + { + return new ScrollListener(); + } + + /** + * This method creates a new TrackListener. + * + * @return A new TrackListener. + */ + protected TrackListener createTrackListener() + { + return new TrackListener(); + } + + /** + * This method returns a new BasicScrollBarUI. + * + * @param c The JComponent to create a UI for. + * + * @return A new BasicScrollBarUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicScrollBarUI(); + } + + /** + * This method returns the maximum size for this JComponent. + * + * @param c The JComponent to measure the maximum size for. + * + * @return The maximum size for the component. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum thumb size. + * + * @return The maximum thumb size. + */ + protected Dimension getMaximumThumbSize() + { + return maximumThumbSize; + } + + /** + * This method returns the minimum size for this JComponent. + * + * @param c The JComponent to measure the minimum size for. + * + * @return The minimum size for the component. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the minimum thumb size. + * + * @return The minimum thumb size. + */ + protected Dimension getMinimumThumbSize() + { + return minimumThumbSize; + } + + /** + * This method calculates the preferred size since + * calling getPreferredSize() returns a cached value. + */ + private void calculatePreferredSize() + { + int height; + int width; + height = width = 0; + + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + { + width += incrButton.getPreferredSize().getWidth(); + width += decrButton.getPreferredSize().getWidth(); + + width += Math.max(200, scrollbar.getVisibleAmount()); + + height = Math.max(incrButton.getPreferredSize().height, + decrButton.getPreferredSize().height); + height = Math.max(getMinimumThumbSize().height, height); + height = Math.max(20, height); + height = Math.min(getMaximumThumbSize().height, height); + } + else + { + height += incrButton.getPreferredSize().getHeight(); + height += decrButton.getPreferredSize().getHeight(); + + height += Math.max(200, scrollbar.getVisibleAmount()); + + width = Math.max(incrButton.getPreferredSize().width, + decrButton.getPreferredSize().width); + width = Math.max(getMinimumThumbSize().width, width); + width = Math.max(20, width); + width = Math.min(getMaximumThumbSize().width, width); + } + + Insets insets = scrollbar.getInsets(); + + height += insets.top + insets.bottom; + width += insets.left + insets.right; + + preferredSize = new Dimension(width, height); + } + + /** + * This method returns a cached value of the preferredSize. + * The only restrictions are: If the scrollbar is horizontal, the + * height should be the maximum of the height of the JButtons and + * the minimum width of the thumb. For vertical scrollbars, the + * calculation is similar (swap width for height and vice versa). + * + * @param c The JComponent to measure. + * + * @return The preferredSize. + */ + public Dimension getPreferredSize(JComponent c) + { + layoutContainer(scrollbar); + return preferredSize; + } + + /** + * This method returns the thumb's bounds based on the + * current value of the scrollbar. This method updates the + * cached value and returns that. + * + * @return The thumb bounds. + */ + protected Rectangle getThumbBounds() + { + int max = scrollbar.getMaximum(); + int min = scrollbar.getMinimum(); + int value = scrollbar.getValue(); + int extent = scrollbar.getVisibleAmount(); + + if (max == min) + { + thumbRect.x = trackRect.x; + thumbRect.y = trackRect.y; + if (scrollbar.getOrientation() == HORIZONTAL) + { + thumbRect.width = getMinimumThumbSize().width; + thumbRect.height = trackRect.height; + } + else + { + thumbRect.width = trackRect.width; + thumbRect.height = getMinimumThumbSize().height; + } + return thumbRect; + } + + + if (scrollbar.getOrientation() == HORIZONTAL) + { + thumbRect.x = trackRect.x; + thumbRect.x += (value - min) * trackRect.width / (max - min); + thumbRect.y = trackRect.y; + + thumbRect.width = extent * trackRect.width / (max - min); + thumbRect.height = trackRect.height; + } + else + { + thumbRect.x = trackRect.x; + thumbRect.y = trackRect.y + + value * trackRect.height / (max - min); + + thumbRect.width = trackRect.width; + thumbRect.height = extent * trackRect.height / (max - min); + } + return thumbRect; + } + + /** + * This method calculates the bounds of the track. This method + * updates the cached value and returns it. + * + * @return The track's bounds. + */ + protected Rectangle getTrackBounds() + { + SwingUtilities.calculateInnerArea(scrollbar, trackRect); + + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + { + trackRect.width -= incrButton.getPreferredSize().getWidth(); + trackRect.width -= decrButton.getPreferredSize().getWidth(); + + trackRect.x += decrButton.getPreferredSize().getWidth(); + } + else + { + trackRect.height -= incrButton.getPreferredSize().getHeight(); + trackRect.height -= decrButton.getPreferredSize().getHeight(); + + trackRect.y += incrButton.getPreferredSize().getHeight(); + } + return trackRect; + } + + /** + * This method installs any addition Components that + * are a part of or related to this scrollbar. + */ + protected void installComponents() + { + incrButton = createIncreaseButton(scrollbar.getOrientation()); + scrollbar.add(incrButton); + decrButton = createDecreaseButton(scrollbar.getOrientation()); + scrollbar.add(decrButton); + } + + /** + * This method installs the defaults for the scrollbar specified + * by the Basic L&F. + */ + protected void installDefaults() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + scrollbar.setForeground(defaults.getColor("ScrollBar.foreground")); + scrollbar.setBackground(defaults.getColor("ScrollBar.background")); + + scrollbar.setBorder(defaults.getBorder("ScrollBar.border")); + + maximumThumbSize = defaults.getDimension("ScrollBar.maximumThumbSize"); + minimumThumbSize = defaults.getDimension("ScrollBar.minimumThumbSize"); + } + + /** + * This method installs the keyboard actions for the scrollbar. + */ + protected void installKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method installs any listeners for the scrollbar. + * This method also installs listeners for things such as + * the JButtons and the timer. + */ + protected void installListeners() + { + scrollListener = createScrollListener(); + trackListener = createTrackListener(); + buttonListener = createArrowButtonListener(); + modelListener = createModelListener(); + propertyChangeListener = createPropertyChangeListener(); + + scrollbar.addMouseMotionListener(trackListener); + scrollbar.addMouseListener(trackListener); + + incrButton.addMouseListener(buttonListener); + decrButton.addMouseListener(buttonListener); + + scrollbar.addPropertyChangeListener(propertyChangeListener); + scrollbar.getModel().addChangeListener(modelListener); + + scrollTimer.addActionListener(scrollListener); + } + + /** + * This method installs the UI for the component. + * This can include setting up listeners, defaults, + * and components. This also includes initializing any data + * objects. + * + * @param c The JComponent to install. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JScrollBar) + { + scrollbar = (JScrollBar) c; + + trackRect = new Rectangle(); + thumbRect = new Rectangle(); + + scrollTimer = new Timer(); + scrollTimer.setDelay(200); + scrollTimer.setRepeats(true); + + installComponents(); + installListeners(); + installDefaults(); + configureScrollBarColors(); + + calculatePreferredSize(); + layoutContainer(scrollbar); + } + } + + /** + * This method lays out the scrollbar. + * + * @param scrollbarContainer The Container to layout. + */ + public void layoutContainer(Container scrollbarContainer) + { + if (scrollbarContainer instanceof JScrollBar) + { + if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) + layoutHScrollbar((JScrollBar) scrollbarContainer); + else + layoutVScrollbar((JScrollBar) scrollbarContainer); + } + } + + /** + * This method lays out the scrollbar horizontally. + * + * @param sb The JScrollBar to layout. + */ + protected void layoutHScrollbar(JScrollBar sb) + { + // All we have to do is layout the 2 buttons? + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(scrollbar, vr); + + // Update the rectangles. + getTrackBounds(); + getThumbBounds(); + + Dimension incrDims = incrButton.getPreferredSize(); + Dimension decrDims = decrButton.getPreferredSize(); + + decrButton.setBounds(vr.x, vr.y, decrDims.width, trackRect.height); + incrButton.setBounds(trackRect.x + trackRect.width, vr.y, incrDims.width, + trackRect.height); + } + + /** + * This method lays out the scrollbar vertically. + * + * @param sb The JScrollBar to layout. + */ + protected void layoutVScrollbar(JScrollBar sb) + { + Rectangle vr = new Rectangle(); + SwingUtilities.calculateInnerArea(scrollbar, vr); + + // Update rectangles + getTrackBounds(); + getThumbBounds(); + + Dimension incrDims = incrButton.getPreferredSize(); + Dimension decrDims = decrButton.getPreferredSize(); + + decrButton.setBounds(vr.x, vr.y, trackRect.width, decrDims.height); + incrButton.setBounds(vr.x, trackRect.y + trackRect.height, + trackRect.width, incrDims.height); + } + + /** + * This method returns the minimum size required for the layout. + * + * @param scrollbarContainer The Container that is laid out. + * + * @return The minimum size. + */ + public Dimension minimumLayoutSize(Container scrollbarContainer) + { + return preferredLayoutSize(scrollbarContainer); + } + + /** + * This method is called when the component is painted. + * + * @param g The Graphics object to paint with. + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + layoutContainer(scrollbar); + +// Rectangle r = incrButton.getBounds(); +// SwingUtilities.paintComponent(g, incrButton, scrollbar, r.x, r.y, r.width, +// r.height); +// r = decrButton.getBounds(); +// SwingUtilities.paintComponent(g, decrButton, scrollbar, r.x, r.y, r.width, +// r.height); + + paintTrack(g, c, getTrackBounds()); + paintThumb(g, c, getThumbBounds()); + + if (trackHighlight == INCREASE_HIGHLIGHT) + paintIncreaseHighlight(g); + else if (trackHighlight == DECREASE_HIGHLIGHT) + paintDecreaseHighlight(g); + } + + /** + * This method is called when repainting and the mouse is + * pressed in the track. It paints the track below the thumb + * with the trackHighlight color. + * + * @param g The Graphics object to paint with. + */ + protected void paintDecreaseHighlight(Graphics g) + { + Color saved = g.getColor(); + + g.setColor(trackHighlightColor); + if (scrollbar.getOrientation() == HORIZONTAL) + g.fillRect(trackRect.x, trackRect.y, thumbRect.x - trackRect.x, + trackRect.height); + else + g.fillRect(trackRect.x, trackRect.y, trackRect.width, + thumbRect.y - trackRect.y); + g.setColor(saved); + } + + /** + * This method is called when repainting and the mouse is + * pressed in the track. It paints the track above the thumb + * with the trackHighlight color. + * + * @param g The Graphics objet to paint with. + */ + protected void paintIncreaseHighlight(Graphics g) + { + Color saved = g.getColor(); + + g.setColor(trackHighlightColor); + if (scrollbar.getOrientation() == HORIZONTAL) + g.fillRect(thumbRect.x + thumbRect.width, trackRect.y, + trackRect.x + trackRect.width - thumbRect.x - thumbRect.width, + trackRect.height); + else + g.fillRect(trackRect.x, thumbRect.y + thumbRect.height, + trackRect.width, + trackRect.y + trackRect.height - thumbRect.y - + thumbRect.height); + g.setColor(saved); + } + + /** + * This method paints the thumb. + * + * @param g The Graphics object to paint with. + * @param c The Component that is being painted. + * @param thumbBounds The thumb bounds. + */ + protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) + { + Color saved = g.getColor(); + Point x; + Point y; + Point z; + Polygon lines; + + g.setColor(thumbHighlightColor); + x = new Point(thumbBounds.x + 1, thumbBounds.y + 1); + y = new Point(x); + y.translate(thumbBounds.width - 2, 0); + z = new Point(x); + z.translate(0, thumbBounds.height - 2); + + lines = new Polygon(new int[] { x.x, y.x, z.x }, + new int[] { x.y, y.y, z.y }, 3); + + g.drawPolygon(lines); + + g.setColor(thumbLightShadowColor); + x = new Point(thumbBounds.x + thumbBounds.width - 1, + thumbBounds.y + thumbBounds.height - 1); + y = new Point(x); + y.translate(-(thumbBounds.width - 2), 0); + z = new Point(x); + z.translate(0, -(thumbBounds.height - 2)); + + lines = new Polygon(new int[] { x.x, y.x, z.x }, + new int[] { x.y, y.y, z.y }, 3); + g.drawPolygon(lines); + + g.setColor(thumbDarkShadowColor); + x = new Point(thumbBounds.x + thumbBounds.width, + thumbBounds.y + thumbBounds.height); + y = new Point(x); + y.translate(-thumbBounds.width, 0); + z = new Point(x); + z.translate(0, -thumbBounds.height); + + lines = new Polygon(new int[] { x.x, y.x, z.x }, + new int[] { x.y, y.y, z.y }, 3); + g.drawPolygon(lines); + + g.setColor(thumbColor); + g.fillRect(thumbBounds.x, thumbBounds.y, thumbBounds.width, + thumbBounds.height); + + g.setColor(saved); + } + + /** + * This method paints the track. + * + * @param g The Graphics object to paint with. + * @param c The JComponent being painted. + * @param trackBounds The track's bounds. + */ + protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) + { + Color saved = g.getColor(); + g.setColor(trackColor); + g.fill3DRect(trackBounds.x, trackBounds.y, trackBounds.width, + trackBounds.height, false); + g.setColor(saved); + } + + /** + * This method returns the preferred size for the layout. + * + * @param scrollbarContainer The Container to find a size for. + * + * @return The preferred size for the layout. + */ + public Dimension preferredLayoutSize(Container scrollbarContainer) + { + if (scrollbarContainer instanceof JComponent) + return getPreferredSize((JComponent) scrollbarContainer); + else + return null; + } + + /** + * This method removes a child component from the layout. + * + * @param child The child to remove. + */ + public void removeLayoutComponent(Component child) + { + // You should not be removing stuff from this component. + } + + /** + * The method scrolls the thumb by a block in the + * direction specified. + * + * @param direction The direction to scroll. + */ + protected void scrollByBlock(int direction) + { + scrollbar.setValue(scrollbar.getValue() + scrollbar.getBlockIncrement(direction)); + } + + /** + * The method scrolls the thumb by a unit in the + * direction specified. + * + * @param direction The direction to scroll. + */ + protected void scrollByUnit(int direction) + { + scrollbar.setValue(scrollbar.getValue() + scrollbar.getUnitIncrement(direction)); + } + + /** + * This method sets the thumb's bounds. + * + * @param x The X position of the thumb. + * @param y The Y position of the thumb. + * @param width The width of the thumb. + * @param height The height of the thumb. + */ + protected void setThumbBounds(int x, int y, int width, int height) + { + thumbRect.x = x; + thumbRect.y = y; + thumbRect.width = width; + thumbRect.height = height; + } + + /** + * This method uninstalls any components that + * are a part of or related to this scrollbar. + */ + protected void uninstallComponents() + { + scrollbar.remove(incrButton); + scrollbar.remove(decrButton); + incrButton = null; + decrButton = null; + } + + /** + * This method uninstalls any defaults that this + * scrollbar acquired from the Basic L&F defaults. + */ + protected void uninstallDefaults() + { + scrollbar.setForeground(null); + scrollbar.setBackground(null); + scrollbar.setBorder(null); + } + + /** + * This method uninstalls any keyboard + * actions this scrollbar acquired during install. + */ + protected void uninstallKeyboardActions() + { + // FIXME: implement. + } + + /** + * This method uninstalls any listeners that + * were registered during install. + */ + protected void uninstallListeners() + { + scrollTimer.removeActionListener(scrollListener); + + scrollbar.getModel().removeChangeListener(modelListener); + scrollbar.removePropertyChangeListener(propertyChangeListener); + + decrButton.removeMouseListener(buttonListener); + incrButton.removeMouseListener(buttonListener); + + scrollbar.removeMouseListener(trackListener); + scrollbar.removeMouseMotionListener(trackListener); + + propertyChangeListener = null; + modelListener = null; + buttonListener = null; + trackListener = null; + scrollListener = null; + } + + /** + * This method uninstalls the UI. This includes + * removing any defaults, listeners, and components + * that this UI may have initialized. It also nulls + * any instance data. + * + * @param c The Component to uninstall for. + */ + public void uninstallUI(JComponent c) + { + uninstallDefaults(); + uninstallListeners(); + uninstallComponents(); + + scrollTimer = null; + + thumbRect = null; + trackRect = null; + + trackColor = null; + trackHighlightColor = null; + thumbColor = null; + thumbHighlightColor = null; + thumbDarkShadowColor = null; + thumbLightShadowColor = null; + + scrollbar = null; + } + + /** + * This method returns the value in the scrollbar's range given the y + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param yPos The y coordinate to calculate a value for. + * + * @return The value for the y coordinate. + */ + private int valueForYPosition(int yPos) + { + int min = scrollbar.getMinimum(); + int max = scrollbar.getMaximum(); + int len = trackRect.height; + + int value; + + // If the length is 0, you shouldn't be able to even see where the thumb is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + value = ((yPos - trackRect.y) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method returns the value in the scrollbar's range given the x + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param xPos The x coordinate to calculate a value for. + * + * @return The value for the x coordinate. + */ + private int valueForXPosition(int xPos) + { + int min = scrollbar.getMinimum(); + int max = scrollbar.getMaximum(); + int len = trackRect.width; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + value = ((xPos - trackRect.x) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicScrollPaneUI.java b/libjava/javax/swing/plaf/basic/BasicScrollPaneUI.java index 2dac794a23b..4f60fb48dc5 100644 --- a/libjava/javax/swing/plaf/basic/BasicScrollPaneUI.java +++ b/libjava/javax/swing/plaf/basic/BasicScrollPaneUI.java @@ -41,14 +41,14 @@ package javax.swing.plaf.basic; import java.awt.Dimension; import java.awt.Graphics; import javax.swing.JComponent; +import javax.swing.JScrollBar; import javax.swing.JScrollPane; +import javax.swing.ScrollPaneLayout; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ScrollPaneUI; public class BasicScrollPaneUI extends ScrollPaneUI { - int min_w = 50; - int min_h = 50; public static ComponentUI createUI(final JComponent c) { @@ -61,33 +61,25 @@ public class BasicScrollPaneUI extends ScrollPaneUI super.installUI(c); } + public Dimension getMinimumSize(JComponent c) + { + JScrollPane p = (JScrollPane ) c; + ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout(); + return sl.minimumLayoutSize(c); + } public Dimension getPreferredSize(JComponent c) { JScrollPane p = (JScrollPane ) c; - - Dimension d = new Dimension(min_w, - min_h); - - Dimension a = p.getViewport().getPreferredSize(); - - if (a != null) - { - d.width = Math.max(d.width, a.width); - d.height = Math.max(d.height, a.height); - } - - - System.out.println("BasicScrollPaneUI->preff->"+d); - return d; + ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout(); + return sl.preferredLayoutSize(c); } + public void paint(Graphics g, JComponent c) { - System.out.println("BasicScrollPaneUI->paint()->"+c); - - JScrollPane p = (JScrollPane ) c; - p.getViewport().paint(g); + // do nothing; the normal painting-of-children algorithm, along with + // ScrollPaneLayout, does all the relevant work. } } diff --git a/libjava/javax/swing/plaf/basic/BasicSeparatorUI.java b/libjava/javax/swing/plaf/basic/BasicSeparatorUI.java new file mode 100644 index 00000000000..b7df0acb27d --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicSeparatorUI.java @@ -0,0 +1,266 @@ +/* BasicSeparatorUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Dimension; +import java.awt.Color; +import java.awt.Rectangle; +import java.awt.Graphics; +import java.awt.Insets; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SeparatorUI; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.JComponent; +import javax.swing.JSeparator; +import javax.swing.SwingUtilities; + +/** + * The Basic L&F UI delegate for JSeparator. + */ +public class BasicSeparatorUI extends SeparatorUI +{ + /** The shadow color. */ + protected Color shadow; + + /** The highlight color. */ + protected Color highlight; + + /** + * Creates a new UI delegate for the given JComponent. + * + * @param c The JComponent to create a delegate for. + * + * @return A new BasicSeparatorUI. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicSeparatorUI(); + } + + /** + * This method installs the UI for the given JComponent. + * This can include installing defaults, listeners, and + * initializing any instance data. + * + * @param c The JComponent that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + installDefaults(s); + installListeners(s); + } + } + + /** + * Uninstalls the UI for the given JComponent. This + * method reverses what was done when installing + * the UI on the JComponent. + * + * @param c The JComponent that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + uninstallListeners(s); + uninstallDefaults(s); + } + } + + /** + * This method installs the defaults that are given by + * the Basic L&F. + * + * @param s The JSeparator that is being installed. + */ + protected void installDefaults(JSeparator s) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + shadow = defaults.getColor("Separator.shadow"); + highlight = defaults.getColor("Separator.highlight"); + } + + /** + * This method removes the defaults that were given + * by the Basic L&F. + * + * @param s The JSeparator that is being uninstalled. + */ + protected void uninstallDefaults(JSeparator s) + { + shadow = null; + highlight = null; + } + + /** + * This method installs any listeners that need + * to be attached to the JSeparator or any of its + * components. + * + * @param s The JSeparator that is being installed. + */ + protected void installListeners(JSeparator s) + { + // Separators don't receive events. + } + + /** + * This method uninstalls any listeners that + * were installed during the install UI process. + * + * @param s The JSeparator that is being uninstalled. + */ + protected void uninstallListeners(JSeparator s) + { + // Separators don't receive events. + } + + /** + * The separator is made of two lines. The top line will be + * the highlight color (or left line if it's vertical). The bottom + * or right line will be the shadow color. The two lines will + * be centered inside the bounds box. If the separator is horizontal, + * then it will be vertically centered, or if it's vertical, it will + * be horizontally centered. + * + * @param g The Graphics object to paint with + * @param c The JComponent to paint. + */ + public void paint(Graphics g, JComponent c) + { + Rectangle r = new Rectangle(); + SwingUtilities.calculateInnerArea(c, r); + Color saved = g.getColor(); + + int midAB = r.width / 2 + r.x; + int midAD = r.height / 2 + r.y; + + JSeparator s; + if (c instanceof JSeparator) + s = (JSeparator) c; + else + return; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + g.setColor(highlight); + g.drawLine(r.x, midAD, r.x + r.width, midAD); + + g.setColor(shadow); + g.drawLine(r.x, midAD + 1, r.x + r.width, midAD + 1); + } + else + { + g.setColor(highlight); + g.drawLine(midAB, r.y, midAB, r.y + r.height); + + g.setColor(shadow); + g.drawLine(midAB + 1, r.y, midAB + 1, r.y + r.height); + } + } + + /** + * This method returns the preferred size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + Dimension dims = new Dimension(0, 0); + Insets insets = c.getInsets(); + + if (c instanceof JSeparator) + { + JSeparator s = (JSeparator) c; + + if (s.getOrientation() == JSeparator.HORIZONTAL) + { + dims.height = 2; + dims.width = 40; + } + else + { + dims.width = 2; + dims.height = 40; + } + } + dims.width += insets.left + insets.right; + dims.height += insets.top + insets.bottom; + + return dims; + } + + /** + * This method returns the minimum size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + return getPreferredSize(c); + } + + /** + * This method returns the maximum size of the + * JComponent. + * + * @param c The JComponent to measure. + * + * @return The maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + return getPreferredSize(c); + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/javax/swing/plaf/basic/BasicSliderUI.java new file mode 100644 index 00000000000..2ee481e317d --- /dev/null +++ b/libjava/javax/swing/plaf/basic/BasicSliderUI.java @@ -0,0 +1,2213 @@ +/* BasicSliderUI.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.plaf.basic; + +import java.awt.Color; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.MouseEvent; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.Dictionary; +import java.util.Enumeration; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JSlider; +import javax.swing.KeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.BoundedRangeModel; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MouseInputAdapter; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.SliderUI; + + +/** + *

+ * BasicSliderUI.java This is the UI delegate in the Basic look and feel that + * paints JSliders. + *

+ * + *

+ * The UI delegate keeps track of 6 rectangles that place the various parts of + * the JSlider inside the component. + *

+ * + *

+ * The rectangles are organized as follows: + *

+ *
+ *     +-------------------------------------------------------+ <-- focusRect
+ *     |                                                       |
+ *     |  +==+-------------------+==+--------------------+==+<------ contentRect
+ *     |  |  |                   |  |<---thumbRect       |  |  |
+ *     |  |  |    TRACK          |  |                    |<--------- trackRect
+ *     |  |  +-------------------+==+--------------------+  |  |
+ *     |  |  |                                           |  |  |
+ *     |  |  |          TICKS GO HERE                    |<-------- tickRect
+ *     |  |  |                                           |  |  |
+ *     |  +==+-------------------------------------------+==+  |
+ *     |  |  |                                           |  |  |
+ *     |  |  |                                           |  |<----- labelRect
+ *     |  |  |                 LABELS GO HERE            |  |  |
+ *     |  |  |                                           |  |  |
+ *     |  |  |                                           |  |  |
+ *     |  |  |                                           |  |  |
+ *     |  |  |                                           |  |  |
+ *     |  |                                              |  |  |
+ * 
+ * + *

+ * The space between the contentRect and the focusRect are the FocusInsets. + *

+ * + *

+ * The space between the focusRect and the component bounds is the insetCache + * which are the component's insets. + *

+ * + *

+ * The top of the thumb is the top of the contentRect. The trackRect has to be + * as tall as the thumb. + *

+ * + *

+ * The trackRect and tickRect do not start from the left edge of the + * focusRect. They are trackBuffer away from each side of the focusRect. This + * is so that the thumb has room to move. + *

+ * + *

+ * The labelRect does start right against the contentRect's left and right + * edges and it gets all remaining space. + *

+ */ +public class BasicSliderUI extends SliderUI +{ + /** + * Helper class that listens to the {@link JSlider}'s model for changes. + */ + protected class ChangeHandler implements ChangeListener + { + /** + * Called when the slider's model has been altered. The UI delegate should + * recalculate any rectangles that are dependent on the model for their + * positions and repaint. + * + * @param e A static {@link ChangeEvent} passed from the model. + */ + public void stateChanged(ChangeEvent e) + { + // Maximum, minimum, and extent values will be taken + // care of automatically when the slider is repainted. + + // Only thing that needs recalculation is the thumb. + calculateThumbLocation(); + slider.repaint(); + } + } + + /** + * Helper class that listens for resize events. + */ + protected class ComponentHandler extends ComponentAdapter + { + /** + * Called when the size of the component changes. The UI delegate should + * recalculate any rectangles that are dependent on the model for their + * positions and repaint. + * + * @param e A {@link ComponentEvent}. + */ + public void componentResized(ComponentEvent e) + { + calculateGeometry(); + + slider.revalidate(); + slider.repaint(); + } + } + + /** + * Helper class that listens for focus events. + */ + protected class FocusHandler implements FocusListener + { + /** + * Called when the {@link JSlider} has gained focus. It should repaint + * the slider with the focus drawn. + * + * @param e A {@link FocusEvent}. + */ + public void focusGained(FocusEvent e) + { + // FIXME: implement. + } + + /** + * Called when the {@link JSlider} has lost focus. It should repaint the + * slider without the focus drawn. + * + * @param e A {@link FocusEvent}. + */ + public void focusLost(FocusEvent e) + { + // FIXME: implement. + } + } + + /** + * Helper class that listens for changes to the properties of the {@link + * JSlider}. + */ + protected class PropertyChangeHandler implements PropertyChangeListener + { + /** + * Called when one of the properties change. The UI should recalculate any + * rectangles if necessary and repaint. + * + * @param e A {@link PropertyChangeEvent}. + */ + public void propertyChange(PropertyChangeEvent e) + { + // Check for orientation changes. + if (e.getPropertyName().equals(JSlider.ORIENTATION_CHANGED_PROPERTY)) + recalculateIfOrientationChanged(); + else if (e.getPropertyName().equals(JSlider.MODEL_CHANGED_PROPERTY)) + { + BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue(); + oldModel.removeChangeListener(changeListener); + slider.getModel().addChangeListener(changeListener); + calculateThumbLocation(); + } + // elif the componentOrientation changes (this is a bound property, + // just undocumented) we change leftToRightCache. In Sun's + // implementation, the LTR cache changes on a repaint. This is strange + // since there is no need to do so. We could events here and + // update the cache. + + // elif the border/insets change, we recalculateInsets. + slider.repaint(); + } + } + + /** + * Helper class that listens to our swing timer. This class is responsible + * for listening to the timer and moving the thumb in the proper direction + * every interval. + */ + protected class ScrollListener implements ActionListener + { + /** Indicates which direction the thumb should scroll. */ + private transient int direction; + + /** Indicates whether we should scroll in blocks or in units. */ + private transient boolean block; + + /** + * Creates a new ScrollListener object. + */ + public ScrollListener() + { + direction = POSITIVE_SCROLL; + block = false; + } + + /** + * Creates a new ScrollListener object. + * + * @param dir The direction to scroll in. + * @param block If movement will be in blocks. + */ + public ScrollListener(int dir, boolean block) + { + direction = dir; + this.block = block; + } + + /** + * Called every time the swing timer reaches its interval. If the thumb + * needs to move, then this method will move the thumb one block or unit + * in the direction desired. Otherwise, the timer can be stopped. + * + * @param e An {@link ActionEvent}. + */ + public void actionPerformed(ActionEvent e) + { + if (! trackListener.shouldScroll(direction)) + { + scrollTimer.stop(); + return; + } + + if (block) + scrollByBlock(direction); + else + scrollByUnit(direction); + } + + /** + * Sets the direction to scroll in. + * + * @param direction The direction to scroll in. + */ + public void setDirection(int direction) + { + this.direction = direction; + } + + /** + * Sets whether movement will be in blocks. + * + * @param block If movement will be in blocks. + */ + public void setScrollByBlock(boolean block) + { + this.block = block; + } + } + + /** + * Helper class that listens for mouse events. + */ + protected class TrackListener extends MouseInputAdapter + { + /** The current X position of the mouse. */ + protected int currentMouseX; + + /** The current Y position of the mouse. */ + protected int currentMouseY; + + /** The offset between the current slider value + and the cursor's position. */ + protected int offset; + + /** + * Called when the mouse has been dragged. This should find the mouse's + * current position and adjust the value of the {@link JSlider} + * accordingly. + * + * @param e A {@link MouseEvent} + */ + public void mouseDragged(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (slider.getValueIsAdjusting()) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + slider.setValue(value); + } + } + + /** + * Called when the mouse has moved over a component but no buttons have + * been pressed yet. + * + * @param e A {@link MouseEvent} + */ + public void mouseMoved(MouseEvent e) + { + // Don't care that we're moved unless we're dragging. + } + + /** + * Called when the mouse is pressed. When the press occurs on the thumb + * itself, the {@link JSlider} should have its value set to where the + * mouse was pressed. If the press occurs on the track, then the thumb + * should move one block towards the direction of the mouse. + * + * @param e A {@link MouseEvent} + */ + public void mousePressed(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (slider.getSnapToTicks()) + value = findClosestTick(value); + + if (value == slider.getValue()) + return; + + // If the thumb is hit, then we don't need to set the timers to move it. + if (!thumbRect.contains(e.getPoint())) + { + // The mouse has hit some other part of the slider. + // The value moves no matter where in the slider you hit. + if (value > slider.getValue()) + scrollDueToClickInTrack(POSITIVE_SCROLL); + else + scrollDueToClickInTrack(NEGATIVE_SCROLL); + } + else + { + slider.setValueIsAdjusting(true); + offset = value - slider.getValue(); + } + } + + /** + * Called when the mouse is released. This should stop the timer that + * scrolls the thumb. + * + * @param e A {@link MouseEvent} + */ + public void mouseReleased(MouseEvent e) + { + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + if (slider.getValueIsAdjusting()) + { + slider.setValueIsAdjusting(false); + if (slider.getSnapToTicks()) + slider.setValue(findClosestTick(slider.getValue())); + } + if (scrollTimer != null) + scrollTimer.stop(); + } + + /** + * Indicates whether the thumb should scroll in the given direction. + * + * @param direction The direction to check. + * + * @return True if the thumb should move in that direction. + */ + public boolean shouldScroll(int direction) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (direction == POSITIVE_SCROLL) + return (value > slider.getValue()); + else + return (value < slider.getValue()); + } + } + + /** The preferred height of the thumb. */ + private transient int thumbHeight; + + /** The preferred width of the thumb. */ + private transient int thumbWidth; + + /** The preferred height of the tick rectangle. */ + private transient int tickHeight; + + /** Listener for changes from the model. */ + protected ChangeListener changeListener; + + /** Listener for changes to the {@link JSlider}. */ + protected PropertyChangeListener propertyChangeListener; + + /** Listener for the scrollTimer. */ + protected ScrollListener scrollListener; + + /** Listener for component resizing. */ + protected ComponentListener componentListener; + + /** Listener for focus handling. */ + protected FocusListener focusListener; + + /** Listener for mouse events. */ + protected TrackListener trackListener; + + /** The insets between the FocusRectangle and the ContentRectangle. */ + protected Insets focusInsets; + + /** The {@link JSlider}'s insets. */ + protected Insets insetCache; + + /** Rectangle describing content bounds. See diagram above. */ + protected Rectangle contentRect; + + /** Rectangle describing focus bounds. See diagram above. */ + protected Rectangle focusRect; + + /** Rectangle describing the thumb's bounds. See diagram above. */ + protected Rectangle thumbRect; + + /** Rectangle describing the tick bounds. See diagram above. */ + protected Rectangle tickRect; + + /** Rectangle describing the label bounds. See diagram above. */ + protected Rectangle labelRect; + + /** Rectangle describing the track bounds. See diagram above. */ + protected Rectangle trackRect; + + /** FIXME: use this somewhere. */ + public static final int MAX_SCROLL = 2; + + /** FIXME: use this somewhere. */ + public static final int MIN_SCROLL = -2; + + /** A constant describing scrolling towards the minimum. */ + public static final int NEGATIVE_SCROLL = -1; + + /** A constant describing scrolling towards the maximum. */ + public static final int POSITIVE_SCROLL = 1; + + /** The gap between the edges of the contentRect and trackRect. */ + protected int trackBuffer; + + /** Whether this slider is actually drawn left to right. */ + protected boolean leftToRightCache; + + /** A timer that periodically moves the thumb. */ + protected Timer scrollTimer; + + /** A reference to the {@link JSlider} that this UI was created for. */ + protected JSlider slider; + + /** The shadow color. */ + private transient Color shadowColor; + + /** The highlight color. */ + private transient Color highlightColor; + + /** The focus color. */ + private transient Color focusColor; + + /** + * Creates a new Basic look and feel Slider UI. + * + * @param b The {@link JSlider} that this UI was created for. + */ + public BasicSliderUI(JSlider b) + { + super(); + } + + /** + * Gets the shadow color to be used for this slider. The shadow color is the + * color used for drawing the top and left edges of the track. + * + * @return The shadow color. + */ + protected Color getShadowColor() + { + return shadowColor; + } + + /** + * Gets the highlight color to be used for this slider. The highlight color + * is the color used for drawing the bottom and right edges of the track. + * + * @return The highlight color. + */ + protected Color getHighlightColor() + { + return highlightColor; + } + + /** + * Gets the focus color to be used for this slider. The focus color is the + * color used for drawing the focus rectangle when the component gains + * focus. + * + * @return The focus color. + */ + protected Color getFocusColor() + { + return focusColor; + } + + /** + * Factory method to create a BasicSliderUI for the given {@link + * JComponent}, which should be a {@link JSlider}. + * + * @param b The {@link JComponent} a UI is being created for. + * + * @return A BasicSliderUI for the {@link JComponent}. + */ + public static ComponentUI createUI(JComponent b) + { + return new BasicSliderUI((JSlider) b); + } + + /** + * Installs and initializes all fields for this UI delegate. Any properties + * of the UI that need to be initialized and/or set to defaults will be + * done now. It will also install any listeners necessary. + * + * @param c The {@link JComponent} that is having this UI installed. + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JSlider) + { + slider = (JSlider) c; + + focusRect = new Rectangle(); + contentRect = new Rectangle(); + thumbRect = new Rectangle(); + trackRect = new Rectangle(); + tickRect = new Rectangle(); + labelRect = new Rectangle(); + + insetCache = slider.getInsets(); + leftToRightCache = ! slider.getInverted(); + + scrollTimer = new Timer(); + scrollTimer.setDelay(200); + scrollTimer.setRepeats(true); + + installDefaults(slider); + installListeners(slider); + installKeyboardActions(slider); + + calculateFocusRect(); + + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + } + + /** + * Performs the opposite of installUI. Any properties or resources that need + * to be cleaned up will be done now. It will also uninstall any listeners + * it has. In addition, any properties of this UI will be nulled. + * + * @param c The {@link JComponent} that is having this UI uninstalled. + */ + public void uninstallUI(JComponent c) + { + super.uninstallUI(c); + + uninstallKeyboardActions(slider); + uninstallListeners(slider); + + scrollTimer = null; + + focusRect = null; + contentRect = null; + thumbRect = null; + trackRect = null; + tickRect = null; + labelRect = null; + + focusInsets = null; + } + + /** + * Initializes any default properties that this UI has from the defaults for + * the Basic look and feel. + * + * @param slider The {@link JSlider} that is having this UI installed. + */ + protected void installDefaults(JSlider slider) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + slider.setForeground(defaults.getColor("Slider.foreground")); + slider.setBackground(defaults.getColor("Slider.background")); + shadowColor = defaults.getColor("Slider.shadow"); + highlightColor = defaults.getColor("Slider.highlight"); + focusColor = defaults.getColor("Slider.focus"); + slider.setBorder(defaults.getBorder("Slider.border")); + + thumbHeight = defaults.getInt("Slider.thumbHeight"); + thumbWidth = defaults.getInt("Slider.thumbWidth"); + tickHeight = defaults.getInt("Slider.tickHeight"); + + focusInsets = defaults.getInsets("Slider.focusInsets"); + } + + /** + * Creates a new {@link TrackListener}. + * + * @param slider The {@link JSlider} that this {@link TrackListener} is + * created for. + * + * @return A new {@link TrackListener}. + */ + protected TrackListener createTrackListener(JSlider slider) + { + return new TrackListener(); + } + + /** + * Creates a new {@link ChangeListener}. + * + * @param slider The {@link JSlider} that this {@link ChangeListener} is + * created for. + * + * @return A new {@link ChangeListener}. + */ + protected ChangeListener createChangeListener(JSlider slider) + { + return new ChangeHandler(); + } + + /** + * Creates a new {@link ComponentListener}. + * + * @param slider The {@link JSlider} that this {@link ComponentListener} is + * created for. + * + * @return A new {@link ComponentListener}. + */ + protected ComponentListener createComponentListener(JSlider slider) + { + return new ComponentHandler(); + } + + /** + * Creates a new {@link FocusListener}. + * + * @param slider The {@link JSlider} that this {@link FocusListener} is + * created for. + * + * @return A new {@link FocusListener}. + */ + protected FocusListener createFocusListener(JSlider slider) + { + return new FocusHandler(); + } + + /** + * Creates a new {@link ScrollListener}. + * + * @param slider The {@link JSlider} that this {@link ScrollListener} is + * created for. + * + * @return A new {@link ScrollListener}. + */ + protected ScrollListener createScrollListener(JSlider slider) + { + return new ScrollListener(); + } + + /** + * Creates a new {@link PropertyChangeListener}. + * + * @param slider The {@link JSlider} that this {@link + * PropertyChangeListener} is created for. + * + * @return A new {@link PropertyChangeListener}. + */ + protected PropertyChangeListener createPropertyChangeListener(JSlider slider) + { + return new PropertyChangeHandler(); + } + + /** + * Creates and registers all the listeners for this UI delegate. This + * includes creating the ScrollListener and registering it to the timer. + * + * @param slider The {@link JSlider} is having listeners installed. + */ + protected void installListeners(JSlider slider) + { + propertyChangeListener = createPropertyChangeListener(slider); + componentListener = createComponentListener(slider); + trackListener = createTrackListener(slider); + focusListener = createFocusListener(slider); + changeListener = createChangeListener(slider); + scrollListener = createScrollListener(slider); + + slider.addPropertyChangeListener(propertyChangeListener); + slider.addComponentListener(componentListener); + slider.addMouseListener(trackListener); + slider.addMouseMotionListener(trackListener); + slider.addFocusListener(focusListener); + slider.getModel().addChangeListener(changeListener); + + scrollTimer.addActionListener(scrollListener); + } + + /** + * Unregisters all the listeners that this UI delegate was using. In + * addition, it will also null any listeners that it was using. + * + * @param slider The {@link JSlider} that is having listeners removed. + */ + protected void uninstallListeners(JSlider slider) + { + slider.removePropertyChangeListener(propertyChangeListener); + slider.removeComponentListener(componentListener); + slider.removeMouseListener(trackListener); + slider.removeMouseMotionListener(trackListener); + slider.removeFocusListener(focusListener); + slider.getModel().removeChangeListener(changeListener); + + scrollTimer.removeActionListener(scrollListener); + + propertyChangeListener = null; + componentListener = null; + trackListener = null; + focusListener = null; + changeListener = null; + scrollListener = null; + } + + /** + * Installs any keyboard actions. The list of keys that need to be bound are + * listed in Basic look and feel's defaults. + * + * @param slider The {@link JSlider} that is having keyboard actions + * installed. + */ + protected void installKeyboardActions(JSlider slider) + { + // FIXME: implement. + } + + /** + * Uninstalls any keyboard actions. The list of keys used are listed in + * Basic look and feel's defaults. + * + * @param slider The {@link JSlider} that is having keyboard actions + * uninstalled. + */ + protected void uninstallKeyboardActions(JSlider slider) + { + // FIXME: implement. + } + + /* XXX: This is all after experimentation with SUN's implementation. + + PreferredHorizontalSize seems to be 200x21. + PreferredVerticalSize seems to be 21x200. + + MinimumHorizontalSize seems to be 36x21. + MinimumVerticalSize seems to be 21x36. + + PreferredSize seems to be 200x63. Or Components.getBounds? + + MinimumSize seems to be 36x63. + + MaximumSize seems to be 32767x63. + */ + + /** + * This method returns the preferred size when the slider is + * horizontally oriented. + * + * @return The dimensions of the preferred horizontal size. + */ + public Dimension getPreferredHorizontalSize() + { + Insets insets = slider.getInsets(); + + // The width should cover all the labels (which are usually the + // deciding factor of the width) + int width = getWidthOfWidestLabel() * (slider.getLabelTable() == null ? + 0 : slider.getLabelTable().size()); + + // If there are not enough labels. + // This number is pretty much arbitrary, but it looks nice. + if (width < 200) + width = 200; + + // We can only draw inside of the focusRectangle, so we have to + // pad it with insets. + width += insets.left + insets.right + focusInsets.left + + focusInsets.right; + + // Height is determined by the thumb, the ticks and the labels. + int height = thumbHeight; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 || + slider.getMinorTickSpacing() > 0) + height += tickHeight; + + if (slider.getPaintLabels()) + height += getHeightOfTallestLabel(); + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + return new Dimension(width, height); + } + + /** + * This method returns the preferred size when the slider is + * vertically oriented. + * + * @return The dimensions of the preferred vertical size. + */ + public Dimension getPreferredVerticalSize() + { + Insets insets = slider.getInsets(); + + int height = getHeightOfTallestLabel() * (slider.getLabelTable() == null ? + 0 : slider.getLabelTable().size()); + + if (height < 200) + height = 200; + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + int width = thumbHeight; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 || + slider.getMinorTickSpacing() > 0) + width += tickHeight; + + if (slider.getPaintLabels()) + width += getWidthOfWidestLabel(); + + width += insets.left + insets.right + focusInsets.left + + focusInsets.right; + + return new Dimension(width, height); + } + + /** + * This method returns the minimum size when the slider is + * horizontally oriented. + * + * @return The dimensions of the minimum horizontal size. + */ + public Dimension getMinimumHorizontalSize() + { + return getPreferredHorizontalSize(); + } + + /** + * This method returns the minimum size of the slider when it + * is vertically oriented. + * + * @return The dimensions of the minimum vertical size. + */ + public Dimension getMinimumVerticalSize() + { + return getPreferredVerticalSize(); + } + + /** + * This method returns the preferred size of the component. If it returns + * null, then it is up to the Layout Manager to give the {@link JComponent} + * a size. + * + * @param c The {@link JComponent} to find the preferred size for. + * + * @return The dimensions of the preferred size. + */ + public Dimension getPreferredSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method returns the minimum size for this {@link JSlider} for this + * look and feel. If it returns null, then it is up to the Layout Manager + * to give the {@link JComponent} a size. + * + * @param c The {@link JComponent} to find the minimum size for. + * + * @return The dimensions of the minimum size. + */ + public Dimension getMinimumSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method returns the maximum size for this {@link JSlider} for this + * look and feel. If it returns null, then it is up to the Layout Manager + * to give the {@link JComponent} a size. + * + * @param c The {@link JComponent} to find a maximum size for. + * + * @return The dimensions of the maximum size. + */ + public Dimension getMaximumSize(JComponent c) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + return getPreferredHorizontalSize(); + else + return getPreferredVerticalSize(); + } + + /** + * This method calculates all the sizes of the rectangles by delegating + * to the helper methods calculateXXXRect. + */ + protected void calculateGeometry() + { + calculateFocusRect(); + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateTickRect(); + calculateLabelRect(); + calculateThumbLocation(); + } + + /** + * This method calculates the size and position of the focusRect. This + * method does not need to be called if the orientation changes. + */ + protected void calculateFocusRect() + { + insetCache = slider.getInsets(); + focusRect = SwingUtilities.calculateInnerArea(slider, focusRect); + + if (focusRect.width < 0) + focusRect.width = 0; + if (focusRect.height < 0) + focusRect.height = 0; + } + + /** + * This method calculates the size but not the position of the thumbRect. It + * must take into account the orientation of the slider. + */ + protected void calculateThumbSize() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + if (thumbWidth > contentRect.width) + thumbRect.width = contentRect.width / 4; + else + thumbRect.width = thumbWidth; + if (thumbHeight > contentRect.height) + thumbRect.height = contentRect.height; + else + thumbRect.height = thumbHeight; + } + else + { + // The thumb gets flipped when inverted, so thumbWidth + // actually is the height and vice versa. + if (thumbWidth > contentRect.height) + thumbRect.height = contentRect.height / 4; + else + thumbRect.height = thumbWidth; + if (thumbHeight > contentRect.width) + thumbRect.width = contentRect.width; + else + thumbRect.width = thumbHeight; + } + } + + /** + * This method calculates the size and position of the contentRect. This + * method does not need to be called if the orientation changes. + */ + protected void calculateContentRect() + { + contentRect.x = focusRect.x + focusInsets.left; + contentRect.y = focusRect.y + focusInsets.top; + contentRect.width = focusRect.width - focusInsets.left - focusInsets.right; + contentRect.height = focusRect.height - focusInsets.top + - focusInsets.bottom; + + if (contentRect.width < 0) + contentRect.width = 0; + if (contentRect.height < 0) + contentRect.height = 0; + } + + /** + * Calculates the position of the thumbRect based on the current value of + * the slider. It must take into account the orientation of the slider. + */ + protected void calculateThumbLocation() + { + int value = slider.getValue(); + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + thumbRect.x = xPositionForValue(value) - thumbRect.width / 2; + thumbRect.y = contentRect.y; + } + else + { + thumbRect.x = contentRect.x; + thumbRect.y = yPositionForValue(value) - thumbRect.height / 2; + } + } + + /** + * Calculates the gap size between the left edge of the contentRect and the + * left edge of the trackRect. + */ + protected void calculateTrackBuffer() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + trackBuffer = thumbRect.width; + else + trackBuffer = thumbRect.height; + } + + /** + * This method returns the size of the thumbRect. + * + * @return The dimensions of the thumb. + */ + protected Dimension getThumbSize() + { + // This is really just the bounds box for the thumb. + // The thumb will actually be pointed (like a rectangle + triangle at bottom) + return thumbRect.getSize(); + } + + /** + * Calculates the size and position of the trackRect. It must take into + * account the orientation of the slider. + */ + protected void calculateTrackRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + trackRect.x = contentRect.x + trackBuffer; + trackRect.y = contentRect.y; + trackRect.width = contentRect.width - 2 * trackBuffer; + trackRect.height = thumbRect.height; + } + else + { + trackRect.x = contentRect.x; + trackRect.y = contentRect.y + trackBuffer; + trackRect.width = thumbRect.width; + trackRect.height = contentRect.height - 2 * trackBuffer; + } + } + + /** + * This method returns the height of the tick area box if the slider is + * horizontal and the width of the tick area box is the slider is vertical. + * It not necessarily how long the ticks will be. If a gap between the edge + * of tick box and the actual tick is desired, then that will need to be + * handled in the tick painting methods. + * + * @return The height (or width if the slider is vertical) of the tick + * rectangle. + */ + protected int getTickLength() + { + return tickHeight; + } + + /** + * This method calculates the size and position of the tickRect. It must + * take into account the orientation of the slider. + */ + protected void calculateTickRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + tickRect.x = trackRect.x; + tickRect.y = trackRect.y + trackRect.height; + tickRect.width = trackRect.width; + tickRect.height = getTickLength(); + + if (tickRect.y + tickRect.height > contentRect.y + contentRect.height) + tickRect.height = contentRect.y + contentRect.height - tickRect.y; + } + else + { + tickRect.x = trackRect.x + trackRect.width; + tickRect.y = trackRect.y; + tickRect.width = getTickLength(); + tickRect.height = trackRect.height; + + if (tickRect.x + tickRect.width > contentRect.x + contentRect.width) + tickRect.width = contentRect.x + contentRect.width - tickRect.x; + } + } + + /** + * This method calculates the size and position of the labelRect. It must + * take into account the orientation of the slider. + */ + protected void calculateLabelRect() + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + labelRect.x = contentRect.x; + labelRect.y = tickRect.y + tickRect.height; + labelRect.width = contentRect.width; + labelRect.height = contentRect.height - labelRect.y; + } + else + { + labelRect.x = tickRect.x + tickRect.width; + labelRect.y = contentRect.y; + labelRect.width = contentRect.width - labelRect.x; + labelRect.height = contentRect.height; + } + } + + /** + * This method returns the width of the widest label in the slider's label + * table. + * + * @return The width of the widest label or 0 if no label table exists. + */ + protected int getWidthOfWidestLabel() + { + int widest = 0; + Component label; + + if (slider.getLabelTable() == null) + return 0; + + for (Enumeration list = slider.getLabelTable().elements(); + list.hasMoreElements();) + { + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + if (label.getWidth() > widest) + widest = label.getWidth(); + } + return widest; + } + + /** + * This method returns the height of the tallest label in the slider's label + * table. + * + * @return The height of the tallest label or 0 if no label table exists. + */ + protected int getHeightOfTallestLabel() + { + int tallest = 0; + Component label; + + if (slider.getLabelTable() == null) + return 0; + + for (Enumeration list = slider.getLabelTable().elements(); + list.hasMoreElements();) + { + Object comp = list.nextElement(); + if (! (comp instanceof Component)) + continue; + label = (Component) comp; + if (label.getHeight() > tallest) + tallest = label.getHeight(); + } + return tallest; + } + + /** + * This method returns the width of the label whose key has the highest + * value. + * + * @return The width of the high value label or 0 if no label table exists. + */ + protected int getWidthOfHighValueLabel() + { + Component highValueLabel = getHighestValueLabel(); + if (highValueLabel != null) + return highValueLabel.getWidth(); + else + return 0; + } + + /** + * This method returns the width of the label whose key has the lowest + * value. + * + * @return The width of the low value label or 0 if no label table exists. + */ + protected int getWidthOfLowValueLabel() + { + Component lowValueLabel = getLowestValueLabel(); + if (lowValueLabel != null) + return lowValueLabel.getWidth(); + else + return 0; + } + + /** + * This method returns the height of the label whose key has the highest + * value. + * + * @return The height of the high value label or 0 if no label table exists. + */ + protected int getHeightOfHighValueLabel() + { + Component highValueLabel = getHighestValueLabel(); + if (highValueLabel != null) + return highValueLabel.getHeight(); + else + return 0; + } + + /** + * This method returns the height of the label whose key has the lowest + * value. + * + * @return The height of the low value label or 0 if no label table exists. + */ + protected int getHeightOfLowValueLabel() + { + Component lowValueLabel = getLowestValueLabel(); + if (lowValueLabel != null) + return lowValueLabel.getHeight(); + else + return 0; + } + + /** + * This method returns whether the slider is to be drawn inverted. + * + * @return True is the slider is to be drawn inverted. + */ + protected boolean drawInverted() + { + return ! (slider.getInverted() ^ leftToRightCache); + } + + /** + * This method returns the label whose key has the lowest value. + * + * @return The low value label or null if no label table exists. + */ + protected Component getLowestValueLabel() + { + Integer key = new Integer(Integer.MAX_VALUE); + Integer tmpKey; + Dictionary labelTable = slider.getLabelTable(); + + if (labelTable == null) + return null; + + for (Enumeration list = labelTable.keys(); list.hasMoreElements();) + { + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() < key.intValue()) + key = tmpKey; + } + Object comp = labelTable.get(key); + if (! (comp instanceof Component)) + return null; + return (Component) comp; + } + + /** + * This method returns the label whose key has the highest value. + * + * @return The high value label or null if no label table exists. + */ + protected Component getHighestValueLabel() + { + Integer key = new Integer(Integer.MIN_VALUE); + Integer tmpKey; + Dictionary labelTable = slider.getLabelTable(); + + if (labelTable == null) + return null; + + for (Enumeration list = labelTable.keys(); list.hasMoreElements();) + { + Object value = list.nextElement(); + if (! (value instanceof Integer)) + continue; + tmpKey = (Integer) value; + if (tmpKey.intValue() > key.intValue()) + key = tmpKey; + } + Object comp = labelTable.get(key); + if (! (comp instanceof Component)) + return null; + return (Component) comp; + } + + /** + * This method is used to paint the {@link JSlider}. It delegates all its + * duties to the various paint methods like paintTicks(), paintTrack(), + * paintThumb(), etc. + * + * @param g The {@link Graphics} object to paint with. + * @param c The {@link JComponent} that is being painted. + */ + public void paint(Graphics g, JComponent c) + { + // FIXME: Move this to propertyChangeEvent handler, when we get those. + leftToRightCache = slider.getComponentOrientation() != ComponentOrientation.RIGHT_TO_LEFT; + // FIXME: This next line is only here because the above line is here. + calculateThumbLocation(); + + if (slider.getPaintTrack()) + paintTrack(g); + if (slider.getPaintTicks()) + paintTicks(g); + if (slider.getPaintLabels()) + paintLabels(g); + + //FIXME: Paint focus. + paintThumb(g); + } + + /** + * This method recalculates any rectangles that need to be recalculated + * after the insets of the component have changed. + */ + protected void recalculateIfInsetsChanged() + { + // Examining a test program shows that either Sun calls private + // methods that we don't know about, or these don't do anything. + calculateFocusRect(); + + calculateContentRect(); + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + + /** + * This method recalculates any rectangles that need to be recalculated + * after the orientation of the slider changes. + */ + protected void recalculateIfOrientationChanged() + { + // Examining a test program shows that either Sun calls private + // methods that we don't know about, or these don't do anything. + calculateThumbSize(); + calculateTrackBuffer(); + calculateTrackRect(); + calculateThumbLocation(); + + calculateTickRect(); + calculateLabelRect(); + } + + /** + * This method is called during a repaint if the slider has focus. It draws + * an outline of the focusRect using the color returned by + * getFocusColor(). + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintFocus(Graphics g) + { + Color saved_color = g.getColor(); + + g.setColor(getFocusColor()); + + g.drawRect(focusRect.x, focusRect.y, focusRect.width, focusRect.height); + + g.setColor(saved_color); + } + + /** + *

+ * This method is called during a repaint if the track is to be drawn. It + * draws a 3D rectangle to represent the track. The track is not the size + * of the trackRect. The top and left edges of the track should be outlined + * with the shadow color. The bottom and right edges should be outlined + * with the highlight color. + *

+ *
+   *    a---d   
+   *    |   |   
+   *    |   |   a------------------------d
+   *    |   |   |                        |
+   *    |   |   b------------------------c
+   *    |   |
+   *    |   |   
+   *    b---c
+   * 
+ * + *

+ * The b-a-d path needs to be drawn with the shadow color and the b-c-d path + * needs to be drawn with the highlight color. + *

+ * + * @param g The {@link Graphics} object to draw with. + */ + public void paintTrack(Graphics g) + { + Color saved_color = g.getColor(); + int width; + int height; + + Point a = new Point(trackRect.x, trackRect.y); + Point b = new Point(a); + Point c = new Point(a); + Point d = new Point(a); + + Polygon high; + Polygon shadow; + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + width = trackRect.width; + height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4; + + a.translate(0, (trackRect.height / 2) - (height / 2)); + b.translate(0, (trackRect.height / 2) + (height / 2)); + c.translate(trackRect.width, (trackRect.height / 2) + (height / 2)); + d.translate(trackRect.width, (trackRect.height / 2) - (height / 2)); + } + else + { + width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4; + height = trackRect.height; + + a.translate((trackRect.width / 2) - (width / 2), 0); + b.translate((trackRect.width / 2) - (width / 2), trackRect.height); + c.translate((trackRect.width / 2) + (width / 2), trackRect.height); + d.translate((trackRect.width / 2) + (width / 2), 0); + } + high = new Polygon(new int[] { b.x, c.x, d.x }, + new int[] { b.y, c.y, d.y }, 3); + shadow = new Polygon(new int[] { b.x, a.x, d.x }, + new int[] { b.y, a.y, d.y }, 3); + + g.setColor(getHighlightColor()); + g.drawPolygon(high); + g.setColor(getShadowColor()); + g.drawPolygon(shadow); + + g.setColor(Color.GRAY); + g.fillRect(a.x + 1, a.y + 1, width - 2, height - 2); + g.setColor(saved_color); + } + + /** + * This method is called during a repaint if the ticks are to be drawn. This + * method must still verify that the majorTickSpacing and minorTickSpacing + * are greater than zero before drawing the ticks. + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintTicks(Graphics g) + { + int max = slider.getMaximum(); + int min = slider.getMinimum(); + int majorSpace = slider.getMajorTickSpacing(); + int minorSpace = slider.getMinorTickSpacing(); + + if (majorSpace > 0) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + double loc = tickRect.x; + double increment = (max == min) ? 0 + : majorSpace * (double) tickRect.width / (max + - min); + if (drawInverted()) + { + loc += tickRect.width; + increment *= -1; + } + for (int i = min; i <= max; i += majorSpace) + { + paintMajorTickForHorizSlider(g, tickRect, (int) loc); + loc += increment; + } + } + else + { + double loc = tickRect.height + tickRect.y; + double increment = (max == min) ? 0 + : -majorSpace * (double) tickRect.height / (max + - min); + if (drawInverted()) + { + loc = tickRect.y; + increment *= -1; + } + for (int i = min; i <= max; i += majorSpace) + { + paintMajorTickForVertSlider(g, tickRect, (int) loc); + loc += increment; + } + } + } + if (minorSpace > 0) + { + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + double loc = tickRect.x; + double increment = (max == min) ? 0 + : minorSpace * (double) tickRect.width / (max + - min); + if (drawInverted()) + { + loc += tickRect.width; + increment *= -1; + } + for (int i = min; i <= max; i += minorSpace) + { + paintMinorTickForHorizSlider(g, tickRect, (int) loc); + loc += increment; + } + } + else + { + double loc = tickRect.height + tickRect.y; + double increment = (max == min) ? 0 + : -minorSpace * (double) tickRect.height / (max + - min); + if (drawInverted()) + { + loc = tickRect.y; + increment *= -1; + } + for (int i = min; i <= max; i += minorSpace) + { + paintMinorTickForVertSlider(g, tickRect, (int) loc); + loc += increment; + } + } + } + } + + /* Minor ticks start at 1/4 of the height (or width) of the tickRect and extend + to 1/2 of the tickRect. + + Major ticks start at 1/4 of the height and extend to 3/4. + */ + + /** + * This method paints a minor tick for a horizontal slider at the given x + * value. x represents the x coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param x The x coordinate to draw the tick at. + */ + protected void paintMinorTickForHorizSlider(Graphics g, + Rectangle tickBounds, int x) + { + int y = tickRect.y + tickRect.height / 4; + + g.drawLine(x, y, x, y + tickRect.height / 4); + } + + /** + * This method paints a major tick for a horizontal slider at the given x + * value. x represents the x coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param x The x coordinate to draw the tick at. + */ + protected void paintMajorTickForHorizSlider(Graphics g, + Rectangle tickBounds, int x) + { + int y = tickRect.y + tickRect.height / 4; + + g.drawLine(x, y, x, y + tickRect.height / 2); + } + + /** + * This method paints a minor tick for a vertical slider at the given y + * value. y represents the y coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param y The y coordinate to draw the tick at. + */ + protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + int x = tickRect.x + tickRect.width / 4; + + g.drawLine(x, y, x + tickRect.width / 4, y); + } + + /** + * This method paints a major tick for a vertical slider at the given y + * value. y represents the y coordinate to paint at. + * + * @param g The {@link Graphics} object to draw with. + * @param tickBounds The tickRect rectangle. + * @param y The y coordinate to draw the tick at. + */ + protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, + int y) + { + int x = tickRect.x + tickRect.width / 4; + + g.drawLine(x, y, x + tickRect.width / 2, y); + } + + /** + * This method paints all the labels from the slider's label table. This + * method must make sure that the label table is not null before painting + * the labels. Each entry in the label table is a (integer, component) + * pair. Every label is painted at the value of the integer. + * + * @param g The {@link Graphics} object to draw with. + */ + public void paintLabels(Graphics g) + { + if (slider.getLabelTable() != null) + { + Dictionary table = slider.getLabelTable(); + Integer tmpKey; + Object key; + Object element; + Component label; + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintHorizontalLabel(g, tmpKey.intValue(), label); + } + } + else + { + for (Enumeration list = table.keys(); list.hasMoreElements();) + { + key = list.nextElement(); + if (! (key instanceof Integer)) + continue; + tmpKey = (Integer) key; + element = table.get(tmpKey); + // We won't paint them if they're not + // JLabels so continue anyway + if (! (element instanceof JLabel)) + continue; + label = (Component) element; + paintVerticalLabel(g, tmpKey.intValue(), label); + } + } + } + } + + /** + * This method paints the label on the horizontal slider at the value + * specified. The value is not a coordinate. It is a value within the range + * of the slider. If the value is not within the range of the slider, this + * method will do nothing. This method should not paint outside the + * boundaries of the labelRect. + * + * @param g The {@link Graphics} object to draw with. + * @param value The value to paint at. + * @param label The label to paint. + */ + protected void paintHorizontalLabel(Graphics g, int value, Component label) + { + // This relies on clipping working properly or we'll end up + // painting all over the place. If our preferred size is ignored, then + // the labels may not fit inside the slider's bounds. Rather than mucking + // with font sizes and possible icon sizes, we'll set the bounds for + // the label and let it get clipped. + + Dimension dim = label.getPreferredSize(); + int w = (int) dim.getWidth(); + int h = (int) dim.getHeight(); + + int max = slider.getMaximum(); + int min = slider.getMinimum(); + + if (value > max || value < min) + return; + + // value + // | + // ------------ + // | | + // | | + // | | + // The label must move w/2 to the right to fit directly under the value. + + + int xpos = xPositionForValue(value) - w / 2; + int ypos = labelRect.y; + + // We want to center the label around the xPositionForValue + // So we use xpos - w / 2. However, if value is min and the label + // is large, we run the risk of going out of bounds. So we bring it back + // to 0 if it becomes negative. + if (xpos < 0) + xpos = 0; + + // If the label + starting x position is greater than + // the x space in the label rectangle, we reset it to the largest + // amount possible in the rectangle. This means ugliness. + if (xpos + w > labelRect.x + labelRect.width) + w = labelRect.x + labelRect.width - xpos; + + // If the label is too tall. We reset it to the height of the label + // rectangle. + if (h > labelRect.height) + h = labelRect.height; + + label.setBounds(xpos, ypos, w, h); + javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + } + + /** + * This method paints the label on the vertical slider at the value + * specified. The value is not a coordinate. It is a value within the range + * of the slider. If the value is not within the range of the slider, this + * method will do nothing. This method should not paint outside the + * boundaries of the labelRect. + * + * @param g The {@link Graphics} object to draw with. + * @param value The value to paint at. + * @param label The label to paint. + */ + protected void paintVerticalLabel(Graphics g, int value, Component label) + { + Dimension dim = label.getPreferredSize(); + int w = (int) dim.getWidth(); + int h = (int) dim.getHeight(); + + int max = slider.getMaximum(); + int min = slider.getMinimum(); + + if (value > max || value < min) + return; + + int xpos = labelRect.x; + int ypos = yPositionForValue(value) - h / 2; + + if (ypos < 0) + ypos = 0; + + if (ypos + h > labelRect.y + labelRect.height) + h = labelRect.y + labelRect.height - ypos; + + if (w > labelRect.width) + w = labelRect.width; + + label.setBounds(xpos, ypos, w, h); + javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds()); + } + + /** + *

+ * This method paints a thumb. There are two types of thumb: + *

+ *
+   *   Vertical         Horizontal
+   *    a---b            a-----b
+   *    |   |            |      \
+   *    e   c            |       c
+   *     \ /             |      /
+   *      d              e-----d
+   *  
+ * + *

+ * In the case of vertical thumbs, we highlight the path b-a-e-d and shadow + * the path b-c-d. In the case of horizontal thumbs, we highlight the path + * c-b-a-e and shadow the path c-d-e. In both cases we fill the path + * a-b-c-d-e before shadows and highlights are drawn. + *

+ * + * @param g The graphics object to paint with + */ + public void paintThumb(Graphics g) + { + Color saved_color = g.getColor(); + + Polygon thumb = new Polygon(); + + Point a = new Point(thumbRect.x, thumbRect.y); + Point b = new Point(a); + Point c = new Point(a); + Point d = new Point(a); + Point e = new Point(a); + + Polygon bright; + Polygon dark; + Polygon all; + + // This will be in X-dimension if the slider is inverted and y if it isn't. + int turnPoint; + + if (slider.getOrientation() == JSlider.HORIZONTAL) + { + turnPoint = thumbRect.height * 3 / 4; + + b.translate(thumbRect.width, 0); + c.translate(thumbRect.width, turnPoint); + d.translate(thumbRect.width / 2, thumbRect.height); + e.translate(0, turnPoint); + + bright = new Polygon(new int[] { b.x, a.x, e.x, d.x }, + new int[] { b.y, a.y, e.y, d.y }, 4); + + dark = new Polygon(new int[] { b.x, c.x, d.x }, + new int[] { b.y, c.y, d.y }, 3); + all = new Polygon(new int[] { a.x + 1, b.x, c.x, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y, d.y + 1, e.y }, 5); + } + else + { + turnPoint = thumbRect.width * 3 / 4; + + b.translate(turnPoint, 0); + c.translate(thumbRect.width, thumbRect.height / 2); + d.translate(turnPoint, thumbRect.height); + e.translate(0, thumbRect.height); + + bright = new Polygon(new int[] { c.x, b.x, a.x, e.x }, + new int[] { c.y, b.y, a.y, e.y }, 4); + + dark = new Polygon(new int[] { c.x, d.x, e.x + 1 }, + new int[] { c.y, d.y, e.y }, 3); + + all = new Polygon(new int[] { a.x + 1, b.x, c.x - 1, d.x, e.x + 1 }, + new int[] { a.y + 1, b.y + 1, c.y, d.y, e.y }, 5); + } + + g.setColor(Color.WHITE); + g.drawPolygon(bright); + + g.setColor(Color.BLACK); + g.drawPolygon(dark); + + g.setColor(Color.GRAY); + g.fillPolygon(all); + + g.setColor(saved_color); + } + + /** + * This method sets the position of the thumbRect. + * + * @param x The new x position. + * @param y The new y position. + */ + public void setThumbLocation(int x, int y) + { + thumbRect.x = x; + thumbRect.y = y; + } + + /** + * This method is used to move the thumb one block in the direction + * specified. If the slider snaps to ticks, this method is responsible for + * snapping it to a tick after the thumb has been moved. + * + * @param direction The direction to move in. + */ + public void scrollByBlock(int direction) + { + // The direction is -1 for backwards and 1 for forwards. + int unit = direction * (slider.getMaximum() - slider.getMinimum()) / 10; + + int moveTo = slider.getValue() + unit; + + if (slider.getSnapToTicks()) + moveTo = findClosestTick(moveTo); + + slider.setValue(moveTo); + } + + /** + * This method is used to move the thumb one unit in the direction + * specified. If the slider snaps to ticks, this method is responsible for + * snapping it to a tick after the thumb has been moved. + * + * @param direction The direction to move in. + */ + public void scrollByUnit(int direction) + { + // The direction is -1 for backwards and 1 for forwards. + int moveTo = slider.getValue() + direction; + + if (slider.getSnapToTicks()) + moveTo = findClosestTick(moveTo); + + slider.setValue(moveTo); + } + + /** + * This method is called when there has been a click in the track and the + * thumb needs to be scrolled on regular intervals. This method is only + * responsible for starting the timer and not for stopping it. + * + * @param dir The direction to move in. + */ + protected void scrollDueToClickInTrack(int dir) + { + scrollTimer.stop(); + + scrollListener.setDirection(dir); + scrollListener.setScrollByBlock(true); + + scrollTimer.start(); + } + + /** + * This method returns the X coordinate for the value passed in. + * + * @param value The value to calculate an x coordinate for. + * + * @return The x coordinate for the value. + */ + protected int xPositionForValue(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int extent = slider.getExtent(); + int len = trackRect.width; + + int xPos = (max == min) ? 0 : (value - min) * len / (max - min); + + if (! drawInverted()) + xPos += trackRect.x; + else + { + xPos = trackRect.width - xPos; + xPos += trackRect.x; + } + return xPos; + } + + /** + * This method returns the y coordinate for the value passed in. + * + * @param value The value to calculate a y coordinate for. + * + * @return The y coordinate for the value. + */ + protected int yPositionForValue(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int extent = slider.getExtent(); + int len = trackRect.height; + + int yPos = (max == min) ? 0 : (value - min) * len / (max - min); + + if (! drawInverted()) + { + yPos = trackRect.height - yPos; + yPos += trackRect.y; + } + else + yPos += trackRect.y; + return yPos; + } + + /** + * This method returns the value in the slider's range given the y + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param yPos The y coordinate to calculate a value for. + * + * @return The value for the y coordinate. + */ + public int valueForYPosition(int yPos) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int len = trackRect.height; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + if (! drawInverted()) + value = ((len - (yPos - trackRect.y)) * (max - min) / len + min); + else + value = ((yPos - trackRect.y) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method returns the value in the slider's range given the x + * coordinate. If the value is out of range, it will return the closest + * legal value. + * + * @param xPos The x coordinate to calculate a value for. + * + * @return The value for the x coordinate. + */ + public int valueForXPosition(int xPos) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int len = trackRect.width; + + int value; + + // If the length is 0, you shouldn't be able to even see where the slider is. + // This really shouldn't ever happen, but just in case, we'll return the middle. + if (len == 0) + return ((max - min) / 2); + + if (! drawInverted()) + value = ((xPos - trackRect.x) * (max - min) / len + min); + else + value = ((len - (xPos - trackRect.x)) * (max - min) / len + min); + + // If this isn't a legal value, then we'll have to move to one now. + if (value > max) + value = max; + else if (value < min) + value = min; + return value; + } + + /** + * This method finds the closest value that has a tick associated with it. + * + * @param value The value to search from. + * + * @return The closest value that has a tick associated with it. + */ + private int findClosestTick(int value) + { + int min = slider.getMinimum(); + int max = slider.getMaximum(); + int majorSpace = slider.getMajorTickSpacing(); + int minorSpace = slider.getMinorTickSpacing(); + + // The default value to return is value + minor or + // value + major. + // Initializing at min - value leaves us with a default + // return value of min, which always has tick marks + // (if ticks are painted). + int minor = min - value; + int major = min - value; + + // If there are no major tick marks or minor tick marks + // e.g. snap is set to true but no ticks are set, then + // we can just return the value. + if (majorSpace <= 0 && minorSpace <= 0) + return value; + + // First check the major ticks. + if (majorSpace > 0) + { + int lowerBound = (value - min) / majorSpace; + int majLower = majorSpace * lowerBound + min; + int majHigher = majorSpace * (lowerBound + 1) + min; + + if (majHigher <= max && majHigher - value <= value - majLower) + major = majHigher - value; + else + major = majLower - value; + } + + if (minorSpace > 0) + { + int lowerBound = value / minorSpace; + int minLower = minorSpace * lowerBound; + int minHigher = minorSpace * (lowerBound + 1); + + if (minHigher <= max && minHigher - value <= value - minLower) + minor = minHigher - value; + else + minor = minLower - value; + } + + // Give preference to minor ticks + if (Math.abs(minor) > Math.abs(major)) + return value + major; + else + return value + minor; + } +} diff --git a/libjava/javax/swing/plaf/basic/BasicViewportUI.java b/libjava/javax/swing/plaf/basic/BasicViewportUI.java index 963747c7343..62e51e114ee 100644 --- a/libjava/javax/swing/plaf/basic/BasicViewportUI.java +++ b/libjava/javax/swing/plaf/basic/BasicViewportUI.java @@ -38,36 +38,110 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.ImageObserver; import javax.swing.JComponent; +import javax.swing.JViewport; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ViewportUI; public class BasicViewportUI extends ViewportUI { - public static ComponentUI createUI(final JComponent c) + ChangeListener changeListener; + Image backingStoreImage; + int backingStoreWidth = -1; + int backingStoreHeight = -1; + + class ChangeHandler implements ChangeListener + { + public void stateChanged(ChangeEvent event) { - return new BasicViewportUI(); + JViewport v = (JViewport)event.source; + v.repaint(); } + } - - public void installUI(final JComponent c) - { - super.installUI(c); - } + void installDefaults(JComponent c) + { + } + + void uninstallDefaults(JComponent c) + { + } + + void installListeners(JComponent c) + { + ((JViewport)c).addChangeListener(changeListener); + } + + void uninstallListeners(JComponent c) + { + ((JViewport)c).removeChangeListener(changeListener); + } + + public BasicViewportUI() + { + changeListener = new ChangeHandler(); + } + + public static ComponentUI createUI(JComponent c) + { + return new BasicViewportUI(); + } + + public void installUI(JComponent c) + { + super.installUI(c); + installListeners(c); + } + + public void uninstallUI(JComponent c) + { + uninstallListeners(c); + } - public Dimension getPreferredSize(JComponent c) - { - Dimension d = new Dimension(100,100); - System.out.println("BasicViewportUI->preff->"+d); - return d; - } + public Dimension getPreferredSize(JComponent c) + { + // FIXME: integrate with Scrollable + Dimension d = new Dimension(100,100); + return d; + } - public void paint(Graphics g, JComponent c) - { - System.out.println("BasicViewportUI->paint->"+c); - } + public void paint(Graphics g, JComponent c) + { + + JViewport v = (JViewport)c; + Component view = v.getView(); + + if (view == null) + return; + + Point pos = v.getViewPosition(); + Rectangle viewBounds = view.getBounds(); + + if (backingStoreImage == null + || backingStoreWidth != viewBounds.width + || backingStoreHeight != viewBounds.height) + { + backingStoreImage = v.createImage(viewBounds.width, viewBounds.height); + backingStoreWidth = viewBounds.width; + backingStoreHeight = viewBounds.height; + } + + Graphics g2 = backingStoreImage.getGraphics(); + view.paint(g2); + g2 = null; + g.drawImage(backingStoreImage, + -pos.x, -pos.y, + (ImageObserver)null); + } } -- cgit v1.2.1