summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/plaf/basic
diff options
context:
space:
mode:
authorMark Wielaard <mark@gcc.gnu.org>2006-08-14 23:12:35 +0000
committerMark Wielaard <mark@gcc.gnu.org>2006-08-14 23:12:35 +0000
commitac1ed908de999523efc36f38e69bca1aadfe0808 (patch)
tree97037d2c09c8384d80531f67ec36a01205df6bdb /libjava/classpath/javax/swing/plaf/basic
parentabab460491408e05ea93fb85e1975296a87df504 (diff)
downloadgcc-ac1ed908de999523efc36f38e69bca1aadfe0808.tar.gz
Imported GNU Classpath 0.92
2006-08-14 Mark Wielaard <mark@klomp.org> Imported GNU Classpath 0.92 * HACKING: Add more importing hints. Update automake version requirement. * configure.ac (gconf-peer): New enable AC argument. Add --disable-gconf-peer and --enable-default-preferences-peer to classpath configure when gconf is disabled. * scripts/makemake.tcl: Set gnu/java/util/prefs/gconf and gnu/java/awt/dnd/peer/gtk to bc. Classify gnu/java/security/Configuration.java as generated source file. * gnu/java/lang/management/VMGarbageCollectorMXBeanImpl.java, gnu/java/lang/management/VMMemoryPoolMXBeanImpl.java, gnu/java/lang/management/VMClassLoadingMXBeanImpl.java, gnu/java/lang/management/VMRuntimeMXBeanImpl.java, gnu/java/lang/management/VMMemoryManagerMXBeanImpl.java, gnu/java/lang/management/VMThreadMXBeanImpl.java, gnu/java/lang/management/VMMemoryMXBeanImpl.java, gnu/java/lang/management/VMCompilationMXBeanImpl.java: New VM stub classes. * java/lang/management/VMManagementFactory.java: Likewise. * java/net/VMURLConnection.java: Likewise. * gnu/java/nio/VMChannel.java: Likewise. * java/lang/Thread.java (getState): Add stub implementation. * java/lang/Class.java (isEnum): Likewise. * java/lang/Class.h (isEnum): Likewise. * gnu/awt/xlib/XToolkit.java (getClasspathTextLayoutPeer): Removed. * javax/naming/spi/NamingManager.java: New override for StackWalker functionality. * configure, sources.am, Makefile.in, gcj/Makefile.in, include/Makefile.in, testsuite/Makefile.in: Regenerated. From-SVN: r116139
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic')
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java50
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java29
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java8
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java99
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java464
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java57
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java174
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java280
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java72
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicListUI.java124
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java26
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java98
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java30
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java28
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java220
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java675
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java78
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java50
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java17
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java1218
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java329
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java19
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java264
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java196
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java309
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java13
26 files changed, 3712 insertions, 1215 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java
index f796d9a730a..781269b2adf 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java
@@ -1,5 +1,5 @@
/* BasicArrowButton.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,7 +42,6 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
-import java.awt.Rectangle;
import javax.swing.ButtonModel;
import javax.swing.JButton;
@@ -86,7 +85,9 @@ public class BasicArrowButton extends JButton implements SwingConstants
transient Color highlight = Color.WHITE;
/**
- * Creates a new <code>BasicArrowButton</code> object.
+ * Creates a new <code>BasicArrowButton</code> object with an arrow pointing
+ * in the specified direction. If the <code>direction</code> is not one of
+ * the specified constants, no arrow is drawn.
*
* @param direction The direction the arrow points in (one of:
* {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}).
@@ -95,6 +96,7 @@ public class BasicArrowButton extends JButton implements SwingConstants
{
super();
setDirection(direction);
+ setFocusable(false);
}
/**
@@ -116,8 +118,7 @@ public class BasicArrowButton extends JButton implements SwingConstants
this.shadow = shadow;
this.darkShadow = darkShadow;
this.highlight = highlight;
- // Mark the button as not closing the popup, we handle this ourselves.
- putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP, Boolean.TRUE);
+ setFocusable(false);
}
/**
@@ -162,28 +163,22 @@ public class BasicArrowButton extends JButton implements SwingConstants
public void paint(Graphics g)
{
super.paint(g);
- Rectangle bounds = getBounds();
- int size = bounds.height / 4;
- int x = bounds.x + (bounds.width - size) / 2;
- int y = (bounds.height - size) / 4;
+
+ int height = getHeight();
+ int size = height / 4;
+
+ int x = (getWidth() - size) / 2;
+ int y = (height - size) / 2;
+
ButtonModel m = getModel();
if (m.isArmed())
{
x++;
y++;
}
+
paintTriangle(g, x, y, size, direction, isEnabled());
}
-
- /** The preferred size for the button. */
- private static final Dimension PREFERRED_SIZE = new Dimension(16, 16);
-
- /** The minimum size for the button. */
- private static final Dimension MINIMUM_SIZE = new Dimension(5, 5);
-
- /** The maximum size for the button. */
- private static final Dimension MAXIMUM_SIZE
- = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
/**
* Returns the preferred size of the arrow button.
@@ -192,7 +187,10 @@ public class BasicArrowButton extends JButton implements SwingConstants
*/
public Dimension getPreferredSize()
{
- return PREFERRED_SIZE;
+ // since Dimension is NOT immutable, we must return a new instance
+ // every time (if we return a cached value, the caller might modify it)
+ // - tests show that the reference implementation does the same.
+ return new Dimension(16, 16);
}
/**
@@ -202,17 +200,23 @@ public class BasicArrowButton extends JButton implements SwingConstants
*/
public Dimension getMinimumSize()
{
- return MINIMUM_SIZE;
+ // since Dimension is NOT immutable, we must return a new instance
+ // every time (if we return a cached value, the caller might modify it)
+ // - tests show that the reference implementation does the same.
+ return new Dimension(5, 5);
}
/**
* Returns the maximum size of the arrow button.
*
- * @return The maximum size.
+ * @return The maximum size (always Integer.MAX_VALUE x Integer.MAX_VALUE).
*/
public Dimension getMaximumSize()
{
- return MAXIMUM_SIZE;
+ // since Dimension is NOT immutable, we must return a new instance
+ // every time (if we return a cached value, the caller might modify it)
+ // - tests show that the reference implementation does the same.
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java
index 89e99a29a31..84895821518 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java
@@ -38,13 +38,17 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
-import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -66,7 +70,23 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
public void propertyChange(PropertyChangeEvent e)
{
- // TODO: What should be done here, if anything?
+ // Store the TextLayout for this in a client property for speed-up
+ // painting of the label.
+ String property = e.getPropertyName();
+ if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
+ || property.equals("font"))
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
+ == null)
+ {
+ AbstractButton b = (AbstractButton) e.getSource();
+ String text = b.getText();
+ if (text == null)
+ text = "";
+ FontRenderContext frc = new FontRenderContext(new AffineTransform(),
+ false, false);
+ TextLayout layout = new TextLayout(text, b.getFont(), frc);
+ b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
+ }
}
protected void checkOpacity(AbstractButton b)
@@ -160,11 +180,14 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
{
AbstractButton button = (AbstractButton) e.getSource();
ButtonModel model = button.getModel();
- if (e.getButton() == MouseEvent.BUTTON1)
+ if (SwingUtilities.isLeftMouseButton(e))
{
// It is important that these transitions happen in this order.
model.setArmed(true);
model.setPressed(true);
+
+ if (! button.isFocusOwner() && button.isRequestFocusEnabled())
+ button.requestFocus();
}
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java
index 0a537c4bdd8..d531133ba26 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java
@@ -442,13 +442,17 @@ public class BasicButtonUI extends ButtonUI
if (b.isEnabled())
{
g.setColor(b.getForeground());
- g.drawString(text, textRect.x, textRect.y + fm.getAscent());
+ // FIXME: Underline mnemonic.
+ BasicGraphicsUtils.drawString(b, g, text, -1, textRect.x,
+ textRect.y + fm.getAscent());
}
else
{
String prefix = getPropertyPrefix();
g.setColor(UIManager.getColor(prefix + "disabledText"));
- g.drawString(text, textRect.x, textRect.y + fm.getAscent());
+ // FIXME: Underline mnemonic.
+ BasicGraphicsUtils.drawString(b, g, text, -1, textRect.x,
+ textRect.y + fm.getAscent());
}
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java
index 2cb1623cbc2..d98fd2afe38 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -62,6 +60,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
import javax.swing.CellRendererPane;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
@@ -241,6 +240,8 @@ public class BasicComboBoxUI extends ComboBoxUI
comboBox.setLayout(createLayoutManager());
comboBox.setFocusable(true);
installKeyboardActions();
+ comboBox.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
+ Boolean.TRUE);
}
}
@@ -288,7 +289,7 @@ public class BasicComboBoxUI extends ComboBoxUI
comboBox.addPropertyChangeListener(propertyChangeListener);
focusListener = createFocusListener();
- editor.addFocusListener(focusListener);
+ comboBox.addFocusListener(focusListener);
itemListener = createItemListener();
comboBox.addItemListener(itemListener);
@@ -542,7 +543,9 @@ public class BasicComboBoxUI extends ComboBoxUI
{
editor.setFont(comboBox.getFont());
if (popupKeyListener != null)
- editor.addKeyListener(popupKeyListener);
+ editor.addKeyListener(popupKeyListener);
+ if (keyListener != null)
+ editor.addKeyListener(keyListener);
comboBox.configureEditor(comboBox.getEditor(),
comboBox.getSelectedItem());
}
@@ -554,6 +557,8 @@ public class BasicComboBoxUI extends ComboBoxUI
{
if (popupKeyListener != null)
editor.removeKeyListener(popupKeyListener);
+ if (keyListener != null)
+ editor.removeKeyListener(keyListener);
}
/**
@@ -571,6 +576,10 @@ public class BasicComboBoxUI extends ComboBoxUI
arrowButton.addMouseListener(popupMouseListener);
if (popupMouseMotionListener != null)
arrowButton.addMouseMotionListener(popupMouseMotionListener);
+
+ // Mark the button as not closing the popup, we handle this ourselves.
+ arrowButton.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
+ Boolean.TRUE);
}
}
@@ -712,18 +721,51 @@ public class BasicComboBoxUI extends ComboBoxUI
return new Dimension(32767, 32767);
}
+ /**
+ * Returns the number of accessible children of the combobox.
+ *
+ * @param c the component (combobox) to check, ignored
+ *
+ * @return the number of accessible children of the combobox
+ */
public int getAccessibleChildrenCount(JComponent c)
- throws NotImplementedException
{
- // FIXME: Need to implement
- return 0;
+ int count = 1;
+ if (comboBox.isEditable())
+ count = 2;
+ return count;
}
+ /**
+ * Returns the accessible child with the specified index.
+ *
+ * @param c the component, this is ignored
+ * @param i the index of the accessible child to return
+ */
public Accessible getAccessibleChild(JComponent c, int i)
- throws NotImplementedException
{
- // FIXME: Need to implement
- return null;
+ Accessible child = null;
+ switch (i)
+ {
+ case 0: // The popup.
+ if (popup instanceof Accessible)
+ {
+ AccessibleContext ctx = ((Accessible) popup).getAccessibleContext();
+ ctx.setAccessibleParent(comboBox);
+ child = (Accessible) popup;
+ }
+ break;
+ case 1: // The editor, if any.
+ if (comboBox.isEditable() && editor instanceof Accessible)
+ {
+ AccessibleContext ctx =
+ ((Accessible) editor).getAccessibleContext();
+ ctx.setAccessibleParent(comboBox);
+ child = (Accessible) editor;
+ }
+ break;
+ }
+ return child;
}
/**
@@ -735,10 +777,11 @@ public class BasicComboBoxUI extends ComboBoxUI
* @return true if the specified key is a navigation key and false otherwis
*/
protected boolean isNavigationKey(int keyCode)
- throws NotImplementedException
{
- // FIXME: Need to implement
- return false;
+ return keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN
+ || keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT
+ || keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_ESCAPE
+ || keyCode == KeyEvent.VK_TAB;
}
/**
@@ -759,7 +802,7 @@ public class BasicComboBoxUI extends ComboBoxUI
protected void selectPreviousPossibleValue()
{
int index = comboBox.getSelectedIndex();
- if (index != 0)
+ if (index > 0)
comboBox.setSelectedIndex(index - 1);
}
@@ -1163,10 +1206,31 @@ public class BasicComboBoxUI extends ComboBoxUI
* Invoked whenever key is pressed while JComboBox is in focus.
*/
public void keyPressed(KeyEvent e)
- throws NotImplementedException
{
- // FIXME: This method calls JComboBox.selectWithKeyChar if the key that
- // was pressed is not a navigation key.
+ if (comboBox.getModel().getSize() != 0 && comboBox.isEnabled())
+ {
+ if (! isNavigationKey(e.getKeyCode()))
+ {
+ if (! comboBox.isEditable())
+ if (comboBox.selectWithKeyChar(e.getKeyChar()))
+ e.consume();
+ }
+ else
+ {
+ if (e.getKeyCode() == KeyEvent.VK_UP && comboBox.isPopupVisible())
+ selectPreviousPossibleValue();
+ else if (e.getKeyCode() == KeyEvent.VK_DOWN)
+ {
+ if (comboBox.isPopupVisible())
+ selectNextPossibleValue();
+ else
+ comboBox.showPopup();
+ }
+ else if (e.getKeyCode() == KeyEvent.VK_ENTER
+ || e.getKeyCode() == KeyEvent.VK_ESCAPE)
+ popup.hide();
+ }
+ }
}
}
@@ -1330,5 +1394,4 @@ public class BasicComboBoxUI extends ComboBoxUI
// FIXME: Need to handle changes in other bound properties.
}
}
-
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java
index ef7a880c2ac..ed916cb5f1a 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java
@@ -1,5 +1,5 @@
/* BasicDirectoryModel.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,35 +40,296 @@ package javax.swing.plaf.basic;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
import java.util.Vector;
import javax.swing.AbstractListModel;
import javax.swing.JFileChooser;
+import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.filechooser.FileSystemView;
/**
- * DOCUMENT ME!
+ * Implements an AbstractListModel for directories where the source
+ * of the files is a JFileChooser object.
+ *
+ * This class is used for sorting and ordering the file list in
+ * a JFileChooser L&F object.
*/
public class BasicDirectoryModel extends AbstractListModel
implements PropertyChangeListener
{
- /** DOCUMENT ME! */
+ /** The list of files itself */
private Vector contents;
- /** DOCUMENT ME! */
- private int directories;
+ /**
+ * The directories in the list.
+ */
+ private Vector directories;
+
+ /**
+ * The files in the list.
+ */
+ private Vector files;
- /** DOCUMENT ME! */
+ /** The listing mode of the associated JFileChooser,
+ either FILES_ONLY, DIRECTORIES_ONLY or FILES_AND_DIRECTORIES */
private int listingMode;
- /** DOCUMENT ME! */
+ /** The JFileCooser associated with this model */
private JFileChooser filechooser;
- /** DOCUMENT ME! */
+ /**
+ * The thread that loads the file view.
+ */
+ private DirectoryLoadThread loadThread;
+
+ /**
+ * This thread is responsible for loading file lists from the
+ * current directory and updating the model.
+ */
+ private class DirectoryLoadThread extends Thread
+ {
+
+ /**
+ * Updates the Swing list model.
+ */
+ private class UpdateSwingRequest
+ implements Runnable
+ {
+
+ private List added;
+ private int addIndex;
+ private List removed;
+ private int removeIndex;
+ private boolean cancel;
+
+ UpdateSwingRequest(List add, int ai, List rem, int ri)
+ {
+ added = add;
+ addIndex = ai;
+ removed = rem;
+ removeIndex = ri;
+ cancel = false;
+ }
+
+ public void run()
+ {
+ if (! cancel)
+ {
+ int numRemoved = removed == null ? 0 : removed.size();
+ int numAdded = added == null ? 0 : added.size();
+ synchronized (contents)
+ {
+ if (numRemoved > 0)
+ contents.removeAll(removed);
+ if (numAdded > 0)
+ contents.addAll(added);
+
+ files = null;
+ directories = null;
+ }
+ if (numRemoved > 0 && numAdded == 0)
+ fireIntervalRemoved(BasicDirectoryModel.this, removeIndex,
+ removeIndex + numRemoved - 1);
+ else if (numRemoved == 0 && numAdded > 0)
+ fireIntervalAdded(BasicDirectoryModel.this, addIndex,
+ addIndex + numAdded - 1);
+ else
+ fireContentsChanged();
+ }
+ }
+
+ void cancel()
+ {
+ cancel = true;
+ }
+ }
+
+ /**
+ * The directory beeing loaded.
+ */
+ File directory;
+
+ /**
+ * Stores all UpdateSwingRequests that are sent to the event queue.
+ */
+ private UpdateSwingRequest pending;
+
+ /**
+ * Creates a new DirectoryLoadThread that loads the specified
+ * directory.
+ *
+ * @param dir the directory to load
+ */
+ DirectoryLoadThread(File dir)
+ {
+ super("Basic L&F directory loader");
+ directory = dir;
+ }
+
+ public void run()
+ {
+ FileSystemView fsv = filechooser.getFileSystemView();
+ File[] files = fsv.getFiles(directory,
+ filechooser.isFileHidingEnabled());
+
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ // Check list for accepted files.
+ Vector accepted = new Vector();
+ for (int i = 0; i < files.length; i++)
+ {
+ if (filechooser.accept(files[i]))
+ accepted.add(files[i]);
+ }
+
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ // Sort list.
+ sort(accepted);
+
+ // Now split up directories from files so that we get the directories
+ // listed before the files.
+ Vector newFiles = new Vector();
+ Vector newDirectories = new Vector();
+ for (Iterator i = accepted.iterator(); i.hasNext();)
+ {
+ File f = (File) i.next();
+ boolean traversable = filechooser.isTraversable(f);
+ if (traversable)
+ newDirectories.add(f);
+ else if (! traversable && filechooser.isFileSelectionEnabled())
+ newFiles.add(f);
+
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ }
+
+ // Build up new file cache. Try to update only the changed elements.
+ // This will be important for actions like adding new files or
+ // directories inside a large file list.
+ Vector newCache = new Vector(newDirectories);
+ newCache.addAll(newFiles);
+
+ int newSize = newCache.size();
+ int oldSize = contents.size();
+ if (newSize < oldSize)
+ {
+ // Check for removed interval.
+ int start = -1;
+ int end = -1;
+ boolean found = false;
+ for (int i = 0; i < newSize && !found; i++)
+ {
+ if (! newCache.get(i).equals(contents.get(i)))
+ {
+ start = i;
+ end = i + oldSize - newSize;
+ found = true;
+ }
+ }
+ if (start >= 0 && end > start
+ && contents.subList(end, oldSize)
+ .equals(newCache.subList(start, newSize)))
+ {
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ Vector removed = new Vector(contents.subList(start, end));
+ UpdateSwingRequest r = new UpdateSwingRequest(null, 0,
+ removed, start);
+ invokeLater(r);
+ newCache = null;
+ }
+ }
+ else if (newSize > oldSize)
+ {
+ // Check for inserted interval.
+ int start = oldSize;
+ int end = newSize;
+ boolean found = false;
+ for (int i = 0; i < oldSize && ! found; i++)
+ {
+ if (! newCache.get(i).equals(contents.get(i)))
+ {
+ start = i;
+ boolean foundEnd = false;
+ for (int j = i; j < newSize && ! foundEnd; j++)
+ {
+ if (newCache.get(j).equals(contents.get(i)))
+ {
+ end = j;
+ foundEnd = true;
+ }
+ }
+ end = i + oldSize - newSize;
+ }
+ }
+ if (start >= 0 && end > start
+ && newCache.subList(end, newSize)
+ .equals(contents.subList(start, oldSize)))
+ {
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ List added = newCache.subList(start, end);
+ UpdateSwingRequest r = new UpdateSwingRequest(added, start,
+ null, 0);
+ invokeLater(r);
+ newCache = null;
+ }
+ }
+
+ // Handle complete list changes (newCache != null).
+ if (newCache != null && ! contents.equals(newCache))
+ {
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+ UpdateSwingRequest r = new UpdateSwingRequest(newCache, 0,
+ contents, 0);
+ invokeLater(r);
+ }
+ }
+
+ /**
+ * Wraps SwingUtilities.invokeLater() and stores the request in
+ * a Vector so that we can still cancel it later.
+ *
+ * @param update the request to invoke
+ */
+ private void invokeLater(UpdateSwingRequest update)
+ {
+ pending = update;
+ SwingUtilities.invokeLater(update);
+ }
+
+ /**
+ * Cancels all pending update requests that might be in the AWT
+ * event queue.
+ */
+ void cancelPending()
+ {
+ if (pending != null)
+ pending.cancel();
+ }
+ }
+
+ /** A Comparator class/object for sorting the file list. */
private Comparator comparator = new Comparator()
{
public int compare(Object o1, Object o2)
@@ -91,14 +352,15 @@ public class BasicDirectoryModel extends AbstractListModel
filechooser.addPropertyChangeListener(this);
listingMode = filechooser.getFileSelectionMode();
contents = new Vector();
+ validateFileCache();
}
/**
- * DOCUMENT ME!
+ * Returns whether a given (File) object is included in the list.
*
- * @param o DOCUMENT ME!
+ * @param o - The file object to test.
*
- * @return DOCUMENT ME!
+ * @return <code>true</code> if the list contains the given object.
*/
public boolean contains(Object o)
{
@@ -106,7 +368,7 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Fires a content change event.
*/
public void fireContentsChanged()
{
@@ -114,80 +376,99 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Returns a Vector of (java.io.File) objects containing
+ * the directories in this list.
*
- * @return DOCUMENT ME!
+ * @return a Vector
*/
public Vector getDirectories()
{
- Vector tmp = new Vector();
- for (int i = 0; i < directories; i++)
- tmp.add(contents.get(i));
- return tmp;
+ // Synchronize this with the UpdateSwingRequest for the case when
+ // contents is modified.
+ synchronized (contents)
+ {
+ Vector dirs = directories;
+ if (dirs == null)
+ {
+ // Initializes this in getFiles().
+ getFiles();
+ dirs = directories;
+ }
+ return dirs;
+ }
}
/**
- * DOCUMENT ME!
+ * Returns the (java.io.File) object at
+ * an index in the list.
*
- * @param index DOCUMENT ME!
- *
- * @return DOCUMENT ME!
+ * @param index The list index
+ * @return a File object
*/
public Object getElementAt(int index)
{
if (index > getSize() - 1)
return null;
- if (listingMode == JFileChooser.FILES_ONLY)
- return contents.get(directories + index);
- else
- return contents.elementAt(index);
+ return contents.elementAt(index);
}
/**
- * DOCUMENT ME!
+ * Returns a Vector of (java.io.File) objects containing
+ * the files in this list.
*
- * @return DOCUMENT ME!
+ * @return a Vector
*/
public Vector getFiles()
{
- Vector tmp = new Vector();
- for (int i = directories; i < getSize(); i++)
- tmp.add(contents.get(i));
- return tmp;
+ synchronized (contents)
+ {
+ Vector f = files;
+ if (f == null)
+ {
+ f = new Vector();
+ Vector d = new Vector(); // Directories;
+ for (Iterator i = contents.iterator(); i.hasNext();)
+ {
+ File file = (File) i.next();
+ if (filechooser.isTraversable(file))
+ d.add(file);
+ else
+ f.add(file);
+ }
+ files = f;
+ directories = d;
+ }
+ return f;
+ }
}
/**
- * DOCUMENT ME!
+ * Returns the size of the list, which only includes directories
+ * if the JFileChooser is set to DIRECTORIES_ONLY.
+ *
+ * Otherwise, both directories and files are included in the count.
*
- * @return DOCUMENT ME!
+ * @return The size of the list.
*/
public int getSize()
{
- if (listingMode == JFileChooser.DIRECTORIES_ONLY)
- return directories;
- else if (listingMode == JFileChooser.FILES_ONLY)
- return contents.size() - directories;
return contents.size();
}
/**
- * DOCUMENT ME!
+ * Returns the index of an (java.io.File) object in the list.
*
- * @param o DOCUMENT ME!
+ * @param o The object - normally a File.
*
- * @return DOCUMENT ME!
+ * @return the index of that object, or -1 if it is not in the list.
*/
public int indexOf(Object o)
{
- if (listingMode == JFileChooser.FILES_ONLY)
- return contents.indexOf(o) - directories;
return contents.indexOf(o);
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Obsoleted method which does nothing.
*/
public void intervalAdded(ListDataEvent e)
{
@@ -195,9 +476,7 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Obsoleted method which does nothing.
*/
public void intervalRemoved(ListDataEvent e)
{
@@ -205,7 +484,7 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Obsoleted method which does nothing.
*/
public void invalidateFileCache()
{
@@ -213,12 +492,16 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Less than, determine the relative order in the list of two files
+ * for sorting purposes.
+ *
+ * The order is: directories < files, and thereafter alphabetically,
+ * using the default locale collation.
*
- * @param a DOCUMENT ME!
- * @param b DOCUMENT ME!
+ * @param a the first file
+ * @param b the second file
*
- * @return DOCUMENT ME!
+ * @return <code>true</code> if a > b, <code>false</code> if a < b.
*/
protected boolean lt(File a, File b)
{
@@ -241,73 +524,66 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Listens for a property change; the change in file selection mode of the
+ * associated JFileChooser. Reloads the file cache on that event.
*
- * @param e DOCUMENT ME!
+ * @param e - A PropertyChangeEvent.
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getPropertyName().equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY))
- listingMode = filechooser.getFileSelectionMode();
+ String property = e.getPropertyName();
+ if (property.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_VIEW_CHANGED_PROPERTY)
+ )
+ {
+ validateFileCache();
+ }
}
/**
- * DOCUMENT ME!
+ * Renames a file - However, does <I>not</I> re-sort the list
+ * or replace the old file with the new one in the list.
*
- * @param oldFile DOCUMENT ME!
- * @param newFile DOCUMENT ME!
+ * @param oldFile The old file
+ * @param newFile The new file name
*
- * @return DOCUMENT ME!
+ * @return <code>true</code> if the rename succeeded
*/
public boolean renameFile(File oldFile, File newFile)
{
- // FIXME: implement
- return false;
+ return oldFile.renameTo( newFile );
}
/**
- * DOCUMENT ME!
+ * Sorts a Vector of File objects.
*
- * @param v DOCUMENT ME!
+ * @param v The Vector to sort.
*/
protected void sort(Vector v)
{
Collections.sort(v, comparator);
- Enumeration e = Collections.enumeration(v);
- Vector tmp = new Vector();
- for (; e.hasMoreElements();)
- tmp.add(e.nextElement());
-
- contents = tmp;
}
/**
- * DOCUMENT ME!
+ * Re-loads the list of files
*/
public void validateFileCache()
{
- contents.clear();
- directories = 0;
- FileSystemView fsv = filechooser.getFileSystemView();
- File[] list = fsv.getFiles(filechooser.getCurrentDirectory(),
- filechooser.isFileHidingEnabled());
-
- if (list == null)
- return;
-
- for (int i = 0; i < list.length; i++)
+ File dir = filechooser.getCurrentDirectory();
+ if (dir != null)
{
- if (list[i] == null)
- continue;
- if (filechooser.accept(list[i]))
- {
- contents.add(list[i]);
- if (filechooser.isTraversable(list[i]))
- directories++;
- }
+ // Cancel all pending requests.
+ if (loadThread != null)
+ {
+ loadThread.interrupt();
+ loadThread.cancelPending();
+ }
+ loadThread = new DirectoryLoadThread(dir);
+ loadThread.start();
}
- sort(contents);
- filechooser.revalidate();
- filechooser.repaint();
}
}
+
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java
index 1356db4aeec..dc1c051225c 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java
@@ -160,6 +160,8 @@ public class BasicFileChooserUI extends FileChooserUI
else
{
File f = new File(filechooser.getCurrentDirectory(), getFileName());
+ if ( selectedDir != null )
+ f = selectedDir;
if (filechooser.isTraversable(f))
{
filechooser.setCurrentDirectory(f);
@@ -266,7 +268,14 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public String getName(File f)
{
- return f.getName();
+ String name = null;
+ if (f != null)
+ {
+ JFileChooser c = getFileChooser();
+ FileSystemView v = c.getFileSystemView();
+ name = v.getSystemDisplayName(f);
+ }
+ return name;
}
/**
@@ -409,7 +418,7 @@ public class BasicFileChooserUI extends FileChooserUI
closeDialog();
}
}
- else
+ else // single click
{
String path = p.toString();
File f = fsv.createFileObject(path);
@@ -436,10 +445,11 @@ public class BasicFileChooserUI extends FileChooserUI
}
lastSelected = path;
parentPath = path.substring(0, path.lastIndexOf("/") + 1);
+
if (f.isFile())
setFileName(path.substring(path.lastIndexOf("/") + 1));
- else if (filechooser.getFileSelectionMode() ==
- JFileChooser.DIRECTORIES_ONLY)
+ else if (filechooser.getFileSelectionMode() !=
+ JFileChooser.FILES_ONLY)
setFileName(path);
}
}
@@ -538,7 +548,7 @@ public class BasicFileChooserUI extends FileChooserUI
}
/**
- * DOCUMENT ME!
+ * Sets the JFileChooser to the selected file on an update
*
* @param e DOCUMENT ME!
*/
@@ -550,9 +560,15 @@ public class BasicFileChooserUI extends FileChooserUI
return;
File file = filechooser.getFileSystemView().createFileObject(f.toString());
if (! filechooser.isTraversable(file))
- filechooser.setSelectedFile(file);
+ {
+ selectedDir = null;
+ filechooser.setSelectedFile(file);
+ }
else
- filechooser.setSelectedFile(null);
+ {
+ selectedDir = file;
+ filechooser.setSelectedFile(null);
+ }
}
}
@@ -752,6 +768,13 @@ public class BasicFileChooserUI extends FileChooserUI
* @see #getUpdateAction()
*/
private UpdateAction updateAction;
+
+ /**
+ * When in FILES_ONLY, mode a directory cannot be selected, so
+ * we save a reference to any it here. This is used to enter
+ * the directory on "Open" when in that mode.
+ */
+ private File selectedDir;
// -- end private --
@@ -874,7 +897,9 @@ public class BasicFileChooserUI extends FileChooserUI
protected void installListeners(JFileChooser fc)
{
propertyChangeListener = createPropertyChangeListener(filechooser);
- filechooser.addPropertyChangeListener(propertyChangeListener);
+ if (propertyChangeListener != null)
+ filechooser.addPropertyChangeListener(propertyChangeListener);
+ fc.addPropertyChangeListener(getModel());
}
/**
@@ -884,8 +909,12 @@ public class BasicFileChooserUI extends FileChooserUI
*/
protected void uninstallListeners(JFileChooser fc)
{
- filechooser.removePropertyChangeListener(propertyChangeListener);
- propertyChangeListener = null;
+ if (propertyChangeListener != null)
+ {
+ filechooser.removePropertyChangeListener(propertyChangeListener);
+ propertyChangeListener = null;
+ }
+ fc.removePropertyChangeListener(getModel());
}
/**
@@ -1046,12 +1075,8 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
{
- return new PropertyChangeListener()
- {
- public void propertyChange(PropertyChangeEvent e)
- {
- }
- };
+ // The RI returns null here, so do we.
+ return null;
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
index 068de345bec..1e84be93282 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
@@ -65,6 +67,14 @@ import javax.swing.SwingUtilities;
public class BasicGraphicsUtils
{
/**
+ * Used as a key for a client property to store cached TextLayouts in. This
+ * is used for speed-up drawing of text in
+ * {@link #drawString(Graphics, String, int, int, int)}.
+ */
+ static final String CACHED_TEXT_LAYOUT =
+ "BasicGraphicsUtils.cachedTextLayout";
+
+ /**
* Constructor. It is utterly unclear why this class should
* be constructable, but this is what the API specification
* says.
@@ -536,6 +546,170 @@ public class BasicGraphicsUtils
g2.fill(underline);
}
+ /**
+ * Draws a string on the specified component.
+ *
+ * @param c the component
+ * @param g the Graphics context
+ * @param text the string
+ * @param underlinedChar the character to be underlined
+ * @param x the X location
+ * @param y the Y location
+ */
+ static void drawString(JComponent c, Graphics g, String text,
+ int underlinedChar, int x, int y)
+ {
+ int index = -1;
+
+ /* It is intentional that lower case is used. In some languages,
+ * the set of lowercase characters is larger than the set of
+ * uppercase ones. Therefore, it is good practice to use lowercase
+ * for such comparisons (which really means that the author of this
+ * code can vaguely remember having read some Unicode techreport
+ * with this recommendation, but is too lazy to look for the URL).
+ */
+ if ((underlinedChar >= 0) || (underlinedChar <= 0xffff))
+ index = text.toLowerCase().indexOf(
+ Character.toLowerCase((char) underlinedChar));
+
+ drawStringUnderlineCharAt(c, g, text, index, x, y);
+ }
+
+
+ /**
+ * Draws a String at the given location, underlining the character
+ * at the specified index. Drawing is performed in the current color
+ * and font of <code>g</code>.
+ *
+ * <p><img src="doc-files/BasicGraphicsUtils-5.png" width="500"
+ * height="100" alt="[An illustration showing how to use the
+ * method]" />
+ *
+ * This is an accelerated version of the method with the same name. It
+ * uses a pre-laid out TextLayout stored in a client property.
+ *
+ * @param c the component that is drawn
+ * @param g the graphics into which the String is drawn.
+ *
+ * @param text the String to draw.
+ *
+ * @param underlinedIndex the index of the underlined character in
+ * <code>text</code>. If <code>underlinedIndex</code> falls
+ * outside the range <code>[0, text.length() - 1]</code>, the
+ * text will be drawn without underlining anything.
+ *
+ * @param x the x coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ *
+ * @param y the y coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ */
+ static void drawStringUnderlineCharAt(JComponent c, Graphics g, String text,
+ int underlinedIndex,
+ int x, int y)
+ {
+ Graphics2D g2;
+ Rectangle2D.Double underline;
+ FontRenderContext frc;
+ FontMetrics fmet;
+ LineMetrics lineMetrics;
+ Font font;
+ TextLayout layout;
+ double underlineX1, underlineX2;
+ boolean drawUnderline;
+ int textLength;
+
+ textLength = text.length();
+ if (textLength == 0)
+ return;
+
+ drawUnderline = (underlinedIndex >= 0) && (underlinedIndex < textLength);
+
+ // FIXME: unfortunately pango and cairo can't agree on metrics
+ // so for the time being we continue to *not* use TextLayouts.
+ if (!(g instanceof Graphics2D)
+ || SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null)
+ {
+ /* Fall-back. This is likely to produce garbage for any text
+ * containing right-to-left (Hebrew or Arabic) characters, even
+ * if the underlined character is left-to-right.
+ */
+ g.drawString(text, x, y);
+ if (drawUnderline)
+ {
+ fmet = g.getFontMetrics();
+ g.fillRect(
+ /* x */ x + fmet.stringWidth(text.substring(0, underlinedIndex)),
+ /* y */ y + fmet.getDescent() - 1,
+ /* width */ fmet.charWidth(text.charAt(underlinedIndex)),
+ /* height */ 1);
+ }
+
+ return;
+ }
+
+ g2 = (Graphics2D) g;
+ font = g2.getFont();
+ frc = g2.getFontRenderContext();
+ lineMetrics = font.getLineMetrics(text, frc);
+ layout = (TextLayout) c.getClientProperty(CACHED_TEXT_LAYOUT);
+ if (layout == null)
+ {
+ layout = new TextLayout(text, font, frc);
+ System.err.println("Unable to use cached TextLayout for: " + text);
+ }
+
+ /* Draw the text. */
+ layout.draw(g2, x, y);
+ if (!drawUnderline)
+ return;
+
+ underlineX1 = x + layout.getLogicalHighlightShape(
+ underlinedIndex, underlinedIndex).getBounds2D().getX();
+ underlineX2 = x + layout.getLogicalHighlightShape(
+ underlinedIndex + 1, underlinedIndex + 1).getBounds2D().getX();
+
+ underline = new Rectangle2D.Double();
+ if (underlineX1 < underlineX2)
+ {
+ underline.x = underlineX1;
+ underline.width = underlineX2 - underlineX1;
+ }
+ else
+ {
+ underline.x = underlineX2;
+ underline.width = underlineX1 - underlineX2;
+ }
+
+
+ underline.height = lineMetrics.getUnderlineThickness();
+ underline.y = lineMetrics.getUnderlineOffset();
+ if (underline.y == 0)
+ {
+ /* Some fonts do not specify an underline offset, although they
+ * actually should do so. In that case, the result of calling
+ * lineMetrics.getUnderlineOffset() will be zero. Since it would
+ * look very ugly if the underline was be positioned immediately
+ * below the baseline, we check for this and move the underline
+ * below the descent, as shown in the following ASCII picture:
+ *
+ * ##### ##### #
+ * # # # #
+ * # # # #
+ * # # # #
+ * ##### ###### ---- baseline (0)
+ * #
+ * #
+ * ------------------###----------- lineMetrics.getDescent()
+ */
+ underline.y = lineMetrics.getDescent();
+ }
+
+ underline.y += y;
+ g2.fill(underline);
+ }
/**
* Draws a rectangle, simulating a dotted stroke by painting only
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
index 23bcdc315ee..8f2181336cb 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -692,17 +691,12 @@ public class BasicInternalFrameUI extends InternalFrameUI
/** The MouseEvent target. */
private transient Component mouseEventTarget;
- /** The component pressed. */
- private transient Component pressedComponent;
+ private Component dragTarget;
- /** The last component entered. */
- private transient Component lastComponentEntered;
-
- /** Used to store/reset lastComponentEntered. */
- private transient Component tempComponent;
-
- /** The number of presses. */
- private transient int pressCount;
+ /**
+ * Indicates if we are currently in a dragging operation or not.
+ */
+ private boolean isDragging;
/**
* This method is called when the mouse enters the glass pane.
@@ -767,7 +761,10 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
public void mousePressed(MouseEvent e)
{
- activateFrame(frame);
+ // Experiments show that this seems to call the
+ // borderListener.mousePressed() method to activate the frame.
+ if (borderListener != null)
+ borderListener.mousePressed(e);
handleEvent(e);
}
@@ -783,149 +780,104 @@ public class BasicInternalFrameUI extends InternalFrameUI
}
/**
- * This method acquires a candidate component to dispatch the MouseEvent to.
+ * This is a helper method that dispatches the GlassPane MouseEvents to the
+ * proper component.
*
- * @param me
- * The MouseEvent to acquire a component for.
+ * @param e the mouse event to be dispatched
*/
- private void acquireComponentForMouseEvent(MouseEvent me)
+ private void handleEvent(MouseEvent e)
{
- int x = me.getX();
- int y = me.getY();
-
- // Find the candidate which should receive this event.
- Component parent = frame.getLayeredPane();
- if (parent == null)
- return;
- Component candidate = null;
- Point p = me.getPoint();
- while (candidate == null && parent != null)
- {
- candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
- if (candidate == null)
- {
- p = SwingUtilities.convertPoint(parent, p.x, p.y,
- parent.getParent());
- parent = parent.getParent();
- }
- }
-
- // If the only candidate we found was the native container itself,
- // don't dispatch any event at all. We only care about the lightweight
- // children here.
- if (candidate == frame.getContentPane())
- candidate = null;
-
- // If our candidate is new, inform the old target we're leaving.
- if (lastComponentEntered != null && lastComponentEntered.isShowing()
- && lastComponentEntered != candidate)
+ // Find candidate component inside the JInternalFrame.
+ Component target = frame.getLayeredPane().findComponentAt(e.getX(),
+ e.getY());
+
+ // Now search upwards to find a component that actually has
+ // a MouseListener attached.
+ while (target != null
+ && target.getMouseListeners().length == 0
+ && target.getMouseMotionListeners().length == 0
+ && target.getMouseWheelListeners().length == 0)
{
- Point tp = SwingUtilities.convertPoint(frame.getContentPane(), x, y,
- lastComponentEntered);
- MouseEvent exited = new MouseEvent(lastComponentEntered,
- MouseEvent.MOUSE_EXITED,
- me.getWhen(), me.getModifiersEx(),
- tp.x, tp.y, me.getClickCount(),
- me.isPopupTrigger(),
- me.getButton());
- tempComponent = lastComponentEntered;
- lastComponentEntered = null;
- tempComponent.dispatchEvent(exited);
+ target = target.getParent();
}
- // If we have a candidate, maybe enter it.
- if (candidate != null)
+ if (target != null)
{
- mouseEventTarget = candidate;
- if (candidate.isLightweight() && candidate.isShowing()
- && candidate != frame.getContentPane()
- && candidate != lastComponentEntered)
- {
- lastComponentEntered = mouseEventTarget;
- Point cp = SwingUtilities.convertPoint(frame.getContentPane(), x,
- y, lastComponentEntered);
- MouseEvent entered = new MouseEvent(lastComponentEntered,
- MouseEvent.MOUSE_ENTERED,
- me.getWhen(),
- me.getModifiersEx(), cp.x,
- cp.y, me.getClickCount(),
- me.isPopupTrigger(),
- me.getButton());
- lastComponentEntered.dispatchEvent(entered);
- }
- }
-
- if (me.getID() == MouseEvent.MOUSE_RELEASED
- || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
- || me.getID() == MouseEvent.MOUSE_DRAGGED)
- // If any of the following events occur while a button is held down,
- // they should be dispatched to the same component to which the
- // original MOUSE_PRESSED event was dispatched:
- // - MOUSE_RELEASED
- // - MOUSE_PRESSED: another button pressed while the first is held down
- // - MOUSE_DRAGGED
- mouseEventTarget = pressedComponent;
- else if (me.getID() == MouseEvent.MOUSE_CLICKED)
- {
- // Don't dispatch CLICKED events whose target is not the same as the
- // target for the original PRESSED event.
- if (candidate != pressedComponent)
- mouseEventTarget = null;
- else if (pressCount == 0)
- pressedComponent = null;
+ int id = e.getID();
+ switch (id)
+ {
+ case MouseEvent.MOUSE_ENTERED:
+ // Now redispatch the thing.
+ if (! isDragging || frame.isSelected())
+ {
+ mouseEventTarget = target;
+ redispatch(id, e, mouseEventTarget);
+ }
+ break;
+ case MouseEvent.MOUSE_EXITED:
+ if (! isDragging || frame.isSelected())
+ {
+ redispatch(id, e, mouseEventTarget);
+ }
+ break;
+ case MouseEvent.MOUSE_PRESSED:
+ mouseEventTarget = target;
+ redispatch(id, e, mouseEventTarget);
+ // Start dragging.
+ dragTarget = target;
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ if (isDragging)
+ {
+ redispatch(id, e, dragTarget);
+ isDragging = false;
+ }
+ else
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_CLICKED:
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_MOVED:
+ if (target != mouseEventTarget)
+ {
+ // Create additional MOUSE_EXITED/MOUSE_ENTERED pairs.
+ redispatch(MouseEvent.MOUSE_EXITED, e, mouseEventTarget);
+ mouseEventTarget = target;
+ redispatch(MouseEvent.MOUSE_ENTERED, e, mouseEventTarget);
+ }
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_DRAGGED:
+ if (! isDragging)
+ isDragging = true;
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_WHEEL:
+ redispatch(id, e, mouseEventTarget);
+ break;
+ default:
+ assert false : "Must not reach here";
+ }
}
}
/**
- * This is a helper method that dispatches the GlassPane MouseEvents to the
- * proper component.
- *
- * @param e
- * The AWTEvent to be dispatched. Usually an instance of
- * MouseEvent.
+ * Redispatches the event to the real target with the specified id.
+ *
+ * @param id the new event ID
+ * @param e the original event
+ * @param target the real event target
*/
- private void handleEvent(AWTEvent e)
+ private void redispatch(int id, MouseEvent e, Component target)
{
- if (e instanceof MouseEvent)
- {
- MouseEvent me = (MouseEvent) e;
- acquireComponentForMouseEvent(me);
-
- //If there is no target, return
- if (mouseEventTarget == null)
- return;
-
- //Avoid re-dispatching to ourselves and causing an infinite loop
- if (mouseEventTarget.equals(frame.getGlassPane()))
- return;
-
- // Avoid dispatching ENTERED and EXITED events twice.
- if (mouseEventTarget.isShowing()
- && e.getID() != MouseEvent.MOUSE_ENTERED
- && e.getID() != MouseEvent.MOUSE_EXITED)
- {
- MouseEvent newEvt = SwingUtilities.convertMouseEvent(
- frame.getGlassPane(),
- me,
- mouseEventTarget);
- mouseEventTarget.dispatchEvent(newEvt);
-
- switch (e.getID())
- {
- case MouseEvent.MOUSE_PRESSED:
- if (pressCount++ == 0)
- pressedComponent = mouseEventTarget;
- break;
- case MouseEvent.MOUSE_RELEASED:
- // Clear our memory of the original PRESSED event, only if
- // we're not expecting a CLICKED event after this. If
- // there is a CLICKED event after this, it will do clean up.
- if (--pressCount == 0 && mouseEventTarget != pressedComponent)
- pressedComponent = null;
- break;
- }
- }
- }
+ Point p = SwingUtilities.convertPoint(frame.getLayeredPane(), e.getX(),
+ e.getY(), target);
+ MouseEvent ev = new MouseEvent(target, id, e.getWhen(),
+ e.getModifiers() | e.getModifiersEx(),
+ p.x, p.y, e.getClickCount(),
+ e.isPopupTrigger());
+ target.dispatchEvent(ev);
}
}
@@ -945,41 +897,61 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
public void propertyChange(PropertyChangeEvent evt)
{
- if (evt.getPropertyName().equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
+ String property = evt.getPropertyName();
+ if (property.equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
{
if (frame.isMaximum())
maximizeFrame(frame);
else
minimizeFrame(frame);
}
- else if (evt.getPropertyName().equals(JInternalFrame.IS_ICON_PROPERTY))
+ else if (property.equals(JInternalFrame.IS_ICON_PROPERTY))
{
if (frame.isIcon())
iconifyFrame(frame);
else
deiconifyFrame(frame);
}
- else if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY))
+ else if (property.equals(JInternalFrame.IS_SELECTED_PROPERTY))
{
+ Component glassPane = frame.getGlassPane();
if (frame.isSelected())
- activateFrame(frame);
+ {
+ activateFrame(frame);
+ glassPane.setVisible(false);
+ }
else
- deactivateFrame(frame);
+ {
+ deactivateFrame(frame);
+ glassPane.setVisible(true);
+ }
}
- else if (evt.getPropertyName().equals(JInternalFrame.ROOT_PANE_PROPERTY)
- || evt.getPropertyName().equals(
- JInternalFrame.GLASS_PANE_PROPERTY))
+ else if (property.equals(JInternalFrame.ROOT_PANE_PROPERTY)
+ || property.equals(JInternalFrame.GLASS_PANE_PROPERTY))
{
Component old = (Component) evt.getOldValue();
- old.removeMouseListener(glassPaneDispatcher);
- old.removeMouseMotionListener(glassPaneDispatcher);
+ if (old != null)
+ {
+ old.removeMouseListener(glassPaneDispatcher);
+ old.removeMouseMotionListener(glassPaneDispatcher);
+ }
Component newPane = (Component) evt.getNewValue();
- newPane.addMouseListener(glassPaneDispatcher);
- newPane.addMouseMotionListener(glassPaneDispatcher);
+ if (newPane != null)
+ {
+ newPane.addMouseListener(glassPaneDispatcher);
+ newPane.addMouseMotionListener(glassPaneDispatcher);
+ }
frame.revalidate();
}
+ else if (property.equals(JInternalFrame.IS_CLOSED_PROPERTY))
+ {
+ if (evt.getNewValue() == Boolean.TRUE)
+ {
+ closeFrame(frame);
+ }
+ }
/*
* FIXME: need to add ancestor properties to JComponents. else if
* (evt.getPropertyName().equals(JComponent.ANCESTOR_PROPERTY)) { if
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
index 60e3a98684f..304e13ad735 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
@@ -1,5 +1,5 @@
/* BasicLabelUI.java
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,20 +37,25 @@
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
import javax.swing.Icon;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
+import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
@@ -369,14 +374,39 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
}
/**
- * This method installs the keyboard actions for the given {@link JLabel}.
+ * Installs the keyboard actions for the given {@link JLabel}.
*
* @param l The {@link JLabel} to install keyboard actions for.
*/
protected void installKeyboardActions(JLabel l)
- throws NotImplementedException
{
- //FIXME: implement.
+ Component c = l.getLabelFor();
+ if (c != null)
+ {
+ int mnemonic = l.getDisplayedMnemonic();
+ if (mnemonic > 0)
+ {
+ // add a keystroke for the given mnemonic mapping to 'press';
+ InputMap keyMap = new InputMap();
+ keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.VK_ALT),
+ "press");
+ SwingUtilities.replaceUIInputMap(l,
+ JComponent.WHEN_IN_FOCUSED_WINDOW, keyMap);
+
+ // add an action to focus the component when 'press' happens
+ ActionMap map = new ActionMap();
+ map.put("press", new AbstractAction() {
+ public void actionPerformed(ActionEvent event)
+ {
+ JLabel label = (JLabel) event.getSource();
+ Component c = label.getLabelFor();
+ if (c != null)
+ c.requestFocus();
+ }
+ });
+ SwingUtilities.replaceUIActionMap(l, map);
+ }
+ }
}
/**
@@ -385,9 +415,10 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
* @param l The {@link JLabel} to uninstall keyboard actions for.
*/
protected void uninstallKeyboardActions(JLabel l)
- throws NotImplementedException
{
- //FIXME: implement.
+ SwingUtilities.replaceUIActionMap(l, null);
+ SwingUtilities.replaceUIInputMap(l, JComponent.WHEN_IN_FOCUSED_WINDOW,
+ null);
}
/**
@@ -426,5 +457,30 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
JLabel l = (JLabel) e.getSource();
BasicHTML.updateRenderer(l, text);
}
+ else if (e.getPropertyName().equals("displayedMnemonic"))
+ {
+ // update the key to action mapping
+ JLabel label = (JLabel) e.getSource();
+ if (label.getLabelFor() != null)
+ {
+ int oldMnemonic = ((Integer) e.getOldValue()).intValue();
+ int newMnemonic = ((Integer) e.getNewValue()).intValue();
+ InputMap keyMap = label.getInputMap(
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ keyMap.put(KeyStroke.getKeyStroke(oldMnemonic,
+ KeyEvent.ALT_DOWN_MASK), null);
+ keyMap.put(KeyStroke.getKeyStroke(newMnemonic,
+ KeyEvent.ALT_DOWN_MASK), "press");
+ }
+ }
+ else if (e.getPropertyName().equals("labelFor"))
+ {
+ JLabel label = (JLabel) e.getSource();
+ InputMap keyMap = label.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ int mnemonic = label.getDisplayedMnemonic();
+ if (mnemonic > 0)
+ keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.ALT_DOWN_MASK),
+ "press");
+ }
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
index 44f6a408984..493fc0578e3 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -61,12 +59,12 @@ import javax.swing.DefaultListSelectionModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JList;
-import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
@@ -76,8 +74,8 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
-import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.ListUI;
+import javax.swing.plaf.UIResource;
/**
* The Basic Look and Feel UI delegate for the
@@ -215,9 +213,26 @@ public class BasicListUI extends ListUI
target.actionPerformed(derivedEvent);
}
}
-
- class ListAction extends AbstractAction
+
+ /**
+ * Implements the action for the JList's keyboard commands.
+ */
+ private class ListAction
+ extends AbstractAction
{
+ // TODO: Maybe make a couple of classes out of this bulk Action.
+ // Form logical groups of Actions when doing this.
+
+ /**
+ * Creates a new ListAction for the specified command.
+ *
+ * @param cmd the actionCommand to set
+ */
+ ListAction(String cmd)
+ {
+ putValue(ACTION_COMMAND_KEY, cmd);
+ }
+
public void actionPerformed(ActionEvent e)
{
int lead = list.getLeadSelectionIndex();
@@ -398,7 +413,7 @@ public class BasicListUI extends ListUI
list.ensureIndexIsVisible(list.getLeadSelectionIndex());
}
}
-
+
/**
* A helper class which listens for {@link MouseEvent}s
* from the {@link JList}.
@@ -464,7 +479,8 @@ public class BasicListUI extends ListUI
*/
public void mousePressed(MouseEvent event)
{
- // TODO: What should be done here, if anything?
+ // We need to explicitly request focus.
+ list.requestFocusInWindow();
}
/**
@@ -992,39 +1008,83 @@ public class BasicListUI extends ListUI
*/
protected void installKeyboardActions()
{
+ // Install UI InputMap.
InputMap focusInputMap = (InputMap) UIManager.get("List.focusInputMap");
- InputMapUIResource parentInputMap = new InputMapUIResource();
- // FIXME: The JDK uses a LazyActionMap for parentActionMap
- ActionMap parentActionMap = new ActionMapUIResource();
- action = new ListAction();
- Object keys[] = focusInputMap.allKeys();
- // Register key bindings in the UI InputMap-ActionMap pair
- for (int i = 0; i < keys.length; i++)
+ SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED,
+ focusInputMap);
+
+ // Install UI ActionMap.
+ ActionMap am = (ActionMap) UIManager.get("List.actionMap");
+ if (am == null)
{
- KeyStroke stroke = (KeyStroke) keys[i];
- String actionString = (String) focusInputMap.get(stroke);
- parentInputMap.put(KeyStroke.getKeyStroke(stroke.getKeyCode(),
- stroke.getModifiers()),
- actionString);
-
- parentActionMap.put(actionString,
- new ActionListenerProxy(action, actionString));
+ // Create the actionMap once and store it in the current UIDefaults
+ // for use in other components.
+ am = new ActionMapUIResource();
+ ListAction action;
+ action = new ListAction("selectPreviousRow");
+ am.put("selectPreviousRow", action);
+ action = new ListAction("selectNextRow");
+ am.put("selectNextRow", action);
+ action = new ListAction("selectPreviousRowExtendSelection");
+ am.put("selectPreviousRowExtendSelection", action);
+ action = new ListAction("selectNextRowExtendSelection");
+ am.put("selectNextRowExtendSelection", action);
+
+ action = new ListAction("selectPreviousColumn");
+ am.put("selectPreviousColumn", action);
+ action = new ListAction("selectNextColumn");
+ am.put("selectNextColumn", action);
+ action = new ListAction("selectPreviousColumnExtendSelection");
+ am.put("selectPreviousColumnExtendSelection", action);
+ action = new ListAction("selectNextColumnExtendSelection");
+ am.put("selectNextColumnExtendSelection", action);
+
+ action = new ListAction("selectFirstRow");
+ am.put("selectFirstRow", action);
+ action = new ListAction("selectLastRow");
+ am.put("selectLastRow", action);
+ action = new ListAction("selectFirstRowExtendSelection");
+ am.put("selectFirstRowExtendSelection", action);
+ action = new ListAction("selectLastRowExtendSelection");
+ am.put("selectLastRowExtendSelection", action);
+
+ action = new ListAction("scrollUp");
+ am.put("scrollUp", action);
+ action = new ListAction("scrollUpExtendSelection");
+ am.put("scrollUpExtendSelection", action);
+ action = new ListAction("scrollDown");
+ am.put("scrollDown", action);
+ action = new ListAction("scrollDownExtendSelection");
+ am.put("scrollDownExtendSelection", action);
+
+ action = new ListAction("selectAll");
+ am.put("selectAll", action);
+ action = new ListAction("clearSelection");
+ am.put("clearSelection", action);
+
+ am.put("copy", TransferHandler.getCopyAction());
+ am.put("cut", TransferHandler.getCutAction());
+ am.put("paste", TransferHandler.getPasteAction());
+
+ UIManager.put("List.actionMap", am);
}
- // Register the new InputMap-ActionMap as the parents of the list's
- // InputMap and ActionMap
- parentInputMap.setParent(list.getInputMap().getParent());
- parentActionMap.setParent(list.getActionMap().getParent());
- list.getInputMap().setParent(parentInputMap);
- list.getActionMap().setParent(parentActionMap);
+
+ SwingUtilities.replaceUIActionMap(list, am);
}
/**
* Uninstalls keyboard actions for this UI in the {@link JList}.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // TODO: Implement this properly.
+ // Uninstall the InputMap.
+ InputMap im = SwingUtilities.getUIInputMap(list, JComponent.WHEN_FOCUSED);
+ if (im instanceof UIResource)
+ SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null);
+
+ // Uninstall the ActionMap.
+ if (SwingUtilities.getUIActionMap(list) instanceof UIResource)
+ SwingUtilities.replaceUIActionMap(list, null);
}
/**
@@ -1151,7 +1211,7 @@ public class BasicListUI extends ListUI
boolean hasFocus = (list.getLeadSelectionIndex() == row) && BasicListUI.this.list.hasFocus();
Component comp = rend.getListCellRendererComponent(list,
data.getElementAt(row),
- 0, isSel, hasFocus);
+ row, isSel, hasFocus);
rendererPane.paintComponent(g, comp, list, bounds);
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
index 0f6e0243fcf..c056a2403f9 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
@@ -64,6 +64,7 @@ import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
+import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.MenuSelectionManager;
@@ -129,7 +130,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel
if (target instanceof Container)
target = ((Container) target).findComponentAt(ev.getPoint());
if (m.getSelectedPath().length > 0
- && ! m.isComponentPartOfCurrentMenu(target))
+ && ! m.isComponentPartOfCurrentMenu(target)
+ && (((JComponent)target).getClientProperty(DONT_CANCEL_POPUP) == null
+ || !((JComponent)target).getClientProperty(DONT_CANCEL_POPUP).equals(Boolean.TRUE)))
{
m.clearSelectedPath();
}
@@ -1028,6 +1031,25 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"PopupMenu.border", new BorderUIResource.BevelBorderUIResource(0),
"PopupMenu.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"PopupMenu.foreground", new ColorUIResource(darkShadow),
+ "PopupMenu.selectedWindowInputMapBindings",
+ new Object[] {"ESCAPE", "cancel",
+ "DOWN", "selectNext",
+ "KP_DOWN", "selectNext",
+ "UP", "selectPrevious",
+ "KP_UP", "selectPrevious",
+ "LEFT", "selectParent",
+ "KP_LEFT", "selectParent",
+ "RIGHT", "selectChild",
+ "KP_RIGHT", "selectChild",
+ "ENTER", "return",
+ "SPACE", "return"
+ },
+ "PopupMenu.selectedWindowInputMapBindings.RightToLeft",
+ new Object[] {"LEFT", "selectChild",
+ "KP_LEFT", "selectChild",
+ "RIGHT", "selectParent",
+ "KP_RIGHT", "selectParent",
+ },
"ProgressBar.background", new ColorUIResource(Color.LIGHT_GRAY),
"ProgressBar.border",
new BorderUIResource.LineBorderUIResource(Color.GREEN, 2),
@@ -1607,7 +1629,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
}),
"Tree.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"Tree.foreground", new ColorUIResource(Color.black),
- "Tree.hash", new ColorUIResource(new Color(128, 128, 128)),
+ "Tree.hash", new ColorUIResource(new Color(184, 207, 228)),
"Tree.leftChildIndent", new Integer(7),
"Tree.rightChildIndent", new Integer(13),
"Tree.rowHeight", new Integer(16),
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java
index f258ebe3069..cd25a3baf77 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java
@@ -38,24 +38,31 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Dimension;
+import java.awt.event.ActionEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BoxLayout;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
+import javax.swing.MenuSelectionManager;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuBarUI;
@@ -64,6 +71,47 @@ import javax.swing.plaf.MenuBarUI;
*/
public class BasicMenuBarUI extends MenuBarUI
{
+
+ /**
+ * This action is performed for the action command 'takeFocus'.
+ */
+ private static class FocusAction
+ extends AbstractAction
+ {
+
+ /**
+ * Creates a new FocusAction.
+ */
+ FocusAction()
+ {
+ super("takeFocus");
+ }
+
+ /**
+ * Performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ // In the JDK this action seems to pop up the first menu of the
+ // menu bar.
+ JMenuBar menuBar = (JMenuBar) event.getSource();
+ MenuSelectionManager defaultManager =
+ MenuSelectionManager.defaultManager();
+ MenuElement me[];
+ MenuElement subElements[];
+ JMenu menu = menuBar.getMenu(0);
+ if (menu != null)
+ {
+ me = new MenuElement[3];
+ me[0] = (MenuElement) menuBar;
+ me[1] = (MenuElement) menu;
+ me[2] = (MenuElement) menu.getPopupMenu();
+ defaultManager.setSelectedPath(me);
+ }
+ }
+
+ }
+
protected ChangeListener changeListener;
/*ContainerListener that listens to the ContainerEvents fired from menu bar*/
@@ -178,9 +226,46 @@ public class BasicMenuBarUI extends MenuBarUI
* This method installs the keyboard actions for the JMenuBar.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement
+ // Install InputMap.
+ Object[] bindings =
+ (Object[]) SharedUIDefaults.get("MenuBar.windowBindings");
+ InputMap inputMap = LookAndFeel.makeComponentInputMap(menuBar, bindings);
+ SwingUtilities.replaceUIInputMap(menuBar,
+ JComponent.WHEN_IN_FOCUSED_WINDOW,
+ inputMap);
+
+ // Install ActionMap.
+ SwingUtilities.replaceUIActionMap(menuBar, getActionMap());
+ }
+
+ /**
+ * Creates and returns the shared action map for JTrees.
+ *
+ * @return the shared action map for JTrees
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("MenuBar.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("MenuBar.actionMap", am);
+ }
+ return am;
+ }
+
+ /**
+ * Creates the default actions when there are none specified by the L&F.
+ *
+ * @return the default actions
+ */
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new FocusAction();
+ am.put(action.getValue(Action.NAME), action);
+ return am;
}
/**
@@ -226,9 +311,10 @@ public class BasicMenuBarUI extends MenuBarUI
* This method reverses the work done in installKeyboardActions.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ SwingUtilities.replaceUIInputMap(menuBar,
+ JComponent.WHEN_IN_FOCUSED_WINDOW, null);
+ SwingUtilities.replaceUIActionMap(menuBar, null);
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
index 63a09bff6a2..bbc08535cdc 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -52,11 +54,15 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
import javax.swing.ActionMap;
import javax.swing.ButtonModel;
import javax.swing.Icon;
@@ -237,7 +243,8 @@ public class BasicMenuItemUI extends MenuItemUI
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getPropertyName() == "accelerator")
+ String property = e.getPropertyName();
+ if (property.equals("accelerator"))
{
InputMap map = SwingUtilities.getUIInputMap(menuItem,
JComponent.WHEN_IN_FOCUSED_WINDOW);
@@ -250,6 +257,22 @@ public class BasicMenuItemUI extends MenuItemUI
if (accelerator != null)
map.put(accelerator, "doClick");
}
+ // TextLayout caching for speed-up drawing of text.
+ else if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
+ || property.equals("font"))
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
+ == null)
+
+ {
+ AbstractButton b = (AbstractButton) e.getSource();
+ String text = b.getText();
+ if (text == null)
+ text = "";
+ FontRenderContext frc = new FontRenderContext(new AffineTransform(),
+ false, false);
+ TextLayout layout = new TextLayout(text, b.getFont(), frc);
+ b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
+ }
}
}
@@ -833,12 +856,13 @@ public class BasicMenuItemUI extends MenuItemUI
int mnemonicIndex = menuItem.getDisplayedMnemonicIndex();
if (mnemonicIndex != -1)
- BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemonicIndex,
+ BasicGraphicsUtils.drawStringUnderlineCharAt(menuItem, g, text,
+ mnemonicIndex,
textRect.x,
textRect.y
+ fm.getAscent());
else
- BasicGraphicsUtils.drawString(g, text, 0, textRect.x,
+ BasicGraphicsUtils.drawString(menuItem, g, text, 0, textRect.x,
textRect.y + fm.getAscent());
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java
index f8936be5b66..7d8784fd15a 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java
@@ -220,9 +220,8 @@ public class BasicMenuUI extends BasicMenuItemUI
*
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ super.installKeyboardActions();
}
/**
@@ -230,13 +229,12 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
protected void installListeners()
{
- ((JMenu) menuItem).addMouseListener(mouseInputListener);
- ((JMenu) menuItem).addMouseMotionListener(mouseInputListener);
+ super.installListeners();
((JMenu) menuItem).addMenuListener(menuListener);
- ((JMenu) menuItem).addMenuDragMouseListener(menuDragMouseListener);
}
protected void setupPostTimer(JMenu menu)
+ throws NotImplementedException
{
// TODO: Implement this properly.
}
@@ -265,9 +263,8 @@ public class BasicMenuUI extends BasicMenuItemUI
* Basic look and feel's defaults.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ super.installKeyboardActions();
}
/**
@@ -276,9 +273,8 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
protected void uninstallListeners()
{
- ((JMenu) menuItem).removeMouseListener(mouseInputListener);
+ super.uninstallListeners();
((JMenu) menuItem).removeMenuListener(menuListener);
- ((JMenu) menuItem).removePropertyChangeListener(propertyChangeListener);
}
/**
@@ -351,7 +347,7 @@ public class BasicMenuUI extends BasicMenuItemUI
public void mouseMoved(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
public void mousePressed(MouseEvent e)
@@ -472,7 +468,8 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public ChangeHandler(JMenu m, BasicMenuUI ui)
{
- // Not used.
+ menu = m;
+ this.ui = ui;
}
/**
@@ -520,7 +517,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuDragMouseExited(MenuDragMouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -531,7 +528,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuDragMouseReleased(MenuDragMouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
}
@@ -548,7 +545,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuKeyPressed(MenuKeyEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -558,7 +555,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuKeyReleased(MenuKeyEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -568,6 +565,7 @@ public class BasicMenuUI extends BasicMenuItemUI
* @param e A {@link MenuKeyEvent}.
*/
public void menuKeyTyped(MenuKeyEvent e)
+ throws NotImplementedException
{
// TODO: What should be done here, if anything?
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
index 9acf8210d9e..e2380858098 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
@@ -38,13 +38,12 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
+import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -58,10 +57,14 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
+import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
@@ -76,6 +79,7 @@ import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.OptionPaneUI;
@@ -85,6 +89,21 @@ import javax.swing.plaf.OptionPaneUI;
public class BasicOptionPaneUI extends OptionPaneUI
{
/**
+ * Implements the "close" keyboard action.
+ */
+ static class OptionPaneCloseAction
+ extends AbstractAction
+ {
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JOptionPane op = (JOptionPane) event.getSource();
+ op.setValue(new Integer(JOptionPane.CLOSED_OPTION));
+ }
+
+ }
+
+ /**
* This is a helper class that listens to the buttons located at the bottom
* of the JOptionPane.
*
@@ -389,36 +408,20 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getPropertyName().equals(JOptionPane.ICON_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.MESSAGE_TYPE_PROPERTY))
- addIcon(messageAreaContainer);
- else if (e.getPropertyName().equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY))
- resetSelectedValue();
- else if (e.getPropertyName().equals(JOptionPane.INITIAL_VALUE_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.OPTIONS_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.OPTION_TYPE_PROPERTY))
+ String property = e.getPropertyName();
+ if (property.equals(JOptionPane.ICON_PROPERTY)
+ || property.equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY)
+ || property.equals(JOptionPane.INITIAL_VALUE_PROPERTY)
+ || property.equals(JOptionPane.MESSAGE_PROPERTY)
+ || property.equals(JOptionPane.MESSAGE_TYPE_PROPERTY)
+ || property.equals(JOptionPane.OPTION_TYPE_PROPERTY)
+ || property.equals(JOptionPane.OPTIONS_PROPERTY)
+ || property.equals(JOptionPane.WANTS_INPUT_PROPERTY))
{
- Container newButtons = createButtonArea();
- optionPane.remove(buttonContainer);
- optionPane.add(newButtons);
- buttonContainer = newButtons;
+ uninstallComponents();
+ installComponents();
+ optionPane.validate();
}
-
- else if (e.getPropertyName().equals(JOptionPane.MESSAGE_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.WANTS_INPUT_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.SELECTION_VALUES_PROPERTY))
- {
- optionPane.remove(messageAreaContainer);
- messageAreaContainer = createMessageArea();
- optionPane.add(messageAreaContainer);
- Container newButtons = createButtonArea();
- optionPane.remove(buttonContainer);
- optionPane.add(newButtons);
- buttonContainer = newButtons;
- optionPane.add(buttonContainer);
- }
- optionPane.invalidate();
- optionPane.repaint();
}
}
@@ -460,17 +463,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
protected JOptionPane optionPane;
/** The size of the icons. */
- // FIXME: wrong name for a constant.
- private static final int iconSize = 36;
-
- /** The foreground color for the message area. */
- private transient Color messageForeground;
-
- /** The border around the message area. */
- private transient Border messageBorder;
-
- /** The border around the button area. */
- private transient Border buttonBorder;
+ private static final int ICON_SIZE = 36;
/** The string used to describe OK buttons. */
private static final String OK_STRING = "OK";
@@ -505,7 +498,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
public int getIconWidth()
{
- return iconSize;
+ return ICON_SIZE;
}
/**
@@ -515,7 +508,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
public int getIconHeight()
{
- return iconSize;
+ return ICON_SIZE;
}
/**
@@ -566,7 +559,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
// Should be purple.
g.setColor(Color.RED);
- g.fillOval(0, 0, iconSize, iconSize);
+ g.fillOval(0, 0, ICON_SIZE, ICON_SIZE);
g.setColor(Color.BLACK);
g.drawOval(16, 6, 4, 4);
@@ -615,7 +608,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
Color saved = g.getColor();
g.setColor(Color.GREEN);
- g.fillRect(0, 0, iconSize, iconSize);
+ g.fillRect(0, 0, ICON_SIZE, ICON_SIZE);
g.setColor(Color.BLACK);
@@ -623,7 +616,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
g.drawOval(14, 5, 10, 10);
g.setColor(Color.GREEN);
- g.fillRect(0, 10, iconSize, iconSize - 10);
+ g.fillRect(0, 10, ICON_SIZE, ICON_SIZE - 10);
g.setColor(Color.BLACK);
@@ -640,10 +633,6 @@ public class BasicOptionPaneUI extends OptionPaneUI
}
};
- // FIXME: Uncomment when the ImageIcons are fixed.
-
- /* IconUIResource warningIcon, questionIcon, infoIcon, errorIcon;*/
-
/**
* Creates a new BasicOptionPaneUI object.
*/
@@ -705,6 +694,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
if (icon != null)
{
iconLabel = new JLabel(icon);
+ configureLabel(iconLabel);
top.add(iconLabel, BorderLayout.WEST);
}
}
@@ -766,7 +756,9 @@ public class BasicOptionPaneUI extends OptionPaneUI
}
else if (msg instanceof Icon)
{
- container.add(new JLabel((Icon) msg), cons);
+ JLabel label = new JLabel((Icon) msg);
+ configureLabel(label);
+ container.add(label, cons);
cons.gridy++;
}
else
@@ -783,8 +775,11 @@ public class BasicOptionPaneUI extends OptionPaneUI
addMessageComponents(container, cons, tmp, maxll, true);
}
else
- addMessageComponents(container, cons, new JLabel(msg.toString()),
- maxll, true);
+ {
+ JLabel label = new JLabel(msg.toString());
+ configureLabel(label);
+ addMessageComponents(container, cons, label, maxll, true);
+ }
}
}
@@ -815,6 +810,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
remainder = d.substring(maxll);
}
JLabel label = new JLabel(line);
+ configureLabel(label);
c.add(label);
// If there is nothing left to burst, then we can stop.
@@ -825,8 +821,12 @@ public class BasicOptionPaneUI extends OptionPaneUI
if (remainder.length() > maxll || remainder.contains("\n"))
burstStringInto(c, remainder, maxll);
else
- // Add the remainder to the container and be done.
- c.add(new JLabel(remainder));
+ {
+ // Add the remainder to the container and be done.
+ JLabel l = new JLabel(remainder);
+ configureLabel(l);
+ c.add(l);
+ }
}
/**
@@ -862,6 +862,9 @@ public class BasicOptionPaneUI extends OptionPaneUI
protected Container createButtonArea()
{
JPanel buttonPanel = new JPanel();
+ Border b = UIManager.getBorder("OptionPane.buttonAreaBorder");
+ if (b != null)
+ buttonPanel.setBorder(b);
buttonPanel.setLayout(createLayoutManager());
addButtonComponents(buttonPanel, getButtons(), getInitialValueIndex());
@@ -887,6 +890,10 @@ public class BasicOptionPaneUI extends OptionPaneUI
protected Container createMessageArea()
{
JPanel messageArea = new JPanel();
+ Border messageBorder = UIManager.getBorder("OptionPane.messageAreaBorder");
+ if (messageBorder != null)
+ messageArea.setBorder(messageBorder);
+
messageArea.setLayout(new BorderLayout());
addIcon(messageArea);
@@ -941,8 +948,9 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
protected Container createSeparator()
{
- // FIXME: Figure out what this method is supposed to return and where
- // this should be added to the OptionPane.
+ // The reference implementation returns null here. When overriding
+ // to return something non-null, the component gets added between
+ // the message area and the button area. See installComponents().
return null;
}
@@ -1143,35 +1151,17 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
protected void installComponents()
{
- // reset it.
- hasCustomComponents = false;
- Container msg = createMessageArea();
- if (msg != null)
- {
- ((JComponent) msg).setBorder(messageBorder);
- msg.setForeground(messageForeground);
- messageAreaContainer = msg;
- optionPane.add(msg);
- }
+ // First thing is the message area.
+ optionPane.add(createMessageArea());
- // FIXME: Figure out if the separator should be inserted here or what
- // this thing is supposed to do. Note: The JDK does NOT insert another
- // component at this place. The JOptionPane only has two panels in it
- // and there actually are applications that depend on this beeing so.
+ // Add separator when createSeparator() is overridden to return
+ // something other than null.
Container sep = createSeparator();
if (sep != null)
optionPane.add(sep);
- Container button = createButtonArea();
- if (button != null)
- {
- ((JComponent) button).setBorder(buttonBorder);
- buttonContainer = button;
- optionPane.add(button);
- }
-
- optionPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 11, 11));
- optionPane.invalidate();
+ // Last thing is the button area.
+ optionPane.add(createButtonArea());
}
/**
@@ -1185,10 +1175,6 @@ public class BasicOptionPaneUI extends OptionPaneUI
LookAndFeel.installBorder(optionPane, "OptionPane.border");
optionPane.setOpaque(true);
- messageBorder = UIManager.getBorder("OptionPane.messageAreaBorder");
- messageForeground = UIManager.getColor("OptionPane.messageForeground");
- buttonBorder = UIManager.getBorder("OptionPane.buttonAreaBorder");
-
minimumSize = UIManager.getDimension("OptionPane.minimumSize");
// FIXME: Image icons don't seem to work properly right now.
@@ -1206,9 +1192,44 @@ public class BasicOptionPaneUI extends OptionPaneUI
* This method installs keyboard actions for the JOptionpane.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ // Install the input map.
+ Object[] bindings =
+ (Object[]) SharedUIDefaults.get("OptionPane.windowBindings");
+ InputMap inputMap = LookAndFeel.makeComponentInputMap(optionPane,
+ bindings);
+ SwingUtilities.replaceUIInputMap(optionPane,
+ JComponent.WHEN_IN_FOCUSED_WINDOW,
+ inputMap);
+
+ // FIXME: The JDK uses a LazyActionMap for parentActionMap
+ SwingUtilities.replaceUIActionMap(optionPane, getActionMap());
+ }
+
+ /**
+ * Fetches the action map from the UI defaults, or create a new one
+ * if the action map hasn't been initialized.
+ *
+ * @return the action map
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("OptionPane.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("OptionPane.actionMap", am);
+ }
+ return am;
+ }
+
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new OptionPaneCloseAction();
+
+ am.put("close", action);
+ return am;
}
/**
@@ -1321,10 +1342,6 @@ public class BasicOptionPaneUI extends OptionPaneUI
minimumSize = null;
- messageBorder = null;
- buttonBorder = null;
- messageForeground = null;
-
// FIXME: ImageIcons don't seem to work properly
/*
@@ -1339,9 +1356,10 @@ public class BasicOptionPaneUI extends OptionPaneUI
* This method uninstalls keyboard actions for the JOptionPane.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ SwingUtilities.replaceUIInputMap(optionPane, JComponent.
+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities.replaceUIActionMap(optionPane, null);
}
/**
@@ -1367,4 +1385,20 @@ public class BasicOptionPaneUI extends OptionPaneUI
optionPane = null;
}
+
+ /**
+ * Applies the proper UI configuration to labels that are added to
+ * the OptionPane.
+ *
+ * @param l the label to configure
+ */
+ private void configureLabel(JLabel l)
+ {
+ Color c = UIManager.getColor("OptionPane.messageForeground");
+ if (c != null)
+ l.setForeground(c);
+ Font f = UIManager.getFont("OptionPane.messageFont");
+ if (f != null)
+ l.setFont(f);
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
index a26a5c7c46b..8c0fe6757e3 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
@@ -37,33 +37,574 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.KeyboardFocusManager;
+import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
+import java.util.EventListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BoxLayout;
+import javax.swing.InputMap;
+import javax.swing.JApplet;
import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
+import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PopupMenuUI;
-
/**
* UI Delegate for JPopupMenu
*/
public class BasicPopupMenuUI extends PopupMenuUI
{
+ /**
+ * Handles keyboard navigation through menus.
+ */
+ private static class NavigateAction
+ extends AbstractAction
+ {
+
+ /**
+ * Creates a new NavigateAction instance.
+ *
+ * @param name the name of the action
+ */
+ NavigateAction(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Actually performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ String name = (String) getValue(Action.NAME);
+ if (name.equals("selectNext"))
+ navigateNextPrevious(true);
+ else if (name.equals("selectPrevious"))
+ navigateNextPrevious(false);
+ else if (name.equals("selectChild"))
+ navigateParentChild(true);
+ else if (name.equals("selectParent"))
+ navigateParentChild(false);
+ else if (name.equals("cancel"))
+ cancel();
+ else if (name.equals("return"))
+ doReturn();
+ else
+ assert false : "Must not reach here";
+ }
+
+ /**
+ * Navigates to the next or previous menu item.
+ *
+ * @param dir <code>true</code>: navigate to next, <code>false</code>:
+ * navigate to previous
+ */
+ private void navigateNextPrevious(boolean dir)
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ int len = path.length;
+ if (len >= 2)
+ {
+
+ if (path[0] instanceof JMenuBar &&
+ path[1] instanceof JMenu && len == 2)
+ {
+
+ // A toplevel menu is selected, but its popup not yet shown.
+ // Show the popup and select the first item
+ JPopupMenu popup = ((JMenu)path[1]).getPopupMenu();
+ MenuElement next =
+ findEnabledChild(popup.getSubElements(), -1, true);
+ MenuElement[] newPath;
+
+ if (next != null)
+ {
+ newPath = new MenuElement[4];
+ newPath[3] = next;
+ }
+ else
+ {
+ // Menu has no enabled items, show the popup anyway.
+ newPath = new MenuElement[3];
+ }
+ System.arraycopy(path, 0, newPath, 0, 2);
+ newPath[2] = popup;
+ msm.setSelectedPath(newPath);
+ }
+ else if (path[len - 1] instanceof JPopupMenu &&
+ path[len - 2] instanceof JMenu)
+ {
+ // Select next item in already shown popup menu.
+ JMenu menu = (JMenu) path[len - 2];
+ JPopupMenu popup = menu.getPopupMenu();
+ MenuElement next =
+ findEnabledChild(popup.getSubElements(), -1, dir);
+
+ if (next != null)
+ {
+ MenuElement[] newPath = new MenuElement[len + 1];
+ System.arraycopy(path, 0, newPath, 0, len);
+ newPath[len] = next;
+ msm.setSelectedPath(newPath);
+ }
+ else
+ {
+ // All items in the popup are disabled.
+ // Find the parent popup menu and select
+ // its next item. If there's no parent popup menu , do nothing.
+ if (len > 2 && path[len - 3] instanceof JPopupMenu)
+ {
+ popup = ((JPopupMenu) path[len - 3]);
+ next = findEnabledChild(popup.getSubElements(),
+ menu, dir);
+ if (next != null && next != menu)
+ {
+ MenuElement[] newPath = new MenuElement[len - 1];
+ System.arraycopy(path, 0, newPath, 0, len - 2);
+ newPath[len - 2] = next;
+ msm.setSelectedPath(newPath);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Only select the next item.
+ MenuElement subs[] = path[len - 2].getSubElements();
+ MenuElement nextChild =
+ findEnabledChild(subs, path[len - 1], dir);
+ if (nextChild == null)
+ {
+ nextChild = findEnabledChild(subs, -1, dir);
+ }
+ if (nextChild != null)
+ {
+ path[len-1] = nextChild;
+ msm.setSelectedPath(path);
+ }
+ }
+ }
+ }
+
+ private MenuElement findEnabledChild(MenuElement[] children,
+ MenuElement start, boolean dir)
+ {
+ MenuElement found = null;
+ for (int i = 0; i < children.length && found == null; i++)
+ {
+ if (children[i] == start)
+ {
+ found = findEnabledChild(children, i, dir);
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Searches the next or previous enabled child menu element.
+ *
+ * @param children the children to search through
+ * @param start the index at which to start
+ * @param dir the direction (true == forward, false == backward)
+ *
+ * @return the found element or null
+ */
+ private MenuElement findEnabledChild(MenuElement[] children,
+ int start, boolean dir)
+ {
+ MenuElement result = null;
+ if (dir)
+ {
+ result = findNextEnabledChild(children, start + 1, children.length-1);
+ if (result == null)
+ result = findNextEnabledChild(children, 0, start - 1);
+ }
+ else
+ {
+ result = findPreviousEnabledChild(children, start - 1, 0);
+ if (result == null)
+ result = findPreviousEnabledChild(children, children.length-1,
+ start + 1);
+ }
+ return result;
+ }
+
+ /**
+ * Finds the next child element that is enabled and visible.
+ *
+ * @param children the children to search through
+ * @param start the start index
+ * @param end the end index
+ *
+ * @return the found child, or null
+ */
+ private MenuElement findNextEnabledChild(MenuElement[] children, int start,
+ int end)
+ {
+ MenuElement found = null;
+ for (int i = start; i <= end && found == null; i++)
+ {
+ if (children[i] != null)
+ {
+ Component comp = children[i].getComponent();
+ if (comp != null && comp.isEnabled() && comp.isVisible())
+ {
+ found = children[i];
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Finds the previous child element that is enabled and visible.
+ *
+ * @param children the children to search through
+ * @param start the start index
+ * @param end the end index
+ *
+ * @return the found child, or null
+ */
+ private MenuElement findPreviousEnabledChild(MenuElement[] children,
+ int start, int end)
+ {
+ MenuElement found = null;
+ for (int i = start; i >= end && found == null; i--)
+ {
+ if (children[i] != null)
+ {
+ Component comp = children[i].getComponent();
+ if (comp != null && comp.isEnabled() && comp.isVisible())
+ {
+ found = children[i];
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Navigates to the parent or child menu item.
+ *
+ * @param selectChild <code>true</code>: navigate to child,
+ * <code>false</code>: navigate to parent
+ */
+ private void navigateParentChild(boolean selectChild)
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ int len = path.length;
+
+ if (selectChild)
+ {
+ if (len > 0 && path[len - 1] instanceof JMenu
+ && ! ((JMenu) path[len-1]).isTopLevelMenu())
+ {
+ // We have a submenu, open it.
+ JMenu menu = (JMenu) path[len - 1];
+ JPopupMenu popup = menu.getPopupMenu();
+ MenuElement[] subs = popup.getSubElements();
+ MenuElement item = findEnabledChild(subs, -1, true);
+ MenuElement[] newPath;
+
+ if (item == null)
+ {
+ newPath = new MenuElement[len + 1];
+ }
+ else
+ {
+ newPath = new MenuElement[len + 2];
+ newPath[len + 1] = item;
+ }
+ System.arraycopy(path, 0, newPath, 0, len);
+ newPath[len] = popup;
+ msm.setSelectedPath(newPath);
+ return;
+ }
+ }
+ else
+ {
+ int popupIndex = len-1;
+ if (len > 2
+ && (path[popupIndex] instanceof JPopupMenu
+ || path[--popupIndex] instanceof JPopupMenu)
+ && ! ((JMenu) path[popupIndex - 1]).isTopLevelMenu())
+ {
+ // We have a submenu, close it.
+ MenuElement newPath[] = new MenuElement[popupIndex];
+ System.arraycopy(path, 0, newPath, 0, popupIndex);
+ msm.setSelectedPath(newPath);
+ return;
+ }
+ }
+
+ // If we got here, we have not selected a child or parent.
+ // Check if we have a toplevel menu selected. If so, then select
+ // another one.
+ if (len > 1 && path[0] instanceof JMenuBar)
+ {
+ MenuElement currentMenu = path[1];
+ MenuElement nextMenu = findEnabledChild(path[0].getSubElements(),
+ currentMenu, selectChild);
+
+ if (nextMenu != null && nextMenu != currentMenu)
+ {
+ MenuElement newSelection[];
+ if (len == 2)
+ {
+ // Menu is selected but its popup not shown.
+ newSelection = new MenuElement[2];
+ newSelection[0] = path[0];
+ newSelection[1] = nextMenu;
+ }
+ else
+ {
+ // Menu is selected and its popup is shown.
+ newSelection = new MenuElement[3];
+ newSelection[0] = path[0];
+ newSelection[1] = nextMenu;
+ newSelection[2] = ((JMenu) nextMenu).getPopupMenu();
+ }
+ msm.setSelectedPath(newSelection);
+ }
+ }
+ }
+
+ /**
+ * Handles cancel requests (ESC key).
+ */
+ private void cancel()
+ {
+ // Fire popup menu cancelled event. Unfortunately the
+ // firePopupMenuCancelled() is protected in JPopupMenu so we work
+ // around this limitation by fetching the listeners and notifying them
+ // directly.
+ JPopupMenu lastPopup = (JPopupMenu) getLastPopup();
+ EventListener[] ll = lastPopup.getListeners(PopupMenuListener.class);
+ for (int i = 0; i < ll.length; i++)
+ {
+ PopupMenuEvent ev = new PopupMenuEvent(lastPopup);
+ ((PopupMenuListener) ll[i]).popupMenuCanceled(ev);
+ }
+
+ // Close the last popup or the whole selection if there's only one
+ // popup left.
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ if(path.length > 4)
+ {
+ MenuElement newPath[] = new MenuElement[path.length - 2];
+ System.arraycopy(path,0,newPath,0,path.length-2);
+ MenuSelectionManager.defaultManager().setSelectedPath(newPath);
+ }
+ else
+ msm.clearSelectedPath();
+ }
+
+ /**
+ * Returns the last popup menu in the current selection or null.
+ *
+ * @return the last popup menu in the current selection or null
+ */
+ private JPopupMenu getLastPopup()
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement[] p = msm.getSelectedPath();
+ JPopupMenu popup = null;
+ for(int i = p.length - 1; popup == null && i >= 0; i--)
+ {
+ if (p[i] instanceof JPopupMenu)
+ popup = (JPopupMenu) p[i];
+ }
+ return popup;
+ }
+
+ /**
+ * Handles ENTER key requests. This normally opens submenus on JMenu
+ * items, or activates the menu item as if it's been clicked on it.
+ */
+ private void doReturn()
+ {
+ KeyboardFocusManager fmgr =
+ KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Component focusOwner = fmgr.getFocusOwner();
+ if((focusOwner == null || (focusOwner instanceof JRootPane)))
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ MenuElement lastElement;
+ if(path.length > 0)
+ {
+ lastElement = path[path.length - 1];
+ if(lastElement instanceof JMenu)
+ {
+ MenuElement newPath[] = new MenuElement[path.length + 1];
+ System.arraycopy(path,0,newPath,0,path.length);
+ newPath[path.length] = ((JMenu) lastElement).getPopupMenu();
+ msm.setSelectedPath(newPath);
+ }
+ else if(lastElement instanceof JMenuItem)
+ {
+ JMenuItem mi = (JMenuItem)lastElement;
+ if (mi.getUI() instanceof BasicMenuItemUI)
+ {
+ ((BasicMenuItemUI)mi.getUI()).doClick(msm);
+ }
+ else
+ {
+ msm.clearSelectedPath();
+ mi.doClick(0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Installs keyboard actions when a popup is opened, and uninstalls the
+ * keyboard actions when closed. This listens on the default
+ * MenuSelectionManager.
+ */
+ private class KeyboardHelper
+ implements ChangeListener
+ {
+ private MenuElement[] lastSelectedPath = new MenuElement[0];
+ private Component lastFocused;
+ private JRootPane invokerRootPane;
+
+ public void stateChanged(ChangeEvent event)
+ {
+ MenuSelectionManager msm = (MenuSelectionManager) event.getSource();
+ MenuElement[] p = msm.getSelectedPath();
+ JPopupMenu popup = getActivePopup(p);
+ if (popup == null || popup.isFocusable())
+ {
+ if (lastSelectedPath.length != 0 && p.length != 0 )
+ {
+ if (! invokerEquals(p[0], lastSelectedPath[0]))
+ {
+ uninstallKeyboardActionsImpl();
+ lastSelectedPath = new MenuElement[0];
+ }
+ }
+
+ if (lastSelectedPath.length == 0 && p.length > 0)
+ {
+ JComponent invoker;
+ if (popup == null)
+ {
+ if (p.length == 2 && p[0] instanceof JMenuBar
+ && p[1] instanceof JMenu)
+ {
+ // A menu has been selected but not opened.
+ invoker = (JComponent)p[1];
+ popup = ((JMenu)invoker).getPopupMenu();
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ Component c = popup.getInvoker();
+ if(c instanceof JFrame)
+ {
+ invoker = ((JFrame) c).getRootPane();
+ }
+ else if(c instanceof JApplet)
+ {
+ invoker = ((JApplet) c).getRootPane();
+ }
+ else
+ {
+ while (!(c instanceof JComponent))
+ {
+ if (c == null)
+ {
+ return;
+ }
+ c = c.getParent();
+ }
+ invoker = (JComponent)c;
+ }
+ }
+
+ // Remember current focus owner.
+ lastFocused = KeyboardFocusManager.
+ getCurrentKeyboardFocusManager().getFocusOwner();
+
+ // Install keybindings used for menu navigation.
+ invokerRootPane = SwingUtilities.getRootPane(invoker);
+ if (invokerRootPane != null)
+ {
+ invokerRootPane.requestFocus(true);
+ installKeyboardActionsImpl();
+ }
+ }
+ else if (lastSelectedPath.length != 0 && p.length == 0)
+ {
+ // menu hidden -- return focus to where it had been before
+ // and uninstall menu keybindings
+ uninstallKeyboardActionsImpl();
+ }
+ }
+
+ // Remember the last path selected
+ lastSelectedPath = p;
+ }
+
+ private JPopupMenu getActivePopup(MenuElement[] path)
+ {
+ JPopupMenu active = null;
+ for (int i = path.length - 1; i >= 0 && active == null; i--)
+ {
+ MenuElement elem = path[i];
+ if (elem instanceof JPopupMenu)
+ {
+ active = (JPopupMenu) elem;
+ }
+ }
+ return active;
+ }
+
+ private boolean invokerEquals(MenuElement el1, MenuElement el2)
+ {
+ Component invoker1 = el1.getComponent();
+ Component invoker2 = el2.getComponent();
+ if (invoker1 instanceof JPopupMenu)
+ invoker1 = ((JPopupMenu) invoker1).getInvoker();
+ if (invoker2 instanceof JPopupMenu)
+ invoker2 = ((JPopupMenu) invoker2).getInvoker();
+ return invoker1 == invoker2;
+ }
+ }
+
/* popupMenu for which this UI delegate is for*/
protected JPopupMenu popupMenu;
@@ -75,6 +616,19 @@ public class BasicPopupMenuUI extends PopupMenuUI
TopWindowListener topWindowListener;
/**
+ * Counts how many popup menus are handled by this UI or a subclass.
+ * This is used to install a KeyboardHelper on the MenuSelectionManager
+ * for the first popup, and uninstall this same KeyboardHelper when the
+ * last popup is uninstalled.
+ */
+ private static int numPopups;
+
+ /**
+ * This is the KeyboardHelper that listens on the MenuSelectionManager.
+ */
+ private static KeyboardHelper keyboardHelper;
+
+ /**
* Creates a new BasicPopupMenuUI object.
*/
public BasicPopupMenuUI()
@@ -106,6 +660,16 @@ public class BasicPopupMenuUI extends PopupMenuUI
public void installUI(JComponent c)
{
super.installUI(c);
+
+ // Install KeyboardHelper when the first popup is initialized.
+ if (numPopups == 0)
+ {
+ keyboardHelper = new KeyboardHelper();
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ msm.addChangeListener(keyboardHelper);
+ }
+ numPopups++;
+
popupMenu = (JPopupMenu) c;
popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS));
popupMenu.setBorderPainted(true);
@@ -113,6 +677,7 @@ public class BasicPopupMenuUI extends PopupMenuUI
installDefaults();
installListeners();
+ installKeyboardActions();
}
/**
@@ -139,9 +704,77 @@ public class BasicPopupMenuUI extends PopupMenuUI
* This method installs the keyboard actions for this {@link JPopupMenu}.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ // We can't install the keyboard actions here, because then all
+ // popup menus would have their actions registered in the KeyboardManager.
+ // So we install it when the popup menu is opened, and uninstall it
+ // when it's closed. This is done in the KeyboardHelper class.
+ // Install InputMap.
+ }
+
+ /**
+ * Called by the KeyboardHandler when a popup is made visible.
+ */
+ void installKeyboardActionsImpl()
+ {
+ Object[] bindings;
+ if (popupMenu.getComponentOrientation().isLeftToRight())
+ {
+ bindings = (Object[])
+ SharedUIDefaults.get("PopupMenu.selectedWindowInputMapBindings");
+ }
+ else
+ {
+ bindings = (Object[]) SharedUIDefaults.get
+ ("PopupMenu.selectedWindowInputMapBindings.RightToLeft");
+ }
+ InputMap inputMap = LookAndFeel.makeComponentInputMap(popupMenu, bindings);
+ SwingUtilities.replaceUIInputMap(popupMenu,
+ JComponent.WHEN_IN_FOCUSED_WINDOW,
+ inputMap);
+
+ // Install ActionMap.
+ SwingUtilities.replaceUIActionMap(popupMenu, getActionMap());
+ }
+
+ /**
+ * Creates and returns the shared action map for JTrees.
+ *
+ * @return the shared action map for JTrees
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("PopupMenu.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("PopupMenu.actionMap", am);
+ }
+ return am;
+ }
+
+ /**
+ * Creates the default actions when there are none specified by the L&F.
+ *
+ * @return the default actions
+ */
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new NavigateAction("selectNext");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("selectPrevious");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("selectParent");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("selectChild");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("return");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("cancel");
+ am.put(action.getValue(Action.NAME), action);
+
+ return am;
}
/**
@@ -155,7 +788,17 @@ public class BasicPopupMenuUI extends PopupMenuUI
{
uninstallListeners();
uninstallDefaults();
+ uninstallKeyboardActions();
popupMenu = null;
+
+ // Install KeyboardHelper when the first popup is initialized.
+ numPopups--;
+ if (numPopups == 0)
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ msm.removeChangeListener(keyboardHelper);
+ }
+
}
/**
@@ -182,9 +825,22 @@ public class BasicPopupMenuUI extends PopupMenuUI
* Uninstalls any keyboard actions.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ // We can't install the keyboard actions here, because then all
+ // popup menus would have their actions registered in the KeyboardManager.
+ // So we install it when the popup menu is opened, and uninstall it
+ // when it's closed. This is done in the KeyboardHelper class.
+ // Install InputMap.
+ }
+
+ /**
+ * Called by the KeyboardHandler when a popup is made invisible.
+ */
+ void uninstallKeyboardActionsImpl()
+ {
+ SwingUtilities.replaceUIInputMap(popupMenu,
+ JComponent.WHEN_IN_FOCUSED_WINDOW, null);
+ SwingUtilities.replaceUIActionMap(popupMenu, null);
}
/**
@@ -278,9 +934,10 @@ public class BasicPopupMenuUI extends PopupMenuUI
// Adds topWindowListener to top-level window to listener to
// ComponentEvents fired by it. We need to cancel this popup menu
// if topWindow to which this popup belongs was resized or moved.
- Component invoker = popupMenu.getInvoker();
+ Component invoker = popupMenu.getInvoker();
Component rootContainer = SwingUtilities.getRoot(invoker);
- rootContainer.addComponentListener(topWindowListener);
+ if (rootContainer != null)
+ rootContainer.addComponentListener(topWindowListener);
// if this popup menu is a free floating popup menu,
// then by default its first element should be always selected when
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
index a7da21c4f6e..aed4d69d6d5 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
@@ -42,6 +42,7 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
@@ -92,14 +93,6 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
protected void installDefaults(AbstractButton b)
{
super.installDefaults(b);
- if (b.getIcon() == null)
- b.setIcon(icon);
- if (b.getSelectedIcon() == null)
- b.setSelectedIcon(icon);
- if (b.getDisabledIcon() == null)
- b.setDisabledIcon(icon);
- if (b.getDisabledSelectedIcon() == null)
- b.setDisabledSelectedIcon(icon);
}
/**
@@ -145,16 +138,17 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
g.setFont(f);
ButtonModel m = b.getModel();
- Icon currentIcon = null;
- if (m.isSelected() && m.isEnabled())
- currentIcon = b.getSelectedIcon();
- else if (! m.isSelected() && m.isEnabled())
- currentIcon = b.getIcon();
- else if (m.isSelected() && ! m.isEnabled())
- currentIcon = b.getDisabledSelectedIcon();
- else // (!m.isSelected() && ! m.isEnabled())
- currentIcon = b.getDisabledIcon();
+ // FIXME: Do a filtering on any customized icon if the following property
+ // is set.
+ boolean enabled = b.isEnabled();
+
+ Icon currentIcon = b.getIcon();
+ if (currentIcon == null)
+ {
+ currentIcon = getDefaultIcon();
+ }
+
SwingUtilities.calculateInnerArea(b, vr);
String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f),
b.getText(), currentIcon,
@@ -162,15 +156,57 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
vr, ir, tr, b.getIconTextGap() + defaultTextShiftOffset);
- if (currentIcon != null)
- {
- currentIcon.paintIcon(c, g, ir.x, ir.y);
- }
+ currentIcon.paintIcon(c, g, ir.x, ir.y);
+
if (text != null)
paintText(g, b, tr, text);
if (b.hasFocus() && b.isFocusPainted() && m.isEnabled())
paintFocus(g, tr, c.getSize());
}
+
+ public Dimension getPreferredSize(JComponent c)
+ {
+ // This is basically the same code as in
+ // BasicGraphicsUtils.getPreferredButtonSize() but takes the default icon
+ // property into account. JRadioButton and subclasses always have an icon:
+ // the check box. If the user explicitly changes it with setIcon() that
+ // one will be used for layout calculations and painting instead.
+ // The other icon properties are ignored.
+ AbstractButton b = (AbstractButton) c;
+
+ Rectangle contentRect;
+ Rectangle viewRect;
+ Rectangle iconRect = new Rectangle();
+ Rectangle textRect = new Rectangle();
+ Insets insets = b.getInsets();
+
+ Icon i = b.getIcon();
+ if (i == null)
+ i = getDefaultIcon();
+
+ viewRect = new Rectangle();
+
+ SwingUtilities.layoutCompoundLabel(
+ b, // for the component orientation
+ b.getFontMetrics(b.getFont()),
+ b.getText(),
+ i,
+ b.getVerticalAlignment(),
+ b.getHorizontalAlignment(),
+ b.getVerticalTextPosition(),
+ b.getHorizontalTextPosition(),
+ viewRect, iconRect, textRect,
+ defaultTextIconGap + defaultTextShiftOffset);
+
+ contentRect = textRect.union(iconRect);
+
+ return new Dimension(insets.left
+ + contentRect.width
+ + insets.right + b.getHorizontalAlignment(),
+ insets.top
+ + contentRect.height
+ + insets.bottom);
+ }
/**
* Paints the focus indicator for JRadioButtons.
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
index b29026342e0..78e5168fc80 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
@@ -302,8 +302,10 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
*/
public void mouseMoved(MouseEvent e)
{
- // Not interested in where the mouse
- // is unless it is being dragged.
+ if (thumbRect.contains(e.getPoint()))
+ thumbRollover = true;
+ else
+ thumbRollover = false;
}
/**
@@ -486,6 +488,9 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
/** The scrollbar this UI is acting for. */
protected JScrollBar scrollbar;
+
+ /** True if the mouse is over the thumb. */
+ boolean thumbRollover;
/**
* This method adds a component to the layout.
@@ -1401,4 +1406,45 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
value = min;
return value;
}
+
+ /**
+ * Returns true if the mouse is over the thumb.
+ *
+ * @return true if the mouse is over the thumb.
+ *
+ * @since 1.5
+ */
+ public boolean isThumbRollover()
+ {
+ return thumbRollover;
+ }
+
+ /**
+ * Set thumbRollover to active. This indicates
+ * whether or not the mouse is over the thumb.
+ *
+ * @param active - true if the mouse is over the thumb.
+ *
+ * @since 1.5
+ */
+ protected void setThumbRollover(boolean active)
+ {
+ thumbRollover = active;
+ }
+
+ /**
+ * Indicates whether the user can position the thumb with
+ * a mouse click (i.e. middle button).
+ *
+ * @return true if the user can position the thumb with a mouse
+ * click.
+ *
+ * @since 1.5
+ */
+ public boolean getSupportsAbsolutePositioning()
+ {
+ // The positioning feature has not been implemented.
+ // So, false is always returned.
+ return false;
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
index 2fb16f12e63..3811eebdfd6 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
@@ -371,6 +371,7 @@ public class BasicSliderUI extends SliderUI
*/
public void mouseDragged(MouseEvent e)
{
+ dragging = true;
if (slider.isEnabled())
{
currentMouseX = e.getX();
@@ -450,6 +451,7 @@ public class BasicSliderUI extends SliderUI
*/
public void mouseReleased(MouseEvent e)
{
+ dragging = false;
if (slider.isEnabled())
{
currentMouseX = e.getX();
@@ -593,6 +595,9 @@ public class BasicSliderUI extends SliderUI
/** True if the slider has focus. */
private transient boolean hasFocus;
+
+ /** True if the user is dragging the slider. */
+ boolean dragging;
/**
* Creates a new Basic look and feel Slider UI.
@@ -605,6 +610,18 @@ public class BasicSliderUI extends SliderUI
}
/**
+ * Returns true if the user is dragging the slider.
+ *
+ * @return true if the slider is being dragged.
+ *
+ * @since 1.5
+ */
+ protected boolean isDragging()
+ {
+ return dragging;
+ }
+
+ /**
* 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.
*
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
index 1b2552837c6..11f25167d21 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
@@ -1,5 +1,5 @@
/* BasicTabbedPaneUI.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -51,6 +49,7 @@ import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
@@ -60,7 +59,10 @@ import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
import javax.swing.Icon;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
@@ -72,6 +74,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import javax.swing.plaf.TabbedPaneUI;
@@ -80,11 +83,127 @@ import javax.swing.text.View;
/**
* This is the Basic Look and Feel's UI delegate for JTabbedPane.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ * @author Kim Ho (kho@redhat.com)
+ * @author Roman Kennke (kennke@aicas.com)
+ * @author Robert Schuster (robertschuster@fsfe.org)
*/
public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
+
+ static class NavigateAction extends AbstractAction
+ {
+ int direction;
+
+ NavigateAction(String name, int dir)
+ {
+ super(name);
+ direction = dir;
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+ BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+ ui.navigateSelectedTab(direction);
+ }
+
+ }
+
+ static class NavigatePageDownAction extends AbstractAction
+ {
+
+ public NavigatePageDownAction()
+ {
+ super("navigatePageDown");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+ BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+ int i = tp.getSelectedIndex();
+
+ if (i < 0)
+ i = 0;
+
+ ui.selectNextTabInRun(i);
+ }
+
+ }
+
+ static class NavigatePageUpAction extends AbstractAction
+ {
+
+ public NavigatePageUpAction()
+ {
+ super("navigatePageUp");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+ BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+ int i = tp.getSelectedIndex();
+
+ if (i < 0)
+ i = 0;
+
+ ui.selectPreviousTabInRun(i);
+
+ }
+ }
+
+ static class RequestFocusAction extends AbstractAction
+ {
+
+ public RequestFocusAction()
+ {
+ super("requestFocus");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ ((JTabbedPane) event.getSource()).requestFocus();
+ }
+
+ }
+
+ static class RequestFocusForVisibleComponentAction extends AbstractAction
+ {
+
+ public RequestFocusForVisibleComponentAction()
+ {
+ super("requestFocusForVisibleComponent");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+
+ // FIXME: This should select a suitable component within
+ // the tab content. However I dont know whether we have
+ // to search for this component or wether the called is
+ // supposed to do that.
+ tp.getSelectedComponent().requestFocus();
+ }
+
+ }
+
/**
- * A helper class that handles focus.
+ * A helper class that handles focus.
+ * <p>The purpose of this class is to implement a more flexible focus
+ * handling for the tabbed pane, which is used to determine whether the
+ * focus indicator should be painted or not. When in scrolling layout
+ * mode the area containing the tabs is a scrollpane, so simply testing
+ * whether the tabbed pane has the focus does not work.</p>
+ * <p>The <code>FocusHandler</code> is installed on the scrollpane and
+ * the tabbed pane and sets the variable <code>hasFocus</code> to
+ * <code>false</code> only when both components do not hold the focus.</p>
*
* @specnote Apparently this class was intended to be protected,
* but was made public by a compiler bug and is now
@@ -99,7 +218,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void focusGained(FocusEvent e)
{
- // FIXME: Implement.
+ Object source = e.getSource();
+ if (source == panel )
+ tabPane.requestFocus();
+ else if (source == tabPane)
+ tabPane.repaint();
}
/**
@@ -109,7 +232,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void focusLost(FocusEvent e)
{
- // FIXME: Implement.
+ if (e.getOppositeComponent() == tabPane.getSelectedComponent())
+ tabPane.requestFocus();
+ else if (e.getSource() == tabPane)
+ tabPane.repaint();
}
}
@@ -124,6 +250,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public class MouseHandler extends MouseAdapter
{
+ public void mouseReleased(MouseEvent e)
+ {
+ // Nothing to do here.
+ }
+
/**
* This method is called when the mouse is pressed. The index cannot
* change to a tab that is not enabled.
@@ -132,14 +263,84 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void mousePressed(MouseEvent e)
{
- if (tabPane.isEnabled())
+ Object s = e.getSource();
+ int placement = tabPane.getTabPlacement();
+
+ if (s == incrButton)
{
- int index = tabForCoordinate(tabPane, e.getX(), e.getY());
- if (index >= 0 && tabPane.isEnabledAt(index))
+ if(!incrButton.isEnabled())
+ return;
+
+ currentScrollLocation++;
+
+ switch (placement)
{
- tabPane.setSelectedIndex(index);
+ case JTabbedPane.TOP:
+ case JTabbedPane.BOTTOM:
+ currentScrollOffset = getTabAreaInsets(placement).left;
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].width;
+ break;
+ default:
+ currentScrollOffset = getTabAreaInsets(placement).top;
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].height;
+ break;
}
+
+ updateViewPosition();
+ updateButtons();
+
+ tabPane.repaint();
+ }
+ else if (s == decrButton)
+ {
+ if(!decrButton.isEnabled())
+ return;
+
+ // The scroll location may be zero but the offset
+ // greater than zero because of an adjustement to
+ // make a partially visible tab completely visible.
+ if (currentScrollLocation > 0)
+ currentScrollLocation--;
+
+ // Set the offset back to 0 and recompute it.
+ currentScrollOffset = 0;
+
+ switch (placement)
+ {
+ case JTabbedPane.TOP:
+ case JTabbedPane.BOTTOM:
+ // Take the tab area inset into account.
+ if (currentScrollLocation > 0)
+ currentScrollOffset = getTabAreaInsets(placement).left;
+ // Recompute scroll offset.
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].width;
+ break;
+ default:
+ // Take the tab area inset into account.
+ if (currentScrollLocation > 0)
+ currentScrollOffset = getTabAreaInsets(placement).top;
+
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].height;
+ }
+
+ updateViewPosition();
+ updateButtons();
+
+ tabPane.repaint();
+ } else if (tabPane.isEnabled())
+ {
+ int index = tabForCoordinate(tabPane, e.getX(), e.getY());
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT
+ && s == panel)
+ scrollTab(index, placement);
+
+ tabPane.setSelectedIndex(index);
}
+
}
/**
@@ -197,6 +398,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
if (e.getPropertyName().equals("tabLayoutPolicy"))
{
+ currentScrollLocation = currentScrollOffset = 0;
+
layoutManager = createLayoutManager();
tabPane.setLayout(layoutManager);
@@ -265,7 +468,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// Find out the minimum/preferred size to display the largest child
// of the tabbed pane.
- for (int i = 0; i < tabPane.getTabCount(); i++)
+ int count = tabPane.getTabCount();
+ for (int i = 0; i < count; i++)
{
c = tabPane.getComponentAt(i);
if (c == null)
@@ -282,21 +486,19 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
- int min = calculateMaxTabWidth(tabPlacement);
- width = Math.max(min, width);
- int tabAreaHeight = preferredTabAreaHeight(tabPlacement,
- width - tabAreaInsets.left
- - tabAreaInsets.right);
- height += tabAreaHeight;
+ width = Math.max(calculateMaxTabWidth(tabPlacement), width);
+
+ height += preferredTabAreaHeight(tabPlacement,
+ width - tabAreaInsets.left
+ - tabAreaInsets.right);
}
else
{
- int min = calculateMaxTabHeight(tabPlacement);
- height = Math.max(min, height);
- int tabAreaWidth = preferredTabAreaWidth(tabPlacement,
- height - tabAreaInsets.top
- - tabAreaInsets.bottom);
- width += tabAreaWidth;
+ height = Math.max(calculateMaxTabHeight(tabPlacement), height);
+
+ width += preferredTabAreaWidth(tabPlacement,
+ height - tabAreaInsets.top
+ - tabAreaInsets.bottom);
}
Insets tabPaneInsets = tabPane.getInsets();
@@ -306,7 +508,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// if tab placement is LEFT OR RIGHT, they share width.
// if tab placement is TOP OR BOTTOM, they share height
- // PRE STEP: finds the default sizes for the labels as well as their locations.
+ // PRE STEP: finds the default sizes for the labels as well as their
+ // locations.
// AND where they will be placed within the run system.
// 1. calls normalizeTab Runs.
// 2. calls rotate tab runs.
@@ -345,7 +548,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
break;
case RIGHT:
maxTabWidth = calculateMaxTabWidth(tabPlacement);
- x = size.width - (insets.right + tabAreaInsets.right) - maxTabWidth;
+ x = size.width - (insets.right + tabAreaInsets.right)
+ - maxTabWidth - 1;
y = insets.top + tabAreaInsets.top;
breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
break;
@@ -353,7 +557,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
maxTabHeight = calculateMaxTabHeight(tabPlacement);
x = insets.left + tabAreaInsets.left;
y = size.height - (insets.bottom + tabAreaInsets.bottom)
- - maxTabHeight;
+ - maxTabHeight - 1;
breakAt = size.width - (insets.right + tabAreaInsets.right);
break;
case TOP:
@@ -372,6 +576,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
runCount = 0;
selectedRun = -1;
int selectedIndex = tabPane.getSelectedIndex();
+ if (selectedIndex < 0)
+ selectedIndex = 0;
Rectangle rect;
@@ -409,7 +615,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
rect.height = maxTabHeight;
if (i == selectedIndex)
selectedRun = runCount - 1;
-
}
}
else
@@ -454,9 +659,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int start;
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
- start = y;
- else
start = x;
+ else
+ start = y;
normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
selectedRun = getRunForTab(tabCount, selectedIndex);
if (shouldRotateTabRuns(tabPlacement))
@@ -464,7 +669,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
rotateTabRuns(tabPlacement, selectedRun);
}
}
-
+
+ // Suppress padding if we have only one tab run.
+ if (runCount == 1)
+ return;
+
// Pad the runs.
int tabRunOverlay = getTabRunOverlay(tabPlacement);
for (int i = runCount - 1; i >= 0; --i)
@@ -604,16 +813,18 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public Dimension minimumLayoutSize(Container parent)
{
- return calculateSize(false);
+ return calculateSize(true);
}
- // If there is more free space in an adjacent run AND the tab in the run can fit in the
- // adjacent run, move it. This method is not perfect, it is merely an approximation.
+ // If there is more free space in an adjacent run AND the tab
+ // in the run can fit in the adjacent run, move it. This method
+ // is not perfect, it is merely an approximation.
// If you play around with Sun's JTabbedPane, you'll see that
// it does do some pretty strange things with regards to not moving tabs
// that should be moved.
// start = the x position where the tabs will begin
- // max = the maximum position of where the tabs can go to (tabAreaInsets.left + the width of the tab area)
+ // max = the maximum position of where the tabs can go to
+ // (tabAreaInsets.left + the width of the tab area)
/**
* This method tries to "even out" the number of tabs in each run based on
@@ -631,18 +842,20 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabPlacement == SwingUtilities.TOP
|| tabPlacement == SwingUtilities.BOTTOM)
{
- // We should only do this for runCount - 1, cause we can only shift that many times between
- // runs.
+ // We should only do this for runCount - 1, cause we can
+ // only shift that many times between runs.
for (int i = 1; i < runCount; i++)
{
Rectangle currRun = rects[lastTabInRun(tabCount, i)];
- Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
+ Rectangle nextRun = rects[lastTabInRun(tabCount,
+ getNextTabRun(i))];
int spaceInCurr = currRun.x + currRun.width;
int spaceInNext = nextRun.x + nextRun.width;
int diffNow = spaceInCurr - spaceInNext;
int diffLater = (spaceInCurr - currRun.width)
- (spaceInNext + currRun.width);
+
while (Math.abs(diffLater) < Math.abs(diffNow)
&& spaceInNext + currRun.width < max)
{
@@ -654,11 +867,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
diffLater = (spaceInCurr - currRun.width)
- (spaceInNext + currRun.width);
}
-
- // Fix the bounds.
- int first = lastTabInRun(tabCount, i) + 1;
- int last = lastTabInRun(tabCount, getNextTabRun(i));
- int currX = tabAreaInsets.left;
+
+ // Fixes the bounds of all tabs in the current
+ // run.
+ int first = tabRuns[i];
+ int last = lastTabInRun(tabCount, i);
+ int currX = start;
for (int j = first; j <= last; j++)
{
rects[j].x = currX;
@@ -671,7 +885,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
for (int i = 1; i < runCount; i++)
{
Rectangle currRun = rects[lastTabInRun(tabCount, i)];
- Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
+ Rectangle nextRun = rects[lastTabInRun(tabCount,
+ getNextTabRun(i))];
int spaceInCurr = currRun.y + currRun.height;
int spaceInNext = nextRun.y + nextRun.height;
@@ -690,9 +905,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
- (spaceInNext + currRun.height);
}
- int first = lastTabInRun(tabCount, i) + 1;
- int last = lastTabInRun(tabCount, getNextTabRun(i));
- int currY = tabAreaInsets.top;
+ // Fixes the bounds of tabs in the current run.
+ int first = tabRuns[i];
+ int last = lastTabInRun(tabCount, i);
+ int currY = start;
for (int j = first; j <= last; j++)
{
rects[j].y = currY;
@@ -718,7 +934,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
rects[selectedIndex].height += insets.top + insets.bottom;
}
- // If the tabs on the run don't fill the width of the window, make it fit now.
+ // If the tabs on the run don't fill the width of the window, make it
+ // fit now.
// start = starting index of the run
// end = last index of the run
// max = tabAreaInsets.left + width (or equivalent)
@@ -742,7 +959,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int runWidth = rects[end].x + rects[end].width;
int spaceRemaining = max - runWidth;
int numTabs = end - start + 1;
-
+
// now divvy up the space.
int spaceAllocated = spaceRemaining / numTabs;
int currX = rects[start].x;
@@ -750,11 +967,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
rects[i].x = currX;
rects[i].width += spaceAllocated;
+
currX += rects[i].width;
// This is used because since the spaceAllocated
// variable is an int, it rounds down. Sometimes,
// we don't fill an entire row, so we make it do
// so now.
+
if (i == end && rects[i].x + rects[i].width != max)
rects[i].width = max - rects[i].x;
}
@@ -819,7 +1038,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// The reason why we can't use runCount:
// This method is only called to calculate the size request
- // for the tabbedPane. However, this size request is dependent on
+ // for the tabbedPane. However, this size request is dependent on
// our desired width. We need to find out what the height would
// be IF we got our desired width.
for (int i = 0; i < tabPane.getTabCount(); i++)
@@ -882,7 +1101,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
runs++;
int maxTabWidth = calculateMaxTabWidth(tabPlacement);
- int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
+ int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs,
+ maxTabWidth);
return tabAreaWidth;
}
@@ -896,11 +1116,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void rotateTabRuns(int tabPlacement, int selectedRun)
{
- if (runCount == 1 || selectedRun == 1 || selectedRun == -1)
+ if (runCount == 1 || selectedRun == 0 || selectedRun == -1)
return;
int[] newTabRuns = new int[tabRuns.length];
int currentRun = selectedRun;
- int i = 1;
+ int i = 0;
do
{
newTabRuns[i] = tabRuns[currentRun];
@@ -908,8 +1128,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
i++;
}
while (i < runCount);
- if (runCount > 1)
- newTabRuns[0] = tabRuns[currentRun];
tabRuns = newTabRuns;
BasicTabbedPaneUI.this.selectedRun = 1;
@@ -942,7 +1160,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public Dimension preferredLayoutSize(Container parent)
{
- return super.calculateSize(true);
+ return super.calculateSize(false);
}
/**
@@ -1016,29 +1234,27 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
SwingUtilities.calculateInnerArea(tabPane, calcRect);
Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
Insets insets = tabPane.getInsets();
- int runs = 1;
- int start = 0;
- int top = 0;
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
int maxHeight = calculateMaxTabHeight(tabPlacement);
calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
- start = tabAreaInsets.left + insets.left;
int width = 0;
- int runWidth = start;
- top = insets.top + tabAreaInsets.top;
+ int runWidth = tabAreaInsets.left + insets.left;
+ int top = insets.top + tabAreaInsets.top;
for (int i = 0; i < tabCount; i++)
{
width = calculateTabWidth(tabPlacement, i, fm);
-
- rects[i] = new Rectangle(runWidth, top, width, maxHeight);
+
+ // The proper instances should exists because
+ // assureRectsCreated() was being run already.
+ rects[i].setBounds(runWidth, top, width, maxHeight);
+
runWidth += width;
}
tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
- tabAreaRect.height = runs * maxTabHeight
- - (runs - 1) * tabRunOverlay
- + tabAreaInsets.top + tabAreaInsets.bottom;
+ tabAreaRect.height = maxTabHeight + tabAreaInsets.top
+ + tabAreaInsets.bottom;
contentRect.width = tabAreaRect.width;
contentRect.height = tabPane.getHeight() - insets.top
- insets.bottom - tabAreaRect.height;
@@ -1061,23 +1277,25 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
int height = 0;
- start = tabAreaInsets.top + insets.top;
- int runHeight = start;
+ int runHeight = tabAreaInsets.top + insets.top;;
int fontHeight = fm.getHeight();
- top = insets.left + tabAreaInsets.left;
+ int left = insets.left + tabAreaInsets.left;
for (int i = 0; i < tabCount; i++)
{
height = calculateTabHeight(tabPlacement, i, fontHeight);
- rects[i] = new Rectangle(top, runHeight, maxWidth, height);
+
+ // The proper instances should exists because
+ // assureRectsCreated() was being run already.
+ rects[i].setBounds(left, runHeight, maxWidth, height);
runHeight += height;
}
- tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
- + tabAreaInsets.left + tabAreaInsets.right;
+ tabAreaRect.width = maxTabWidth + tabAreaInsets.left
+ + tabAreaInsets.right;
tabAreaRect.height = tabPane.getHeight() - insets.top
- - insets.bottom;
+ - insets.bottom;
tabAreaRect.y = insets.top;
contentRect.width = tabPane.getWidth() - insets.left - insets.right
- - tabAreaRect.width;
+ - tabAreaRect.width;
contentRect.height = tabAreaRect.height;
contentRect.y = insets.top;
if (tabPlacement == SwingConstants.LEFT)
@@ -1091,11 +1309,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabAreaRect.x = contentRect.x + contentRect.width;
}
}
- runCount = runs;
- if (runCount > tabRuns.length)
- expandTabRunsArray();
-
- padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
+
+ // Unlike the behavior in the WRAP_TAB_LAYOUT the selected
+ // tab is not padded specially.
}
/**
@@ -1113,8 +1329,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabCount == 0)
return;
int tabPlacement = tabPane.getTabPlacement();
- incrButton.setVisible(false);
- decrButton.setVisible(false);
+
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
@@ -1124,18 +1339,49 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Dimension incrDims = incrButton.getPreferredSize();
Dimension decrDims = decrButton.getPreferredSize();
- decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
- - incrDims.width - decrDims.width,
- tabAreaRect.y, decrDims.width,
- tabAreaRect.height);
- incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
- - incrDims.width, tabAreaRect.y,
- decrDims.width, tabAreaRect.height);
-
+ if (tabPlacement == SwingConstants.BOTTOM)
+ {
+ // Align scroll buttons with the bottom border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width - decrDims.width,
+ tabAreaRect.y, decrDims.width,
+ decrDims.height);
+ incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width, tabAreaRect.y,
+ incrDims.width, incrDims.height);
+ }
+ else
+ {
+ // Align scroll buttons with the top border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width - decrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - decrDims.height, decrDims.width,
+ decrDims.height);
+ incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height,
+ incrDims.width, incrDims.height);
+ }
+
tabAreaRect.width -= decrDims.width + incrDims.width;
+
+ updateButtons();
+
incrButton.setVisible(true);
decrButton.setVisible(true);
}
+ else
+ {
+ incrButton.setVisible(false);
+ decrButton.setVisible(false);
+
+ currentScrollOffset = 0;
+ currentScrollLocation = 0;
+ }
}
if (tabPlacement == SwingConstants.LEFT
@@ -1147,34 +1393,54 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Dimension incrDims = incrButton.getPreferredSize();
Dimension decrDims = decrButton.getPreferredSize();
- decrButton.setBounds(tabAreaRect.x,
- tabAreaRect.y + tabAreaRect.height
- - incrDims.height - decrDims.height,
- tabAreaRect.width, decrDims.height);
- incrButton.setBounds(tabAreaRect.x,
- tabAreaRect.y + tabAreaRect.height
- - incrDims.height, tabAreaRect.width,
- incrDims.height);
+ if (tabPlacement == SwingConstants.RIGHT)
+ {
+ // Align scroll buttons with the right border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height - decrDims.height,
+ decrDims.width, decrDims.height);
+ incrButton.setBounds(tabAreaRect.x,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height, incrDims.width,
+ incrDims.height);
+ }
+ else
+ {
+ // Align scroll buttons with the left border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - decrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height - decrDims.height,
+ decrDims.width, decrDims.height);
+ incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height, incrDims.width,
+ incrDims.height);
+ }
tabAreaRect.height -= decrDims.height + incrDims.height;
+
incrButton.setVisible(true);
decrButton.setVisible(true);
}
+ else
+ {
+ incrButton.setVisible(false);
+ decrButton.setVisible(false);
+
+ currentScrollOffset = 0;
+ currentScrollLocation = 0;
+ }
}
viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
tabAreaRect.height);
- int tabC = tabPane.getTabCount() - 1;
- if (tabCount > 0)
- {
- int w = Math.max(rects[tabC].width + rects[tabC].x, tabAreaRect.width);
- int h = Math.max(rects[tabC].height, tabAreaRect.height);
- p = findPointForIndex(currentScrollLocation);
-
- // we want to cover that entire space so that borders that run under
- // the tab area don't show up when we move the viewport around.
- panel.setSize(w + p.x, h + p.y);
- }
- viewport.setViewPosition(p);
+
+ updateViewPosition();
+
viewport.repaint();
}
}
@@ -1198,7 +1464,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
selectedRun = getRunForTab(tabPane.getTabCount(),
tabPane.getSelectedIndex());
- tabPane.revalidate();
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+ tabPane.revalidate();
tabPane.repaint();
}
}
@@ -1224,7 +1492,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void paint(Graphics g, JComponent c)
{
- paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
+ int placement = tabPane.getTabPlacement();
+ g.setColor(highlight);
+ if (placement == SwingUtilities.TOP
+ || placement == SwingUtilities.BOTTOM)
+ g.fillRect(currentScrollOffset, 0,
+ tabAreaRect.width, tabAreaRect.height);
+ else
+ g.fillRect(0, currentScrollOffset,
+ tabAreaRect.width, tabAreaRect.height);
+
+ paintTabArea(g, placement, tabPane.getSelectedIndex());
}
}
@@ -1285,6 +1563,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
/** The starting visible tab in the run in SCROLL_TAB_MODE.
* This is package-private to avoid an accessor method. */
transient int currentScrollLocation;
+
+ transient int currentScrollOffset;
/** A reusable rectangle. */
protected Rectangle calcRect;
@@ -1340,16 +1620,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
/** The gap between text and label */
protected int textIconGap;
- // Keeps track of tab runs.
- // The organization of this array is as follows (lots of experimentation to
- // figure this out)
- // index 0 = furthest away from the component area (aka outer run)
- // index 1 = closest to component area (aka selected run)
- // index > 1 = listed in order leading from selected run to outer run.
- // each int in the array is the tab index + 1 (counting starts at 1)
- // for the last tab in the run. (same as the rects array)
-
- /** This array keeps track of which tabs are in which run. See above. */
+ /** This array keeps track of which tabs are in which run.
+ * <p>The value at index i denotes the index of the first tab in run i.</p>
+ * <p>If the value for any index (i > 0) is 0 then (i - 1) is the last
+ * run.</p>
+ */
protected int[] tabRuns;
/**
@@ -1428,7 +1703,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
* The currently visible component.
*/
private Component visibleComponent;
-
+
+ private Color selectedColor;
+
+ private Rectangle tempTextRect = new Rectangle();
+
+ private Rectangle tempIconRect = new Rectangle();
+
/**
* Creates a new BasicTabbedPaneUI object.
*/
@@ -1517,8 +1798,115 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Point p = new Point(w, h);
return p;
}
+
+ /** TabbedPanes in scrolling mode should use this method to
+ * scroll properly to the tab given by the index argument.
+ *
+ * @param index The tab to scroll to.
+ * @param placement The tab's placement.
+ */
+ final void scrollTab(int index, int placement)
+ {
+ int diff;
+ if (index >= 0 && tabPane.isEnabledAt(index))
+ {
+ // If the user clicked on the last tab and that one was
+ // only partially visible shift the scroll offset to make
+ // it completely visible.
+ switch (placement)
+ {
+ case JTabbedPane.TOP:
+ case JTabbedPane.BOTTOM:
+ if ((diff = rects[index].x
+ + rects[index].width
+ - decrButton.getX() - currentScrollOffset) > 0)
+ currentScrollOffset += diff;
+ else if ((diff = rects[index].x - currentScrollOffset) < 0)
+ {
+ if (index == 0)
+ currentScrollOffset = 0;
+ else
+ currentScrollOffset += diff;
+ }
+
+ currentScrollLocation = tabForCoordinate(tabPane,
+ currentScrollOffset,
+ rects[index].y);
+ break;
+ default:
+ if ((diff = rects[index].y + rects[index].height
+ - decrButton.getY() - currentScrollOffset) > 0)
+ currentScrollOffset += diff;
+ else if ((diff = rects[index].y - currentScrollOffset) < 0)
+ {
+ if (index == 0)
+ currentScrollOffset = 0;
+ else
+ currentScrollOffset += diff;
+ }
+
+ currentScrollLocation = tabForCoordinate(tabPane,
+ rects[index].x,
+ currentScrollOffset);
+ }
+
+ updateViewPosition();
+ updateButtons();
+ }
+ }
+
+ /** Sets the enabled state of the increase and decrease button
+ * according to the current scrolling offset and tab pane width
+ * (or height in TOP/BOTTOM placement).
+ */
+ final void updateButtons()
+ {
+ int tc = tabPane.getTabCount();
+
+ // The increase button should be enabled as long as the
+ // right/bottom border of the last tab is under the left/top
+ // border of the decrease button.
+ switch (tabPane.getTabPlacement())
+ {
+ case JTabbedPane.BOTTOM:
+ case JTabbedPane.TOP:
+ incrButton.setEnabled(currentScrollLocation + 1 < tc
+ && rects[tc-1].x + rects[tc-1].width
+ - currentScrollOffset > decrButton.getX());
+ break;
+ default:
+ incrButton.setEnabled(currentScrollLocation + 1 < tc
+ && rects[tc-1].y + rects[tc-1].height
+ - currentScrollOffset > decrButton.getY());
+ }
+
+ // The decrease button is enabled when the tab pane is scrolled in any way.
+ decrButton.setEnabled(currentScrollOffset > 0);
+
+ }
/**
+ * Updates the position of the scrolling viewport's view
+ * according to the current scroll offset.
+ */
+ final void updateViewPosition()
+ {
+ Point p = viewport.getViewPosition();
+
+ switch (tabPane.getTabPlacement())
+ {
+ case JTabbedPane.LEFT:
+ case JTabbedPane.RIGHT:
+ p.y = currentScrollOffset;
+ break;
+ default:
+ p.x = currentScrollOffset;
+ }
+
+ viewport.setViewPosition(p);
+ }
+
+ /**
* This method creates a new BasicTabbedPaneUI.
*
* @param c The JComponent to create a UI for.
@@ -1583,22 +1971,30 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
return new TabbedPaneLayout();
else
{
+ runCount = 1;
+ tabRuns[0] = 0;
+
incrButton = createIncreaseButton();
+ incrButton.addMouseListener(mouseListener);
+
decrButton = createDecreaseButton();
- viewport = new ScrollingViewport();
- viewport.setLayout(null);
+ decrButton.addMouseListener(mouseListener);
+ decrButton.setEnabled(false);
+
panel = new ScrollingPanel();
+ panel.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ panel.addMouseListener(mouseListener);
+ panel.addFocusListener(focusListener);
+
+ viewport = new ScrollingViewport();
+ viewport.setBackground(Color.LIGHT_GRAY);
viewport.setView(panel);
+ viewport.setLayout(null);
+
tabPane.add(incrButton);
tabPane.add(decrButton);
tabPane.add(viewport);
- currentScrollLocation = 0;
- decrButton.setEnabled(false);
- panel.addMouseListener(mouseListener);
- incrButton.addMouseListener(mouseListener);
- decrButton.addMouseListener(mouseListener);
- viewport.setBackground(Color.LIGHT_GRAY);
-
+
return new TabbedPaneScrollLayout();
}
}
@@ -1616,7 +2012,14 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void uninstallComponents()
{
- // Nothing to be done.
+ if (incrButton != null)
+ tabPane.remove(incrButton);
+
+ if (decrButton != null)
+ tabPane.remove(decrButton);
+
+ if (viewport != null)
+ tabPane.remove(viewport);
}
/**
@@ -1629,8 +2032,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
"TabbedPane.font");
tabPane.setOpaque(false);
- highlight = UIManager.getColor("TabbedPane.highlight");
- lightHighlight = UIManager.getColor("TabbedPane.lightHighlight");
+ lightHighlight = UIManager.getColor("TabbedPane.highlight");
+ highlight = UIManager.getColor("TabbedPane.light");
shadow = UIManager.getColor("TabbedPane.shadow");
darkShadow = UIManager.getColor("TabbedPane.darkShadow");
@@ -1641,10 +2044,18 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
- selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets");
+ selectedTabPadInsets
+ = UIManager.getInsets("TabbedPane.selectedTabPadInsets");
tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
- contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
+ contentBorderInsets
+ = UIManager.getInsets("TabbedPane.contentBorderInsets");
tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
+
+ // Although 'TabbedPane.contentAreaColor' is not defined in the defaults
+ // of BasicLookAndFeel it is used by this class.
+ selectedColor = UIManager.getColor("TabbedPane.contentAreaColor");
+ if (selectedColor == null)
+ selectedColor = UIManager.getColor("control");
calcRect = new Rectangle();
tabRuns = new int[10];
@@ -1661,6 +2072,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabAreaRect = null;
contentRect = null;
tabRuns = null;
+
+ tempIconRect = null;
+ tempTextRect = null;
contentBorderInsets = null;
tabAreaInsets = null;
@@ -1672,11 +2086,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
shadow = null;
lightHighlight = null;
highlight = null;
-
- // Install UI colors and fonts.
- LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
- "TabbedPane.foreground",
- "TabbedPane.font");
+
+ selectedColor = null;
}
/**
@@ -1704,6 +2115,18 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabPane.removePropertyChangeListener(propertyChangeListener);
tabPane.removeChangeListener(tabChangeListener);
tabPane.removeMouseListener(mouseListener);
+
+ if (incrButton != null)
+ incrButton.removeMouseListener(mouseListener);
+
+ if (decrButton != null)
+ decrButton.removeMouseListener(mouseListener);
+
+ if (panel != null)
+ {
+ panel.removeMouseListener(mouseListener);
+ panel.removeFocusListener(focusListener);
+ }
focusListener = null;
propertyChangeListener = null;
@@ -1755,18 +2178,31 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
* This method installs keyboard actions for the JTabbedPane.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Implement.
+ InputMap keyMap = (InputMap) UIManager.get("TabbedPane.focusInputMap");
+ SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, keyMap);
+
+ keyMap = (InputMap) UIManager.get("TabbedPane.ancestorInputMap");
+ SwingUtilities
+ .replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ keyMap);
+
+ ActionMap map = getActionMap();
+ SwingUtilities.replaceUIActionMap(tabPane, map);
}
/**
* This method uninstalls keyboard actions for the JTabbedPane.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Implement.
+ SwingUtilities.replaceUIActionMap(tabPane, null);
+ SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
+ SwingUtilities
+ .replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ null);
}
/**
@@ -1806,9 +2242,25 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabPane.getTabCount() == 0)
return;
+
+ int index = tabPane.getSelectedIndex();
+ if (index < 0)
+ index = 0;
+
+ int tabPlacement = tabPane.getTabPlacement();
+
+ // Paint the tab area only in WRAP_TAB_LAYOUT Mode from this method
+ // because it is done through the ScrollingViewport.paint() method
+ // for the SCROLL_TAB_LAYOUT mode.
if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
- paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
- paintContentBorder(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
+ {
+ g.setColor(highlight);
+ g.fillRect(tabAreaRect.x, tabAreaRect.y,
+ tabAreaRect.width, tabAreaRect.height);
+ paintTabArea(g, tabPlacement, index);
+ }
+
+ paintContentBorder(g, tabPlacement, index);
}
/**
@@ -1821,14 +2273,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
{
- Rectangle ir = new Rectangle();
- Rectangle tr = new Rectangle();
-
- boolean isScroll = tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
-
// Please note: the ordering of the painting is important.
// we WANT to paint the outermost run first and then work our way in.
+
+ // The following drawing code works for both tab layouts.
int tabCount = tabPane.getTabCount();
+
for (int i = runCount - 1; i >= 0; --i)
{
int start = tabRuns[i];
@@ -1842,14 +2292,16 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
if (j != selectedIndex)
{
- paintTab(g, tabPlacement, rects, j, ir, tr);
+ paintTab(g, tabPlacement, rects, j,
+ tempIconRect, tempTextRect);
}
}
}
-
+
// Paint selected tab in front of every other tab.
if (selectedIndex >= 0)
- paintTab(g, tabPlacement, rects, selectedIndex, ir, tr);
+ paintTab(g, tabPlacement, rects, selectedIndex,
+ tempIconRect, tempTextRect);
}
/**
@@ -1889,8 +2341,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// Paint the text.
paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
textRect, isSelected);
+
// Paint icon if necessary.
paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
+
// Paint focus indicator.
paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect,
isSelected);
@@ -2030,8 +2484,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
boolean isSelected)
{
- // No reason to shift.
- return 0;
+ switch (tabPlacement)
+ {
+ default:
+ case SwingUtilities.TOP:
+ case SwingUtilities.BOTTOM:
+ return 1;
+ case SwingUtilities.LEFT:
+ return (isSelected) ? -1 : 1;
+ case SwingUtilities.RIGHT:
+ return (isSelected) ? 1 : -1;
+ }
}
/**
@@ -2047,8 +2510,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
boolean isSelected)
{
- // No reason to shift.
- return 0;
+ switch (tabPlacement)
+ {
+ default:
+ case SwingUtilities.TOP:
+ return (isSelected) ? -1 : 1;
+ case SwingUtilities.BOTTOM:
+ return (isSelected) ? 1 : -1;
+ case SwingUtilities.LEFT:
+ case SwingUtilities.RIGHT:
+ return 0;
+ }
}
/**
@@ -2078,32 +2550,33 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
g.setColor(focus);
switch (tabPlacement)
- {
- case LEFT:
- x = rect.x + 3;
- y = rect.y + 3;
- w = rect.width - 5;
- h = rect.height - 6;
- break;
- case RIGHT:
- x = rect.x + 2;
- y = rect.y + 3;
- w = rect.width - 6;
- h = rect.height - 5;
- break;
- case BOTTOM:
- x = rect.x + 3;
- y = rect.y + 2;
- w = rect.width - 6;
- h = rect.height - 5;
- break;
- case TOP:
- default:
- x = rect.x + 3;
- y = rect.y + 3;
- w = rect.width - 6;
- h = rect.height - 5;
- }
+ {
+ case LEFT:
+ x = rect.x + 3;
+ y = rect.y + 3;
+ w = rect.width - 5;
+ h = rect.height - 6;
+ break;
+ case RIGHT:
+ x = rect.x + 2;
+ y = rect.y + 3;
+ w = rect.width - 6;
+ h = rect.height - 5;
+ break;
+ case BOTTOM:
+ x = rect.x + 3;
+ y = rect.y + 2;
+ w = rect.width - 6;
+ h = rect.height - 5;
+ break;
+ case TOP:
+ default:
+ x = rect.x + 3;
+ y = rect.y + 3;
+ w = rect.width - 6;
+ h = rect.height - 5;
+ }
+
BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
}
}
@@ -2125,34 +2598,109 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
Color saved = g.getColor();
- if (! isSelected || tabPlacement != SwingConstants.TOP)
- {
+ switch (tabPlacement)
+ {
+ case SwingConstants.TOP:
g.setColor(shadow);
- g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
- g.setColor(darkShadow);
- g.drawLine(x, y + h, x + w, y + h);
- }
+ // Inner right line.
+ g.drawLine(x + w - 2, y + 2, x + w - 2, y + h);
- if (! isSelected || tabPlacement != SwingConstants.LEFT)
- {
g.setColor(darkShadow);
- g.drawLine(x + w, y, x + w, y + h);
+ // Outer right line.
+ g.drawLine(x + w - 1, y + 2, x + w - 1, y + h);
+
+ // Upper right corner.
+ g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
+
+ g.setColor(lightHighlight);
+
+ // Left line.
+ g.drawLine(x, y + 3, x, y + h);
+
+ // Upper line.
+ g.drawLine(x + 3, y, x + w - 3, y);
+
+ // Upper left corner.
+ g.drawLine(x, y + 2, x + 2, y);
+
+ break;
+ case SwingConstants.LEFT:
+ g.setColor(lightHighlight);
+ // Top line.
+ g.drawLine(x + 3, y, x + w - 1, y);
+
+ // Top left border.
+ g.drawLine(x + 2, y, x, y + 2);
+
+ // Left line.
+ g.drawLine(x, y + 3, x, y + h - 4);
+
+ // Bottom left corner.
+ g.drawLine(x, y + h - 3, x + 1, y + h - 2);
+
+ g.setColor(darkShadow);
+ // Outer bottom line.
+ g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
+
g.setColor(shadow);
- g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
- }
+ // Inner bottom line.
+ g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2);
+
+ break;
+ case SwingConstants.BOTTOM:
+ g.setColor(shadow);
+ // Inner right line.
+ g.drawLine(x + w - 2, y, x + w - 2, y + h - 2);
- if (! isSelected || tabPlacement != SwingConstants.RIGHT)
- {
- g.setColor(lightHighlight);
- g.drawLine(x, y, x, y + h);
- }
+ // Inner bottom line.
+ g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1);
- if (! isSelected || tabPlacement != SwingConstants.BOTTOM)
- {
+ g.setColor(darkShadow);
+ // Outer right line.
+ g.drawLine(x + w - 1, y, x + w - 1, y + h - 3);
+
+ // Bottom right corner.
+ g.drawLine(x + w - 1, y + h - 2, x + w - 3, y + h);
+
+ // Bottom line.
+ g.drawLine(x + 2, y + h, x + w - 4, y + h);
+
g.setColor(lightHighlight);
- g.drawLine(x, y, x + w, y);
- }
-
+ // Left line.
+ g.drawLine(x, y, x, y + h - 3);
+
+ // Bottom left corner.
+ g.drawLine(x, y + h - 2, x + 1, y + h - 1);
+ break;
+ case SwingConstants.RIGHT:
+ g.setColor(lightHighlight);
+ // Top line.
+ g.drawLine(x, y, x + w - 3, y);
+
+ g.setColor(darkShadow);
+ // Top right corner.
+ g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
+
+ // Outer right line.
+ g.drawLine(x + w - 1, y + 3, x + w - 1, y + h - 3);
+
+ // Bottom right corner.
+ g.drawLine(x + w - 2, y + h - 2, x + w - 3, y + h - 1);
+
+ // Bottom line.
+ g.drawLine(x, y + h - 1, x + w - 4, y + h - 1);
+
+ g.setColor(shadow);
+
+ // Inner right line.
+ g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3);
+
+ // Inner bottom line.
+ g.drawLine(x, y + h - 2, x + w - 3, y + h - 2);
+
+ break;
+ }
+
g.setColor(saved);
}
@@ -2173,17 +2721,32 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
boolean isSelected)
{
Color saved = g.getColor();
+
if (isSelected)
- g.setColor(Color.LIGHT_GRAY);
+ g.setColor(selectedColor);
else
{
Color bg = tabPane.getBackgroundAt(tabIndex);
if (bg == null)
- bg = Color.GRAY;
+ bg = Color.LIGHT_GRAY;
g.setColor(bg);
}
- g.fillRect(x, y, w, h);
+ switch (tabPlacement)
+ {
+ case SwingConstants.TOP:
+ g.fillRect(x + 1, y + 1, w - 1, h - 1);
+ break;
+ case SwingConstants.BOTTOM:
+ g.fillRect(x, y, w - 1, h - 1);
+ break;
+ case SwingConstants.LEFT:
+ g.fillRect(x + 1, y + 1, w - 1, h - 2);
+ break;
+ case SwingConstants.RIGHT:
+ g.fillRect(x, y + 1, w - 1, h - 2);
+ break;
+ }
g.setColor(saved);
}
@@ -2260,25 +2823,27 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Color saved = g.getColor();
g.setColor(lightHighlight);
- int startgap = rects[selectedIndex].x;
- int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
-
- int diff = 0;
+ int startgap = rects[selectedIndex].x - currentScrollOffset;
+ int endgap = rects[selectedIndex].x + rects[selectedIndex].width
+ - currentScrollOffset;
- if (tabPlacement == SwingConstants.TOP)
+ // Paint the highlight line with a gap if the tabs are at the top
+ // and the selected tab is inside the visible area.
+ if (tabPlacement == SwingConstants.TOP && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.x;
- }
-
- g.drawLine(x, y, startgap - diff, y);
- g.drawLine(endgap - diff, y, x + w, y);
+ g.drawLine(x, y, startgap, y);
+ g.drawLine(endgap, y, x + w - 1, y);
+
+ g.setColor(selectedColor);
+ g.drawLine(startgap, y, endgap - 1, y);
}
else
g.drawLine(x, y, x + w, y);
-
+
+ g.setColor(selectedColor);
+ g.drawLine(x, y + 1, x + w - 1, y + 1);
+ g.drawLine(x, y + 2, x + w - 1, y + 2);
+
g.setColor(saved);
}
@@ -2300,24 +2865,25 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Color saved = g.getColor();
g.setColor(lightHighlight);
- int startgap = rects[selectedIndex].y;
- int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
+ int startgap = rects[selectedIndex].y - currentScrollOffset;
+ int endgap = rects[selectedIndex].y + rects[selectedIndex].height
+ - currentScrollOffset;
int diff = 0;
- if (tabPlacement == SwingConstants.LEFT)
+ if (tabPlacement == SwingConstants.LEFT && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.y;
- }
-
- g.drawLine(x, y, x, startgap - diff);
- g.drawLine(x, endgap - diff, x, y + h);
+ g.drawLine(x, y, x, startgap);
+ g.drawLine(x, endgap, x, y + h - 1);
+
+ g.setColor(selectedColor);
+ g.drawLine(x, startgap, x, endgap - 1);
}
else
- g.drawLine(x, y, x, y + h);
+ g.drawLine(x, y, x, y + h - 1);
+
+ g.setColor(selectedColor);
+ g.drawLine(x + 1, y + 1, x + 1, y + h - 4);
g.setColor(saved);
}
@@ -2339,34 +2905,34 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
Color saved = g.getColor();
- int startgap = rects[selectedIndex].x;
- int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
-
- int diff = 0;
+ int startgap = rects[selectedIndex].x - currentScrollOffset;
+ int endgap = rects[selectedIndex].x + rects[selectedIndex].width
+ - currentScrollOffset;
- if (tabPlacement == SwingConstants.BOTTOM)
+ if (tabPlacement == SwingConstants.BOTTOM && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.x;
- }
-
g.setColor(shadow);
- g.drawLine(x + 1, y + h - 1, startgap - diff, y + h - 1);
- g.drawLine(endgap - diff, y + h - 1, x + w - 1, y + h - 1);
+ g.drawLine(x + 1, y + h - 2, startgap, y + h - 2);
+ g.drawLine(endgap, y + h - 2, x + w - 2, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x, y + h, startgap - diff, y + h);
- g.drawLine(endgap - diff, y + h, x + w, y + h);
+ g.drawLine(x, y + h - 1, startgap , y + h - 1);
+ g.drawLine(endgap, y + h - 1, x + w - 1, y + h - 1);
+
+ g.setColor(selectedColor);
+ g.drawLine(startgap, y + h - 1, endgap - 1, y + h - 1);
+ g.drawLine(startgap, y + h - 2, endgap - 1, y + h - 2);
}
else
{
g.setColor(shadow);
- g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
+ g.drawLine(x + 1, y + h - 2, x + w - 1, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x, y + h, x + w, y + h);
+ g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
}
+
+ g.setColor(selectedColor);
+ g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3);
g.setColor(saved);
}
@@ -2387,34 +2953,36 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int w, int h)
{
Color saved = g.getColor();
- int startgap = rects[selectedIndex].y;
- int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
+ int startgap = rects[selectedIndex].y - currentScrollOffset;
+ int endgap = rects[selectedIndex].y + rects[selectedIndex].height
+ - currentScrollOffset;
int diff = 0;
- if (tabPlacement == SwingConstants.RIGHT)
+ if (tabPlacement == SwingConstants.RIGHT && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.y;
- }
-
g.setColor(shadow);
- g.drawLine(x + w - 1, y + 1, x + w - 1, startgap - diff);
- g.drawLine(x + w - 1, endgap - diff, x + w - 1, y + h - 1);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, startgap);
+ g.drawLine(x + w - 2, endgap, x + w - 2, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x + w, y, x + w, startgap - diff);
- g.drawLine(x + w, endgap - diff, x + w, y + h);
+ g.drawLine(x + w - 1, y, x + w - 1, startgap);
+ g.drawLine(x + w - 1, endgap, x + w - 1, y + h - 2);
+
+ g.setColor(selectedColor);
+ g.drawLine(x + w - 2, startgap, x + w - 2, endgap - 1);
+ g.drawLine(x + w - 1, startgap, x + w - 1, endgap - 1);
}
else
{
g.setColor(shadow);
- g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x + w, y, x + w, y + h);
+ g.drawLine(x + w - 1, y, x + w - 1, y + h - 2);
}
+
+ g.setColor(selectedColor);
+ g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 4);
g.setColor(saved);
}
@@ -2458,11 +3026,15 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public int tabForCoordinate(JTabbedPane pane, int x, int y)
{
+ // Note: This code is tab layout mode agnostic.
if (! tabPane.isValid())
tabPane.validate();
-
+
int tabCount = tabPane.getTabCount();
- int index = -1;
+
+ // If the user clicked outside of any tab rect the
+ // selection should not change.
+ int index = tabPane.getSelectedIndex();
for (int i = 0; i < tabCount; ++i)
{
if (rects[i].contains(x, y))
@@ -2472,8 +3044,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
}
}
- // FIXME: Handle scrollable tab layout.
-
return index;
}
@@ -2569,7 +3139,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int getRunForTab(int tabCount, int tabIndex)
{
if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
- return 1;
+ return 0;
for (int i = 0; i < runCount; i++)
{
int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
@@ -2688,6 +3258,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected View getTextViewForTab(int tabIndex)
{
+ // FIXME: When the label contains HTML this should return something
+ // non-null.
return null;
}
@@ -2704,7 +3276,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int calculateTabHeight(int tabPlacement, int tabIndex,
int fontHeight)
{
- // FIXME: Handle HTML somehow.
+ // FIXME: Handle HTML by using the view (see getTextViewForTab).
int height = fontHeight;
Icon icon = getIconForTab(tabIndex);
@@ -2921,8 +3493,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
tabPane.getSelectedIndex(),
- (tabPlacement == SwingConstants.RIGHT)
- ? true : false);
+ (tabPlacement == SwingConstants.TOP)
+ ? direction == SwingConstants.NORTH
+ : direction == SwingConstants.SOUTH);
selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
offset);
}
@@ -2938,8 +3511,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
tabPane.getSelectedIndex(),
- (tabPlacement == SwingConstants.RIGHT)
- ? true : false);
+ (tabPlacement == SwingConstants.LEFT)
+ ? direction == SwingConstants.WEST
+ : direction == SwingConstants.EAST);
selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
offset);
}
@@ -2953,8 +3527,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectNextTabInRun(int current)
{
- tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(),
- current));
+ current = getNextTabIndexInRun(tabPane.getTabCount(),
+ current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -2964,8 +3543,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectPreviousTabInRun(int current)
{
- tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(),
- current));
+ current = getPreviousTabIndexInRun(tabPane.getTabCount(),
+ current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -2975,7 +3559,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectNextTab(int current)
{
- tabPane.setSelectedIndex(getNextTabIndex(current));
+ current = getNextTabIndex(current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -2985,7 +3574,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectPreviousTab(int current)
{
- tabPane.setSelectedIndex(getPreviousTabIndex(current));
+ current = getPreviousTabIndex(current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -3019,7 +3613,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int index = tabForCoordinate(tabPane, x, y);
if (index != -1)
- tabPane.setSelectedIndex(index);
+ {
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(index, tabPlacement);
+ tabPane.setSelectedIndex(index);
+ }
}
// This method is called when you press up/down to cycle through tab runs.
@@ -3056,6 +3654,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
else
offset = rects[lastTabInRun(tabCount, nextRun)].x
- rects[lastTabInRun(tabCount, currRun)].x;
+
return offset;
}
@@ -3102,9 +3701,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
int index = getNextTabIndex(base);
int run = getRunForTab(tabCount, base);
- if (index == lastTabInRun(tabCount, run) + 1)
- index = lastTabInRun(tabCount, getPreviousTabRun(run)) + 1;
- return getNextTabIndex(base);
+ if (base == lastTabInRun(tabCount, run))
+ index = (run > 0)
+ ? lastTabInRun(tabCount, getPreviousTabRun(run)) + 1
+ : 0;
+
+ return index;
}
/**
@@ -3122,7 +3724,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int run = getRunForTab(tabCount, base);
if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
index = lastTabInRun(tabCount, run);
- return getPreviousTabIndex(base);
+
+ return index;
}
/**
@@ -3180,6 +3783,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// so I won't check it either.
switch (targetPlacement)
{
+ default:
case SwingConstants.TOP:
targetInsets.top = topInsets.top;
targetInsets.left = topInsets.left;
@@ -3206,6 +3810,44 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
break;
}
}
+
+ ActionMap getActionMap()
+ {
+ ActionMap map = (ActionMap) UIManager.get("TabbedPane.actionMap");
+
+ if (map == null) // first time here
+ {
+ map = createActionMap();
+ if (map != null)
+ UIManager.put("TabbedPane.actionMap", map);
+ }
+ return map;
+ }
+
+ ActionMap createActionMap()
+ {
+ ActionMap map = new ActionMapUIResource();
+
+ map.put("navigatePageDown", new NavigatePageDownAction());
+ map.put("navigatePageUp", new NavigatePageUpAction());
+ map.put("navigateDown",
+ new NavigateAction("navigateDown", SwingConstants.SOUTH));
+
+ map.put("navigateUp",
+ new NavigateAction("navigateUp", SwingConstants.NORTH));
+
+ map.put("navigateLeft",
+ new NavigateAction("navigateLeft", SwingConstants.WEST));
+
+ map.put("navigateRight",
+ new NavigateAction("navigateRight", SwingConstants.EAST));
+
+ map.put("requestFocusForVisibleComponent",
+ new RequestFocusForVisibleComponentAction());
+ map.put("requestFocus", new RequestFocusAction());
+
+ return map;
+ }
/**
* Sets the tab which should be highlighted when in rollover mode. And
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
index cdd44a711e7..15be4d57e62 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
@@ -48,7 +46,6 @@ import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
@@ -58,6 +55,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.CellRendererPane;
import javax.swing.DefaultCellEditor;
@@ -65,16 +63,16 @@ import javax.swing.DefaultListSelectionModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JTable;
-import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
-import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TableUI;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
@@ -164,14 +162,37 @@ public class BasicTableUI extends TableUI
public class FocusHandler implements FocusListener
{
- public void focusGained(FocusEvent e)
+ public void focusGained(FocusEvent e)
{
- // TODO: Implement this properly.
+ // The only thing that is affected by a focus change seems to be
+ // how the lead cell is painted. So we repaint this cell.
+ repaintLeadCell();
}
- public void focusLost(FocusEvent e)
+ public void focusLost(FocusEvent e)
+ {
+ // The only thing that is affected by a focus change seems to be
+ // how the lead cell is painted. So we repaint this cell.
+ repaintLeadCell();
+ }
+
+ /**
+ * Repaints the lead cell in response to a focus change, to refresh
+ * the display of the focus indicator.
+ */
+ private void repaintLeadCell()
{
- // TODO: Implement this properly.
+ int rowCount = table.getRowCount();
+ int columnCount = table.getColumnCount();
+ int rowLead = table.getSelectionModel().getLeadSelectionIndex();
+ int columnLead = table.getColumnModel().getSelectionModel().
+ getLeadSelectionIndex();
+ if (rowLead >= 0 && rowLead < rowCount && columnLead >= 0
+ && columnLead < columnCount)
+ {
+ Rectangle dirtyRect = table.getCellRect(rowLead, columnLead, false);
+ table.repaint(dirtyRect);
+ }
}
}
@@ -242,19 +263,19 @@ public class BasicTableUI extends TableUI
}
}
- public void mouseEntered(MouseEvent e)
+ public void mouseEntered(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
- public void mouseExited(MouseEvent e)
+ public void mouseExited(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
- public void mouseMoved(MouseEvent e)
+ public void mouseMoved(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
public void mousePressed(MouseEvent e)
@@ -287,6 +308,9 @@ public class BasicTableUI extends TableUI
colLead != colModel.getLeadSelectionIndex())
if (table.isEditing())
table.editingStopped(new ChangeEvent(e));
+
+ // Must request focus explicitly.
+ table.requestFocusInWindow();
}
}
@@ -456,66 +480,100 @@ public class BasicTableUI extends TableUI
table.setOpaque(true);
}
+ /**
+ * Installs keyboard actions on the table.
+ */
protected void installKeyboardActions()
{
- InputMap ancestorMap = (InputMap) UIManager.get("Table.ancestorInputMap");
- InputMapUIResource parentInputMap = new InputMapUIResource();
- // FIXME: The JDK uses a LazyActionMap for parentActionMap
- ActionMap parentActionMap = new ActionMapUIResource();
- action = new TableAction();
- Object keys[] = ancestorMap.allKeys();
- // Register key bindings in the UI InputMap-ActionMap pair
- for (int i = 0; i < keys.length; i++)
- {
- KeyStroke stroke = (KeyStroke) keys[i];
- String actionString = (String) ancestorMap.get(stroke);
+ // Install the input map.
+ InputMap inputMap =
+ (InputMap) SharedUIDefaults.get("Table.ancestorInputMap");
+ SwingUtilities.replaceUIInputMap(table,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ inputMap);
- parentInputMap.put(KeyStroke.getKeyStroke(stroke.getKeyCode(),
- stroke.getModifiers()),
- actionString);
-
- parentActionMap.put(actionString,
- new ActionListenerProxy(action, actionString));
+ // FIXME: The JDK uses a LazyActionMap for parentActionMap
+ SwingUtilities.replaceUIActionMap(table, getActionMap());
- }
- // Set the UI InputMap-ActionMap pair to be the parents of the
- // JTable's InputMap-ActionMap pair
- parentInputMap.setParent(table.getInputMap(
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent());
- parentActionMap.setParent(table.getActionMap().getParent());
- table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
- setParent(parentInputMap);
- table.getActionMap().setParent(parentActionMap);
}
/**
- * This class is used to mimmic the behaviour of the JDK when registering
- * keyboard actions. It is the same as the private class used in JComponent
- * for the same reason. This class receives an action event and dispatches
- * it to the true receiver after altering the actionCommand property of the
- * event.
+ * Fetches the action map from the UI defaults, or create a new one
+ * if the action map hasn't been initialized.
+ *
+ * @return the action map
*/
- private static class ActionListenerProxy
- extends AbstractAction
+ private ActionMap getActionMap()
{
- ActionListener target;
- String bindingCommandName;
-
- public ActionListenerProxy(ActionListener li,
- String cmd)
- {
- target = li;
- bindingCommandName = cmd;
- }
+ ActionMap am = (ActionMap) UIManager.get("Table.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("Table.actionMap", am);
+ }
+ return am;
+ }
- public void actionPerformed(ActionEvent e)
- {
- ActionEvent derivedEvent = new ActionEvent(e.getSource(),
- e.getID(),
- bindingCommandName,
- e.getModifiers());
- target.actionPerformed(derivedEvent);
- }
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new TableAction();
+
+ am.put("cut", TransferHandler.getCutAction());
+ am.put("copy", TransferHandler.getCopyAction());
+ am.put("paste", TransferHandler.getPasteAction());
+
+ am.put("cancel", action);
+ am.put("selectAll", action);
+ am.put("clearSelection", action);
+ am.put("startEditing", action);
+
+ am.put("selectNextRow", action);
+ am.put("selectNextRowCell", action);
+ am.put("selectNextRowExtendSelection", action);
+ am.put("selectNextRowChangeLead", action);
+
+ am.put("selectPreviousRow", action);
+ am.put("selectPreviousRowCell", action);
+ am.put("selectPreviousRowExtendSelection", action);
+ am.put("selectPreviousRowChangeLead", action);
+
+ am.put("selectNextColumn", action);
+ am.put("selectNextColumnCell", action);
+ am.put("selectNextColumnExtendSelection", action);
+ am.put("selectNextColumnChangeLead", action);
+
+ am.put("selectPreviousColumn", action);
+ am.put("selectPreviousColumnCell", action);
+ am.put("selectPreviousColumnExtendSelection", action);
+ am.put("selectPreviousColumnChangeLead", action);
+
+ am.put("scrollLeftChangeSelection", action);
+ am.put("scrollLeftExtendSelection", action);
+ am.put("scrollRightChangeSelection", action);
+ am.put("scrollRightExtendSelection", action);
+
+ am.put("scrollUpChangeSelection", action);
+ am.put("scrollUpExtendSelection", action);
+ am.put("scrollDownChangeSelection", action);
+ am.put("scrolldownExtendSelection", action);
+
+ am.put("selectFirstColumn", action);
+ am.put("selectFirstColumnExtendSelection", action);
+ am.put("selectLastColumn", action);
+ am.put("selectLastColumnExtendSelection", action);
+
+ am.put("selectFirstRow", action);
+ am.put("selectFirstRowExtendSelection", action);
+ am.put("selectLastRow", action);
+ am.put("selectLastRowExtendSelection", action);
+
+ am.put("addToSelection", action);
+ am.put("toggleAndAnchor", action);
+ am.put("extendTo", action);
+ am.put("moveSelectionTo", action);
+
+ return am;
}
/**
@@ -524,7 +582,8 @@ public class BasicTableUI extends TableUI
* method is called when a key that has been registered for the JTable
* is received.
*/
- class TableAction extends AbstractAction
+ private static class TableAction
+ extends AbstractAction
{
/**
* What to do when this action is called.
@@ -533,6 +592,8 @@ public class BasicTableUI extends TableUI
*/
public void actionPerformed(ActionEvent e)
{
+ JTable table = (JTable) e.getSource();
+
DefaultListSelectionModel rowModel
= (DefaultListSelectionModel) table.getSelectionModel();
DefaultListSelectionModel colModel
@@ -543,9 +604,11 @@ public class BasicTableUI extends TableUI
int colLead = colModel.getLeadSelectionIndex();
int colMax = table.getModel().getColumnCount() - 1;
-
- String command = e.getActionCommand();
-
+
+ // The command with which the action has been called is stored
+ // in this undocumented action value. This allows us to have only
+ // one Action instance to serve all keyboard input for JTable.
+ String command = (String) getValue("__command__");
if (command.equals("selectPreviousRowExtendSelection"))
{
rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0));
@@ -603,11 +666,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollUpExtendSelection"))
{
int target;
- if (rowLead == getFirstVisibleRowIndex())
- target = Math.max(0, rowLead - (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getFirstVisibleRowIndex(table))
+ target = Math.max(0, rowLead - (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getFirstVisibleRowIndex();
+ target = getFirstVisibleRowIndex(table);
rowModel.setLeadSelectionIndex(target);
colModel.setLeadSelectionIndex(colLead);
@@ -620,11 +683,12 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollRightChangeSelection"))
{
int target;
- if (colLead == getLastVisibleColumnIndex())
- target = Math.min(colMax, colLead + (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getLastVisibleColumnIndex(table))
+ target = Math.min(colMax, colLead
+ + (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getLastVisibleColumnIndex();
+ target = getLastVisibleColumnIndex(table);
colModel.setSelectionInterval(target, target);
rowModel.setSelectionInterval(rowLead, rowLead);
@@ -637,11 +701,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollLeftChangeSelection"))
{
int target;
- if (colLead == getFirstVisibleColumnIndex())
- target = Math.max(0, colLead - (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getFirstVisibleColumnIndex(table))
+ target = Math.max(0, colLead - (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getFirstVisibleColumnIndex();
+ target = getFirstVisibleColumnIndex(table);
colModel.setSelectionInterval(target, target);
rowModel.setSelectionInterval(rowLead, rowLead);
@@ -723,14 +787,18 @@ public class BasicTableUI extends TableUI
// If there are multiple rows and columns selected, select the next
// cell and wrap at the edges of the selection.
if (command.indexOf("Column") != -1)
- advanceMultipleSelection(colModel, colMinSelected, colMaxSelected,
- rowModel, rowMinSelected, rowMaxSelected,
- command.equals("selectPreviousColumnCell"), true);
+ advanceMultipleSelection(table, colModel, colMinSelected,
+ colMaxSelected, rowModel, rowMinSelected,
+ rowMaxSelected,
+ command.equals("selectPreviousColumnCell"),
+ true);
else
- advanceMultipleSelection(rowModel, rowMinSelected, rowMaxSelected,
- colModel, colMinSelected, colMaxSelected,
- command.equals("selectPreviousRowCell"), false);
+ advanceMultipleSelection(table, rowModel, rowMinSelected,
+ rowMaxSelected, colModel, colMinSelected,
+ colMaxSelected,
+ command.equals("selectPreviousRowCell"),
+ false);
}
else if (command.equals("selectNextColumn"))
{
@@ -740,11 +808,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollLeftExtendSelection"))
{
int target;
- if (colLead == getFirstVisibleColumnIndex())
- target = Math.max(0, colLead - (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getFirstVisibleColumnIndex(table))
+ target = Math.max(0, colLead - (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getFirstVisibleColumnIndex();
+ target = getFirstVisibleColumnIndex(table);
colModel.setLeadSelectionIndex(target);
rowModel.setLeadSelectionIndex(rowLead);
@@ -752,11 +820,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollDownChangeSelection"))
{
int target;
- if (rowLead == getLastVisibleRowIndex())
- target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getLastVisibleRowIndex(table))
+ target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getLastVisibleRowIndex();
+ target = getLastVisibleRowIndex(table);
rowModel.setSelectionInterval(target, target);
colModel.setSelectionInterval(colLead, colLead);
@@ -764,11 +832,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollRightExtendSelection"))
{
int target;
- if (colLead == getLastVisibleColumnIndex())
- target = Math.min(colMax, colLead + (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getLastVisibleColumnIndex(table))
+ target = Math.min(colMax, colLead + (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getLastVisibleColumnIndex();
+ target = getLastVisibleColumnIndex(table);
colModel.setLeadSelectionIndex(target);
rowModel.setLeadSelectionIndex(rowLead);
@@ -785,11 +853,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollDownExtendSelection"))
{
int target;
- if (rowLead == getLastVisibleRowIndex())
- target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getLastVisibleRowIndex(table))
+ target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getLastVisibleRowIndex();
+ target = getLastVisibleRowIndex(table);
rowModel.setLeadSelectionIndex(target);
colModel.setLeadSelectionIndex(colLead);
@@ -797,11 +865,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollUpChangeSelection"))
{
int target;
- if (rowLead == getFirstVisibleRowIndex())
- target = Math.max(0, rowLead - (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getFirstVisibleRowIndex(table))
+ target = Math.max(0, rowLead - (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getFirstVisibleRowIndex();
+ target = getFirstVisibleRowIndex(table);
rowModel.setSelectionInterval(target, target);
colModel.setSelectionInterval(colLead, colLead);
@@ -926,7 +994,7 @@ public class BasicTableUI extends TableUI
* Returns the column index of the first visible column.
* @return the column index of the first visible column.
*/
- int getFirstVisibleColumnIndex()
+ int getFirstVisibleColumnIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -939,7 +1007,7 @@ public class BasicTableUI extends TableUI
* Returns the column index of the last visible column.
*
*/
- int getLastVisibleColumnIndex()
+ int getLastVisibleColumnIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -952,7 +1020,7 @@ public class BasicTableUI extends TableUI
* Returns the row index of the first visible row.
*
*/
- int getFirstVisibleRowIndex()
+ int getFirstVisibleRowIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -965,7 +1033,7 @@ public class BasicTableUI extends TableUI
* Returns the row index of the last visible row.
*
*/
- int getLastVisibleRowIndex()
+ int getLastVisibleRowIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -977,7 +1045,7 @@ public class BasicTableUI extends TableUI
// area is larger than the table)
if (table.rowAtPoint(r.getLocation()) == -1)
{
- if (getFirstVisibleRowIndex() == -1)
+ if (getFirstVisibleRowIndex(table) == -1)
return -1;
else
return table.getModel().getRowCount() - 1;
@@ -1003,7 +1071,8 @@ public class BasicTableUI extends TableUI
* @param reverse true if shift was held for the event
* @param eventIsTab true if TAB was pressed, false if ENTER pressed
*/
- void advanceMultipleSelection(ListSelectionModel firstModel, int firstMin,
+ void advanceMultipleSelection(JTable table, ListSelectionModel firstModel,
+ int firstMin,
int firstMax, ListSelectionModel secondModel,
int secondMin, int secondMax, boolean reverse,
boolean eventIsTab)
@@ -1167,30 +1236,24 @@ public class BasicTableUI extends TableUI
table.addPropertyChangeListener(propertyChangeListener);
}
- protected void uninstallDefaults()
+ /**
+ * Uninstalls UI defaults that have been installed by
+ * {@link #installDefaults()}.
+ */
+ protected void uninstallDefaults()
{
- // TODO: this method used to do the following which is not
- // quite right (at least it breaks apps that run fine with the
- // JDK):
- //
- // table.setFont(null);
- // table.setGridColor(null);
- // table.setForeground(null);
- // table.setBackground(null);
- // table.setSelectionForeground(null);
- // table.setSelectionBackground(null);
- //
- // This would leave the component in a corrupt state, which is
- // not acceptable. A possible solution would be to have component
- // level defaults installed, that get overridden by the UI defaults
- // and get restored in this method. I am not quite sure about this
- // though. / Roman Kennke
+ // Nothing to do here for now.
}
- protected void uninstallKeyboardActions()
- throws NotImplementedException
+ /**
+ * Uninstalls the keyboard actions that have been installed by
+ * {@link #installKeyboardActions()}.
+ */
+ protected void uninstallKeyboardActions()
{
- // TODO: Implement this properly.
+ SwingUtilities.replaceUIInputMap(table, JComponent.
+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities.replaceUIActionMap(table, null);
}
protected void uninstallListeners()
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
index 89c4e5a7562..6792aa065da 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.Color;
import java.beans.PropertyChangeEvent;
import javax.swing.JComponent;
@@ -94,12 +95,24 @@ public class BasicTextFieldUI extends BasicTextUI
{
if (event.getPropertyName().equals("editable"))
{
- boolean editable = ((Boolean) event.getNewValue()).booleanValue();
-
// Changing the color only if the current background is an instance of
// ColorUIResource is the behavior of the RI.
if (textComponent.getBackground() instanceof ColorUIResource)
- textComponent.setBackground(editable ? background : inactiveBackground);
+ {
+ Color c = null;
+ Color old = textComponent.getBackground();
+ String prefix = getPropertyPrefix();
+ if (! textComponent.isEnabled())
+ c = SharedUIDefaults.getColor(prefix + ".disabledBackground");
+ if (c == null && ! textComponent.isEditable())
+ c = SharedUIDefaults.getColor(prefix + ".inactiveBackground");
+ if (c == null)
+ c = SharedUIDefaults.getColor(prefix + ".background");
+ if (c != null && c != old)
+ {
+ textComponent.setBackground(c);
+ }
+ }
}
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
index 34261cfe644..8e9c8c949f3 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
@@ -83,7 +83,6 @@ import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.Position;
-import javax.swing.text.Utilities;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
@@ -418,7 +417,19 @@ public abstract class BasicTextUI extends TextUI
if (event.getPropertyName().equals("document"))
{
// Document changed.
- modelChanged();
+ Object oldValue = event.getOldValue();
+ if (oldValue != null)
+ {
+ Document oldDoc = (Document) oldValue;
+ oldDoc.removeDocumentListener(documentHandler);
+ }
+ Object newValue = event.getNewValue();
+ if (newValue != null)
+ {
+ Document newDoc = (Document) newValue;
+ newDoc.addDocumentListener(documentHandler);
+ }
+ modelChanged();
}
BasicTextUI.this.propertyChange(event);
@@ -501,18 +512,6 @@ public abstract class BasicTextUI extends TextUI
DocumentHandler documentHandler = new DocumentHandler();
/**
- * The standard background color. This is the color which is used to paint
- * text in enabled text components.
- */
- Color background;
-
- /**
- * The inactive background color. This is the color which is used to paint
- * text in disabled text components.
- */
- Color inactiveBackground;
-
- /**
* Creates a new <code>BasicTextUI</code> instance.
*/
public BasicTextUI()
@@ -558,22 +557,23 @@ public abstract class BasicTextUI extends TextUI
*/
public void installUI(final JComponent c)
{
- super.installUI(c);
-
textComponent = (JTextComponent) c;
+ installDefaults();
+ textComponent.addPropertyChangeListener(updateHandler);
Document doc = textComponent.getDocument();
if (doc == null)
{
doc = getEditorKit(textComponent).createDefaultDocument();
textComponent.setDocument(doc);
}
- installDefaults();
+ else
+ {
+ doc.addDocumentListener(documentHandler);
+ modelChanged();
+ }
+
installListeners();
installKeyboardActions();
-
- // We need to trigger this so that the view hierarchy gets initialized.
- modelChanged();
-
}
/**
@@ -581,34 +581,60 @@ public abstract class BasicTextUI extends TextUI
*/
protected void installDefaults()
{
+ String prefix = getPropertyPrefix();
+ // Install the standard properties.
+ LookAndFeel.installColorsAndFont(textComponent, prefix + ".background",
+ prefix + ".foreground", prefix + ".font");
+ LookAndFeel.installBorder(textComponent, prefix + ".border");
+ textComponent.setMargin(UIManager.getInsets(prefix + ".margin"));
+
+ // Some additional text component only properties.
+ Color color = textComponent.getCaretColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".caretForeground");
+ textComponent.setCaretColor(color);
+ }
+
+ // Fetch the colors for enabled/disabled text components.
+ color = textComponent.getDisabledTextColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".inactiveBackground");
+ textComponent.setDisabledTextColor(color);
+ }
+ color = textComponent.getSelectedTextColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".selectionForeground");
+ textComponent.setSelectedTextColor(color);
+ }
+ color = textComponent.getSelectionColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".selectionBackground");
+ textComponent.setSelectionColor(color);
+ }
+
+ Insets margin = textComponent.getMargin();
+ if (margin == null || margin instanceof UIResource)
+ {
+ margin = UIManager.getInsets(prefix + ".margin");
+ textComponent.setMargin(margin);
+ }
+
Caret caret = textComponent.getCaret();
- if (caret == null)
+ if (caret == null || caret instanceof UIResource)
{
caret = createCaret();
textComponent.setCaret(caret);
+ caret.setBlinkRate(UIManager.getInt(prefix + ".caretBlinkRate"));
}
Highlighter highlighter = textComponent.getHighlighter();
- if (highlighter == null)
+ if (highlighter == null || highlighter instanceof UIResource)
textComponent.setHighlighter(createHighlighter());
- String prefix = getPropertyPrefix();
- LookAndFeel.installColorsAndFont(textComponent, prefix + ".background",
- prefix + ".foreground", prefix + ".font");
- LookAndFeel.installBorder(textComponent, prefix + ".border");
- textComponent.setMargin(UIManager.getInsets(prefix + ".margin"));
-
- caret.setBlinkRate(UIManager.getInt(prefix + ".caretBlinkRate"));
-
- // Fetch the colors for enabled/disabled text components.
- background = UIManager.getColor(prefix + ".background");
- inactiveBackground = UIManager.getColor(prefix + ".inactiveBackground");
- textComponent.setDisabledTextColor(UIManager.getColor(prefix
- + ".inactiveForeground"));
- textComponent.setSelectedTextColor(UIManager.getColor(prefix
- + ".selectionForeground"));
- textComponent.setSelectionColor(UIManager.getColor(prefix
- + ".selectionBackground"));
}
/**
@@ -670,18 +696,6 @@ public abstract class BasicTextUI extends TextUI
protected void installListeners()
{
textComponent.addFocusListener(focuslistener);
- textComponent.addPropertyChangeListener(updateHandler);
- installDocumentListeners();
- }
-
- /**
- * Installs the document listeners on the textComponent's model.
- */
- private void installDocumentListeners()
- {
- Document doc = textComponent.getDocument();
- if (doc != null)
- doc.addDocumentListener(documentHandler);
}
/**
@@ -845,9 +859,7 @@ public abstract class BasicTextUI extends TextUI
*/
protected void uninstallListeners()
{
- textComponent.removePropertyChangeListener(updateHandler);
textComponent.removeFocusListener(focuslistener);
- textComponent.getDocument().removeDocumentListener(documentHandler);
}
/**
@@ -1029,7 +1041,7 @@ public abstract class BasicTextUI extends TextUI
*/
public void damageRange(JTextComponent t, int p0, int p1)
{
- damageRange(t, p0, p1, null, null);
+ damageRange(t, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
}
/**
@@ -1049,106 +1061,36 @@ public abstract class BasicTextUI extends TextUI
public void damageRange(JTextComponent t, int p0, int p1,
Position.Bias firstBias, Position.Bias secondBias)
{
- // Do nothing if the component cannot be properly displayed.
- if (t.getWidth() == 0 || t.getHeight() == 0)
- return;
-
- try
+ Rectangle alloc = getVisibleEditorRect();
+ if (alloc != null)
{
- // Limit p0 and p1 to sane values to prevent unfriendly
- // BadLocationExceptions. This makes it possible for the highlighter
- // to send us illegal values which can happen when a large number
- // of selected characters are removed (eg. by pressing delete
- // or backspace).
- // The reference implementation does not throw an exception, too.
- p0 = Math.min(p0, t.getDocument().getLength());
- p1 = Math.min(p1, t.getDocument().getLength());
-
- Rectangle l1 = modelToView(t, p0, firstBias);
- Rectangle l2 = modelToView(t, p1, secondBias);
- if (l1 == null || l2 == null)
+ Document doc = t.getDocument();
+
+ // Acquire lock here to avoid structural changes in between.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
{
- // Unable to determine the start or end of the selection.
- t.repaint();
+ rootView.setSize(alloc.width, alloc.height);
+ Shape damage = rootView.modelToView(p0, firstBias, p1, secondBias,
+ alloc);
+ Rectangle r = damage instanceof Rectangle ? (Rectangle) damage
+ : damage.getBounds();
+ textComponent.repaint(r.x, r.y, r.width, r.height);
}
- else if (l1.y == l2.y)
+ catch (BadLocationException ex)
{
- SwingUtilities.computeUnion(l2.x, l2.y, l2.width, l2.height, l1);
- t.repaint(l1);
+ // Lets ignore this as it causes no serious problems.
+ // For debugging, comment this out.
+ // ex.printStackTrace();
}
- else
+ finally
{
- // The two rectangles lie on different lines and we need a
- // different algorithm to calculate the damaged area:
- // 1. The line of p0 is damaged from the position of p0
- // to the right border.
- // 2. All lines between the ones where p0 and p1 lie on
- // are completely damaged. Use the allocation area to find
- // out the bounds.
- // 3. The final line is damaged from the left bound to the
- // position of p1.
- Insets insets = t.getInsets();
-
- // Damage first line until the end.
- l1.width = insets.right + t.getWidth() - l1.x;
- t.repaint(l1);
-
- // Note: Utilities.getPositionBelow() may return the offset
- // that was put in. In that case there is no next line and
- // we should stop searching for one.
-
- int posBelow = Utilities.getPositionBelow(t, p0, l1.x);
- int p1RowStart = Utilities.getRowStart(t, p1);
-
- if (posBelow != -1
- && posBelow != p0
- && Utilities.getRowStart(t, posBelow) != p1RowStart)
- {
- // Take the rectangle of the offset we just found and grow it
- // to the maximum width. Retain y because this is our start
- // height.
- Rectangle grow = modelToView(t, posBelow);
- grow.x = insets.left;
- grow.width = t.getWidth() + insets.right;
-
- // Find further lines which have to be damaged completely.
- int nextPosBelow = posBelow;
- while (nextPosBelow != -1
- && posBelow != nextPosBelow
- && Utilities.getRowStart(t, nextPosBelow) != p1RowStart)
- {
- posBelow = nextPosBelow;
- nextPosBelow = Utilities.getPositionBelow(t, posBelow,
- l1.x);
-
- if (posBelow == nextPosBelow)
- break;
- }
- // Now posBelow is an offset on the last line which has to be
- // damaged completely. (newPosBelow is on the same line as p1)
-
- // Retrieve the rectangle of posBelow and use its y and height
- // value to calculate the final height of the multiple line
- // spanning rectangle.
- Rectangle end = modelToView(t, posBelow);
- grow.height = end.y + end.height - grow.y;
-
- // Mark that area as damage.
- t.repaint(grow);
- }
-
- // Damage last line from its beginning to the position of p1.
- l2.width += l2.x;
- l2.x = insets.left;
- t.repaint(l2);
+ // Release lock.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
}
}
- catch (BadLocationException ex)
- {
- AssertionError err = new AssertionError("Unexpected bad location");
- err.initCause(ex);
- throw err;
- }
}
/**
@@ -1245,10 +1187,29 @@ public abstract class BasicTextUI extends TextUI
public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias)
throws BadLocationException
{
- Rectangle r = getVisibleEditorRect();
-
- return (r != null) ? rootView.modelToView(pos, r, bias).getBounds()
- : null;
+ // We need to read-lock here because we depend on the document
+ // structure not beeing changed in between.
+ Document doc = textComponent.getDocument();
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ Rectangle rect = null;
+ try
+ {
+ Rectangle r = getVisibleEditorRect();
+ if (r != null)
+ {
+ rootView.setSize(r.width, r.height);
+ Shape s = rootView.modelToView(pos, r, bias);
+ if (s != null)
+ rect = s.getBounds();
+ }
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ return rect;
}
/**
@@ -1361,7 +1322,6 @@ public abstract class BasicTextUI extends TextUI
Document doc = textComponent.getDocument();
if (doc == null)
return;
- installDocumentListeners();
Element elem = doc.getDefaultRootElement();
if (elem == null)
return;
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
index 8fce2f08a66..1c36b408d5a 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -50,6 +48,7 @@ import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
+import java.awt.event.ActionEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.FocusEvent;
@@ -62,7 +61,11 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Hashtable;
+import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
@@ -77,6 +80,7 @@ import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ToolBarUI;
import javax.swing.plaf.UIResource;
@@ -87,6 +91,35 @@ import javax.swing.plaf.basic.BasicBorders.ButtonBorder;
*/
public class BasicToolBarUI extends ToolBarUI implements SwingConstants
{
+
+ /**
+ * Implements the keyboard actions for JToolBar.
+ */
+ static class ToolBarAction
+ extends AbstractAction
+ {
+ /**
+ * Performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ Object cmd = getValue("__command__");
+ JToolBar toolBar = (JToolBar) event.getSource();
+ BasicToolBarUI ui = (BasicToolBarUI) toolBar.getUI();
+
+ if (cmd.equals("navigateRight"))
+ ui.navigateFocusedComp(EAST);
+ else if (cmd.equals("navigateLeft"))
+ ui.navigateFocusedComp(WEST);
+ else if (cmd.equals("navigateUp"))
+ ui.navigateFocusedComp(NORTH);
+ else if (cmd.equals("navigateDown"))
+ ui.navigateFocusedComp(SOUTH);
+ else
+ assert false : "Shouldn't reach here";
+ }
+ }
+
/** Static owner of all DragWindows.
* This is package-private to avoid an accessor method. */
static JFrame owner = new JFrame();
@@ -619,9 +652,46 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* by the look and feel.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ // Install the input map.
+ InputMap inputMap =
+ (InputMap) SharedUIDefaults.get("ToolBar.ancestorInputMap");
+ SwingUtilities.replaceUIInputMap(toolBar,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ inputMap);
+
+ // FIXME: The JDK uses a LazyActionMap for parentActionMap
+ SwingUtilities.replaceUIActionMap(toolBar, getActionMap());
+ }
+
+ /**
+ * Fetches the action map from the UI defaults, or create a new one
+ * if the action map hasn't been initialized.
+ *
+ * @return the action map
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("ToolBar.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("ToolBar.actionMap", am);
+ }
+ return am;
+ }
+
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new ToolBarAction();
+
+ am.put("navigateLeft", action);
+ am.put("navigateRight", action);
+ am.put("navigateUp", action);
+ am.put("navigateDown", action);
+
+ return am;
}
/**
@@ -643,7 +713,12 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
floatFrame.addWindowListener(windowListener);
toolBarFocusListener = createToolBarFocusListener();
- toolBar.addFocusListener(toolBarFocusListener);
+ if (toolBarFocusListener != null)
+ {
+ int count = toolBar.getComponentCount();
+ for (int i = 0; i < count; i++)
+ toolBar.getComponent(i).addFocusListener(toolBarFocusListener);
+ }
}
/**
@@ -758,9 +833,55 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* @param direction The direction to give focus to.
*/
protected void navigateFocusedComp(int direction)
- throws NotImplementedException
{
- // FIXME: Implement.
+ int count = toolBar.getComponentCount();
+ switch (direction)
+ {
+ case EAST:
+ case SOUTH:
+ if (focusedCompIndex >= 0 && focusedCompIndex < count)
+ {
+ int i = focusedCompIndex + 1;
+ boolean focusRequested = false;
+ // Find component to focus and request focus on it.
+ while (i != focusedCompIndex && ! focusRequested)
+ {
+ if (i >= count)
+ i = 0;
+ Component comp = toolBar.getComponentAtIndex(i++);
+ if (comp != null && comp.isFocusable()
+ && comp.isEnabled())
+ {
+ comp.requestFocus();
+ focusRequested = true;
+ }
+ }
+ }
+ break;
+ case WEST:
+ case NORTH:
+ if (focusedCompIndex >= 0 && focusedCompIndex < count)
+ {
+ int i = focusedCompIndex - 1;
+ boolean focusRequested = false;
+ // Find component to focus and request focus on it.
+ while (i != focusedCompIndex && ! focusRequested)
+ {
+ if (i < 0)
+ i = count - 1;
+ Component comp = toolBar.getComponentAtIndex(i--);
+ if (comp != null && comp.isFocusable()
+ && comp.isEnabled())
+ {
+ comp.requestFocus();
+ focusRequested = true;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
/**
@@ -925,9 +1046,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* This method uninstalls keyboard actions installed by the UI.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ SwingUtilities.replaceUIInputMap(toolBar, JComponent.
+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities.replaceUIActionMap(toolBar, null);
}
/**
@@ -935,8 +1057,13 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
protected void uninstallListeners()
{
- toolBar.removeFocusListener(toolBarFocusListener);
- toolBarFocusListener = null;
+ if (toolBarFocusListener != null)
+ {
+ int count = toolBar.getComponentCount();
+ for (int i = 0; i < count; i++)
+ toolBar.getComponent(i).removeFocusListener(toolBarFocusListener);
+ toolBarFocusListener = null;
+ }
floatFrame.removeWindowListener(windowListener);
windowListener = null;
@@ -998,7 +1125,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseClicked(MouseEvent e)
{
- // Don't care.
+ // Nothing to do here.
}
/**
@@ -1020,7 +1147,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseEntered(MouseEvent e)
{
- // Don't care (yet).
+ // Nothing to do here.
}
/**
@@ -1030,7 +1157,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseExited(MouseEvent e)
{
- // Don't care (yet).
+ // Nothing to do here.
}
/**
@@ -1040,7 +1167,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseMoved(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -1203,13 +1330,17 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
}
/**
- * FIXME: Do something.
+ * Sets the orientation of the toolbar and the
+ * drag window.
*
- * @param o DOCUMENT ME!
+ * @param o - the new orientation of the toolbar and drag
+ * window.
*/
public void setOrientation(int o)
{
- // FIXME: implement.
+ toolBar.setOrientation(o);
+ if (dragWindow != null)
+ dragWindow.setOrientation(o);
}
}
@@ -1290,6 +1421,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
cachedBounds = toolBar.getPreferredSize();
cachedOrientation = toolBar.getOrientation();
+
+ Component c = e.getChild();
+ if (toolBarFocusListener != null)
+ c.addFocusListener(toolBarFocusListener);
}
/**
@@ -1303,6 +1438,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
setBorderToNormal(e.getChild());
cachedBounds = toolBar.getPreferredSize();
cachedOrientation = toolBar.getOrientation();
+
+ Component c = e.getChild();
+ if (toolBarFocusListener != null)
+ c.removeFocusListener(toolBarFocusListener);
}
}
@@ -1332,27 +1471,30 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
protected ToolBarFocusListener()
{
- // FIXME: implement.
+ // Nothing to do here.
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Receives notification when the toolbar or one of it's component
+ * receives the keyboard input focus.
+ *
+ * @param e the focus event
*/
public void focusGained(FocusEvent e)
{
- // FIXME: implement.
+ Component c = e.getComponent();
+ focusedCompIndex = toolBar.getComponentIndex(c);
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Receives notification when the toolbar or one of it's component
+ * looses the keyboard input focus.
+ *
+ * @param e the focus event
*/
public void focusLost(FocusEvent e)
{
- // FIXME: implement.
+ // Do nothing here.
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
index 4c139fe465b..9a193986ac5 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
@@ -174,6 +174,9 @@ public class BasicTreeUI
/**
* Set to false when editing and shouldSelectCall() returns true meaning the
* node should be selected before editing, used in completeEditing.
+ * GNU Classpath editing is implemented differently, so this value is not
+ * actually read anywhere. However it is always set correctly to maintain
+ * interoperability with the derived classes that read this field.
*/
protected boolean stopEditingInCompleteEditing;
@@ -235,9 +238,6 @@ public class BasicTreeUI
/** Set to true if the editor has a different size than the renderer. */
protected boolean editorHasDifferentSize;
- /** The action bound to KeyStrokes. */
- TreeAction action;
-
/** Boolean to keep track of editing. */
boolean isEditing;
@@ -474,8 +474,18 @@ public class BasicTreeUI
*/
protected void setCellRenderer(TreeCellRenderer tcr)
{
- currentCellRenderer = tcr;
+ // Finish editing before changing the renderer.
+ completeEditing();
+
+ // The renderer is set in updateRenderer.
updateRenderer();
+
+ // Refresh the layout if necessary.
+ if (treeState != null)
+ {
+ treeState.invalidateSizes();
+ updateSize();
+ }
}
/**
@@ -845,9 +855,9 @@ public class BasicTreeUI
updateRenderer();
updateDepthOffset();
setSelectionModel(tree.getSelectionModel());
- treeState = createLayoutCache();
- treeSelectionModel.setRowMapper(treeState);
configureLayoutCache();
+ treeState.setRootVisible(tree.isRootVisible());
+ treeSelectionModel.setRowMapper(treeState);
updateSize();
}
@@ -1068,7 +1078,6 @@ public class BasicTreeUI
*/
protected void uninstallKeyboardActions()
{
- action = null;
tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
null);
tree.getActionMap().setParent(null);
@@ -1169,10 +1178,26 @@ public class BasicTreeUI
protected void updateRenderer()
{
if (tree != null)
- currentCellRenderer = tree.getCellRenderer();
-
- if (currentCellRenderer == null)
- currentCellRenderer = createDefaultCellRenderer();
+ {
+ TreeCellRenderer rend = tree.getCellRenderer();
+ if (rend != null)
+ {
+ createdRenderer = false;
+ currentCellRenderer = rend;
+ if (createdCellEditor)
+ tree.setCellEditor(null);
+ }
+ else
+ {
+ tree.setCellRenderer(createDefaultCellRenderer());
+ createdRenderer = true;
+ }
+ }
+ else
+ {
+ currentCellRenderer = null;
+ createdRenderer = false;
+ }
updateCellEditor();
}
@@ -1237,6 +1262,11 @@ public class BasicTreeUI
{
LookAndFeel.installColorsAndFont(tree, "Tree.background",
"Tree.foreground", "Tree.font");
+
+ hashColor = UIManager.getColor("Tree.hash");
+ if (hashColor == null)
+ hashColor = Color.black;
+
tree.setOpaque(true);
rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
@@ -1264,8 +1294,6 @@ public class BasicTreeUI
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
ancestorInputMap);
- action = new TreeAction();
-
SwingUtilities.replaceUIActionMap(tree, getActionMap());
}
@@ -1295,9 +1323,6 @@ public class BasicTreeUI
ActionMapUIResource am = new ActionMapUIResource();
Action action;
- action = new TreeAction();
- am.put(action.getValue(Action.NAME), action);
-
// TreeHomeAction.
action = new TreeHomeAction(-1, "selectFirst");
am.put(action.getValue(Action.NAME), action);
@@ -1349,6 +1374,13 @@ public class BasicTreeUI
am.put(action.getValue(Action.NAME), action);
action = new TreePageAction(1, "scrollDownChangeLead");
am.put(action.getValue(Action.NAME), action);
+
+ // Tree editing actions
+ action = new TreeStartEditingAction("startEditing");
+ am.put(action.getValue(Action.NAME), action);
+ action = new TreeCancelEditingAction("cancel");
+ am.put(action.getValue(Action.NAME), action);
+
return am;
}
@@ -1703,9 +1735,10 @@ public class BasicTreeUI
protected void completeEditing(boolean messageStop, boolean messageCancel,
boolean messageTree)
{
- if (! stopEditingInCompleteEditing || editingComponent == null)
+ // Make no attempt to complete the non existing editing session.
+ if (!isEditing(tree))
return;
-
+
if (messageStop)
{
getCellEditor().stopCellEditing();
@@ -1812,14 +1845,25 @@ public class BasicTreeUI
boolean cntlClick = false;
if (! treeModel.isLeaf(path.getLastPathComponent()))
{
- int width = 8; // Only guessing.
+ int width;
Icon expandedIcon = getExpandedIcon();
if (expandedIcon != null)
width = expandedIcon.getIconWidth();
+ else
+ // Only guessing. This is the width of
+ // the tree control icon in Metal L&F.
+ width = 18;
Insets i = tree.getInsets();
- int left = getRowX(tree.getRowForPath(path), path.getPathCount() - 1)
- - getRightChildIndent() - width / 2 + i.left;
+
+ int depth;
+ if (isRootVisible())
+ depth = path.getPathCount()-1;
+ else
+ depth = path.getPathCount()-2;
+
+ int left = getRowX(tree.getRowForPath(path), depth)
+ - width + i.left;
cntlClick = mouseX >= left && mouseX <= left + width;
}
return cntlClick;
@@ -1848,7 +1892,8 @@ public class BasicTreeUI
*/
protected void toggleExpandState(TreePath path)
{
- if (tree.isExpanded(path))
+ // tree.isExpanded(path) would do the same, but treeState knows faster.
+ if (treeState.isExpanded(path))
tree.collapsePath(path);
else
tree.expandPath(path);
@@ -1975,94 +2020,35 @@ public class BasicTreeUI
Object node = pathForRow.getLastPathComponent();
return treeModel.isLeaf(node);
}
-
+
/**
- * This class implements the actions that we want to happen when specific keys
- * are pressed for the JTree. The actionPerformed method is called when a key
- * that has been registered for the JTree is received.
+ * The action to start editing at the current lead selection path.
*/
- class TreeAction
+ class TreeStartEditingAction
extends AbstractAction
{
-
/**
- * What to do when this action is called.
+ * Creates the new tree cancel editing action.
+ *
+ * @param name the name of the action (used in toString).
+ */
+ public TreeStartEditingAction(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Start editing at the current lead selection path.
*
* @param e the ActionEvent that caused this action.
*/
public void actionPerformed(ActionEvent e)
{
- String command = e.getActionCommand();
TreePath lead = tree.getLeadSelectionPath();
-
- if (command.equals("selectPreviousChangeLead")
- || command.equals("selectPreviousExtendSelection")
- || command.equals("selectPrevious") || command.equals("selectNext")
- || command.equals("selectNextExtendSelection")
- || command.equals("selectNextChangeLead"))
- (new TreeIncrementAction(0, "")).actionPerformed(e);
- else if (command.equals("selectParent") || command.equals("selectChild"))
- (new TreeTraverseAction(0, "")).actionPerformed(e);
- else if (command.equals("selectAll"))
- {
- TreePath[] paths = new TreePath[treeState.getRowCount()];
- for (int i = 0; i < paths.length; i++)
- paths[i] = treeState.getPathForRow(i);
- tree.addSelectionPaths(paths);
- }
- else if (command.equals("startEditing"))
+ if (!tree.isEditing())
tree.startEditingAtPath(lead);
- else if (command.equals("toggle"))
- {
- if (tree.isEditing())
- tree.stopEditing();
- else
- {
- Object last = lead.getLastPathComponent();
- TreePath path = new TreePath(getPathToRoot(last, 0));
- if (! treeModel.isLeaf(last))
- toggleExpandState(path);
- }
- }
- else if (command.equals("clearSelection"))
- tree.clearSelection();
-
- if (tree.isEditing() && ! command.equals("startEditing"))
- tree.stopEditing();
-
- tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
- }
-
- /**
- * This class is used to mimic the behaviour of the JDK when registering
- * keyboard actions. It is the same as the private class used in JComponent
- * for the same reason. This class receives an action event and dispatches it
- * to the true receiver after altering the actionCommand property of the
- * event.
- */
- private static class ActionListenerProxy
- extends AbstractAction
- {
- ActionListener target;
-
- String bindingCommandName;
-
- public ActionListenerProxy(ActionListener li, String cmd)
- {
- target = li;
- bindingCommandName = cmd;
- }
-
- public void actionPerformed(ActionEvent e)
- {
- ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
- bindingCommandName,
- e.getModifiers());
-
- target.actionPerformed(derivedEvent);
- }
- }
+ }
/**
* Updates the preferred size when scrolling, if necessary.
@@ -2290,9 +2276,49 @@ public class BasicTreeUI
* @param e the key typed
*/
public void keyTyped(KeyEvent e)
- throws NotImplementedException
{
- // TODO: What should be done here, if anything?
+ char typed = Character.toLowerCase(e.getKeyChar());
+ for (int row = tree.getLeadSelectionRow() + 1;
+ row < tree.getRowCount(); row++)
+ {
+ if (checkMatch(row, typed))
+ {
+ tree.setSelectionRow(row);
+ tree.scrollRowToVisible(row);
+ return;
+ }
+ }
+
+ // Not found below, search above:
+ for (int row = 0; row < tree.getLeadSelectionRow(); row++)
+ {
+ if (checkMatch(row, typed))
+ {
+ tree.setSelectionRow(row);
+ tree.scrollRowToVisible(row);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Check if the given tree row starts with this character
+ *
+ * @param row the tree row
+ * @param typed the typed char, must be converted to lowercase
+ * @return true if the given tree row starts with this character
+ */
+ boolean checkMatch(int row, char typed)
+ {
+ TreePath path = treeState.getPathForRow(row);
+ String node = path.getLastPathComponent().toString();
+ if (node.length() > 0)
+ {
+ char x = node.charAt(0);
+ if (typed == Character.toLowerCase(x))
+ return true;
+ }
+ return false;
}
/**
@@ -2301,9 +2327,8 @@ public class BasicTreeUI
* @param e the key pressed
*/
public void keyPressed(KeyEvent e)
- throws NotImplementedException
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -2312,9 +2337,8 @@ public class BasicTreeUI
* @param e the key released
*/
public void keyReleased(KeyEvent e)
- throws NotImplementedException
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
}
@@ -2341,14 +2365,23 @@ public class BasicTreeUI
*/
public void mousePressed(MouseEvent e)
{
+ // Any mouse click cancels the previous waiting edit action, initiated
+ // by the single click on the selected node.
+ if (startEditTimer != null)
+ {
+ startEditTimer.stop();
+ startEditTimer = null;
+ }
if (tree != null && tree.isEnabled())
{
- // Maybe stop editing and return.
- if (isEditing(tree) && tree.getInvokesStopCellEditing()
- && !stopEditing(tree))
- return;
-
+ // Always end the current editing session if clicked on the
+ // tree and outside the bounds of the editing component.
+ if (isEditing(tree))
+ if (!stopEditing(tree))
+ // Return if we have failed to cancel the editing session.
+ return;
+
int x = e.getX();
int y = e.getY();
TreePath path = getClosestPathForLocation(tree, x, y);
@@ -2361,11 +2394,47 @@ public class BasicTreeUI
if (x > bounds.x && x <= (bounds.x + bounds.width))
{
- if (! startEditing(path, e))
- selectPathForEvent(path, e);
+ TreePath currentLead = tree.getLeadSelectionPath();
+ if (currentLead != null && currentLead.equals(path)
+ && e.getClickCount() == 1 && tree.isEditable())
+ {
+ // Schedule the editing session.
+ final TreePath editPath = path;
+
+ // The code below handles the required click-pause-click
+ // functionality which must be present in the tree UI.
+ // If the next click comes after the
+ // time longer than the double click interval AND
+ // the same node stays focused for the WAIT_TILL_EDITING
+ // duration, the timer starts the editing session.
+ if (startEditTimer != null)
+ startEditTimer.stop();
+
+ startEditTimer = new Timer(WAIT_TILL_EDITING,
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ startEditing(editPath, EDIT);
+ }
+ });
+
+ startEditTimer.setRepeats(false);
+ startEditTimer.start();
+ }
+ else
+ {
+ if (e.getClickCount() == 2)
+ toggleExpandState(path);
+ else
+ selectPathForEvent(path, e);
+ }
}
}
}
+
+ // We need to request the focus.
+ tree.requestFocusInWindow();
}
/**
@@ -2830,6 +2899,9 @@ public class BasicTreeUI
}
}
}
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
/**
@@ -2945,6 +3017,9 @@ public class BasicTreeUI
tree.setAnchorSelectionPath(newPath);
tree.setLeadSelectionPath(newPath);
}
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
/**
@@ -3249,6 +3324,9 @@ public class BasicTreeUI
// and anchor.
tree.setLeadSelectionPath(leadPath);
tree.setAnchorSelectionPath(anchorPath);
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
}
@@ -3336,6 +3414,9 @@ public class BasicTreeUI
tree.expandPath(current);
}
}
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
/**
@@ -3644,7 +3725,13 @@ public class BasicTreeUI
{
Rectangle bounds = getPathBounds(tree, path);
TreePath parent = path.getParentPath();
- if (parent != null)
+
+ boolean paintLine;
+ if (isRootVisible())
+ paintLine = parent != null;
+ else
+ paintLine = parent != null && parent.getPathCount() > 1;
+ if (paintLine)
{
Rectangle parentBounds = getPathBounds(tree, parent);
paintVerticalLine(g, tree, parentBounds.x + 2 * gap,
diff --git a/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java b/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
index 47876491160..34278052bc1 100644
--- a/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
+++ b/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.Color;
import java.util.HashMap;
import javax.swing.UIManager;
@@ -75,4 +76,16 @@ public class SharedUIDefaults
}
return o;
}
+
+ /**
+ * Returns a shared UI color.
+ *
+ * @param key the key
+ *
+ * @return the shared color instance
+ */
+ static Color getColor(String key)
+ {
+ return (Color) get(key);
+ }
}