I implemented the keyboard actions for BasicToolBarUI. Now you can
navigate over a toolbar using the arrow keys.
2006-07-26 Roman Kennke <[EMAIL PROTECTED]>
* javax/swing/plaf/basic/BasicToolBarUI.java
(ToolBarAction): New inner class for handling keyboard
actions.
(installKeyboardActions): Implemented.
(getActionMap): New helper method.
(createDefaultActions): New helper method.
(installListeners): Install focus listener on toolbar's
children, rather than the toolbar itself.
(navigateFocusedComp): Implemented.
(uninstallKeyboardActions): Implemented.
(uninstallListeners): Uninstall focus listener from
toolbar's children, rather than the toolbar itself.
(ToolBarContListener.componentAdded): Install focus
listener on added child.
(ToolBarContListener.componentRemoved): Uninstall focus
listener from removed child.
(ToolBarFocusListener.ToolBarFocusListener): Nothing to do here.
(ToolBarFocusListener.focusGained): Implemented.
(ToolBarFocusListener.focusLost): Implemented.
/Roman
Index: javax/swing/plaf/basic/BasicToolBarUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicToolBarUI.java,v
retrieving revision 1.26
diff -u -1 -2 -r1.26 BasicToolBarUI.java
--- javax/swing/plaf/basic/BasicToolBarUI.java 4 Jul 2006 18:00:48 -0000 1.26
+++ javax/swing/plaf/basic/BasicToolBarUI.java 26 Jul 2006 11:21:29 -0000
@@ -29,73 +29,106 @@
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module. An independent module is a module which is not derived from
or based on this library. If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so. If you do not wish to do so, delete this
exception statement from your version. */
package javax.swing.plaf.basic;
-import 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.Graphics;
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;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Hashtable;
+import javax.swing.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;
import javax.swing.JFrame;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.RootPaneContainer;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
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;
import javax.swing.plaf.basic.BasicBorders.ButtonBorder;
/**
* This is the Basic Look and Feel UI class for JToolBar.
*/
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();
/** The border used when the JToolBar is in nonrollover mode. */
private static Border nonRolloverBorder;
/** The border used when the JToolBar is in rollover mode. */
private static Border rolloverBorder;
/** The last known BorderLayout constraint before floating. */
protected String constraintBeforeFloating;
@@ -610,49 +643,91 @@
dockingBorderColor = UIManager.getColor("ToolBar.dockingForeground");
dockingColor = UIManager.getColor("ToolBar.dockingBackground");
floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground");
floatingColor = UIManager.getColor("ToolBar.floatingBackground");
}
/**
* This method installs the keyboard actions for the JToolBar as specified
* 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("Table.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("Tree.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;
}
/**
* This method installs listeners for the JToolBar.
*/
protected void installListeners()
{
dockingListener = createDockingListener();
toolBar.addMouseListener(dockingListener);
toolBar.addMouseMotionListener(dockingListener);
propertyListener = createPropertyListener();
toolBar.addPropertyChangeListener(propertyListener);
toolBarContListener = createToolBarContListener();
toolBar.addContainerListener(toolBarContListener);
windowListener = createFrameListener();
floatFrame.addWindowListener(windowListener);
toolBarFocusListener = createToolBarFocusListener();
- toolBar.addFocusListener(toolBarFocusListener);
+ if (toolBarFocusListener != null)
+ {
+ int count = toolBar.getComponentCount();
+ for (int i = 0; i < count; i++)
+ toolBar.getComponent(i).addFocusListener(toolBarFocusListener);
+ }
}
/**
* This method installs non rollover borders for each component inside the
* given JComponent.
*
* @param c The JComponent whose children need to have non rollover borders
* installed.
*/
protected void installNonRolloverBorders(JComponent c)
{
Component[] components = toolBar.getComponents();
@@ -749,27 +824,73 @@
public boolean isRolloverBorders()
{
return toolBar.isRollover();
}
/**
* This method navigates in the given direction giving focus to the next
* component in the given direction.
*
* @param direction The direction to give focus to.
*/
protected void navigateFocusedComp(int direction)
- 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;
+ }
}
/**
* This method sets the border of the given component to a non rollover
* border.
*
* @param c The Component whose border needs to be set.
*/
protected void setBorderToNonRollover(Component c)
{
if (c instanceof AbstractButton)
{
@@ -916,36 +1037,42 @@
toolBar.setFont(null);
dockingBorderColor = null;
dockingColor = null;
floatingBorderColor = null;
floatingColor = null;
}
/**
* 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);
}
/**
* This method uninstalls listeners installed by the UI.
*/
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;
toolBar.removeContainerListener(toolBarContListener);
toolBarContListener = null;
toolBar.removeMouseMotionListener(dockingListener);
toolBar.removeMouseListener(dockingListener);
dockingListener = null;
}
@@ -1285,37 +1412,45 @@
if (b.getBorder() != null)
borders.put(b, b.getBorder());
}
if (isRolloverBorders())
setBorderToRollover(e.getChild());
else
setBorderToNonRollover(e.getChild());
cachedBounds = toolBar.getPreferredSize();
cachedOrientation = toolBar.getOrientation();
+
+ Component c = e.getChild();
+ if (toolBarFocusListener != null)
+ c.addFocusListener(toolBarFocusListener);
}
/**
* This method is responsible for giving the child components their
* original borders when they are removed.
*
* @param e The ContainerEvent.
*/
public void componentRemoved(ContainerEvent e)
{
setBorderToNormal(e.getChild());
cachedBounds = toolBar.getPreferredSize();
cachedOrientation = toolBar.getOrientation();
+
+ Component c = e.getChild();
+ if (toolBarFocusListener != null)
+ c.removeFocusListener(toolBarFocusListener);
}
}
/**
* This is the floating window that is returned when getFloatingWindow is
* called.
*/
private class ToolBarDialog extends JDialog implements UIResource
{
/**
* Creates a new ToolBarDialog object with the name given by the JToolBar.
*/
@@ -1325,47 +1460,50 @@
setName((toolBar.getName() != null) ? toolBar.getName() : "");
}
}
/**
* DOCUMENT ME!
*/
protected class ToolBarFocusListener implements FocusListener
{
/**
* Creates a new ToolBarFocusListener object.
*/
- protected ToolBarFocusListener() throws NotImplementedException
+ protected ToolBarFocusListener()
{
- // FIXME: implement.
+ // Nothing to do here.
}
/**
- * DOCUMENT ME!
+ * Receives notification when the toolbar or one of it's component
+ * receives the keyboard input focus.
*
- * @param e DOCUMENT ME!
+ * @param e the focus event
*/
- public void focusGained(FocusEvent e) throws NotImplementedException
+ public void focusGained(FocusEvent e)
{
- // FIXME: implement.
+ Component c = e.getComponent();
+ focusedCompIndex = toolBar.getComponentIndex(c);
}
/**
- * DOCUMENT ME!
+ * Receives notification when the toolbar or one of it's component
+ * looses the keyboard input focus.
*
- * @param e DOCUMENT ME!
+ * @param e the focus event
*/
- public void focusLost(FocusEvent e) throws NotImplementedException
+ public void focusLost(FocusEvent e)
{
- // FIXME: implement.
+ // Do nothing here.
}
}
/**
* This helper class acts as the border for the JToolBar.
*/
private static class ToolBarBorder implements Border
{
/** The size of the larger, draggable side of the border. */
private static final int offset = 10;
/** The other sides. */