summaryrefslogtreecommitdiff
path: root/javax/swing/plaf
diff options
context:
space:
mode:
authorGuilhem Lavaux <guilhem@kaffe.org>2006-06-06 20:30:07 +0000
committerGuilhem Lavaux <guilhem@kaffe.org>2006-06-06 20:30:07 +0000
commit56c5b96a2d3754736d13eebb73270fb8f925301d (patch)
tree8f13d21d9dadf9810d11284977ed98a0a5c41868 /javax/swing/plaf
parent68d82e8b935385c52f40123538e6e5b0dad7dbc9 (diff)
downloadclasspath-56c5b96a2d3754736d13eebb73270fb8f925301d.tar.gz
2006-06-06 Guilhem Lavaux <guilhem@kaffe.org>
* Merged HEAD as of 2006-05-08.
Diffstat (limited to 'javax/swing/plaf')
-rw-r--r--javax/swing/plaf/basic/BasicButtonListener.java11
-rw-r--r--javax/swing/plaf/basic/BasicButtonUI.java6
-rw-r--r--javax/swing/plaf/basic/BasicComboBoxEditor.java44
-rw-r--r--javax/swing/plaf/basic/BasicComboBoxUI.java108
-rw-r--r--javax/swing/plaf/basic/BasicComboPopup.java12
-rw-r--r--javax/swing/plaf/basic/BasicFileChooserUI.java19
-rw-r--r--javax/swing/plaf/basic/BasicInternalFrameTitlePane.java23
-rw-r--r--javax/swing/plaf/basic/BasicInternalFrameUI.java71
-rw-r--r--javax/swing/plaf/basic/BasicLabelUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicListUI.java3
-rw-r--r--javax/swing/plaf/basic/BasicLookAndFeel.java222
-rw-r--r--javax/swing/plaf/basic/BasicMenuBarUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicMenuItemUI.java487
-rw-r--r--javax/swing/plaf/basic/BasicMenuUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicOptionPaneUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicPopupMenuUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicRadioButtonUI.java12
-rw-r--r--javax/swing/plaf/basic/BasicRootPaneUI.java122
-rw-r--r--javax/swing/plaf/basic/BasicScrollBarUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicScrollPaneUI.java183
-rw-r--r--javax/swing/plaf/basic/BasicSliderUI.java793
-rw-r--r--javax/swing/plaf/basic/BasicSpinnerUI.java9
-rw-r--r--javax/swing/plaf/basic/BasicSplitPaneUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicTabbedPaneUI.java852
-rw-r--r--javax/swing/plaf/basic/BasicTableHeaderUI.java14
-rw-r--r--javax/swing/plaf/basic/BasicTableUI.java65
-rw-r--r--javax/swing/plaf/basic/BasicTextAreaUI.java7
-rw-r--r--javax/swing/plaf/basic/BasicTextFieldUI.java15
-rw-r--r--javax/swing/plaf/basic/BasicTextUI.java123
-rw-r--r--javax/swing/plaf/basic/BasicToolBarUI.java4
-rw-r--r--javax/swing/plaf/basic/BasicTreeUI.java1696
-rw-r--r--javax/swing/plaf/metal/MetalBorders.java92
-rw-r--r--javax/swing/plaf/metal/MetalButtonUI.java13
-rw-r--r--javax/swing/plaf/metal/MetalComboBoxButton.java15
-rw-r--r--javax/swing/plaf/metal/MetalComboBoxEditor.java73
-rw-r--r--javax/swing/plaf/metal/MetalComboBoxUI.java23
-rw-r--r--javax/swing/plaf/metal/MetalDesktopIconUI.java16
-rw-r--r--javax/swing/plaf/metal/MetalInternalFrameTitlePane.java12
-rw-r--r--javax/swing/plaf/metal/MetalLookAndFeel.java2
-rw-r--r--javax/swing/plaf/metal/MetalRootPaneUI.java157
-rw-r--r--javax/swing/plaf/metal/MetalSliderUI.java6
-rw-r--r--javax/swing/plaf/metal/MetalTabbedPaneUI.java861
-rw-r--r--javax/swing/plaf/metal/MetalToggleButtonUI.java9
-rw-r--r--javax/swing/plaf/metal/MetalToolBarUI.java36
-rw-r--r--javax/swing/plaf/metal/MetalTreeUI.java4
-rw-r--r--javax/swing/plaf/metal/OceanTheme.java5
-rw-r--r--javax/swing/plaf/synth/ColorType.java7
-rw-r--r--javax/swing/plaf/synth/SynthGraphicsUtils.java6
-rw-r--r--javax/swing/plaf/synth/SynthLookAndFeel.java11
-rw-r--r--javax/swing/plaf/synth/SynthPainter.java35
-rw-r--r--javax/swing/plaf/synth/SynthStyle.java83
51 files changed, 4007 insertions, 2388 deletions
diff --git a/javax/swing/plaf/basic/BasicButtonListener.java b/javax/swing/plaf/basic/BasicButtonListener.java
index 1fca69451..89e99a29a 100644
--- a/javax/swing/plaf/basic/BasicButtonListener.java
+++ b/javax/swing/plaf/basic/BasicButtonListener.java
@@ -52,6 +52,7 @@ import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
@@ -204,14 +205,12 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
{
AbstractButton button = (AbstractButton) e.getSource();
ButtonModel model = button.getModel();
- if (button.isRolloverEnabled())
+ if (button.isRolloverEnabled()
+ && ! SwingUtilities.isLeftMouseButton(e))
model.setRollover(true);
-
- if (model.isPressed()
- && (e.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0)
+
+ if (model.isPressed())
model.setArmed(true);
- else
- model.setArmed(false);
}
}
diff --git a/javax/swing/plaf/basic/BasicButtonUI.java b/javax/swing/plaf/basic/BasicButtonUI.java
index ab079fc5e..7dbcb9146 100644
--- a/javax/swing/plaf/basic/BasicButtonUI.java
+++ b/javax/swing/plaf/basic/BasicButtonUI.java
@@ -172,8 +172,10 @@ public class BasicButtonUI extends ButtonUI
{
if (b.getFont() instanceof UIResource)
b.setFont(null);
- b.setForeground(null);
- b.setBackground(null);
+ if (b.getForeground() instanceof UIResource)
+ b.setForeground(null);
+ if (b.getBackground() instanceof UIResource)
+ b.setBackground(null);
if (b.getBorder() instanceof UIResource)
b.setBorder(null);
b.setIconTextGap(defaultTextIconGap);
diff --git a/javax/swing/plaf/basic/BasicComboBoxEditor.java b/javax/swing/plaf/basic/BasicComboBoxEditor.java
index 4cbc4ae68..d87926196 100644
--- a/javax/swing/plaf/basic/BasicComboBoxEditor.java
+++ b/javax/swing/plaf/basic/BasicComboBoxEditor.java
@@ -39,14 +39,10 @@ exception statement from your version. */
package javax.swing.plaf.basic;
import java.awt.Component;
-import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
-import java.util.Iterator;
-import java.util.LinkedList;
-
import javax.swing.ComboBoxEditor;
import javax.swing.JTextField;
@@ -62,8 +58,6 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor,
/** The editor component. */
protected JTextField editor;
- private ComboBoxEditorListener listener;
-
/**
* Creates a new <code>BasicComboBoxEditor</code> instance.
*/
@@ -72,7 +66,6 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor,
editor = new JTextField();
editor.setBorder(null);
editor.setColumns(9);
- listener = new ComboBoxEditorListener();
}
/**
@@ -156,7 +149,7 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor,
*/
public void addActionListener(ActionListener l)
{
- listener.addListener(l);
+ editor.addActionListener(l);
}
/**
@@ -166,7 +159,7 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor,
*/
public void removeActionListener(ActionListener l)
{
- listener.removeListener(l);
+ editor.removeActionListener(l);
}
/**
@@ -185,37 +178,4 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor,
}
}
- /**
- * Helper class that forwards action events between the jtextfield
- * editor and the basic combo box editor for use by the combo box.
- */
- class ComboBoxEditorListener implements ActionListener
- {
- private final LinkedList listeners = new LinkedList();
-
- public void actionPerformed(ActionEvent ae)
- {
- ActionEvent nae;
- nae = new ActionEvent(BasicComboBoxEditor.this,
- ae.getID(), ae.getActionCommand(),
- ae.getWhen(), ae.getModifiers());
- Iterator it = listeners.iterator();
- while (it.hasNext())
- ((ActionListener) it.next()).actionPerformed(nae);
- }
-
- void addListener(ActionListener al)
- {
- if (listeners.size() == 0)
- editor.addActionListener(this);
- listeners.add(al);
- }
-
- void removeListener(ActionListener al)
- {
- listeners.remove(al);
- if (listeners.size() == 0)
- editor.removeActionListener(this);
- }
- }
}
diff --git a/javax/swing/plaf/basic/BasicComboBoxUI.java b/javax/swing/plaf/basic/BasicComboBoxUI.java
index 5b183786f..557eea93f 100644
--- a/javax/swing/plaf/basic/BasicComboBoxUI.java
+++ b/javax/swing/plaf/basic/BasicComboBoxUI.java
@@ -38,6 +38,8 @@ 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;
@@ -70,7 +72,6 @@ import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.LookAndFeel;
-import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
@@ -672,9 +673,7 @@ public class BasicComboBoxUI extends ComboBoxUI
*/
public Dimension getPreferredSize(JComponent c)
{
- Dimension size = getMinimumSize(c);
- size.width += 4;
- return size;
+ return getMinimumSize(c);
}
/**
@@ -691,10 +690,8 @@ public class BasicComboBoxUI extends ComboBoxUI
{
Insets i = getInsets();
Dimension d = getDisplaySize();
- d.height += i.top + i.bottom;
- int arrowButtonWidth = d.height - (i.top + i.bottom);
- cachedMinimumSize = new Dimension(d.width + arrowButtonWidth + i.left
- + i.right, d.height);
+ d.width += i.left + i.right + d.height;
+ cachedMinimumSize = new Dimension(d.width, d.height + i.top + i.bottom);
isMinimumSizeDirty = false;
}
return new Dimension(cachedMinimumSize);
@@ -710,9 +707,7 @@ public class BasicComboBoxUI extends ComboBoxUI
*/
public Dimension getMaximumSize(JComponent c)
{
- Dimension size = getPreferredSize(c);
- size.width = 32767;
- return size;
+ return new Dimension(32767, 32767);
}
public int getAccessibleChildrenCount(JComponent c)
@@ -780,11 +775,16 @@ public class BasicComboBoxUI extends ComboBoxUI
*/
protected Rectangle rectangleForCurrentValue()
{
- Rectangle cbBounds = SwingUtilities.getLocalBounds(comboBox);
- Rectangle abBounds = arrowButton.getBounds();
- Rectangle rectForCurrentValue = new Rectangle(cbBounds.x, cbBounds.y,
- cbBounds.width - abBounds.width, cbBounds.height);
- return rectForCurrentValue;
+ int w = comboBox.getWidth();
+ int h = comboBox.getHeight();
+ Insets i = comboBox.getInsets();
+ int arrowSize = h - (i.top + i.bottom);
+ if (arrowButton != null)
+ {
+ arrowSize = arrowButton.getWidth();
+ }
+ return new Rectangle(i.left, i.top, w - (i.left + i.right + arrowSize),
+ h - (i.top + i.left));
}
/**
@@ -902,9 +902,9 @@ public class BasicComboBoxUI extends ComboBoxUI
false);
currentValuePane.add(comp);
comp.setFont(comboBox.getFont());
- int h = comp.getPreferredSize().height;
+ Dimension d = comp.getPreferredSize();
currentValuePane.remove(comp);
- return new Dimension(100, h);
+ return d;
}
/**
@@ -915,37 +915,58 @@ public class BasicComboBoxUI extends ComboBoxUI
*/
protected Dimension getDisplaySize()
{
- if (comboBox.isEditable() && comboBox.getModel().getSize() == 0)
- return new Dimension(100, editor.getPreferredSize().height);
-
Dimension dim = new Dimension();
ListCellRenderer renderer = comboBox.getRenderer();
- ComboBoxModel model = comboBox.getModel();
- if (renderer != null && model.getSize() > 0)
+ if (renderer == null)
{
- // TODO: Optimize using prototype here.
+ renderer = DEFAULT_RENDERER;
+ }
+
+ Object prototype = comboBox.getPrototypeDisplayValue();
+ if (prototype != null)
+ {
+ Component comp = renderer.getListCellRendererComponent
+ (listBox, prototype, -1, false, false);
+ currentValuePane.add(comp);
+ comp.setFont(comboBox.getFont());
+ Dimension renderSize = comp.getPreferredSize();
+ currentValuePane.remove(comp);
+ dim.height = renderSize.height;
+ dim.width = renderSize.width;
+ }
+ else
+ {
+ ComboBoxModel model = comboBox.getModel();
int size = model.getSize();
- for (int i = 0; i < size; ++i)
+ if (size > 0)
{
- Component comp = renderer.getListCellRendererComponent
- (listBox, model.getElementAt(i), -1, false, false);
- currentValuePane.add(comp);
- comp.setFont(comboBox.getFont());
- Dimension renderSize = comp.getPreferredSize();
- currentValuePane.remove(comp);
- dim.width = Math.max(dim.width, renderSize.width);
- dim.height = Math.max(dim.height, renderSize.height);
+ for (int i = 0; i < size; ++i)
+ {
+ Component comp = renderer.getListCellRendererComponent
+ (listBox, model.getElementAt(i), -1, false, false);
+ currentValuePane.add(comp);
+ comp.setFont(comboBox.getFont());
+ Dimension renderSize = comp.getPreferredSize();
+ currentValuePane.remove(comp);
+ dim.width = Math.max(dim.width, renderSize.width);
+ dim.height = Math.max(dim.height, renderSize.height);
+ }
}
- if (comboBox.isEditable())
+ else
{
- Dimension editSize = editor.getPreferredSize();
- dim.width = Math.max(dim.width, editSize.width);
- dim.height = Math.max(dim.height, editSize.height);
+ dim = getDefaultSize();
+ if (comboBox.isEditable())
+ dim.width = 100;
}
- displaySize.setSize(dim.width, dim.height);
- return displaySize;
}
- return getDefaultSize();
+ if (comboBox.isEditable())
+ {
+ Dimension editSize = editor.getPreferredSize();
+ dim.width = Math.max(dim.width, editSize.width);
+ dim.height = Math.max(dim.height, editSize.height);
+ }
+ displaySize.setSize(dim.width, dim.height);
+ return dim;
}
/**
@@ -953,6 +974,7 @@ public class BasicComboBoxUI extends ComboBoxUI
* by the look and feel.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement.
}
@@ -962,6 +984,7 @@ public class BasicComboBoxUI extends ComboBoxUI
* installed by in {@link #installListeners}.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement.
}
@@ -1046,12 +1069,11 @@ public class BasicComboBoxUI extends ComboBoxUI
int arrowSize = comboBox.getHeight() - (i.top + i.bottom);
int editorWidth = comboBox.getBounds().width - arrowSize;
- if (editor != null)
- editor.setBounds(rectangleForCurrentValue());
-
if (arrowButton != null)
arrowButton.setBounds(comboBox.getWidth() - (i.right + arrowSize),
i.top, arrowSize, arrowSize);
+ if (editor != null)
+ editor.setBounds(rectangleForCurrentValue());
}
}
diff --git a/javax/swing/plaf/basic/BasicComboPopup.java b/javax/swing/plaf/basic/BasicComboPopup.java
index aa058b87d..d4eabc602 100644
--- a/javax/swing/plaf/basic/BasicComboPopup.java
+++ b/javax/swing/plaf/basic/BasicComboPopup.java
@@ -38,9 +38,12 @@ 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.Dimension;
+import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
@@ -185,6 +188,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
{
Dimension size = comboBox.getSize();
size.height = getPopupHeightForRowCount(comboBox.getMaximumRowCount());
+ Insets i = getInsets();
+ size.width -= i.left + i.right;
Rectangle bounds = computePopupBounds(0, comboBox.getBounds().height,
size.width, size.height);
@@ -197,7 +202,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
list.ensureIndexIsVisible(list.getSelectedIndex());
setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled());
- show(comboBox, bounds.x, bounds.y); }
+ show(comboBox, bounds.x, bounds.y);
+ }
/**
* This method hides drop down list of items
@@ -288,6 +294,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
* This method uninstalls keyboard actions installed by the UI.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement
}
@@ -555,6 +562,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
* DOCUMENT ME!
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement
}
@@ -710,7 +718,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup
totalHeight += dim.height;
}
- return totalHeight;
+ return totalHeight == 0 ? 100 : totalHeight;
}
/**
diff --git a/javax/swing/plaf/basic/BasicFileChooserUI.java b/javax/swing/plaf/basic/BasicFileChooserUI.java
index 30e3156b4..daa977083 100644
--- a/javax/swing/plaf/basic/BasicFileChooserUI.java
+++ b/javax/swing/plaf/basic/BasicFileChooserUI.java
@@ -157,6 +157,21 @@ public class BasicFileChooserUI extends FileChooserUI
closeDialog();
}
}
+ else
+ {
+ File f = new File(filechooser.getCurrentDirectory(), getFileName());
+ if (filechooser.isTraversable(f))
+ {
+ filechooser.setCurrentDirectory(f);
+ filechooser.rescanCurrentDirectory();
+ }
+ else
+ {
+ filechooser.setSelectedFile(f);
+ filechooser.approveSelection();
+ closeDialog();
+ }
+ }
}
}
@@ -1046,9 +1061,7 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public String getFileName()
{
- // FIXME: I'm thinking that this method just provides access to the
- // text value in the JTextField component...but not sure yet
- return null; //filename;
+ return entry.getText();
}
/**
diff --git a/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java b/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java
index d7e26669f..11980f6ca 100644
--- a/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java
+++ b/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java
@@ -520,22 +520,22 @@ public class BasicInternalFrameTitlePane extends JComponent
}
/** The action command for the Close action. */
- protected static final String CLOSE_CMD = "Close";
+ protected static final String CLOSE_CMD;
/** The action command for the Minimize action. */
- protected static final String ICONIFY_CMD = "Minimize";
+ protected static final String ICONIFY_CMD;
/** The action command for the Maximize action. */
- protected static final String MAXIMIZE_CMD = "Maximize";
+ protected static final String MAXIMIZE_CMD;
/** The action command for the Move action. */
- protected static final String MOVE_CMD = "Move";
+ protected static final String MOVE_CMD;
/** The action command for the Restore action. */
- protected static final String RESTORE_CMD = "Restore";
+ protected static final String RESTORE_CMD;
/** The action command for the Size action. */
- protected static final String SIZE_CMD = "Size";
+ protected static final String SIZE_CMD;
/** The action associated with closing the JInternalFrame. */
protected Action closeAction;
@@ -614,6 +614,17 @@ public class BasicInternalFrameTitlePane extends JComponent
* This is package-private to avoid an accessor method.
*/
transient JLabel title;
+
+ static
+ {
+ // not constants in JDK
+ CLOSE_CMD = "Close";
+ ICONIFY_CMD = "Minimize";
+ MAXIMIZE_CMD = "Maximize";
+ MOVE_CMD = "Move";
+ RESTORE_CMD = "Restore";
+ SIZE_CMD = "Size";
+ }
/**
* Creates a new BasicInternalFrameTitlePane object that is used in the
diff --git a/javax/swing/plaf/basic/BasicInternalFrameUI.java b/javax/swing/plaf/basic/BasicInternalFrameUI.java
index c6f3dd99e..0a330e776 100644
--- a/javax/swing/plaf/basic/BasicInternalFrameUI.java
+++ b/javax/swing/plaf/basic/BasicInternalFrameUI.java
@@ -38,10 +38,13 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.NotImplementedException;
+
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
+import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
@@ -164,6 +167,12 @@ public class BasicInternalFrameUI extends InternalFrameUI
protected class BorderListener extends MouseInputAdapter
implements SwingConstants
{
+ /**
+ * If true, the cursor is being already shown in the alternative "resize"
+ * shape.
+ */
+ transient boolean showingResizeCursor;
+
/** FIXME: Use for something. */
protected final int RESIZE_NONE = 0;
@@ -263,25 +272,69 @@ public class BasicInternalFrameUI extends InternalFrameUI
/**
* This method is called when the mouse exits the JInternalFrame.
- *
+ *
* @param e The MouseEvent.
*/
public void mouseExited(MouseEvent e)
{
- // There is nothing to do when the mouse exits
- // the border area.
+ // Reset the cursor shape.
+ if (showingResizeCursor)
+ {
+ frame.setCursor(Cursor.getDefaultCursor());
+ showingResizeCursor = false;
+ }
}
/**
- * This method is called when the mouse is moved inside the
- * JInternalFrame.
- *
+ * This method is called when the mouse is moved inside the JInternalFrame.
+ *
* @param e The MouseEvent.
*/
public void mouseMoved(MouseEvent e)
{
- // There is nothing to do when the mouse moves
- // over the border area.
+ // Turn off the resize cursor if we are in the frame header.
+ if (showingResizeCursor && e.getSource() != frame)
+ {
+ frame.setCursor(Cursor.getDefaultCursor());
+ showingResizeCursor = false;
+ }
+ else if (e.getSource()==frame && frame.isResizable())
+ {
+ int cursor;
+ switch (sectionOfClick(e.getX(), e.getY()))
+ {
+ case NORTH:
+ cursor = Cursor.N_RESIZE_CURSOR;
+ break;
+ case NORTH_EAST:
+ cursor = Cursor.NE_RESIZE_CURSOR;
+ break;
+ case EAST:
+ cursor = Cursor.E_RESIZE_CURSOR;
+ break;
+ case SOUTH_EAST:
+ cursor = Cursor.SE_RESIZE_CURSOR;
+ break;
+ case SOUTH:
+ cursor = Cursor.S_RESIZE_CURSOR;
+ break;
+ case SOUTH_WEST:
+ cursor = Cursor.SW_RESIZE_CURSOR;
+ break;
+ case WEST:
+ cursor = Cursor.W_RESIZE_CURSOR;
+ break;
+ case NORTH_WEST:
+ cursor = Cursor.NW_RESIZE_CURSOR;
+ break;
+ default:
+ cursor = Cursor.DEFAULT_CURSOR;
+ }
+
+ Cursor resize = Cursor.getPredefinedCursor(cursor);
+ frame.setCursor(resize);
+ showingResizeCursor = true;
+ }
}
/**
@@ -1158,6 +1211,7 @@ public class BasicInternalFrameUI extends InternalFrameUI
* This method installs the keyboard actions for the JInternalFrame.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Implement.
}
@@ -1240,6 +1294,7 @@ public class BasicInternalFrameUI extends InternalFrameUI
* This method uninstalls the keyboard actions for the JInternalFrame.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Implement.
}
diff --git a/javax/swing/plaf/basic/BasicLabelUI.java b/javax/swing/plaf/basic/BasicLabelUI.java
index d0964f473..60e3a9868 100644
--- a/javax/swing/plaf/basic/BasicLabelUI.java
+++ b/javax/swing/plaf/basic/BasicLabelUI.java
@@ -37,6 +37,8 @@
package javax.swing.plaf.basic;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
@@ -372,6 +374,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
* @param l The {@link JLabel} to install keyboard actions for.
*/
protected void installKeyboardActions(JLabel l)
+ throws NotImplementedException
{
//FIXME: implement.
}
@@ -382,6 +385,7 @@ 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.
}
diff --git a/javax/swing/plaf/basic/BasicListUI.java b/javax/swing/plaf/basic/BasicListUI.java
index 5cde9630c..d9bc0676d 100644
--- a/javax/swing/plaf/basic/BasicListUI.java
+++ b/javax/swing/plaf/basic/BasicListUI.java
@@ -38,6 +38,8 @@ 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;
@@ -1025,6 +1027,7 @@ public class BasicListUI extends ListUI
* Uninstalls keyboard actions for this UI in the {@link JList}.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// TODO: Implement this properly.
}
diff --git a/javax/swing/plaf/basic/BasicLookAndFeel.java b/javax/swing/plaf/basic/BasicLookAndFeel.java
index 3451224be..78c16ef08 100644
--- a/javax/swing/plaf/basic/BasicLookAndFeel.java
+++ b/javax/swing/plaf/basic/BasicLookAndFeel.java
@@ -44,6 +44,7 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
+import java.awt.SystemColor;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
@@ -52,10 +53,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Enumeration;
-import java.util.Iterator;
import java.util.ResourceBundle;
-import java.util.Set;
-import java.util.WeakHashMap;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
@@ -66,11 +64,9 @@ import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
-import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.MenuSelectionManager;
-import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.BevelBorder;
@@ -104,11 +100,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel
{
/**
- * Registered popups for autoclose.
- */
- private WeakHashMap autoClosePopups = new WeakHashMap();
-
- /**
* Receives an event from the event queue.
*
* @param event
@@ -137,46 +128,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel
target = ((Container) target).findComponentAt(ev.getPoint());
if (! m.isComponentPartOfCurrentMenu(target))
m.clearSelectedPath();
-
- // Handle other registered popup instances, like ComboBox popups.
- autoClosePopups(ev, target);
- }
-
- /**
- * Registers Popup and its content to be autoclosed when a mouseclick
- * occurs outside of the popup.
- *
- * @param popup the popup to be autoclosed when clicked outside
- */
- void registerForAutoClose(JPopupMenu popup)
- {
- autoClosePopups.put(popup, null);
}
- /**
- * Automatically closes all popups that are not 'hit' by the mouse event.
- *
- * @param ev the mouse event
- * @param target the target of the mouse event
- */
- private void autoClosePopups(MouseEvent ev, Component target)
- {
- if (autoClosePopups.size() != 0)
- {
- Set popups = autoClosePopups.keySet();
- Iterator i = popups.iterator();
- while (i.hasNext())
- {
- JPopupMenu popup = (JPopupMenu) i.next();
- if (!(target == popup
- || SwingUtilities.isDescendingFrom(target, popup)))
- {
- popup.setVisible(false);
- i.remove();
- }
- }
- }
- }
}
/**
@@ -251,7 +204,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
*/
public BasicLookAndFeel()
{
- // TODO
+ // Nothing to do here.
}
/**
@@ -337,59 +290,138 @@ public abstract class BasicLookAndFeel extends LookAndFeel
/**
* Populates the <code>defaults</code> table with system color defaults.
+ *
+ * This sets up a couple of default values and passes them to
+ * {@link #loadSystemColors(UIDefaults, String[], boolean)}. If the
+ * look and feel is a native look and feel, these defaults may be overridden
+ * by the corresponding SystemColor constants.
*
* @param defaults the defaults table (<code>null</code> not permitted).
*/
protected void initSystemColorDefaults(UIDefaults defaults)
{
- Color highLight = new Color(249, 247, 246);
- Color light = new Color(239, 235, 231);
- Color shadow = new Color(139, 136, 134);
- Color darkShadow = new Color(16, 16, 16);
-
- Object[] uiDefaults;
- uiDefaults = new Object[] {
- "activeCaption", new ColorUIResource(0, 0, 128),
- "activeCaptionBorder", new ColorUIResource(Color.lightGray),
- "activeCaptionText", new ColorUIResource(Color.white),
- "control", new ColorUIResource(light),
- "controlDkShadow", new ColorUIResource(shadow),
- "controlHighlight", new ColorUIResource(highLight),
- "controlLtHighlight", new ColorUIResource(highLight),
- "controlShadow", new ColorUIResource(shadow),
- "controlText", new ColorUIResource(darkShadow),
- "desktop", new ColorUIResource(0, 92, 92),
- "inactiveCaption", new ColorUIResource(Color.gray),
- "inactiveCaptionBorder", new ColorUIResource(Color.lightGray),
- "inactiveCaptionText", new ColorUIResource(Color.lightGray),
- "info", new ColorUIResource(light),
- "infoText", new ColorUIResource(darkShadow),
- "menu", new ColorUIResource(light),
- "menuText", new ColorUIResource(darkShadow),
- "scrollbar", new ColorUIResource(light),
- "text", new ColorUIResource(Color.white),
- "textHighlight", new ColorUIResource(Color.black),
- "textHighlightText", new ColorUIResource(Color.white),
- "textInactiveText", new ColorUIResource(Color.gray),
- "textText", new ColorUIResource(Color.black),
- "window", new ColorUIResource(light),
- "windowBorder", new ColorUIResource(Color.black),
- "windowText", new ColorUIResource(darkShadow)
+ String[] defaultColors = new String[] {
+ "activeCaption", "#000080",
+ "activeCaptionBorder", "#C0C0C0",
+ "activeCaptionText", "#FFFFFF",
+ "control", "#C0C0C0",
+ "controlDkShadow", "#000000",
+ "controlHighlight", "#C0C0C0",
+ "controlLtHighlight", "#FFFFFF",
+ "controlShadow", "#808080",
+ "controlText", "#000000",
+ "desktop", "#005C5C",
+ "inactiveCaption", "#808080",
+ "inactiveCaptionBorder", "#C0C0C0",
+ "inactiveCaptionText", "#C0C0C0",
+ "info", "#FFFFE1",
+ "infoText", "#000000",
+ "menu", "#C0C0C0",
+ "menuText", "#000000",
+ "scrollbar", "#E0E0E0",
+ "text", "#C0C0C0",
+ "textHighlight", "#000080",
+ "textHighlightText", "#FFFFFF",
+ "textInactiveText", "#808080",
+ "textText", "#000000",
+ "window", "#FFFFFF",
+ "windowBorder", "#000000",
+ "windowText", "#000000"
};
- defaults.putDefaults(uiDefaults);
+ loadSystemColors(defaults, defaultColors, isNativeLookAndFeel());
}
/**
- * Loads the system colors. This method is not implemented yet.
- *
+ * Populates the <code>defaults</code> table with the system colors. If
+ * <code>useNative</code> is <code>true</code>, the table is populated
+ * with the constants in {@link SystemColor}, otherwise the
+ * <code>systemColors</code> parameter is decoded into the defaults table.
+ * The system colors array is made up of pairs, where the first entry is the
+ * name of the system color, and the second entry is a string denoting
+ * an RGB color value like &quot;#C0C0C0&quot;, which is decoded using
+ * {@link Color#decode(String)}.
+ *
* @param defaults the defaults table (<code>null</code> not permitted).
- * @param systemColors TODO
- * @param useNative TODO
+ * @param systemColors defaults to use when <code>useNative</code> is
+ * <code>false</code>
+ * @param useNative when <code>true</code>, installs the values of the
+ * SystemColor constants, when <code>false</code>, install the values
+ * from <code>systemColors</code>
*/
protected void loadSystemColors(UIDefaults defaults, String[] systemColors,
boolean useNative)
{
- // TODO
+ if (useNative)
+ {
+ defaults.put("activeCaption",
+ new ColorUIResource(SystemColor.ACTIVE_CAPTION));
+ defaults.put("activeCaptionBorder",
+ new ColorUIResource(SystemColor.ACTIVE_CAPTION_BORDER));
+ defaults.put("activeCaptionText",
+ new ColorUIResource(SystemColor.ACTIVE_CAPTION_TEXT));
+ defaults.put("control",
+ new ColorUIResource(SystemColor.CONTROL));
+ defaults.put("controlDkShadow",
+ new ColorUIResource(SystemColor.CONTROL_DK_SHADOW));
+ defaults.put("controlHighlight",
+ new ColorUIResource(SystemColor.CONTROL_HIGHLIGHT));
+ defaults.put("controlLtHighlight",
+ new ColorUIResource(SystemColor.CONTROL_LT_HIGHLIGHT));
+ defaults.put("controlShadow",
+ new ColorUIResource(SystemColor.CONTROL_SHADOW));
+ defaults.put("controlText",
+ new ColorUIResource(SystemColor.CONTROL_TEXT));
+ defaults.put("desktop",
+ new ColorUIResource(SystemColor.DESKTOP));
+ defaults.put("inactiveCaption",
+ new ColorUIResource(SystemColor.INACTIVE_CAPTION));
+ defaults.put("inactiveCaptionBorder",
+ new ColorUIResource(SystemColor.INACTIVE_CAPTION_BORDER));
+ defaults.put("inactiveCaptionText",
+ new ColorUIResource(SystemColor.INACTIVE_CAPTION_TEXT));
+ defaults.put("info",
+ new ColorUIResource(SystemColor.INFO));
+ defaults.put("infoText",
+ new ColorUIResource(SystemColor.INFO_TEXT));
+ defaults.put("menu",
+ new ColorUIResource(SystemColor.MENU));
+ defaults.put("menuText",
+ new ColorUIResource(SystemColor.MENU_TEXT));
+ defaults.put("scrollbar",
+ new ColorUIResource(SystemColor.SCROLLBAR));
+ defaults.put("text",
+ new ColorUIResource(SystemColor.TEXT));
+ defaults.put("textHighlight",
+ new ColorUIResource(SystemColor.TEXT_HIGHLIGHT));
+ defaults.put("textHighlightText",
+ new ColorUIResource(SystemColor.TEXT_HIGHLIGHT_TEXT));
+ defaults.put("textInactiveText",
+ new ColorUIResource(SystemColor.TEXT_INACTIVE_TEXT));
+ defaults.put("textText",
+ new ColorUIResource(SystemColor.TEXT_TEXT));
+ defaults.put("window",
+ new ColorUIResource(SystemColor.WINDOW));
+ defaults.put("windowBorder",
+ new ColorUIResource(SystemColor.WINDOW_BORDER));
+ defaults.put("windowText",
+ new ColorUIResource(SystemColor.WINDOW_TEXT));
+ }
+ else
+ {
+ for (int i = 0; i < systemColors.length; i += 2)
+ {
+ Color color = Color.BLACK;
+ try
+ {
+ color = Color.decode(systemColors[i + 1]);
+ }
+ catch (NumberFormatException e)
+ {
+ e.printStackTrace();
+ }
+ defaults.put(systemColors[i], new ColorUIResource(color));
+ }
+ }
}
/**
@@ -1162,6 +1194,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"TabbedPane.shadow", new ColorUIResource(shadow),
"TabbedPane.tabbedPaneContentBorderInsets", new InsetsUIResource(3, 2, 1, 2),
"TabbedPane.tabbedPaneTabPadInsets", new InsetsUIResource(1, 1, 1, 1),
+ "TabbedPane.tabsOpaque", Boolean.TRUE,
"TabbedPane.tabAreaInsets", new InsetsUIResource(3, 2, 0, 2),
"TabbedPane.tabInsets", new InsetsUIResource(0, 4, 1, 4),
"TabbedPane.tabRunOverlay", new Integer(2),
@@ -1648,17 +1681,4 @@ public abstract class BasicLookAndFeel extends LookAndFeel
toolkit.removeAWTEventListener(popupHelper);
popupHelper = null;
}
-
- /**
- * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside
- * of the JPopupMenu. This must be called when the popup gets opened. The
- * popup is unregistered from autoclosing as soon as it either got closed
- * by this helper, or when it has been garbage collected.
- *
- * @param popup the popup menu to autoclose
- */
- void registerForAutoClose(JPopupMenu popup)
- {
- popupHelper.registerForAutoClose(popup);
- }
}
diff --git a/javax/swing/plaf/basic/BasicMenuBarUI.java b/javax/swing/plaf/basic/BasicMenuBarUI.java
index a21514467..f258ebe30 100644
--- a/javax/swing/plaf/basic/BasicMenuBarUI.java
+++ b/javax/swing/plaf/basic/BasicMenuBarUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Dimension;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
@@ -176,6 +178,7 @@ public class BasicMenuBarUI extends MenuBarUI
* This method installs the keyboard actions for the JMenuBar.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement
}
@@ -223,6 +226,7 @@ public class BasicMenuBarUI extends MenuBarUI
* This method reverses the work done in installKeyboardActions.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
diff --git a/javax/swing/plaf/basic/BasicMenuItemUI.java b/javax/swing/plaf/basic/BasicMenuItemUI.java
index 9166c49ee..69c9c4507 100644
--- a/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -40,6 +40,7 @@ package javax.swing.plaf.basic;
import java.awt.Color;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
@@ -82,6 +83,7 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentInputMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuItemUI;
+import javax.swing.text.View;
/**
* UI Delegate for JMenuItem.
@@ -183,7 +185,43 @@ public class BasicMenuItemUI extends MenuItemUI
/** A PropertyChangeListener to make UI updates after property changes **/
PropertyChangeHandler propertyChangeListener;
-
+
+ /**
+ * The view rectangle used for layout of the menu item.
+ */
+ private Rectangle viewRect;
+
+ /**
+ * The rectangle that holds the area of the label.
+ */
+ private Rectangle textRect;
+
+ /**
+ * The rectangle that holds the area of the accelerator.
+ */
+ private Rectangle accelRect;
+
+ /**
+ * The rectangle that holds the area of the icon.
+ */
+ private Rectangle iconRect;
+
+ /**
+ * The rectangle that holds the area of the icon.
+ */
+ private Rectangle arrowIconRect;
+
+ /**
+ * The rectangle that holds the area of the check icon.
+ */
+ private Rectangle checkIconRect;
+
+ /**
+ * A rectangle used for temporary storage to avoid creation of new
+ * rectangles.
+ */
+ private Rectangle cachedRect;
+
/**
* A class to handle PropertChangeEvents for the JMenuItem
* @author Anthony Balkissoon abalkiss at redhat dot com.
@@ -242,6 +280,15 @@ public class BasicMenuItemUI extends MenuItemUI
menuKeyListener = createMenuKeyListener(menuItem);
itemListener = new ItemHandler();
propertyChangeListener = new PropertyChangeHandler();
+
+ // Initialize rectangles for layout.
+ viewRect = new Rectangle();
+ textRect = new Rectangle();
+ iconRect = new Rectangle();
+ arrowIconRect = new Rectangle();
+ checkIconRect = new Rectangle();
+ accelRect = new Rectangle();
+ cachedRect = new Rectangle();
}
/**
@@ -378,50 +425,69 @@ public class BasicMenuItemUI extends MenuItemUI
int defaultTextIconGap)
{
JMenuItem m = (JMenuItem) c;
- Dimension d = BasicGraphicsUtils.getPreferredButtonSize(m,
- defaultTextIconGap);
-
- // if menu item has accelerator then take accelerator's size into account
- // when calculating preferred size.
- KeyStroke accelerator = m.getAccelerator();
- Rectangle rect;
-
- if (accelerator != null)
+ String accelText = getAcceleratorString(m);
+
+ // Layout the menu item. The result gets stored in the rectangle
+ // fields of this class.
+ layoutMenuItem(m, accelText);
+
+ // The union of the text and icon areas is the label area.
+ cachedRect.setBounds(textRect);
+ Rectangle pref = SwingUtilities.computeUnion(iconRect.x, iconRect.y,
+ iconRect.width,
+ iconRect.height,
+ cachedRect);
+
+ // Find the widest menu item text and accelerator and store it in
+ // client properties of the parent, so that we can align the accelerators
+ // properly. Of course, we only need can do this, if the parent is
+ // a JComponent and this menu item is not a toplevel menu.
+ Container parent = m.getParent();
+ if (parent != null && parent instanceof JComponent
+ && !(m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
{
- rect = getAcceleratorRect(
- accelerator,
- m.getToolkit().getFontMetrics(acceleratorFont));
+ JComponent p = (JComponent) parent;
- // add width of accelerator's text
- d.width += rect.width + defaultAcceleratorLabelGap;
+ // The widest text so far.
+ Integer maxTextWidth = (Integer) p.getClientProperty("maxTextWidth");
+ int maxTextValue = maxTextWidth == null ? 0 : maxTextWidth.intValue();
+ if (pref.width < maxTextValue)
+ pref.width = maxTextValue;
+ else
+ p.putClientProperty("maxTextWidth", new Integer(pref.width));
- // adjust the heigth of the preferred size if necessary
- if (d.height < rect.height)
- d.height = rect.height;
+ // The widest accelerator so far.
+ Integer maxAccelWidth = (Integer) p.getClientProperty("maxAccelWidth");
+ int maxAccelValue = maxAccelWidth == null ? 0
+ : maxAccelWidth.intValue();
+ if (accelRect.width > maxAccelValue)
+ {
+ maxAccelValue = accelRect.width;
+ p.putClientProperty("maxAccelWidth", new Integer(accelRect.width));
+ }
+ pref.width += maxAccelValue;
+ pref.width += defaultTextIconGap;
}
- if (checkIcon != null)
+ // Add arrow and check size if appropriate.
+ if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
{
- d.width += checkIcon.getIconWidth() + defaultTextIconGap;
-
- if (checkIcon.getIconHeight() > d.height)
- d.height = checkIcon.getIconHeight();
+ pref.width += checkIconRect.width;
+ pref.width += defaultTextIconGap;
+ pref.width += arrowIconRect.width;
+ pref.width += defaultTextIconGap;
}
- if (arrowIcon != null && (c instanceof JMenu))
- {
- int pWidth = m.getParent().getWidth();
- if (!((JMenu)c).isTopLevelMenu() && d.width < pWidth)
- d.width = pWidth
- - m.getInsets().left - m.getInsets().right;
- else
- d.width += arrowIcon.getIconWidth() + MenuGap;
-
- if (arrowIcon.getIconHeight() > d.height)
- d.height = arrowIcon.getIconHeight();
- }
-
- return d;
+ // Add a gap ~2 times as wide as the defaultTextIconGap.
+ pref.width += 2 * defaultTextIconGap;
+
+ // Respect the insets of the menu item.
+ Insets i = m.getInsets();
+ pref.width += i.left + i.right;
+ pref.height += i.top + i.bottom;
+
+ // Return a copy, so that nobody messes with our textRect.
+ return pref.getSize();
}
/**
@@ -541,7 +607,7 @@ public class BasicMenuItemUI extends MenuItemUI
*/
public void paint(Graphics g, JComponent c)
{
- paintMenuItem(g, c, checkIcon, arrowIcon, c.getBackground(),
+ paintMenuItem(g, c, checkIcon, arrowIcon, selectionBackground,
c.getForeground(), defaultTextIconGap);
}
@@ -560,16 +626,18 @@ public class BasicMenuItemUI extends MenuItemUI
// Menu item is considered to be highlighted when it is selected.
// But we don't want to paint the background of JCheckBoxMenuItems
ButtonModel mod = menuItem.getModel();
- if (menuItem.isContentAreaFilled())
+ Color saved = g.getColor();
+ if (mod.isArmed() || ((menuItem instanceof JMenu) && mod.isSelected()))
{
- if ((menuItem.isSelected() && checkIcon == null) || (mod != null &&
- mod.isArmed())
- && (menuItem.getParent() instanceof MenuElement))
- g.setColor(selectionBackground);
- else
- g.setColor(bgColor);
+ g.setColor(bgColor);
+ g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
+ }
+ else if (menuItem.isOpaque())
+ {
+ g.setColor(menuItem.getBackground());
g.fillRect(0, 0, menuItem.getWidth(), menuItem.getHeight());
- }
+ }
+ g.setColor(saved);
}
/**
@@ -595,87 +663,123 @@ public class BasicMenuItemUI extends MenuItemUI
Color foreground, int defaultTextIconGap)
{
JMenuItem m = (JMenuItem) c;
- Rectangle tr = new Rectangle(); // text rectangle
- Rectangle ir = new Rectangle(); // icon rectangle
- Rectangle vr = new Rectangle(); // view rectangle
- Rectangle br = new Rectangle(); // border rectangle
- Rectangle ar = new Rectangle(); // accelerator rectangle
- Rectangle cr = new Rectangle(); // checkIcon rectangle
-
- int vertAlign = m.getVerticalAlignment();
- int horAlign = m.getHorizontalAlignment();
- int vertTextPos = m.getVerticalTextPosition();
- int horTextPos = m.getHorizontalTextPosition();
-
- Font f = m.getFont();
- g.setFont(f);
- FontMetrics fm = g.getFontMetrics(f);
- SwingUtilities.calculateInnerArea(m, vr);
+
+ // Fetch fonts.
+ Font oldFont = g.getFont();
+ Font font = c.getFont();
+ g.setFont(font);
+ FontMetrics accelFm = m.getFontMetrics(acceleratorFont);
+
+ // Create accelerator string.
+ String accelText = getAcceleratorString(m);
+
+ // Layout menu item. The result gets stored in the rectangle fields
+ // of this class.
+ layoutMenuItem(m, accelText);
+
+ // Paint the background.
paintBackground(g, m, background);
- /*
- * MenuItems insets are equal to menuItems margin, space between text and
- * menuItems border. We need to paint insets region as well.
- */
- Insets insets = m.getInsets();
- br.x -= insets.left;
- br.y -= insets.top;
- br.width += insets.right + insets.left;
- br.height += insets.top + insets.bottom;
+ Color oldColor = g.getColor();
- // If this menu item is a JCheckBoxMenuItem then paint check icon
+ // Paint the check icon.
if (checkIcon != null)
{
- SwingUtilities.layoutCompoundLabel(m, fm, null, checkIcon, vertAlign,
- horAlign, vertTextPos, horTextPos,
- vr, cr, tr, defaultTextIconGap);
- checkIcon.paintIcon(m, g, cr.x, cr.y);
- // We need to calculate position of the menu text and position of
- // user menu icon if there exists one relative to the check icon.
- // So we need to adjust view rectangle s.t. its starting point is at
- // checkIcon.width + defaultTextIconGap.
- vr.x = cr.x + cr.width + defaultTextIconGap;
+ checkIcon.paintIcon(m, g, checkIconRect.x, checkIconRect.y);
+ }
+
+ // Paint the icon.
+ ButtonModel model = m.getModel();
+ if (m.getIcon() != null)
+ {
+ // Determine icon depending on the menu item
+ // state (normal/disabled/pressed).
+ Icon icon;
+ if (! m.isEnabled())
+ {
+ icon = m.getDisabledIcon();
+ }
+ else if (model.isPressed() && model.isArmed())
+ {
+ icon = m.getPressedIcon();
+ if (icon == null)
+ {
+ icon = m.getIcon();
+ }
+ }
+ else
+ {
+ icon = m.getIcon();
+ }
+
+ if (icon != null)
+ {
+ icon.paintIcon(m, g, iconRect.x, iconRect.y);
+ }
}
- // if this is a submenu, then paint arrow icon to indicate it.
- if (arrowIcon != null && (c instanceof JMenu))
+ // Paint the text.
+ String text = m.getText();
+ if (text != null)
{
- if (!((JMenu) c).isTopLevelMenu())
+ // Handle HTML.
+ View html = (View) m.getClientProperty(BasicHTML.propertyKey);
+ if (html != null)
+ {
+ html.paint(g, textRect);
+ }
+ else
{
- int width = arrowIcon.getIconWidth();
- int height = arrowIcon.getIconHeight();
- int offset = (vr.height - height) / 2;
- arrowIcon.paintIcon(m, g, vr.width - width, vr.y + offset);
+ paintText(g, m, textRect, text);
}
}
- // paint text and user menu icon if it exists
- Icon i = m.getIcon();
- SwingUtilities.layoutCompoundLabel(c, fm, m.getText(), i, vertAlign,
- horAlign, vertTextPos, horTextPos, vr,
- ir, tr, defaultTextIconGap);
- if (i != null)
- i.paintIcon(c, g, ir.x, ir.y);
- paintText(g, m, tr, m.getText());
+ // Paint accelerator text.
+ if (! accelText.equals(""))
+ {
+ // Align the accelerator text. In getPreferredMenuItemSize() we
+ // store a client property 'maxAccelWidth' in the parent which holds
+ // the maximum accelerator width for the children of this parent.
+ // We use this here to align the accelerators properly.
+ int accelOffset = 0;
+ Container parent = m.getParent();
+ if (parent != null && parent instanceof JComponent)
+ {
+ JComponent p = (JComponent) parent;
+ Integer maxAccelWidth =
+ (Integer) p.getClientProperty("maxAccelWidth");
+ int maxAccelValue = maxAccelWidth == null ? 0
+ : maxAccelWidth.intValue();
+ accelOffset = maxAccelValue - accelRect.width;
+ }
- // paint accelerator
- String acceleratorText = "";
+ g.setFont(acceleratorFont);
+ if (! m.isEnabled())
+ {
+ // Paint accelerator disabled.
+ g.setColor(disabledForeground);
+ }
+ else
+ {
+ if (m.isArmed() || (m instanceof JMenu && m.isSelected()))
+ g.setColor(acceleratorSelectionForeground);
+ else
+ g.setColor(acceleratorForeground);
+ }
+ g.drawString(accelText, accelRect.x - accelOffset,
+ accelRect.y + accelFm.getAscent());
+ }
- if (m.getAccelerator() != null)
+ // Paint arrow.
+ if (arrowIcon != null
+ && ! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
{
- acceleratorText = getAcceleratorText(m.getAccelerator());
- fm = g.getFontMetrics(acceleratorFont);
- ar.width = fm.stringWidth(acceleratorText);
- ar.x = br.width - ar.width;
- vr.x = br.width - ar.width - defaultTextIconGap;
-
- SwingUtilities.layoutCompoundLabel(m, fm, acceleratorText, null,
- vertAlign, horAlign, vertTextPos,
- horTextPos, vr, ir, ar,
- defaultTextIconGap);
-
- paintAccelerator(g, m, ar, acceleratorText);
+ arrowIcon.paintIcon(m, g, arrowIconRect.x, arrowIconRect.y);
}
+
+ g.setFont(oldFont);
+ g.setColor(oldColor);
+
}
/**
@@ -860,37 +964,6 @@ public class BasicMenuItemUI extends MenuItemUI
}
/**
- * Paints accelerator inside menu item
- *
- * @param g
- * The graphics context used to paint the border
- * @param menuItem
- * Menu item for which to draw accelerator
- * @param acceleratorRect
- * rectangle representing position of the accelerator relative to the
- * menu item
- * @param acceleratorText
- * accelerator's text
- */
- private void paintAccelerator(Graphics g, JMenuItem menuItem,
- Rectangle acceleratorRect,
- String acceleratorText)
- {
- g.setFont(acceleratorFont);
- FontMetrics fm = g.getFontMetrics(acceleratorFont);
-
- if (menuItem.isEnabled())
- g.setColor(acceleratorForeground);
- else
- // FIXME: should fix this to use 'disabledForeground', but its
- // default value in BasicLookAndFeel is null.
- g.setColor(Color.gray);
-
- BasicGraphicsUtils.drawString(g, acceleratorText, 0, acceleratorRect.x,
- acceleratorRect.y + fm.getAscent());
- }
-
- /**
* This class handles mouse events occuring inside the menu item. Most of the
* events are forwarded for processing to MenuSelectionManager of the current
* menu hierarchy.
@@ -1139,4 +1212,134 @@ public class BasicMenuItemUI extends MenuItemUI
menuItem.repaint();
}
}
+
+ /**
+ * A helper method to create the accelerator string from the menu item's
+ * accelerator property. The returned string is empty if there is
+ * no accelerator defined.
+ *
+ * @param m the menu item
+ *
+ * @return the accelerator string, not null
+ */
+ private String getAcceleratorString(JMenuItem m)
+ {
+ // Create accelerator string.
+ KeyStroke accel = m.getAccelerator();
+ String accelText = "";
+ if (accel != null)
+ {
+ int mods = accel.getModifiers();
+ if (mods > 0)
+ {
+ accelText = KeyEvent.getKeyModifiersText(mods);
+ accelText += acceleratorDelimiter;
+ }
+ int keycode = accel.getKeyCode();
+ if (keycode != 0)
+ accelText += KeyEvent.getKeyText(keycode);
+ else
+ accelText += accel.getKeyChar();
+ }
+ return accelText;
+ }
+
+ /**
+ * A helper method that lays out the menu item. The layout is stored
+ * in the fields of this class.
+ *
+ * @param m the menu item to layout
+ * @param accelText the accelerator text
+ */
+ private void layoutMenuItem(JMenuItem m, String accelText)
+ {
+ int width = m.getWidth();
+ int height = m.getHeight();
+
+ // Reset rectangles.
+ iconRect.setBounds(0, 0, 0, 0);
+ textRect.setBounds(0, 0, 0, 0);
+ accelRect.setBounds(0, 0, 0, 0);
+ checkIconRect.setBounds(0, 0, 0, 0);
+ arrowIconRect.setBounds(0, 0, 0, 0);
+ viewRect.setBounds(0, 0, width, height);
+
+ // Substract insets to the view rect.
+ Insets insets = m.getInsets();
+ viewRect.x += insets.left;
+ viewRect.y += insets.top;
+ viewRect.width -= (insets.left + insets.right);
+ viewRect.height -= (insets.top + insets.bottom);
+
+ // Fetch the fonts.
+ Font font = m.getFont();
+ FontMetrics fm = m.getFontMetrics(font);
+ FontMetrics accelFm = m.getFontMetrics(acceleratorFont);
+
+ String text = m.getText();
+ SwingUtilities.layoutCompoundLabel(m, fm, text, m.getIcon(),
+ m.getVerticalAlignment(),
+ m.getHorizontalAlignment(),
+ m.getVerticalTextPosition(),
+ m.getHorizontalTextPosition(),
+ viewRect, iconRect, textRect,
+ defaultTextIconGap);
+
+ // Initialize accelerator width and height.
+ if (! accelText.equals(""))
+ {
+ accelRect.width = accelFm.stringWidth(accelText);
+ accelRect.height = accelFm.getHeight();
+ }
+
+ // Initialize check and arrow icon width and height.
+ if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
+ {
+ if (checkIcon != null)
+ {
+ checkIconRect.width = checkIcon.getIconWidth();
+ checkIconRect.height = checkIcon.getIconHeight();
+ }
+ if (arrowIcon != null)
+ {
+ arrowIconRect.width = arrowIcon.getIconWidth();
+ arrowIconRect.height = arrowIcon.getIconHeight();
+ }
+ }
+
+ // The union of the icon and text of the menu item is the 'label area'.
+ cachedRect.setBounds(textRect);
+ Rectangle labelRect = SwingUtilities.computeUnion(iconRect.x,
+ iconRect.y,
+ iconRect.width,
+ iconRect.height,
+ cachedRect);
+ textRect.x += defaultTextIconGap;
+ iconRect.x += defaultTextIconGap;
+
+ // Layout accelerator rect.
+ accelRect.x = viewRect.x + viewRect.width - arrowIconRect.width
+ - defaultTextIconGap - accelRect.width;
+ // Layout check and arrow icons only when not in toplevel menu.
+ if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
+ {
+ checkIconRect.x = viewRect.x + defaultTextIconGap;
+ textRect.x += defaultTextIconGap + checkIconRect.width;
+ iconRect.x += defaultTextIconGap + checkIconRect.width;
+ arrowIconRect.x = viewRect.x + viewRect.width - defaultTextIconGap
+ - arrowIconRect.width;
+ }
+
+ // Align the accelerator text and all the icons vertically centered to
+ // the menu text.
+ accelRect.y = labelRect.y + (labelRect.height / 2)
+ - (accelRect.height / 2);
+ if (! (m instanceof JMenu && ((JMenu) m).isTopLevelMenu()))
+ {
+ arrowIconRect.y = labelRect.y + (labelRect.height / 2)
+ - (arrowIconRect.height / 2);
+ checkIconRect.y = labelRect.y + (labelRect.height / 2)
+ - (checkIconRect.height / 2);
+ }
+ }
}
diff --git a/javax/swing/plaf/basic/BasicMenuUI.java b/javax/swing/plaf/basic/BasicMenuUI.java
index 4fb250d24..f8936be5b 100644
--- a/javax/swing/plaf/basic/BasicMenuUI.java
+++ b/javax/swing/plaf/basic/BasicMenuUI.java
@@ -38,6 +38,8 @@ 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.event.MouseEvent;
@@ -218,6 +220,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement
}
@@ -262,6 +265,7 @@ public class BasicMenuUI extends BasicMenuItemUI
* Basic look and feel's defaults.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement
}
diff --git a/javax/swing/plaf/basic/BasicOptionPaneUI.java b/javax/swing/plaf/basic/BasicOptionPaneUI.java
index 005a3b394..88bca3b53 100644
--- a/javax/swing/plaf/basic/BasicOptionPaneUI.java
+++ b/javax/swing/plaf/basic/BasicOptionPaneUI.java
@@ -38,6 +38,8 @@ 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;
@@ -1204,6 +1206,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
* This method installs keyboard actions for the JOptionpane.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
@@ -1336,6 +1339,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
* This method uninstalls keyboard actions for the JOptionPane.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
diff --git a/javax/swing/plaf/basic/BasicPopupMenuUI.java b/javax/swing/plaf/basic/BasicPopupMenuUI.java
index 6ecd06b39..a26a5c7c4 100644
--- a/javax/swing/plaf/basic/BasicPopupMenuUI.java
+++ b/javax/swing/plaf/basic/BasicPopupMenuUI.java
@@ -37,6 +37,8 @@ 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.event.ComponentEvent;
@@ -137,6 +139,7 @@ public class BasicPopupMenuUI extends PopupMenuUI
* This method installs the keyboard actions for this {@link JPopupMenu}.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement
}
@@ -179,6 +182,7 @@ public class BasicPopupMenuUI extends PopupMenuUI
* Uninstalls any keyboard actions.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Need to implement
}
diff --git a/javax/swing/plaf/basic/BasicRadioButtonUI.java b/javax/swing/plaf/basic/BasicRadioButtonUI.java
index 66e538037..a66fa28e6 100644
--- a/javax/swing/plaf/basic/BasicRadioButtonUI.java
+++ b/javax/swing/plaf/basic/BasicRadioButtonUI.java
@@ -45,6 +45,7 @@ import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
@@ -142,14 +143,15 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
g.setFont(f);
+ ButtonModel m = b.getModel();
Icon currentIcon = null;
- if (b.isSelected() && b.isEnabled())
+ if (m.isSelected() && m.isEnabled())
currentIcon = b.getSelectedIcon();
- else if (!b.isSelected() && b.isEnabled())
+ else if (! m.isSelected() && m.isEnabled())
currentIcon = b.getIcon();
- else if (b.isSelected() && !b.isEnabled())
+ else if (m.isSelected() && ! m.isEnabled())
currentIcon = b.getDisabledSelectedIcon();
- else // (!b.isSelected() && !b.isEnabled())
+ else // (!m.isSelected() && ! m.isEnabled())
currentIcon = b.getDisabledIcon();
SwingUtilities.calculateInnerArea(b, vr);
@@ -166,7 +168,7 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
if (text != null)
paintText(g, b, tr, text);
// TODO: Figure out what is the size parameter?
- if (b.hasFocus() && b.isFocusPainted() && b.isEnabled())
+ if (b.hasFocus() && b.isFocusPainted() && m.isEnabled())
paintFocus(g, tr, null);
}
diff --git a/javax/swing/plaf/basic/BasicRootPaneUI.java b/javax/swing/plaf/basic/BasicRootPaneUI.java
index 28e3b67c1..933db4c6b 100644
--- a/javax/swing/plaf/basic/BasicRootPaneUI.java
+++ b/javax/swing/plaf/basic/BasicRootPaneUI.java
@@ -38,17 +38,98 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.ButtonModel;
+import javax.swing.InputMap;
+import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JRootPane;
+import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.plaf.ActionMapUIResource;
+import javax.swing.plaf.ComponentInputMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.RootPaneUI;
public class BasicRootPaneUI extends RootPaneUI
implements PropertyChangeListener
{
+
+ /**
+ * Performed when the user activates the default button inside the JRootPane,
+ * usually by pressing 'ENTER'.
+ */
+ private class DefaultPressAction
+ extends AbstractAction
+ {
+ /**
+ * The JRootPane for which this action should be installed.
+ */
+ private JRootPane rootPane;
+
+ /**
+ * Creates a new DefaultPressAction for the specified JRootPane.
+ */
+ DefaultPressAction(JRootPane rp)
+ {
+ rootPane = rp;
+ }
+
+ /**
+ * Performes the action.
+ */
+ public void actionPerformed(ActionEvent ev)
+ {
+ JButton b = rootPane.getDefaultButton();
+ if (b != null)
+ {
+ ButtonModel m = b.getModel();
+ m.setArmed(true);
+ m.setPressed(true);
+ }
+ }
+ }
+
+ /**
+ * Performed when the user activates the default button inside the JRootPane,
+ * usually by releasing 'ENTER'.
+ */
+ private class DefaultReleaseAction
+ extends AbstractAction
+ {
+ /**
+ * The JRootPane for which this action should be installed.
+ */
+ private JRootPane rootPane;
+
+ /**
+ * Creates a new DefaultReleaseAction for the specified JRootPane.
+ */
+ DefaultReleaseAction(JRootPane rp)
+ {
+ rootPane = rp;
+ }
+
+ /**
+ * Performes the action.
+ */
+ public void actionPerformed(ActionEvent ev)
+ {
+ JButton b = rootPane.getDefaultButton();
+ if (b != null)
+ {
+ ButtonModel m = b.getModel();
+ m.setPressed(false);
+ m.setArmed(false);
+ }
+ }
+ }
+
public static ComponentUI createUI(JComponent x)
{
return new BasicRootPaneUI();
@@ -107,14 +188,43 @@ public class BasicRootPaneUI extends RootPaneUI
*/
protected void installKeyboardActions(JRootPane rp)
{
- // We currently do not install any keyboard actions here.
- // This method is here anyway for compatibility and to provide
- // the necessary hooks to subclasses.
+ // Install the keyboard actions.
+ ActionMapUIResource am = new ActionMapUIResource();
+ am.put("press", new DefaultPressAction(rp));
+ am.put("release", new DefaultReleaseAction(rp));
+ SwingUtilities.replaceUIActionMap(rp, am);
+
+ // Install the input map from the UIManager. It seems like the actual
+ // bindings are installed in the JRootPane only when the defaultButton
+ // property receives a value. So we also only install an empty
+ // input map here, and fill it in propertyChange.
+ ComponentInputMapUIResource im = new ComponentInputMapUIResource(rp);
+ SwingUtilities.replaceUIInputMap(rp, JComponent.WHEN_IN_FOCUSED_WINDOW,
+ im);
}
public void propertyChange(PropertyChangeEvent event)
{
- // TODO: Implement this properly.
+ JRootPane source = (JRootPane) event.getSource();
+ String propertyName = event.getPropertyName();
+ if (propertyName.equals("defaultButton"))
+ {
+ Object newValue = event.getNewValue();
+ InputMap im =
+ SwingUtilities.getUIInputMap(source,
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ if (newValue != null)
+ {
+ Object[] keybindings =
+ (Object[]) UIManager.get
+ ("RootPane.defaultButtonWindowKeyBindings");
+ LookAndFeel.loadKeyBindings(im, keybindings);
+ }
+ else
+ {
+ im.clear();
+ }
+ }
}
/**
@@ -176,6 +286,8 @@ public class BasicRootPaneUI extends RootPaneUI
*/
protected void uninstallKeyboardActions(JRootPane rp)
{
- // We do nothing here.
+ SwingUtilities.replaceUIActionMap(rp, null);
+ SwingUtilities.replaceUIInputMap(rp, JComponent.WHEN_IN_FOCUSED_WINDOW,
+ null);
}
}
diff --git a/javax/swing/plaf/basic/BasicScrollBarUI.java b/javax/swing/plaf/basic/BasicScrollBarUI.java
index 0ab2914ea..f24485484 100644
--- a/javax/swing/plaf/basic/BasicScrollBarUI.java
+++ b/javax/swing/plaf/basic/BasicScrollBarUI.java
@@ -38,6 +38,8 @@ 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;
@@ -763,6 +765,7 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
* This method installs the keyboard actions for the scrollbar.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
@@ -1141,6 +1144,7 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
* during install.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
diff --git a/javax/swing/plaf/basic/BasicScrollPaneUI.java b/javax/swing/plaf/basic/BasicScrollPaneUI.java
index 71671b799..e6a4eaf4f 100644
--- a/javax/swing/plaf/basic/BasicScrollPaneUI.java
+++ b/javax/swing/plaf/basic/BasicScrollPaneUI.java
@@ -38,9 +38,15 @@ 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;
import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.ContainerEvent;
+import java.awt.event.ContainerListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.beans.PropertyChangeEvent;
@@ -53,6 +59,8 @@ import javax.swing.JViewport;
import javax.swing.LookAndFeel;
import javax.swing.ScrollPaneConstants;
import javax.swing.ScrollPaneLayout;
+import javax.swing.Scrollable;
+import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.ComponentUI;
@@ -222,18 +230,149 @@ public class BasicScrollPaneUI extends ScrollPaneUI
*/
protected class MouseWheelHandler implements MouseWheelListener
{
+ /**
+ * Use to compute the visible rectangle.
+ */
+ final Rectangle rect = new Rectangle();
/**
- * Receives notification whenever the mouse wheel is moved.
- *
- * @param event the mouse wheel event
+ * Scroll with the mouse whell.
+ *
+ * @author Audrius Meskauskas (audriusa@Bioinformatics.org)
*/
- public void mouseWheelMoved(MouseWheelEvent event)
+ public void mouseWheelMoved(MouseWheelEvent e)
{
- // TODO: Implement this properly.
+ if (scrollpane.getViewport().getComponentCount() == 0)
+ return;
+
+ Component target = scrollpane.getViewport().getComponent(0);
+ JScrollBar bar = scrollpane.getVerticalScrollBar();
+ Scrollable scrollable = (target instanceof Scrollable) ? (Scrollable) target
+ : null;
+
+ boolean tracksHeight = scrollable != null
+ && scrollable.getScrollableTracksViewportHeight();
+ int wheel = e.getWheelRotation() * ROWS_PER_WHEEL_CLICK;
+ int delta;
+
+ // If possible, scroll vertically.
+ if (bar != null && ! tracksHeight)
+ {
+ if (scrollable != null)
+ {
+ bounds(target);
+ delta = scrollable.getScrollableUnitIncrement(
+ rect, SwingConstants.VERTICAL, wheel);
+ }
+ else
+ {
+ // Scroll non scrollables.
+ delta = wheel * SCROLL_NON_SCROLLABLES;
+ }
+ scroll(bar, delta);
+ }
+ // If not, try to scroll horizontally
+ else
+ {
+ bar = scrollpane.getHorizontalScrollBar();
+ boolean tracksWidth = scrollable != null
+ && scrollable.getScrollableTracksViewportWidth();
+
+ if (bar != null && ! tracksWidth)
+ {
+ if (scrollable != null)
+ {
+ bounds(target);
+ delta = scrollable.getScrollableUnitIncrement(
+ rect, SwingConstants.HORIZONTAL, wheel);
+ }
+ else
+ {
+ // Scroll non scrollables.
+ delta = wheel * SCROLL_NON_SCROLLABLES;
+ }
+ scroll(bar, delta);
+ }
+ }
}
+
+ /**
+ * Place the component bounds into rect. The x and y values
+ * need to be reversed.
+ *
+ * @param target the target being scrolled
+ */
+ final void bounds(Component target)
+ {
+ // Viewport bounds, translated by the scroll bar positions.
+ target.getParent().getBounds(rect);
+ rect.x = getValue(scrollpane.getHorizontalScrollBar());
+ rect.y = getValue(scrollpane.getVerticalScrollBar());
+ }
+
+ /**
+ * Get the scroll bar value or null if there is no such scroll bar.
+ */
+ final int getValue(JScrollBar bar)
+ {
+ return bar != null ? bar.getValue() : 0;
+ }
+
+ /**
+ * Scroll the given distance.
+ *
+ * @param bar the scrollbar to scroll
+ * @param delta the distance
+ */
+ final void scroll(JScrollBar bar, int delta)
+ {
+ int y = bar.getValue() + delta;
+
+ if (y < bar.getMinimum())
+ y = bar.getMinimum();
+ if (y > bar.getMaximum())
+ y = bar.getMaximum();
+ bar.setValue(y);
+ }
+ }
+
+ /**
+ * Adds/removes the mouse wheel listener when the component is added/removed
+ * to/from the scroll pane view port.
+ *
+ * @author Audrius Meskauskas (audriusa@bioinformatics.org)
+ */
+ class ViewportContainerListener implements ContainerListener
+ {
+ /**
+ * Add the mouse wheel listener, allowing to scroll with the mouse.
+ */
+ public void componentAdded(ContainerEvent e)
+ {
+ e.getChild().addMouseWheelListener(mouseWheelListener);
+ }
+
+ /**
+ * Remove the mouse wheel listener.
+ */
+ public void componentRemoved(ContainerEvent e)
+ {
+ e.getChild().removeMouseWheelListener(mouseWheelListener);
+ }
}
+
+ /**
+ * The number of pixels by that we should scroll the content that does
+ * not implement Scrollable.
+ */
+ static int SCROLL_NON_SCROLLABLES = 10;
+
+ /**
+ * The number of rows to scroll per mouse wheel click. From impression,
+ * Sun seems using the value 3.
+ */
+ static int ROWS_PER_WHEEL_CLICK = 3;
/** The Scrollpane for which the UI is provided by this class. */
protected JScrollPane scrollpane;
@@ -262,6 +401,12 @@ public class BasicScrollPaneUI extends ScrollPaneUI
* The mousewheel listener for the scrollpane.
*/
MouseWheelListener mouseWheelListener;
+
+ /**
+ * The listener to add and remove the mouse wheel listener to/from
+ * the component container.
+ */
+ ContainerListener containerListener;
public static ComponentUI createUI(final JComponent c)
{
@@ -316,11 +461,21 @@ public class BasicScrollPaneUI extends ScrollPaneUI
if (viewportChangeListener == null)
viewportChangeListener = createViewportChangeListener();
- sp.getViewport().addChangeListener(viewportChangeListener);
-
+
if (mouseWheelListener == null)
mouseWheelListener = createMouseWheelListener();
- sp.addMouseWheelListener(mouseWheelListener);
+
+ if (containerListener == null)
+ containerListener = new ViewportContainerListener();
+
+ JViewport v = sp.getViewport();
+ v.addChangeListener(viewportChangeListener);
+ v.addContainerListener(containerListener);
+
+ // Add mouse wheel listeners to the componets that are probably already
+ // in the view port.
+ for (int i = 0; i < v.getComponentCount(); i++)
+ v.getComponent(i).addMouseWheelListener(mouseWheelListener);
}
/**
@@ -331,6 +486,7 @@ public class BasicScrollPaneUI extends ScrollPaneUI
* @param sp the scrollpane to install keyboard actions on
*/
protected void installKeyboardActions(JScrollPane sp)
+ throws NotImplementedException
{
// TODO: Is this only a hook method or should we actually do something
// here? If the latter, than figure out what and implement this.
@@ -408,8 +564,14 @@ public class BasicScrollPaneUI extends ScrollPaneUI
.removeChangeListener(hsbChangeListener);
sp.getVerticalScrollBar().getModel()
.removeChangeListener(vsbChangeListener);
- sp.getViewport().removeChangeListener(viewportChangeListener);
- sp.removeMouseWheelListener(mouseWheelListener);
+
+ JViewport v = sp.getViewport();
+ v.removeChangeListener(viewportChangeListener);
+ v.removeContainerListener(containerListener);
+
+ for (int i = 0; i < v.getComponentCount(); i++)
+ v.getComponent(i).removeMouseWheelListener(mouseWheelListener);
+
}
/**
@@ -420,6 +582,7 @@ public class BasicScrollPaneUI extends ScrollPaneUI
* @param sp the scrollpane to uninstall keyboard actions from
*/
protected void uninstallKeyboardActions(JScrollPane sp)
+ throws NotImplementedException
{
// TODO: Is this only a hook method or should we actually do something
// here? If the latter, than figure out what and implement this.
diff --git a/javax/swing/plaf/basic/BasicSliderUI.java b/javax/swing/plaf/basic/BasicSliderUI.java
index 694aa9612..137ab55a6 100644
--- a/javax/swing/plaf/basic/BasicSliderUI.java
+++ b/javax/swing/plaf/basic/BasicSliderUI.java
@@ -1,5 +1,5 @@
/* BasicSliderUI.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.
@@ -38,6 +38,8 @@ 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;
@@ -61,7 +63,9 @@ import java.util.Dictionary;
import java.util.Enumeration;
import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
import javax.swing.BoundedRangeModel;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JSlider;
@@ -72,6 +76,7 @@ import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputAdapter;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.SliderUI;
@@ -204,6 +209,7 @@ public class BasicSliderUI extends SliderUI
* @param e A {@link FocusEvent}.
*/
public void focusGained(FocusEvent e)
+ throws NotImplementedException
{
// FIXME: implement.
}
@@ -215,6 +221,7 @@ public class BasicSliderUI extends SliderUI
* @param e A {@link FocusEvent}.
*/
public void focusLost(FocusEvent e)
+ throws NotImplementedException
{
// FIXME: implement.
}
@@ -236,14 +243,16 @@ public class BasicSliderUI extends SliderUI
{
// Check for orientation changes.
if (e.getPropertyName().equals("orientation"))
- recalculateIfOrientationChanged();
+ recalculateIfOrientationChanged();
else if (e.getPropertyName().equals("model"))
{
- BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue();
- oldModel.removeChangeListener(changeListener);
- slider.getModel().addChangeListener(changeListener);
- calculateThumbLocation();
+ BoundedRangeModel oldModel = (BoundedRangeModel) e.getOldValue();
+ oldModel.removeChangeListener(changeListener);
+ slider.getModel().addChangeListener(changeListener);
+ calculateThumbLocation();
}
+ else if (e.getPropertyName().equals("paintTicks"))
+ calculateGeometry();
// elif the componentOrientation changes (this is a bound property,
// just undocumented) we change leftToRightCache. In Sun's
@@ -304,14 +313,14 @@ public class BasicSliderUI extends SliderUI
{
if (! trackListener.shouldScroll(direction))
{
- scrollTimer.stop();
- return;
+ scrollTimer.stop();
+ return;
}
if (block)
- scrollByBlock(direction);
+ scrollByBlock(direction);
else
- scrollByUnit(direction);
+ scrollByUnit(direction);
}
/**
@@ -416,7 +425,8 @@ public class BasicSliderUI extends SliderUI
if (slider.getSnapToTicks())
value = findClosestTick(value);
- // If the thumb is hit, then we don't need to set the timers to move it.
+ // If the thumb is hit, then we don't need to set the timers to
+ // move it.
if (! thumbRect.contains(e.getPoint()))
{
// The mouse has hit some other part of the slider.
@@ -469,14 +479,14 @@ public class BasicSliderUI extends SliderUI
{
int value;
if (slider.getOrientation() == JSlider.HORIZONTAL)
- value = valueForXPosition(currentMouseX);
+ value = valueForXPosition(currentMouseX);
else
- value = valueForYPosition(currentMouseY);
+ value = valueForYPosition(currentMouseY);
if (direction == POSITIVE_SCROLL)
- return (value > slider.getValue());
+ return (value > slider.getValue());
else
- return (value < slider.getValue());
+ return (value < slider.getValue());
}
}
@@ -652,35 +662,35 @@ public class BasicSliderUI extends SliderUI
super.installUI(c);
if (c instanceof JSlider)
{
- slider = (JSlider) c;
+ slider = (JSlider) c;
- focusRect = new Rectangle();
- contentRect = new Rectangle();
- thumbRect = new Rectangle();
- trackRect = new Rectangle();
- tickRect = new Rectangle();
- labelRect = new Rectangle();
+ focusRect = new Rectangle();
+ contentRect = new Rectangle();
+ thumbRect = new Rectangle();
+ trackRect = new Rectangle();
+ tickRect = new Rectangle();
+ labelRect = new Rectangle();
- insetCache = slider.getInsets();
- leftToRightCache = ! slider.getInverted();
+ insetCache = slider.getInsets();
+ leftToRightCache = ! slider.getInverted();
- scrollTimer = new Timer(200, null);
- scrollTimer.setRepeats(true);
+ scrollTimer = new Timer(200, null);
+ scrollTimer.setRepeats(true);
- installDefaults(slider);
- installListeners(slider);
- installKeyboardActions(slider);
+ installDefaults(slider);
+ installListeners(slider);
+ installKeyboardActions(slider);
- calculateFocusRect();
+ calculateFocusRect();
- calculateContentRect();
- calculateThumbSize();
- calculateTrackBuffer();
- calculateTrackRect();
- calculateThumbLocation();
+ calculateContentRect();
+ calculateThumbSize();
+ calculateTrackBuffer();
+ calculateTrackRect();
+ calculateThumbLocation();
- calculateTickRect();
- calculateLabelRect();
+ calculateTickRect();
+ calculateLabelRect();
}
}
@@ -865,7 +875,10 @@ public class BasicSliderUI extends SliderUI
*/
protected void installKeyboardActions(JSlider slider)
{
- // FIXME: implement.
+ InputMap keyMap = getInputMap(JComponent.WHEN_FOCUSED);
+ SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, keyMap);
+ ActionMap map = getActionMap();
+ SwingUtilities.replaceUIActionMap(slider, map);
}
/**
@@ -877,7 +890,8 @@ public class BasicSliderUI extends SliderUI
*/
protected void uninstallKeyboardActions(JSlider slider)
{
- // FIXME: implement.
+ SwingUtilities.replaceUIActionMap(slider, null);
+ SwingUtilities.replaceUIInputMap(slider, JComponent.WHEN_FOCUSED, null);
}
/* XXX: This is all after experimentation with SUN's implementation.
@@ -908,8 +922,7 @@ public class BasicSliderUI extends SliderUI
// The width should cover all the labels (which are usually the
// deciding factor of the width)
int width = getWidthOfWidestLabel() * (slider.getLabelTable() == null ? 0
- : slider.getLabelTable()
- .size());
+ : slider.getLabelTable().size());
// If there are not enough labels.
// This number is pretty much arbitrary, but it looks nice.
@@ -1129,8 +1142,8 @@ public class BasicSliderUI extends SliderUI
}
/**
- * This method calculates the size but not the position of the thumbRect. It
- * must take into account the orientation of the slider.
+ * Sets the width and height of the <code>thumbRect</code> field, using the
+ * dimensions returned by {@link #getThumbSize()}.
*/
protected void calculateThumbSize()
{
@@ -1144,8 +1157,9 @@ public class BasicSliderUI extends SliderUI
}
/**
- * This method calculates the size and position of the contentRect. This
- * method does not need to be called if the orientation changes.
+ * Updates the <code>contentRect</code> field to an area inside the
+ * <code>focusRect</code>. This method does not need to be called if the
+ * orientation changes.
*/
protected void calculateContentRect()
{
@@ -1172,36 +1186,50 @@ public class BasicSliderUI extends SliderUI
if (slider.getOrientation() == JSlider.HORIZONTAL)
{
- thumbRect.x = xPositionForValue(value) - thumbRect.width / 2;
- thumbRect.y = trackRect.y;
+ thumbRect.x = xPositionForValue(value) - thumbRect.width / 2;
+ thumbRect.y = trackRect.y;
}
else
{
- thumbRect.x = trackRect.x;
- thumbRect.y = yPositionForValue(value) - thumbRect.height / 2;
+ thumbRect.x = trackRect.x;
+ thumbRect.y = yPositionForValue(value) - thumbRect.height / 2;
}
}
/**
- * Calculates the gap size between the left edge of the contentRect and the
- * left edge of the trackRect.
+ * Calculates the gap size between the edge of the <code>contentRect</code>
+ * and the edge of the <code>trackRect</code>, storing the result in the
+ * <code>trackBuffer</code> field. Sufficient space needs to be reserved
+ * for the slider thumb and/or the labels at each end of the slider track.
*/
protected void calculateTrackBuffer()
{
if (slider.getOrientation() == JSlider.HORIZONTAL)
- trackBuffer = thumbRect.width / 2;
+ {
+ int w = Math.max(getWidthOfLowValueLabel(), getWidthOfHighValueLabel());
+ trackBuffer = Math.max(thumbRect.width / 2, w / 2);
+
+ }
else
- trackBuffer = thumbRect.height / 2;
+ {
+ int h = Math.max(getHeightOfLowValueLabel(),
+ getHeightOfHighValueLabel());
+ trackBuffer = Math.max(thumbRect.height / 2, h / 2);
+ }
}
/**
- * This method returns the size of the thumbRect.
+ * Returns the size of the slider's thumb. The size is hard coded to
+ * <code>11 x 20</code> for horizontal sliders, and <code>20 x 11</code> for
+ * vertical sliders. Note that a new instance of {@link Dimension} is
+ * returned for every call to this method (this seems wasteful, but
+ * {@link Dimension} instances are not immutable, so this is probably
+ * unavoidable).
*
- * @return The dimensions of the thumb.
+ * @return The size of the slider's thumb.
*/
protected Dimension getThumbSize()
{
- // TODO: shouldn't create new objects every time
if (slider.getOrientation() == JSlider.HORIZONTAL)
return new Dimension(11, 20);
else
@@ -1216,14 +1244,16 @@ public class BasicSliderUI extends SliderUI
{
if (slider.getOrientation() == JSlider.HORIZONTAL)
{
- trackRect.x = contentRect.x + trackBuffer;
+ trackRect.x = contentRect.x + trackBuffer;
int h = getThumbSize().height;
if (slider.getPaintTicks() && (slider.getMajorTickSpacing() > 0
|| slider.getMinorTickSpacing() > 0))
h += getTickLength();
- trackRect.y = contentRect.y + (contentRect.height - h) / 2 - 1;
- trackRect.width = contentRect.width - 2 * trackBuffer;
- trackRect.height = thumbRect.height;
+ if (slider.getPaintLabels())
+ h += getHeightOfTallestLabel();
+ trackRect.y = contentRect.y + (contentRect.height - h) / 2 - 1;
+ trackRect.width = contentRect.width - 2 * trackBuffer;
+ trackRect.height = thumbRect.height;
}
else
{
@@ -1231,10 +1261,12 @@ public class BasicSliderUI extends SliderUI
if (slider.getPaintTicks() && (slider.getMajorTickSpacing() > 0
|| slider.getMinorTickSpacing() > 0))
w += getTickLength();
- trackRect.x = contentRect.x + (contentRect.width - w) / 2 - 1;
- trackRect.y = contentRect.y + trackBuffer;
- trackRect.width = thumbRect.width;
- trackRect.height = contentRect.height - 2 * trackBuffer;
+ if (slider.getPaintLabels())
+ w += getWidthOfWidestLabel();
+ trackRect.x = contentRect.x + (contentRect.width - w) / 2 - 1;
+ trackRect.y = contentRect.y + trackBuffer;
+ trackRect.width = thumbRect.width;
+ trackRect.height = contentRect.height - 2 * trackBuffer;
}
}
@@ -1261,23 +1293,23 @@ public class BasicSliderUI extends SliderUI
{
if (slider.getOrientation() == JSlider.HORIZONTAL)
{
- tickRect.x = trackRect.x;
- tickRect.y = trackRect.y + trackRect.height;
- tickRect.width = trackRect.width;
- tickRect.height = getTickLength();
+ tickRect.x = trackRect.x;
+ tickRect.y = trackRect.y + trackRect.height;
+ tickRect.width = trackRect.width;
+ tickRect.height = (slider.getPaintTicks() ? getTickLength() : 0);
- if (tickRect.y + tickRect.height > contentRect.y + contentRect.height)
- tickRect.height = contentRect.y + contentRect.height - tickRect.y;
+ if (tickRect.y + tickRect.height > contentRect.y + contentRect.height)
+ tickRect.height = contentRect.y + contentRect.height - tickRect.y;
}
else
{
- tickRect.x = trackRect.x + trackRect.width;
- tickRect.y = trackRect.y;
- tickRect.width = getTickLength();
- tickRect.height = trackRect.height;
+ tickRect.x = trackRect.x + trackRect.width;
+ tickRect.y = trackRect.y;
+ tickRect.width = (slider.getPaintTicks() ? getTickLength() : 0);
+ tickRect.height = trackRect.height;
- if (tickRect.x + tickRect.width > contentRect.x + contentRect.width)
- tickRect.width = contentRect.x + contentRect.width - tickRect.x;
+ if (tickRect.x + tickRect.width > contentRect.x + contentRect.width)
+ tickRect.width = contentRect.x + contentRect.width - tickRect.x;
}
}
@@ -1289,17 +1321,17 @@ public class BasicSliderUI extends SliderUI
{
if (slider.getOrientation() == JSlider.HORIZONTAL)
{
- labelRect.x = contentRect.x;
- labelRect.y = tickRect.y + tickRect.height;
- labelRect.width = contentRect.width;
- labelRect.height = contentRect.height - labelRect.y;
+ labelRect.x = contentRect.x;
+ labelRect.y = tickRect.y + tickRect.height;
+ labelRect.width = contentRect.width;
+ labelRect.height = getHeightOfTallestLabel();
}
else
{
- labelRect.x = tickRect.x + tickRect.width;
- labelRect.y = contentRect.y;
- labelRect.width = contentRect.width - labelRect.x;
- labelRect.height = contentRect.height;
+ labelRect.x = tickRect.x + tickRect.width;
+ labelRect.y = contentRect.y;
+ labelRect.width = getWidthOfWidestLabel();
+ labelRect.height = contentRect.height;
}
}
@@ -1321,13 +1353,13 @@ public class BasicSliderUI extends SliderUI
for (Enumeration list = slider.getLabelTable().elements();
list.hasMoreElements();)
{
- Object comp = list.nextElement();
- if (! (comp instanceof Component))
- continue;
- label = (Component) comp;
- pref = label.getPreferredSize();
- if (pref != null && pref.width > widest)
- widest = pref.width;
+ Object comp = list.nextElement();
+ if (! (comp instanceof Component))
+ continue;
+ label = (Component) comp;
+ pref = label.getPreferredSize();
+ if (pref != null && pref.width > widest)
+ widest = pref.width;
}
return widest;
}
@@ -1349,50 +1381,54 @@ public class BasicSliderUI extends SliderUI
for (Enumeration list = slider.getLabelTable().elements();
list.hasMoreElements();)
{
- Object comp = list.nextElement();
- if (! (comp instanceof Component))
- continue;
- label = (Component) comp;
- pref = label.getPreferredSize();
- if (pref != null && pref.height > tallest)
- tallest = pref.height;
+ Object comp = list.nextElement();
+ if (! (comp instanceof Component))
+ continue;
+ label = (Component) comp;
+ pref = label.getPreferredSize();
+ if (pref != null && pref.height > tallest)
+ tallest = pref.height;
}
return tallest;
}
/**
- * This method returns the width of the label whose key has the highest
- * value.
+ * Returns the width of the label whose key has the highest value, or 0 if
+ * there are no labels.
*
- * @return The width of the high value label or 0 if no label table exists.
+ * @return The width of the label whose key has the highest value.
+ *
+ * @see #getHighestValueLabel()
*/
protected int getWidthOfHighValueLabel()
{
Component highValueLabel = getHighestValueLabel();
if (highValueLabel != null)
- return highValueLabel.getWidth();
+ return highValueLabel.getPreferredSize().width;
else
return 0;
}
/**
- * This method returns the width of the label whose key has the lowest
- * value.
+ * Returns the width of the label whose key has the lowest value, or 0 if
+ * there are no labels.
*
- * @return The width of the low value label or 0 if no label table exists.
+ * @return The width of the label whose key has the lowest value.
+ *
+ * @see #getLowestValueLabel()
*/
protected int getWidthOfLowValueLabel()
{
Component lowValueLabel = getLowestValueLabel();
if (lowValueLabel != null)
- return lowValueLabel.getWidth();
+ return lowValueLabel.getPreferredSize().width;
else
return 0;
}
/**
- * This method returns the height of the label whose key has the highest
- * value.
+ * Returns the height of the label whose key has the highest value, or 0 if
+ * there are no labels.
*
* @return The height of the high value label or 0 if no label table exists.
*/
@@ -1400,14 +1436,14 @@ public class BasicSliderUI extends SliderUI
{
Component highValueLabel = getHighestValueLabel();
if (highValueLabel != null)
- return highValueLabel.getHeight();
+ return highValueLabel.getPreferredSize().height;
else
return 0;
}
/**
- * This method returns the height of the label whose key has the lowest
- * value.
+ * Returns the height of the label whose key has the lowest value, or 0 if
+ * there are no labels.
*
* @return The height of the low value label or 0 if no label table exists.
*/
@@ -1415,19 +1451,20 @@ public class BasicSliderUI extends SliderUI
{
Component lowValueLabel = getLowestValueLabel();
if (lowValueLabel != null)
- return lowValueLabel.getHeight();
+ return lowValueLabel.getPreferredSize().height;
else
return 0;
}
/**
- * This method returns whether the slider is to be drawn inverted.
+ * Returns <code>true</code> if the slider scale is to be drawn inverted,
+ * and <code>false</code> if not.
*
- * @return True is the slider is to be drawn inverted.
+ * @return <code>true</code> if the slider is to be drawn inverted.
*/
protected boolean drawInverted()
{
- return ! (slider.getInverted() ^ leftToRightCache);
+ return slider.getInverted();
}
/**
@@ -1446,12 +1483,12 @@ public class BasicSliderUI extends SliderUI
for (Enumeration list = labelTable.keys(); list.hasMoreElements();)
{
- Object value = list.nextElement();
- if (! (value instanceof Integer))
- continue;
- tmpKey = (Integer) value;
- if (tmpKey.intValue() < key.intValue())
- key = tmpKey;
+ Object value = list.nextElement();
+ if (! (value instanceof Integer))
+ continue;
+ tmpKey = (Integer) value;
+ if (tmpKey.intValue() < key.intValue())
+ key = tmpKey;
}
Object comp = labelTable.get(key);
if (! (comp instanceof Component))
@@ -1460,9 +1497,10 @@ public class BasicSliderUI extends SliderUI
}
/**
- * This method returns the label whose key has the highest value.
+ * Returns the label whose key has the highest value.
*
- * @return The high value label or null if no label table exists.
+ * @return The label whose key has the highest value or <code>null</code> if
+ * no label table exists.
*/
protected Component getHighestValueLabel()
{
@@ -1475,12 +1513,12 @@ public class BasicSliderUI extends SliderUI
for (Enumeration list = labelTable.keys(); list.hasMoreElements();)
{
- Object value = list.nextElement();
- if (! (value instanceof Integer))
- continue;
- tmpKey = (Integer) value;
- if (tmpKey.intValue() > key.intValue())
- key = tmpKey;
+ Object value = list.nextElement();
+ if (! (value instanceof Integer))
+ continue;
+ tmpKey = (Integer) value;
+ if (tmpKey.intValue() > key.intValue())
+ key = tmpKey;
}
Object comp = labelTable.get(key);
if (! (comp instanceof Component))
@@ -1499,7 +1537,8 @@ public class BasicSliderUI extends SliderUI
public void paint(Graphics g, JComponent c)
{
// FIXME: Move this to propertyChangeEvent handler, when we get those.
- leftToRightCache = slider.getComponentOrientation() != ComponentOrientation.RIGHT_TO_LEFT;
+ leftToRightCache = slider.getComponentOrientation()
+ != ComponentOrientation.RIGHT_TO_LEFT;
// FIXME: This next line is only here because the above line is here.
calculateGeometry();
@@ -1608,23 +1647,23 @@ public class BasicSliderUI extends SliderUI
if (slider.getOrientation() == JSlider.HORIZONTAL)
{
- width = trackRect.width;
- height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4;
+ width = trackRect.width;
+ height = (thumbRect.height / 4 == 0) ? 1 : thumbRect.height / 4;
- a.translate(0, (trackRect.height / 2) - (height / 2));
- b.translate(0, (trackRect.height / 2) + (height / 2));
- c.translate(trackRect.width, (trackRect.height / 2) + (height / 2));
- d.translate(trackRect.width, (trackRect.height / 2) - (height / 2));
+ a.translate(0, (trackRect.height / 2) - (height / 2));
+ b.translate(0, (trackRect.height / 2) + (height / 2));
+ c.translate(trackRect.width, (trackRect.height / 2) + (height / 2));
+ d.translate(trackRect.width, (trackRect.height / 2) - (height / 2));
}
else
{
- width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4;
- height = trackRect.height;
+ width = (thumbRect.width / 4 == 0) ? 1 : thumbRect.width / 4;
+ height = trackRect.height;
- a.translate((trackRect.width / 2) - (width / 2), 0);
- b.translate((trackRect.width / 2) - (width / 2), trackRect.height);
- c.translate((trackRect.width / 2) + (width / 2), trackRect.height);
- d.translate((trackRect.width / 2) + (width / 2), 0);
+ a.translate((trackRect.width / 2) - (width / 2), 0);
+ b.translate((trackRect.width / 2) - (width / 2), trackRect.height);
+ c.translate((trackRect.width / 2) + (width / 2), trackRect.height);
+ d.translate((trackRect.width / 2) + (width / 2), 0);
}
g.setColor(Color.GRAY);
g.fillRect(a.x, a.y, width, height);
@@ -1656,86 +1695,42 @@ public class BasicSliderUI extends SliderUI
if (majorSpace > 0)
{
- if (slider.getOrientation() == JSlider.HORIZONTAL)
- {
- double loc = tickRect.x + 0.5;
- double increment = (max == min) ? 0
- : majorSpace * (double) (tickRect.width - 1) / (max - min);
- if (drawInverted())
- {
- loc += tickRect.width;
- increment *= -1;
- }
+ if (slider.getOrientation() == JSlider.HORIZONTAL)
+ {
g.translate(0, tickRect.y);
- for (int i = min; i <= max; i += majorSpace)
- {
- paintMajorTickForHorizSlider(g, tickRect, (int) loc);
- loc += increment;
- }
+ for (int i = min; i <= max; i += majorSpace)
+ paintMajorTickForHorizSlider(g, tickRect, xPositionForValue(i));
g.translate(0, -tickRect.y);
- }
- else
- {
- double loc = tickRect.height + tickRect.y + 0.5;
- double increment = (max == min) ? 0
- : -majorSpace * (double) (tickRect.height - 1) / (max - min);
- if (drawInverted())
- {
- loc = tickRect.y + 0.5;
- increment *= -1;
- }
+ }
+ else // JSlider.VERTICAL
+ {
g.translate(tickRect.x, 0);
- for (int i = min; i <= max; i += majorSpace)
- {
- paintMajorTickForVertSlider(g, tickRect, (int) loc);
- loc += increment;
- }
+ for (int i = min; i <= max; i += majorSpace)
+ paintMajorTickForVertSlider(g, tickRect, yPositionForValue(i));
g.translate(-tickRect.x, 0);
- }
+ }
}
if (minorSpace > 0)
{
- if (slider.getOrientation() == JSlider.HORIZONTAL)
- {
- double loc = tickRect.x + 0.5;
- double increment = (max == min) ? 0
- : minorSpace * (double) (tickRect.width - 1) / (max - min);
- if (drawInverted())
- {
- loc += tickRect.width;
- increment *= -1;
- }
+ if (slider.getOrientation() == JSlider.HORIZONTAL)
+ {
g.translate(0, tickRect.y);
- for (int i = min; i <= max; i += minorSpace)
- {
- paintMinorTickForHorizSlider(g, tickRect, (int) loc);
- loc += increment;
- }
+ for (int i = min; i <= max; i += minorSpace)
+ paintMinorTickForHorizSlider(g, tickRect, xPositionForValue(i));
g.translate(0, -tickRect.y);
- }
- else
- {
- double loc = tickRect.height + tickRect.y + 0.5;
- double increment = (max == min) ? 0
- : -minorSpace * (double) (tickRect.height - 1) / (max - min);
- if (drawInverted())
- {
- loc = tickRect.y + 0.5;
- increment *= -1;
- }
+ }
+ else
+ {
g.translate(tickRect.x, 0);
- for (int i = min; i <= max; i += minorSpace)
- {
- paintMinorTickForVertSlider(g, tickRect, (int) loc);
- loc += increment;
- }
+ for (int i = min; i <= max; i += minorSpace)
+ paintMinorTickForVertSlider(g, tickRect, yPositionForValue(i));
g.translate(-tickRect.x, 0);
- }
+ }
}
}
- /* Minor ticks start at 1/4 of the height (or width) of the tickRect and extend
- to 1/2 of the tickRect.
+ /* Minor ticks start at 1/4 of the height (or width) of the tickRect and
+ extend to 1/2 of the tickRect.
Major ticks start at 1/4 of the height and extend to 3/4.
*/
@@ -1828,45 +1823,45 @@ public class BasicSliderUI extends SliderUI
{
if (slider.getLabelTable() != null)
{
- Dictionary table = slider.getLabelTable();
- Integer tmpKey;
- Object key;
- Object element;
- Component label;
- if (slider.getOrientation() == JSlider.HORIZONTAL)
- {
- for (Enumeration list = table.keys(); list.hasMoreElements();)
- {
- key = list.nextElement();
- if (! (key instanceof Integer))
- continue;
- tmpKey = (Integer) key;
- element = table.get(tmpKey);
- // We won't paint them if they're not
- // JLabels so continue anyway
- if (! (element instanceof JLabel))
- continue;
- label = (Component) element;
- paintHorizontalLabel(g, tmpKey.intValue(), label);
- }
- }
- else
- {
- for (Enumeration list = table.keys(); list.hasMoreElements();)
- {
- key = list.nextElement();
- if (! (key instanceof Integer))
- continue;
- tmpKey = (Integer) key;
- element = table.get(tmpKey);
- // We won't paint them if they're not
- // JLabels so continue anyway
- if (! (element instanceof JLabel))
- continue;
- label = (Component) element;
- paintVerticalLabel(g, tmpKey.intValue(), label);
- }
- }
+ Dictionary table = slider.getLabelTable();
+ Integer tmpKey;
+ Object key;
+ Object element;
+ Component label;
+ if (slider.getOrientation() == JSlider.HORIZONTAL)
+ {
+ for (Enumeration list = table.keys(); list.hasMoreElements();)
+ {
+ key = list.nextElement();
+ if (! (key instanceof Integer))
+ continue;
+ tmpKey = (Integer) key;
+ element = table.get(tmpKey);
+ // We won't paint them if they're not
+ // JLabels so continue anyway
+ if (! (element instanceof JLabel))
+ continue;
+ label = (Component) element;
+ paintHorizontalLabel(g, tmpKey.intValue(), label);
+ }
+ }
+ else
+ {
+ for (Enumeration list = table.keys(); list.hasMoreElements();)
+ {
+ key = list.nextElement();
+ if (! (key instanceof Integer))
+ continue;
+ tmpKey = (Integer) key;
+ element = table.get(tmpKey);
+ // We won't paint them if they're not
+ // JLabels so continue anyway
+ if (! (element instanceof JLabel))
+ continue;
+ label = (Component) element;
+ paintVerticalLabel(g, tmpKey.intValue(), label);
+ }
+ }
}
}
@@ -1927,7 +1922,7 @@ public class BasicSliderUI extends SliderUI
h = labelRect.height;
label.setBounds(xpos, ypos, w, h);
- javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds());
+ SwingUtilities.paintComponent(g, label, null, label.getBounds());
}
/**
@@ -1966,7 +1961,7 @@ public class BasicSliderUI extends SliderUI
w = labelRect.width;
label.setBounds(xpos, ypos, w, h);
- javax.swing.SwingUtilities.paintComponent(g, label, null, label.getBounds());
+ SwingUtilities.paintComponent(g, label, null, label.getBounds());
}
/**
@@ -2006,49 +2001,52 @@ public class BasicSliderUI extends SliderUI
Polygon dark; // dark shadow
Polygon all;
- // This will be in X-dimension if the slider is inverted and y if it isn't.
+ // This will be in X-dimension if the slider is inverted and y if it isn't.
int turnPoint;
if (slider.getOrientation() == JSlider.HORIZONTAL)
{
- turnPoint = thumbRect.height * 3 / 4;
+ turnPoint = thumbRect.height * 3 / 4;
- b.translate(thumbRect.width - 1, 0);
- c.translate(thumbRect.width - 1, turnPoint);
- d.translate(thumbRect.width / 2 - 1, thumbRect.height - 1);
- e.translate(0, turnPoint);
+ b.translate(thumbRect.width - 1, 0);
+ c.translate(thumbRect.width - 1, turnPoint);
+ d.translate(thumbRect.width / 2 - 1, thumbRect.height - 1);
+ e.translate(0, turnPoint);
- bright = new Polygon(new int[] { b.x - 1, a.x, e.x, d.x },
- new int[] { b.y, a.y, e.y, d.y }, 4);
+ bright = new Polygon(new int[] { b.x - 1, a.x, e.x, d.x },
+ new int[] { b.y, a.y, e.y, d.y }, 4);
- dark = new Polygon(new int[] { b.x, c.x, d.x + 1 },
- new int[] { b.y, c.y - 1, d.y }, 3);
+ dark = new Polygon(new int[] { b.x, c.x, d.x + 1 },
+ new int[] { b.y, c.y - 1, d.y }, 3);
light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 },
new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3);
- all = new Polygon(new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 },
- new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y }, 5);
+ all = new Polygon(new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 },
+ new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y },
+ 5);
}
else
{
- turnPoint = thumbRect.width * 3 / 4 - 1;
+ turnPoint = thumbRect.width * 3 / 4 - 1;
- b.translate(turnPoint, 0);
- c.translate(thumbRect.width - 1, thumbRect.height / 2);
- d.translate(turnPoint, thumbRect.height - 1);
- e.translate(0, thumbRect.height - 1);
+ b.translate(turnPoint, 0);
+ c.translate(thumbRect.width - 1, thumbRect.height / 2);
+ d.translate(turnPoint, thumbRect.height - 1);
+ e.translate(0, thumbRect.height - 1);
- bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x },
- new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4);
+ bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x },
+ new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4);
- dark = new Polygon(new int[] { c.x, d.x, e.x },
- new int[] { c.y, d.y, e.y }, 3);
+ dark = new Polygon(new int[] { c.x, d.x, e.x },
+ new int[] { c.y, d.y, e.y }, 3);
light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1},
new int[] { c.y, d.y - 1, e.y - 1}, 3);
- all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, e.x + 1 },
- new int[] { a.y + 1, b.y + 1, c.y - 1, c.y, d.y - 2, e.y - 2 }, 6);
+ all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x,
+ e.x + 1 },
+ new int[] { a.y + 1, b.y + 1, c.y - 1, c.y, d.y - 2,
+ e.y - 2 }, 6);
}
g.setColor(Color.WHITE);
@@ -2080,18 +2078,22 @@ public class BasicSliderUI extends SliderUI
}
/**
- * This method is used to move the thumb one block in the direction
- * specified. If the slider snaps to ticks, this method is responsible for
- * snapping it to a tick after the thumb has been moved.
+ * Moves the thumb one block in the direction specified (a block is 1/10th
+ * of the slider range). If the slider snaps to ticks, this method is
+ * responsible for snapping it to a tick after the thumb has been moved.
*
- * @param direction The direction to move in.
+ * @param direction the direction (positive values increment the thumb
+ * position by one block, zero/negative values decrement the thumb position
+ * by one block).
*/
public void scrollByBlock(int direction)
{
- // The direction is -1 for backwards and 1 for forwards.
- int unit = direction * (slider.getMaximum() - slider.getMinimum()) / 10;
-
- int moveTo = slider.getValue() + unit;
+ int unit = (slider.getMaximum() - slider.getMinimum()) / 10;
+ int moveTo = slider.getValue();
+ if (direction > 0)
+ moveTo += unit;
+ else
+ moveTo -= unit;
if (slider.getSnapToTicks())
moveTo = findClosestTick(moveTo);
@@ -2100,16 +2102,21 @@ public class BasicSliderUI extends SliderUI
}
/**
- * This method is used to move the thumb one unit in the direction
- * specified. If the slider snaps to ticks, this method is responsible for
- * snapping it to a tick after the thumb has been moved.
+ * Moves the thumb one unit in the specified direction. If the slider snaps
+ * to ticks, this method is responsible for snapping it to a tick after the
+ * thumb has been moved.
*
- * @param direction The direction to move in.
+ * @param direction the direction (positive values increment the thumb
+ * position by one, zero/negative values decrement the thumb position by
+ * one).
*/
public void scrollByUnit(int direction)
{
- // The direction is -1 for backwards and 1 for forwards.
- int moveTo = slider.getValue() + direction;
+ int moveTo = slider.getValue();
+ if (direction > 0)
+ moveTo++;
+ else
+ moveTo--;
if (slider.getSnapToTicks())
moveTo = findClosestTick(moveTo);
@@ -2135,53 +2142,60 @@ public class BasicSliderUI extends SliderUI
}
/**
- * This method returns the X coordinate for the value passed in.
+ * Returns the x-coordinate (relative to the component) for the given slider
+ * value. This method assumes that the <code>trackRect</code> field is
+ * set up.
*
- * @param value The value to calculate an x coordinate for.
+ * @param value the slider value.
*
- * @return The x coordinate for the value.
+ * @return The x-coordinate.
*/
protected int xPositionForValue(int value)
{
- int min = slider.getMinimum();
- int max = slider.getMaximum();
- int len = trackRect.width - 1;
-
- int xPos = (max == min) ? 0 : (value - min) * len / (max - min);
+ double min = slider.getMinimum();
+ if (value < min)
+ value = (int) min;
+ double max = slider.getMaximum();
+ if (value > max)
+ value = (int) max;
+ double len = trackRect.width;
+ if ((max - min) <= 0.0)
+ return 0;
+ int xPos = (int) ((value - min) / (max - min) * len + 0.5);
- if (! drawInverted())
- xPos += trackRect.x;
+ if (drawInverted())
+ return trackRect.x + Math.max(trackRect.width - xPos - 1, 0);
else
- {
- xPos = len - xPos;
- xPos += trackRect.x;
- }
- return xPos;
+ return trackRect.x + Math.min(xPos, trackRect.width - 1);
}
/**
- * This method returns the y coordinate for the value passed in.
+ * Returns the y-coordinate (relative to the component) for the given slider
+ * value. This method assumes that the <code>trackRect</code> field is
+ * set up.
*
- * @param value The value to calculate a y coordinate for.
+ * @param value the slider value.
*
- * @return The y coordinate for the value.
+ * @return The y-coordinate.
*/
protected int yPositionForValue(int value)
{
- int min = slider.getMinimum();
- int max = slider.getMaximum();
- int len = trackRect.height - 1;
+ double min = slider.getMinimum();
+ if (value < min)
+ value = (int) min;
+ double max = slider.getMaximum();
+ if (value > max)
+ value = (int) max;
+ int len = trackRect.height;
+ if ((max - min) <= 0.0)
+ return 0;
- int yPos = (max == min) ? 0 : (value - min) * len / (max - min);
+ int yPos = (int) ((value - min) / (max - min) * len + 0.5);
if (! drawInverted())
- {
- yPos = len - yPos;
- yPos += trackRect.y;
- }
+ return trackRect.y + trackRect.height - Math.max(yPos, 1);
else
- yPos += trackRect.y;
- return yPos;
+ return trackRect.y + Math.min(yPos, trackRect.height - 1);
}
/**
@@ -2288,26 +2302,26 @@ public class BasicSliderUI extends SliderUI
// First check the major ticks.
if (majorSpace > 0)
{
- int lowerBound = (value - min) / majorSpace;
- int majLower = majorSpace * lowerBound + min;
- int majHigher = majorSpace * (lowerBound + 1) + min;
-
- if (majHigher <= max && majHigher - value <= value - majLower)
- major = majHigher - value;
- else
- major = majLower - value;
+ int lowerBound = (value - min) / majorSpace;
+ int majLower = majorSpace * lowerBound + min;
+ int majHigher = majorSpace * (lowerBound + 1) + min;
+
+ if (majHigher <= max && majHigher - value <= value - majLower)
+ major = majHigher - value;
+ else
+ major = majLower - value;
}
if (minorSpace > 0)
{
- int lowerBound = value / minorSpace;
- int minLower = minorSpace * lowerBound;
- int minHigher = minorSpace * (lowerBound + 1);
-
- if (minHigher <= max && minHigher - value <= value - minLower)
- minor = minHigher - value;
- else
- minor = minLower - value;
+ int lowerBound = value / minorSpace;
+ int minLower = minorSpace * lowerBound;
+ int minHigher = minorSpace * (lowerBound + 1);
+
+ if (minHigher <= max && minHigher - value <= value - minLower)
+ minor = minHigher - value;
+ else
+ minor = minLower - value;
}
// Give preference to minor ticks
@@ -2316,4 +2330,123 @@ public class BasicSliderUI extends SliderUI
else
return value + minor;
}
+
+ InputMap getInputMap(int condition)
+ {
+ if (condition == JComponent.WHEN_FOCUSED)
+ return (InputMap) UIManager.get("Slider.focusInputMap");
+ return null;
+ }
+
+ /**
+ * Returns the action map for the {@link JSlider}. All sliders share
+ * a single action map which is created the first time this method is
+ * called, then stored in the UIDefaults table for subsequent access.
+ *
+ * @return The shared action map.
+ */
+ ActionMap getActionMap()
+ {
+ ActionMap map = (ActionMap) UIManager.get("Slider.actionMap");
+
+ if (map == null) // first time here
+ {
+ map = createActionMap();
+ if (map != null)
+ UIManager.put("Slider.actionMap", map);
+ }
+ return map;
+ }
+
+ /**
+ * Creates the action map shared by all {@link JSlider} instances.
+ * This method is called once by {@link #getActionMap()} when it
+ * finds no action map in the UIDefaults table...after the map is
+ * created, it gets added to the defaults table so that subsequent
+ * calls to {@link #getActionMap()} will return the same shared
+ * instance.
+ *
+ * @return The action map.
+ */
+ ActionMap createActionMap()
+ {
+ ActionMap map = new ActionMapUIResource();
+ map.put("positiveUnitIncrement",
+ new AbstractAction("positiveUnitIncrement") {
+ public void actionPerformed(ActionEvent event)
+ {
+ JSlider slider = (JSlider) event.getSource();
+ BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+ if (slider.getInverted())
+ ui.scrollByUnit(BasicSliderUI.NEGATIVE_SCROLL);
+ else
+ ui.scrollByUnit(BasicSliderUI.POSITIVE_SCROLL);
+ }
+ }
+ );
+ map.put("negativeUnitIncrement",
+ new AbstractAction("negativeUnitIncrement") {
+ public void actionPerformed(ActionEvent event)
+ {
+ JSlider slider = (JSlider) event.getSource();
+ BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+ if (slider.getInverted())
+ ui.scrollByUnit(BasicSliderUI.POSITIVE_SCROLL);
+ else
+ ui.scrollByUnit(BasicSliderUI.NEGATIVE_SCROLL);
+ }
+ }
+ );
+ map.put("positiveBlockIncrement",
+ new AbstractAction("positiveBlockIncrement") {
+ public void actionPerformed(ActionEvent event)
+ {
+ JSlider slider = (JSlider) event.getSource();
+ BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+ if (slider.getInverted())
+ ui.scrollByBlock(BasicSliderUI.NEGATIVE_SCROLL);
+ else
+ ui.scrollByBlock(BasicSliderUI.POSITIVE_SCROLL);
+ }
+ }
+ );
+ map.put("negativeBlockIncrement",
+ new AbstractAction("negativeBlockIncrement") {
+ public void actionPerformed(ActionEvent event)
+ {
+ JSlider slider = (JSlider) event.getSource();
+ BasicSliderUI ui = (BasicSliderUI) slider.getUI();
+ if (slider.getInverted())
+ ui.scrollByBlock(BasicSliderUI.POSITIVE_SCROLL);
+ else
+ ui.scrollByBlock(BasicSliderUI.NEGATIVE_SCROLL);
+ }
+ }
+ );
+ map.put("minScroll",
+ new AbstractAction("minScroll") {
+ public void actionPerformed(ActionEvent event)
+ {
+ JSlider slider = (JSlider) event.getSource();
+ if (slider.getInverted())
+ slider.setValue(slider.getMaximum());
+ else
+ slider.setValue(slider.getMinimum());
+ }
+ }
+ );
+ map.put("maxScroll",
+ new AbstractAction("maxScroll") {
+ public void actionPerformed(ActionEvent event)
+ {
+ JSlider slider = (JSlider) event.getSource();
+ if (slider.getInverted())
+ slider.setValue(slider.getMinimum());
+ else
+ slider.setValue(slider.getMaximum());
+ }
+ }
+ );
+ return map;
+ }
}
diff --git a/javax/swing/plaf/basic/BasicSpinnerUI.java b/javax/swing/plaf/basic/BasicSpinnerUI.java
index 6f7a41a1d..465374bfd 100644
--- a/javax/swing/plaf/basic/BasicSpinnerUI.java
+++ b/javax/swing/plaf/basic/BasicSpinnerUI.java
@@ -41,7 +41,6 @@ package javax.swing.plaf.basic;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
-import java.awt.Font;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
@@ -365,9 +364,9 @@ public class BasicSpinnerUI extends SpinnerUI
private class DefaultLayoutManager implements LayoutManager
{
/**
- * DOCUMENT ME!
+ * Layout the spinners inner parts.
*
- * @param parent DOCUMENT ME!
+ * @param parent The parent container
*/
public void layoutContainer(Container parent)
{
@@ -385,12 +384,12 @@ public class BasicSpinnerUI extends SpinnerUI
Dimension e = prefSize(editor);
Dimension n = prefSize(next);
Dimension p = prefSize(previous);
- Dimension s = spinner.getPreferredSize();
+ Dimension s = parent.getSize();
int x = l2r ? i.left : i.right;
int y = i.top;
int w = Math.max(p.width, n.width);
- int h = e.height / 2;
+ int h = (s.height - i.bottom) / 2;
int e_width = s.width - w - i.left - i.right;
if (l2r)
diff --git a/javax/swing/plaf/basic/BasicSplitPaneUI.java b/javax/swing/plaf/basic/BasicSplitPaneUI.java
index 906acfe16..694baadda 100644
--- a/javax/swing/plaf/basic/BasicSplitPaneUI.java
+++ b/javax/swing/plaf/basic/BasicSplitPaneUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
@@ -1047,6 +1049,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
* This method installs the keyboard actions for the JSplitPane.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
@@ -1055,6 +1058,7 @@ public class BasicSplitPaneUI extends SplitPaneUI
* This method reverses the work done in installKeyboardActions.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
diff --git a/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/javax/swing/plaf/basic/BasicTabbedPaneUI.java
index 5b1e1ff0f..6d9bed331 100644
--- a/javax/swing/plaf/basic/BasicTabbedPaneUI.java
+++ b/javax/swing/plaf/basic/BasicTabbedPaneUI.java
@@ -38,6 +38,8 @@ 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;
@@ -130,52 +132,49 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void mousePressed(MouseEvent e)
{
- int x = e.getX();
- int y = e.getY();
- int tabCount = tabPane.getTabCount();
-
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ if (tabPane.isEnabled())
{
- if (e.getSource() == incrButton)
+ int index = tabForCoordinate(tabPane, e.getX(), e.getY());
+ if (index >= 0 && tabPane.isEnabledAt(index))
{
- if (++currentScrollLocation >= tabCount)
- currentScrollLocation = tabCount - 1;
-
- int width = 0;
- for (int i = currentScrollLocation - 1; i < tabCount; i++)
- width += rects[i].width;
- if (width < viewport.getWidth())
- // FIXME: Still getting mouse events after the button is disabled.
- // incrButton.setEnabled(false);
- currentScrollLocation--;
- else if (! decrButton.isEnabled())
- decrButton.setEnabled(true);
- tabPane.revalidate();
- tabPane.repaint();
- return;
- }
- else if (e.getSource() == decrButton)
- {
- if (--currentScrollLocation < 0)
- currentScrollLocation = 0;
- if (currentScrollLocation == 0)
- decrButton.setEnabled(false);
- else if (! incrButton.isEnabled())
- incrButton.setEnabled(true);
- tabPane.revalidate();
- tabPane.repaint();
- return;
+ tabPane.setSelectedIndex(index);
}
}
+ }
- int index = tabForCoordinate(tabPane, x, y);
+ /**
+ * Receives notification when the mouse pointer has entered the tabbed
+ * pane.
+ *
+ * @param ev the mouse event
+ */
+ public void mouseEntered(MouseEvent ev)
+ {
+ int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
+ setRolloverTab(tabIndex);
+ }
- // We need to check since there are areas where tabs cannot be
- // e.g. in the inset area.
- if (index != -1 && tabPane.isEnabledAt(index))
- tabPane.setSelectedIndex(index);
- tabPane.revalidate();
- tabPane.repaint();
+ /**
+ * Receives notification when the mouse pointer has exited the tabbed
+ * pane.
+ *
+ * @param ev the mouse event
+ */
+ public void mouseExited(MouseEvent ev)
+ {
+ setRolloverTab(-1);
+ }
+
+ /**
+ * Receives notification when the mouse pointer has moved over the tabbed
+ * pane.
+ *
+ * @param ev the mouse event
+ */
+ public void mouseMoved(MouseEvent ev)
+ {
+ int tabIndex = tabForCoordinate(tabPane, ev.getX(), ev.getY());
+ setRolloverTab(tabIndex);
}
}
@@ -241,21 +240,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void calculateLayoutInfo()
{
- assureRectsCreated(tabPane.getTabCount());
- contentRect = SwingUtilities.calculateInnerArea(tabPane, contentRect);
-
- calculateTabRects(tabPane.getTabPlacement(), tabPane.getTabCount());
-
- if (tabPane.getSelectedIndex() != -1)
- {
- Component visible = getVisibleComponent();
- Insets insets = getContentBorderInsets(tabPane.getTabPlacement());
- if (visible != null)
- visible.setBounds(contentRect.x + insets.left,
- contentRect.y + insets.top,
- contentRect.width - insets.left - insets.right,
- contentRect.height - insets.top - insets.bottom);
- }
+ int count = tabPane.getTabCount();
+ assureRectsCreated(count);
+ calculateTabRects(tabPane.getTabPlacement(), count);
+ tabRunsDirty = false;
}
/**
@@ -269,45 +257,51 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected Dimension calculateSize(boolean minimum)
{
int tabPlacement = tabPane.getTabPlacement();
+
int width = 0;
int height = 0;
-
- int componentHeight = 0;
- int componentWidth = 0;
Component c;
Dimension dims;
+
+ // Find out the minimum/preferred size to display the largest child
+ // of the tabbed pane.
for (int i = 0; i < tabPane.getTabCount(); i++)
{
c = tabPane.getComponentAt(i);
if (c == null)
continue;
- calcRect = c.getBounds();
- dims = c.getPreferredSize();
+ dims = minimum ? c.getMinimumSize() : c.getPreferredSize();
if (dims != null)
{
- componentHeight = Math.max(componentHeight, dims.height);
- componentWidth = Math.max(componentWidth, dims.width);
+ height = Math.max(height, dims.height);
+ width = Math.max(width, dims.width);
}
}
+
+ Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
int min = calculateMaxTabWidth(tabPlacement);
- width = Math.max(min, componentWidth);
-
- int tabAreaHeight = preferredTabAreaHeight(tabPlacement, width);
- height = tabAreaHeight + componentHeight;
+ width = Math.max(min, width);
+ int tabAreaHeight = preferredTabAreaHeight(tabPlacement,
+ width - tabAreaInsets.left
+ -tabAreaInsets.right);
+ height += tabAreaHeight;
}
else
{
int min = calculateMaxTabHeight(tabPlacement);
- height = Math.max(min, componentHeight);
-
- int tabAreaWidth = preferredTabAreaWidth(tabPlacement, height);
- width = tabAreaWidth + componentWidth;
+ height = Math.max(min, height);
+ int tabAreaWidth = preferredTabAreaWidth(tabPlacement,
+ height - tabAreaInsets.top
+ - tabAreaInsets.bottom);
+ width += tabAreaWidth;
}
- return new Dimension(width, height);
+ Insets tabPaneInsets = tabPane.getInsets();
+ return new Dimension(width + tabPaneInsets.left + tabPaneInsets.right,
+ height + tabPaneInsets.top + tabPaneInsets.bottom);
}
// if tab placement is LEFT OR RIGHT, they share width.
@@ -330,192 +324,197 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void calculateTabRects(int tabPlacement, int tabCount)
{
+ Insets insets = tabPane.getInsets();
+ Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+ Dimension size = tabPane.getSize();
+
+ // The coordinates of the upper left corner of the tab area.
+ int x;
+ int y;
+ // The location at which the runs must be broken.
+ int breakAt;
+
+ // Calculate the bounds for the tab area.
+ switch (tabPlacement)
+ {
+ case LEFT:
+ maxTabWidth = calculateMaxTabWidth(tabPlacement);
+ x = insets.left + tabAreaInsets.left;
+ y = insets.top + tabAreaInsets.top;
+ breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
+ break;
+ case RIGHT:
+ maxTabWidth = calculateMaxTabWidth(tabPlacement);
+ x = size.width - (insets.right + tabAreaInsets.right) - maxTabWidth;
+ y = insets.top + tabAreaInsets.top;
+ breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
+ break;
+ case BOTTOM:
+ maxTabHeight = calculateMaxTabHeight(tabPlacement);
+ x = insets.left + tabAreaInsets.left;
+ y = size.height - (insets.bottom + tabAreaInsets.bottom)
+ - maxTabHeight;
+ breakAt = size.width - (insets.right + tabAreaInsets.right);
+ break;
+ case TOP:
+ default:
+ maxTabHeight = calculateMaxTabHeight(tabPlacement);
+ x = insets.left + tabAreaInsets.left;
+ y = insets.top + tabAreaInsets.top;
+ breakAt = size.width - (insets.right + tabAreaInsets.right);
+ break;
+ }
+
if (tabCount == 0)
return;
FontMetrics fm = getFontMetrics();
- SwingUtilities.calculateInnerArea(tabPane, calcRect);
- Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
- Insets insets = tabPane.getInsets();
- int max = 0;
- int runs = 0;
- int start = getTabRunIndent(tabPlacement, 1);
+ runCount = 0;
+ selectedRun = -1;
+ int selectedIndex = tabPane.getSelectedIndex();
+
+ Rectangle rect;
+
+ // Go through all the tabs and build the tab runs.
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
- int maxHeight = calculateMaxTabHeight(tabPlacement);
-
- calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
- max = calcRect.width + tabAreaInsets.left + insets.left;
- start += tabAreaInsets.left + insets.left;
- int width = 0;
- int runWidth = start;
-
for (int i = 0; i < tabCount; i++)
{
- width = calculateTabWidth(tabPlacement, i, fm);
- if (runWidth + width > max)
+ rect = rects[i];
+ if (i > 0)
{
- runWidth = tabAreaInsets.left + insets.left
- + getTabRunIndent(tabPlacement, ++runs);
- rects[i] = new Rectangle(runWidth,
- insets.top + tabAreaInsets.top,
- width, maxHeight);
- runWidth += width;
- if (runs > tabRuns.length - 1)
- expandTabRunsArray();
- tabRuns[runs] = i;
+ rect.x = rects[i - 1].x + rects[i - 1].width;
}
else
{
- rects[i] = new Rectangle(runWidth,
- insets.top + tabAreaInsets.top,
- width, maxHeight);
- runWidth += width;
+ tabRuns[0] = 0;
+ runCount = 1;
+ maxTabWidth = 0;
+ rect.x = x;
}
- }
- runs++;
- tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
- tabAreaRect.height = runs * maxTabHeight
- - (runs - 1) * tabRunOverlay
- + tabAreaInsets.top + tabAreaInsets.bottom;
- contentRect.width = tabAreaRect.width;
- contentRect.height = tabPane.getHeight() - insets.top
- - insets.bottom - tabAreaRect.height;
- contentRect.x = insets.left;
- tabAreaRect.x = insets.left;
- if (tabPlacement == SwingConstants.BOTTOM)
- {
- contentRect.y = insets.top;
- tabAreaRect.y = contentRect.y + contentRect.height;
- }
- else
- {
- tabAreaRect.y = insets.top;
- contentRect.y = tabAreaRect.y + tabAreaRect.height;
+ rect.width = calculateTabWidth(tabPlacement, i, fm);
+ maxTabWidth = Math.max(maxTabWidth, rect.width);
+
+ if (rect.x != 2 + insets.left && rect.x + rect.width > breakAt)
+ {
+ if (runCount > tabRuns.length - 1)
+ expandTabRunsArray();
+ tabRuns[runCount] = i;
+ runCount++;
+ rect.x = x;
+ }
+
+ rect.y = y;
+ rect.height = maxTabHeight;
+ if (i == selectedIndex)
+ selectedRun = runCount - 1;
+
}
}
else
{
- int maxWidth = calculateMaxTabWidth(tabPlacement);
- calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
- max = calcRect.height + tabAreaInsets.top + insets.top;
-
- int height = 0;
- start += tabAreaInsets.top + insets.top;
- int runHeight = start;
-
- int fontHeight = fm.getHeight();
-
for (int i = 0; i < tabCount; i++)
{
- height = calculateTabHeight(tabPlacement, i, fontHeight);
- if (runHeight + height > max)
+ rect = rects[i];
+ if (i > 0)
{
- runHeight = tabAreaInsets.top + insets.top
- + getTabRunIndent(tabPlacement, ++runs);
- rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
- runHeight, maxWidth, height);
- runHeight += height;
- if (runs > tabRuns.length - 1)
- expandTabRunsArray();
- tabRuns[runs] = i;
+ rect.y = rects[i - 1].y + rects[i - 1].height;
}
else
{
- rects[i] = new Rectangle(insets.left + tabAreaInsets.left,
- runHeight, maxWidth, height);
- runHeight += height;
+ tabRuns[0] = 0;
+ runCount = 1;
+ maxTabHeight = 0;
+ rect.y = y;
}
- }
- runs++;
+ rect.height = calculateTabHeight(tabPlacement, i,
+ fm.getHeight());
+ maxTabHeight = Math.max(maxTabHeight, rect.height);
- tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
- + tabAreaInsets.left + tabAreaInsets.right;
- tabAreaRect.height = tabPane.getHeight() - insets.top
- - insets.bottom;
- tabAreaRect.y = insets.top;
- contentRect.width = tabPane.getWidth() - insets.left - insets.right
- - tabAreaRect.width;
- contentRect.height = tabAreaRect.height;
- contentRect.y = insets.top;
- if (tabPlacement == SwingConstants.LEFT)
- {
- tabAreaRect.x = insets.left;
- contentRect.x = tabAreaRect.x + tabAreaRect.width;
- }
- else
- {
- contentRect.x = insets.left;
- tabAreaRect.x = contentRect.x + contentRect.width;
+ if (rect.y != 2 + insets.top && rect.y + rect.height > breakAt)
+ {
+ if (runCount > tabRuns.length - 1)
+ expandTabRunsArray();
+ tabRuns[runCount] = i;
+ runCount++;
+ rect.y = y;
+ }
+
+ rect.x = x;
+ rect.width = maxTabWidth;
+
+ if (i == selectedIndex)
+ selectedRun = runCount - 1;
}
}
- runCount = runs;
- if (runCount > tabRuns.length)
- expandTabRunsArray();
-
- tabRuns[0] = 0;
- normalizeTabRuns(tabPlacement, tabCount, start, max);
- selectedRun = getRunForTab(tabCount, tabPane.getSelectedIndex());
- if (shouldRotateTabRuns(tabPlacement))
- rotateTabRuns(tabPlacement, selectedRun);
- // Need to pad the runs and move them to the correct location.
- for (int i = 0; i < runCount; i++)
+ if (runCount > 1)
{
- int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
- if (first == tabCount)
- first = 0;
- int last = lastTabInRun(tabCount, i);
- if (shouldPadTabRun(tabPlacement, i))
- padTabRun(tabPlacement, first, last, max);
-
- // Done padding, now need to move it.
- if (tabPlacement == SwingConstants.TOP && i > 0)
+ int start;
+ if (tabPlacement == SwingConstants.TOP
+ || tabPlacement == SwingConstants.BOTTOM)
+ start = y;
+ else
+ start = x;
+ normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
+ selectedRun = getRunForTab(tabCount, selectedIndex);
+ if (shouldRotateTabRuns(tabPlacement))
{
- for (int j = first; j <= last; j++)
- rects[j].y += (runCount - i) * maxTabHeight
- - (runCount - i) * tabRunOverlay;
+ rotateTabRuns(tabPlacement, selectedRun);
}
+ }
- if (tabPlacement == SwingConstants.BOTTOM)
+ // Pad the runs.
+ int tabRunOverlay = getTabRunOverlay(tabPlacement);
+ for (int i = runCount - 1; i >= 0; --i)
+ {
+ int start = tabRuns[i];
+ int nextIndex;
+ if (i == runCount - 1)
+ nextIndex = 0;
+ else
+ nextIndex = i + 1;
+ int next = tabRuns[nextIndex];
+ int end = (next != 0 ? next - 1 : tabCount - 1);
+ if (tabPlacement == SwingConstants.TOP
+ || tabPlacement == SwingConstants.BOTTOM)
{
- int height = tabPane.getBounds().height - insets.bottom
- - tabAreaInsets.bottom;
- int adjustment;
- if (i == 0)
- adjustment = height - maxTabHeight;
+ for (int j = start; j <= end; ++j)
+ {
+ rect = rects[j];
+ rect.y = y;
+ rect.x += getTabRunIndent(tabPlacement, i);
+ }
+ if (shouldPadTabRun(tabPlacement, i))
+ {
+ padTabRun(tabPlacement, start, end, breakAt);
+ }
+ if (tabPlacement == BOTTOM)
+ y -= (maxTabHeight - tabRunOverlay);
else
- adjustment = height - (runCount - i + 1) * maxTabHeight
- - (runCount - i) * tabRunOverlay;
-
- for (int j = first; j <= last; j++)
- rects[j].y = adjustment;
- }
-
- if (tabPlacement == SwingConstants.LEFT && i > 0)
- {
- for (int j = first; j <= last; j++)
- rects[j].x += (runCount - i) * maxTabWidth
- - (runCount - i) * tabRunOverlay;
+ y += (maxTabHeight - tabRunOverlay);
}
-
- if (tabPlacement == SwingConstants.RIGHT)
+ else
{
- int width = tabPane.getBounds().width - insets.right
- - tabAreaInsets.right;
- int adjustment;
- if (i == 0)
- adjustment = width - maxTabWidth;
+ for (int j = start; j <= end; ++j)
+ {
+ rect = rects[j];
+ rect.x = x;
+ rect.y += getTabRunIndent(tabPlacement, i);
+ }
+ if (shouldPadTabRun(tabPlacement, i))
+ {
+ padTabRun(tabPlacement, start, end, breakAt);
+ }
+ if (tabPlacement == RIGHT)
+ x -= (maxTabWidth - tabRunOverlay);
else
- adjustment = width - (runCount - i + 1) * maxTabWidth
- + (runCount - i) * tabRunOverlay;
-
- for (int j = first; j <= last; j++)
- rects[j].x = adjustment;
+ x += (maxTabWidth - tabRunOverlay);
+
}
}
- padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
+ padSelectedTab(tabPlacement, selectedIndex);
}
/**
@@ -528,6 +527,58 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
public void layoutContainer(Container parent)
{
calculateLayoutInfo();
+
+ int tabPlacement = tabPane.getTabPlacement();
+ Insets insets = tabPane.getInsets();
+ int childCount = tabPane.getComponentCount();
+ if (childCount > 0)
+ {
+ int compX;
+ int compY;
+ int tabAreaWidth = 0;
+ int tabAreaHeight = 0;
+ switch (tabPlacement)
+ {
+ case LEFT:
+ tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
+ maxTabWidth);
+ compX = tabAreaWidth + insets.left + contentBorderInsets.left;
+ compY = insets.top + contentBorderInsets.top;
+ break;
+ case RIGHT:
+ tabAreaWidth = calculateTabAreaWidth(tabPlacement, runCount,
+ maxTabWidth);
+ compX = insets.left + contentBorderInsets.left;
+ compY = insets.top + contentBorderInsets.top;
+ break;
+ case BOTTOM:
+ tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
+ maxTabHeight);
+ compX = insets.left + contentBorderInsets.left;
+ compY = insets.top + contentBorderInsets.top;
+ break;
+ case TOP:
+ default:
+ tabAreaHeight = calculateTabAreaHeight(tabPlacement, runCount,
+ maxTabHeight);
+ compX = insets.left + contentBorderInsets.left;
+ compY = tabAreaHeight + insets.top + contentBorderInsets.top;
+ }
+ Rectangle bounds = tabPane.getBounds();
+ int compWidth = bounds.width - tabAreaWidth - insets.left
+ - insets.right - contentBorderInsets.left
+ - contentBorderInsets.right;
+ int compHeight = bounds.height - tabAreaHeight - insets.top
+ - insets.bottom - contentBorderInsets.top
+ - contentBorderInsets.bottom;
+
+
+ for (int i = 0; i < childCount; ++i)
+ {
+ Component c = tabPane.getComponent(i);
+ c.setBounds(compX, compY, compWidth, compHeight);
+ }
+ }
}
/**
@@ -1288,6 +1339,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int[] tabRuns;
/**
+ * Indicates if the layout of the tab runs is ok or not. This is package
+ * private to avoid a synthetic accessor method.
+ */
+ boolean tabRunsDirty;
+
+ /**
* This is the keystroke for moving down.
*
* @deprecated 1.3
@@ -1343,6 +1400,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
transient Rectangle contentRect;
/**
+ * The index over which the mouse is currently moving.
+ */
+ private int rolloverTab;
+
+ /**
+ * Determines if tabs are painted opaque or not. This can be adjusted using
+ * the UIManager property 'TabbedPane.tabsOpaque'.
+ */
+ private boolean tabsOpaque;
+
+ /**
* Creates a new BasicTabbedPaneUI object.
*/
public BasicTabbedPaneUI()
@@ -1557,6 +1625,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets");
tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
+ tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
calcRect = new Rectangle();
tabRuns = new int[10];
@@ -1585,9 +1654,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
lightHighlight = null;
highlight = null;
- tabPane.setBackground(null);
- tabPane.setForeground(null);
- tabPane.setFont(null);
+ // Install UI colors and fonts.
+ LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
+ "TabbedPane.foreground",
+ "TabbedPane.font");
}
/**
@@ -1666,6 +1736,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
* This method installs keyboard actions for the JTabbedPane.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Implement.
}
@@ -1674,6 +1745,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
* This method uninstalls keyboard actions for the JTabbedPane.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Implement.
}
@@ -1710,6 +1782,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void paint(Graphics g, JComponent c)
{
+ if (!tabPane.isValid())
+ tabPane.validate();
+
if (tabPane.getTabCount() == 0)
return;
if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
@@ -1735,42 +1810,26 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// Please note: the ordering of the painting is important.
// we WANT to paint the outermost run first and then work our way in.
int tabCount = tabPane.getTabCount();
- int currRun = 1;
-
- if (tabCount < 1)
- return;
-
- if (runCount > 1)
- currRun = 0;
- for (int i = 0; i < runCount; i++)
+ for (int i = runCount - 1; i >= 0; --i)
{
- int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
- if (isScroll)
- first = currentScrollLocation;
- else if (first == tabCount)
- first = 0;
- int last = lastTabInRun(tabCount, currRun);
- if (isScroll)
+ int start = tabRuns[i];
+ int next;
+ if (i == runCount - 1)
+ next = tabRuns[0];
+ else
+ next = tabRuns[i + 1];
+ int end = (next != 0 ? next - 1 : tabCount - 1);
+ for (int j = start; j <= end; ++j)
{
- for (int k = first; k < tabCount; k++)
+ if (j != selectedIndex)
{
- if (rects[k].x + rects[k].width - rects[first].x > viewport
- .getWidth())
- {
- last = k;
- break;
- }
+ paintTab(g, tabPlacement, rects, j, ir, tr);
}
}
-
- for (int j = first; j <= last; j++)
- {
- if (j != selectedIndex || isScroll)
- paintTab(g, tabPlacement, rects, j, ir, tr);
- }
- currRun = getPreviousTabRun(currRun);
}
- if (! isScroll)
+
+ // Paint selected tab in front of every other tab.
+ if (selectedIndex >= 0)
paintTab(g, tabPlacement, rects, selectedIndex, ir, tr);
}
@@ -1788,49 +1847,34 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected void paintTab(Graphics g, int tabPlacement, Rectangle[] rects,
int tabIndex, Rectangle iconRect, Rectangle textRect)
{
- FontMetrics fm = getFontMetrics();
- Icon icon = getIconForTab(tabIndex);
- String title = tabPane.getTitleAt(tabIndex);
+ Rectangle rect = rects[tabIndex];
boolean isSelected = tabIndex == tabPane.getSelectedIndex();
- calcRect = getTabBounds(tabPane, tabIndex);
-
- int x = calcRect.x;
- int y = calcRect.y;
- int w = calcRect.width;
- int h = calcRect.height;
- if (getRunForTab(tabPane.getTabCount(), tabIndex) == 1)
+ // Paint background if necessary.
+ if (tabsOpaque || tabPane.isOpaque())
{
- Insets insets = getTabAreaInsets(tabPlacement);
- switch (tabPlacement)
- {
- case TOP:
- h += insets.bottom;
- break;
- case LEFT:
- w += insets.right;
- break;
- case BOTTOM:
- y -= insets.top;
- h += insets.top;
- break;
- case RIGHT:
- x -= insets.left;
- w += insets.left;
- break;
- }
+ paintTabBackground(g, tabPlacement, tabIndex, rect.x, rect.y,
+ rect.width, rect.height, isSelected);
}
- layoutLabel(tabPlacement, fm, tabIndex, title, icon, calcRect, iconRect,
- textRect, isSelected);
- paintTabBackground(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
- paintTabBorder(g, tabPlacement, tabIndex, x, y, w, h, isSelected);
+ // Paint border.
+ paintTabBorder(g, tabPlacement, tabIndex, rect.x, rect.y, rect.width,
+ rect.height, isSelected);
- // FIXME: Paint little folding corner and jagged edge clipped tab.
- if (icon != null)
- paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
- if (title != null && ! title.equals(""))
- paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
+
+ // Layout label.
+ FontMetrics fm = getFontMetrics();
+ Icon icon = getIconForTab(tabIndex);
+ String title = tabPane.getTitleAt(tabIndex);
+ layoutLabel(tabPlacement, fm, tabIndex, title, icon, rect, iconRect,
textRect, isSelected);
+ // 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);
}
/**
@@ -1902,6 +1946,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
FontMetrics metrics, int tabIndex, String title,
Rectangle textRect, boolean isSelected)
{
+ g.setFont(font);
View textView = getTextViewForTab(tabIndex);
if (textView != null)
{
@@ -1909,54 +1954,48 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
return;
}
- Color fg = tabPane.getForegroundAt(tabIndex);
- if (fg == null)
- fg = tabPane.getForeground();
- Color bg = tabPane.getBackgroundAt(tabIndex);
- if (bg == null)
- bg = tabPane.getBackground();
-
- Color saved_color = g.getColor();
- Font f = g.getFont();
- g.setFont(font);
+ int ascent = metrics.getAscent();
- if (tabPane.isEnabledAt(tabIndex))
+ int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
+ if (tabPane.isEnabled() && tabPane.isEnabledAt(tabIndex))
{
+ Color fg = tabPane.getForegroundAt(tabIndex);
+ if (isSelected && (fg instanceof UIResource))
+ {
+ Color selectionForeground =
+ UIManager.getColor("TabbedPane.selectionForeground");
+ if (selectionForeground != null)
+ fg = selectionForeground;
+ }
g.setColor(fg);
- int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
-
if (mnemIndex != -1)
BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
textRect.x,
- textRect.y
- + metrics.getAscent());
+ textRect.y + ascent);
else
- g.drawString(title, textRect.x, textRect.y + metrics.getAscent());
+ g.drawString(title, textRect.x, textRect.y + ascent);
}
else
{
+ Color bg = tabPane.getBackgroundAt(tabIndex);
g.setColor(bg.brighter());
-
- int mnemIndex = tabPane.getDisplayedMnemonicIndexAt(tabIndex);
-
if (mnemIndex != -1)
BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
- textRect.x, textRect.y);
+ textRect.x, textRect.y
+ + ascent);
else
- g.drawString(title, textRect.x, textRect.y);
+ g.drawString(title, textRect.x, textRect.y + ascent);
g.setColor(bg.darker());
if (mnemIndex != -1)
BasicGraphicsUtils.drawStringUnderlineCharAt(g, title, mnemIndex,
textRect.x + 1,
- textRect.y + 1);
+ textRect.y + 1
+ + ascent);
else
- g.drawString(title, textRect.x + 1, textRect.y + 1);
+ g.drawString(title, textRect.x + 1, textRect.y + 1 + ascent);
}
-
- g.setColor(saved_color);
- g.setFont(f);
}
/**
@@ -2009,14 +2048,45 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Rectangle iconRect, Rectangle textRect,
boolean isSelected)
{
- Color saved = g.getColor();
- calcRect = iconRect.union(textRect);
-
- g.setColor(focus);
-
- g.drawRect(calcRect.x, calcRect.y, calcRect.width, calcRect.height);
-
- g.setColor(saved);
+ if (tabPane.hasFocus() && isSelected)
+ {
+ Rectangle rect = rects[tabIndex];
+ // The focus rectangle.
+ int x;
+ int y;
+ int w;
+ int h;
+
+ 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;
+ }
+ BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
+ }
}
/**
@@ -2109,10 +2179,44 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected void paintContentBorder(Graphics g, int tabPlacement,
int selectedIndex)
{
- int x = contentRect.x;
- int y = contentRect.y;
- int w = contentRect.width;
- int h = contentRect.height;
+ int width = tabPane.getWidth();
+ int height = tabPane.getHeight();
+ Insets insets = tabPane.getInsets();
+ Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
+
+ // Calculate coordinates of content area.
+ int x = insets.left;
+ int y = insets.top;
+ int w = width - insets.left - insets.right;
+ int h = height - insets.top - insets.bottom;
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ x += calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
+ w -= (x - insets.left);
+ break;
+ case RIGHT:
+ w -= calculateTabAreaWidth(tabPlacement, runCount, maxTabWidth);
+ break;
+ case BOTTOM:
+ h -= calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
+ break;
+ case TOP:
+ default:
+ y += calculateTabAreaHeight(tabPlacement, runCount, maxTabHeight);
+ h -= (y - insets.top);
+ }
+
+ // Fill background if necessary.
+ if (tabPane.isOpaque())
+ {
+ Color bg = UIManager.getColor("TabbedPane.contentAreaColor");
+ g.setColor(bg);
+ g.fillRect(x, y, w, h);
+ }
+
+ // Paint border.
paintContentBorderTopEdge(g, tabPlacement, selectedIndex, x, y, w, h);
paintContentBorderLeftEdge(g, tabPlacement, selectedIndex, x, y, w, h);
paintContentBorderBottomEdge(g, tabPlacement, selectedIndex, x, y, w, h);
@@ -2332,23 +2436,23 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public int tabForCoordinate(JTabbedPane pane, int x, int y)
{
- Point p = new Point(x, y);
+ if (! tabPane.isValid())
+ tabPane.validate();
+
int tabCount = tabPane.getTabCount();
- int currRun = 1;
- for (int i = 0; i < runCount; i++)
+ int index = -1;
+ for (int i = 0; i < tabCount; ++i)
{
- int first = lastTabInRun(tabCount, getPreviousTabRun(currRun)) + 1;
- if (first == tabCount)
- first = 0;
- int last = lastTabInRun(tabCount, currRun);
- for (int j = first; j <= last; j++)
+ if (rects[i].contains(x, y))
{
- if (getTabBounds(pane, j).contains(p))
- return j;
+ index = i;
+ break;
}
- currRun = getNextTabRun(currRun);
}
- return -1;
+
+ // FIXME: Handle scrollable tab layout.
+
+ return index;
}
/**
@@ -2455,10 +2559,23 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected int lastTabInRun(int tabCount, int run)
{
- if (tabRuns[run] == 0)
- return tabCount - 1;
+ int lastTab;
+ if (runCount == 1)
+ lastTab = tabCount - 1;
else
- return tabRuns[run] - 1;
+ {
+ int nextRun;
+ if (run == runCount - 1)
+ nextRun = 0;
+ else
+ nextRun = run + 1;
+
+ if (tabRuns[nextRun] == 0)
+ lastTab = tabCount - 1;
+ else
+ lastTab = tabRuns[nextRun] - 1;
+ }
+ return lastTab;
}
/**
@@ -2554,24 +2671,14 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int calculateTabHeight(int tabPlacement, int tabIndex,
int fontHeight)
{
- Icon icon = getIconForTab(tabIndex);
- Insets insets = getTabInsets(tabPlacement, tabIndex);
+ // FIXME: Handle HTML somehow.
- int height = 0;
+ int height = fontHeight;
+ Icon icon = getIconForTab(tabIndex);
+ Insets tabInsets = getTabInsets(tabPlacement, tabIndex);
if (icon != null)
- {
- Rectangle vr = new Rectangle();
- Rectangle ir = new Rectangle();
- Rectangle tr = new Rectangle();
- layoutLabel(tabPlacement, getFontMetrics(), tabIndex,
- tabPane.getTitleAt(tabIndex), icon, vr, ir, tr,
- tabIndex == tabPane.getSelectedIndex());
- height = tr.union(ir).height;
- }
- else
- height = fontHeight;
-
- height += insets.top + insets.bottom;
+ height = Math.max(height, icon.getIconHeight());
+ height += tabInsets.top + tabInsets.bottom + 2;
return height;
}
@@ -2704,9 +2811,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected Insets getTabInsets(int tabPlacement, int tabIndex)
{
- Insets target = new Insets(0, 0, 0, 0);
- rotateInsets(tabInsets, target, tabPlacement);
- return target;
+ return tabInsets;
}
/**
@@ -3068,4 +3173,33 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
break;
}
}
+
+ /**
+ * Sets the tab which should be highlighted when in rollover mode. And
+ * <code>index</code> of <code>-1</code> means that the rollover tab
+ * is deselected (i.e. the mouse is outside of the tabarea).
+ *
+ * @param index the index of the tab that is under the mouse, <code>-1</code>
+ * for no tab
+ *
+ * @since 1.5
+ */
+ protected void setRolloverTab(int index)
+ {
+ rolloverTab = index;
+ }
+
+ /**
+ * Retunrs the index of the tab over which the mouse is currently moving,
+ * or <code>-1</code> for no tab.
+ *
+ * @return the index of the tab over which the mouse is currently moving,
+ * or <code>-1</code> for no tab
+ *
+ * @since 1.5
+ */
+ protected int getRolloverTab()
+ {
+ return rolloverTab;
+ }
}
diff --git a/javax/swing/plaf/basic/BasicTableHeaderUI.java b/javax/swing/plaf/basic/BasicTableHeaderUI.java
index c6f9e37df..cfbebda21 100644
--- a/javax/swing/plaf/basic/BasicTableHeaderUI.java
+++ b/javax/swing/plaf/basic/BasicTableHeaderUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
@@ -97,6 +99,11 @@ public class BasicTableHeaderUI extends TableHeaderUI
* The header cell border.
*/
private Border cellBorder;
+
+ /**
+ * Original mouse cursor prior to resizing.
+ */
+ private Cursor originalCursor;
/**
* If not null, one of the columns is currently being dragged.
@@ -243,6 +250,7 @@ public class BasicTableHeaderUI extends TableHeaderUI
if (onBoundary)
{
+ originalCursor = header.getCursor();
if (p < x)
header.setCursor(Cursor.getPredefinedCursor
(Cursor.W_RESIZE_CURSOR));
@@ -252,7 +260,7 @@ public class BasicTableHeaderUI extends TableHeaderUI
}
else
{
- header.setCursor(Cursor.getDefaultCursor());
+ header.setCursor(originalCursor);
header.setResizingColumn(null);
}
@@ -343,7 +351,7 @@ public class BasicTableHeaderUI extends TableHeaderUI
showingResizeCursor = false;
if (timer != null)
timer.stop();
- header.setCursor(Cursor.getDefaultCursor());
+ header.setCursor(originalCursor);
}
/**
@@ -415,6 +423,7 @@ public class BasicTableHeaderUI extends TableHeaderUI
}
protected void installKeyboardActions()
+ throws NotImplementedException
{
// TODO: Implement this properly.
}
@@ -447,6 +456,7 @@ public class BasicTableHeaderUI extends TableHeaderUI
}
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// TODO: Implement this properly.
}
diff --git a/javax/swing/plaf/basic/BasicTableUI.java b/javax/swing/plaf/basic/BasicTableUI.java
index 8360a9ec7..ef491cbf1 100644
--- a/javax/swing/plaf/basic/BasicTableUI.java
+++ b/javax/swing/plaf/basic/BasicTableUI.java
@@ -38,6 +38,8 @@ 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;
@@ -88,7 +90,7 @@ public class BasicTableUI extends TableUI
protected FocusListener focusListener;
protected KeyListener keyListener;
- protected MouseInputListener mouseInputListener;
+ protected MouseInputListener mouseInputListener;
protected CellRendererPane rendererPane;
protected JTable table;
@@ -115,6 +117,8 @@ public class BasicTableUI extends TableUI
/**
* Receives notification that a key has been pressed and released.
+ * Activates the editing session for the focused cell by pressing the
+ * character keys.
*
* @param event the key event
*/
@@ -122,6 +126,16 @@ public class BasicTableUI extends TableUI
{
// Key events should be handled through the InputMap/ActionMap mechanism
// since JDK1.3. This class is only there for backwards compatibility.
+
+ // Editor activation is a specific kind of response to ''any''
+ // character key. Hence it is handled here.
+ if (!table.isEditing() && table.isEnabled())
+ {
+ int r = table.getSelectedRow();
+ int c = table.getSelectedColumn();
+ if (table.isCellEditable(r, c))
+ table.editCellAt(r, c);
+ }
}
/**
@@ -509,11 +523,9 @@ public class BasicTableUI extends TableUI
if (command.equals("selectPreviousRowExtendSelection"))
{
rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0));
- colModel.setLeadSelectionIndex(colLead);
}
else if (command.equals("selectLastColumn"))
{
- rowModel.setSelectionInterval(rowLead, rowLead);
colModel.setSelectionInterval(colMax, colMax);
}
else if (command.equals("startEditing"))
@@ -524,53 +536,43 @@ public class BasicTableUI extends TableUI
else if (command.equals("selectFirstRowExtendSelection"))
{
rowModel.setLeadSelectionIndex(0);
- colModel.setLeadSelectionIndex(colLead);
}
else if (command.equals("selectFirstColumn"))
{
- rowModel.setSelectionInterval(rowLead, rowLead);
colModel.setSelectionInterval(0, 0);
}
else if (command.equals("selectFirstColumnExtendSelection"))
{
colModel.setLeadSelectionIndex(0);
- rowModel.setLeadSelectionIndex(rowLead);
}
else if (command.equals("selectLastRow"))
{
rowModel.setSelectionInterval(rowMax,rowMax);
- colModel.setSelectionInterval(colLead, colLead);
}
else if (command.equals("selectNextRowExtendSelection"))
{
rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax));
- colModel.setLeadSelectionIndex(colLead);
}
else if (command.equals("selectFirstRow"))
{
rowModel.setSelectionInterval(0,0);
- colModel.setSelectionInterval(colLead, colLead);
}
else if (command.equals("selectNextColumnExtendSelection"))
{
colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax));
- rowModel.setLeadSelectionIndex(rowLead);
}
else if (command.equals("selectLastColumnExtendSelection"))
{
colModel.setLeadSelectionIndex(colMax);
- rowModel.setLeadSelectionIndex(rowLead);
}
else if (command.equals("selectPreviousColumnExtendSelection"))
{
colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0));
- rowModel.setLeadSelectionIndex(rowLead);
}
else if (command.equals("selectNextRow"))
{
rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax),
Math.min(rowLead + 1, rowMax));
- colModel.setSelectionInterval(colLead,colLead);
}
else if (command.equals("scrollUpExtendSelection"))
{
@@ -589,7 +591,6 @@ public class BasicTableUI extends TableUI
{
rowModel.setSelectionInterval(Math.max(rowLead - 1, 0),
Math.max(rowLead - 1, 0));
- colModel.setSelectionInterval(colLead,colLead);
}
else if (command.equals("scrollRightChangeSelection"))
{
@@ -606,7 +607,6 @@ public class BasicTableUI extends TableUI
}
else if (command.equals("selectPreviousColumn"))
{
- rowModel.setSelectionInterval(rowLead,rowLead);
colModel.setSelectionInterval(Math.max(colLead - 1, 0),
Math.max(colLead - 1, 0));
}
@@ -715,7 +715,6 @@ public class BasicTableUI extends TableUI
}
else if (command.equals("selectNextColumn"))
{
- rowModel.setSelectionInterval(rowLead,rowLead);
colModel.setSelectionInterval(Math.min(colLead + 1, colMax),
Math.min(colLead + 1, colMax));
}
@@ -903,7 +902,6 @@ public class BasicTableUI extends TableUI
table.scrollRectToVisible
(table.getCellRect(rowModel.getLeadSelectionIndex(),
colModel.getLeadSelectionIndex(), false));
- table.repaint();
}
/**
@@ -1172,6 +1170,7 @@ public class BasicTableUI extends TableUI
}
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// TODO: Implement this properly.
}
@@ -1247,16 +1246,18 @@ public class BasicTableUI extends TableUI
if (rn == -1)
rn = table.getRowCount() - 1;
+ int columnMargin = table.getColumnModel().getColumnMargin();
+ int rowMargin = table.getRowMargin();
+
TableColumnModel cmodel = table.getColumnModel();
int [] widths = new int[cn+1];
for (int i = c0; i <=cn ; i++)
{
- widths[i] = cmodel.getColumn(i).getWidth();
+ widths[i] = cmodel.getColumn(i).getWidth() - columnMargin;
}
Rectangle bounds = table.getCellRect(r0, c0, false);
- bounds.height = table.getRowHeight()+table.getRowMargin();
-
+
// The left boundary of the area being repainted.
int left = bounds.x;
@@ -1266,9 +1267,6 @@ public class BasicTableUI extends TableUI
// The bottom boundary of the area being repainted.
int bottom;
- // The cell height.
- int height = bounds.height;
-
// paint the cell contents
Color grid = table.getGridColor();
for (int r = r0; r <= rn; ++r)
@@ -1277,25 +1275,28 @@ public class BasicTableUI extends TableUI
{
bounds.width = widths[c];
paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c));
- bounds.x += widths[c];
+ bounds.x += widths[c] + columnMargin;
}
- bounds.y += height;
bounds.x = left;
+ bounds.y += table.getRowHeight(r) + rowMargin;
+ // Update row height for tables with custom heights.
+ bounds.height = table.getRowHeight(r + 1);
}
- bottom = bounds.y;
+ bottom = bounds.y - rowMargin;
// paint vertical grid lines
if (grid != null && table.getShowVerticalLines())
{
Color save = gfx.getColor();
gfx.setColor(grid);
- int x = left;
-
+ int x = left - columnMargin;
for (int c = c0; c <= cn; ++c)
{
+ // The vertical grid is draw right from the cells, so we
+ // add before drawing.
+ x += widths[c] + columnMargin;
gfx.drawLine(x, top, x, bottom);
- x += widths[c];
}
gfx.setColor(save);
}
@@ -1305,11 +1306,13 @@ public class BasicTableUI extends TableUI
{
Color save = gfx.getColor();
gfx.setColor(grid);
- int y = top;
+ int y = top - rowMargin;
for (int r = r0; r <= rn; ++r)
{
+ // The horizontal grid is draw below the cells, so we
+ // add before drawing.
+ y += table.getRowHeight(r) + rowMargin;
gfx.drawLine(left, y, p2.x, y);
- y += height;
}
gfx.setColor(save);
}
diff --git a/javax/swing/plaf/basic/BasicTextAreaUI.java b/javax/swing/plaf/basic/BasicTextAreaUI.java
index 36854e07f..93e119b31 100644
--- a/javax/swing/plaf/basic/BasicTextAreaUI.java
+++ b/javax/swing/plaf/basic/BasicTextAreaUI.java
@@ -1,5 +1,5 @@
/* BasicTextAreaUI.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -108,6 +108,9 @@ public class BasicTextAreaUI extends BasicTextUI
JTextArea comp = (JTextArea)getComponent();
if (ev.getPropertyName() == "lineWrap"
|| ev.getPropertyName() == "wrapStyleWord")
- modelChanged();
+ {
+ // Changes the View (without modifying the document or it's listeners).
+ setView(create(textComponent.getDocument().getDefaultRootElement()));
+ }
}
}
diff --git a/javax/swing/plaf/basic/BasicTextFieldUI.java b/javax/swing/plaf/basic/BasicTextFieldUI.java
index 4e2ca9f93..89c4e5a75 100644
--- a/javax/swing/plaf/basic/BasicTextFieldUI.java
+++ b/javax/swing/plaf/basic/BasicTextFieldUI.java
@@ -1,5 +1,5 @@
/* BasicTextFieldUI.java
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,6 +42,7 @@ import java.beans.PropertyChangeEvent;
import javax.swing.JComponent;
import javax.swing.UIDefaults;
+import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.text.Element;
import javax.swing.text.FieldView;
@@ -83,6 +84,9 @@ public class BasicTextFieldUI extends BasicTextUI
* Receives notification whenever one of the text component's bound
* properties changes. Here we check for the editable and enabled
* properties and adjust the background color accordingly.
+ *
+ * <p>The colors are only changed if they are not a
+ * <code>ColorUIResource</code>.</p>
*
* @param event the property change event
*/
@@ -91,10 +95,11 @@ public class BasicTextFieldUI extends BasicTextUI
if (event.getPropertyName().equals("editable"))
{
boolean editable = ((Boolean) event.getNewValue()).booleanValue();
- if (editable)
- textComponent.setBackground(background);
- else
- textComponent.setBackground(inactiveBackground);
+
+ // 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);
}
}
}
diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java
index bc5917105..3b620f049 100644
--- a/javax/swing/plaf/basic/BasicTextUI.java
+++ b/javax/swing/plaf/basic/BasicTextUI.java
@@ -38,14 +38,20 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
+import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.StringSelection;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
@@ -55,7 +61,6 @@ import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
-import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
@@ -63,7 +68,6 @@ import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.ActionMapUIResource;
-import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TextUI;
import javax.swing.plaf.UIResource;
import javax.swing.text.AbstractDocument;
@@ -436,6 +440,9 @@ public abstract class BasicTextUI extends TextUI
*/
public void changedUpdate(DocumentEvent ev)
{
+ // Updates are forwarded to the View even if 'getVisibleEditorRect'
+ // method returns null. This means the View classes have to be
+ // aware of that possibility.
rootView.changedUpdate(ev, getVisibleEditorRect(),
rootView.getViewFactory());
}
@@ -447,6 +454,9 @@ public abstract class BasicTextUI extends TextUI
*/
public void insertUpdate(DocumentEvent ev)
{
+ // Updates are forwarded to the View even if 'getVisibleEditorRect'
+ // method returns null. This means the View classes have to be
+ // aware of that possibility.
rootView.insertUpdate(ev, getVisibleEditorRect(),
rootView.getViewFactory());
}
@@ -458,6 +468,9 @@ public abstract class BasicTextUI extends TextUI
*/
public void removeUpdate(DocumentEvent ev)
{
+ // Updates are forwarded to the View even if 'getVisibleEditorRect'
+ // method returns null. This means the View classes have to be
+ // aware of that possibility.
rootView.removeUpdate(ev, getVisibleEditorRect(),
rootView.getViewFactory());
}
@@ -607,6 +620,44 @@ public abstract class BasicTextUI extends TextUI
public void focusLost(FocusEvent e)
{
textComponent.repaint();
+
+ // Integrates Swing text components with the system clipboard:
+ // The idea is that if one wants to copy text around X11-style
+ // (select text and middle-click in the target component) the focus
+ // will move to the new component which gives the old focus owner the
+ // possibility to paste its selection into the clipboard.
+ if (!e.isTemporary()
+ && textComponent.getSelectionStart()
+ != textComponent.getSelectionEnd())
+ {
+ SecurityManager sm = System.getSecurityManager();
+ try
+ {
+ if (sm != null)
+ sm.checkSystemClipboardAccess();
+
+ Clipboard cb = Toolkit.getDefaultToolkit().getSystemSelection();
+ if (cb != null)
+ {
+ StringSelection selection = new StringSelection(textComponent.getSelectedText());
+ cb.setContents(selection, selection);
+ }
+ }
+ catch (SecurityException se)
+ {
+ // Not allowed to access the clipboard: Ignore and
+ // do not access it.
+ }
+ catch (HeadlessException he)
+ {
+ // There is no AWT: Ignore and do not access the
+ // clipboard.
+ }
+ catch (IllegalStateException ise)
+ {
+ // Clipboard is currently unavaible.
+ }
+ }
}
};
@@ -654,33 +705,23 @@ public abstract class BasicTextUI extends TextUI
*/
protected Keymap createKeymap()
{
- // FIXME: It seems to me that this method implementation is wrong. It seems
- // to fetch the focusInputMap and transform it to the KeyBinding/Keymap
- // implemenation. I would think that it should be done the other way,
- // fetching the keybindings (from prefix + ".bindings") and transform
- // it to the newer InputMap/ActionMap implementation.
- JTextComponent.KeyBinding[] bindings = null;
- String prefix = getPropertyPrefix();
- InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap");
- if (m != null)
+ String keymapName = getKeymapName();
+ Keymap keymap = JTextComponent.getKeymap(keymapName);
+ if (keymap == null)
{
- KeyStroke[] keys = m.keys();
- int len = keys.length;
- bindings = new JTextComponent.KeyBinding[len];
- for (int i = 0; i < len; i++)
+ Keymap parentMap =
+ JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
+ keymap = JTextComponent.addKeymap(keymapName, parentMap);
+ Object val = UIManager.get(getPropertyPrefix() + ".keyBindings");
+ if (val != null && val instanceof JTextComponent.KeyBinding[])
{
- KeyStroke curr = keys[i];
- bindings[i] = new JTextComponent.KeyBinding(curr,
- (String) m.get(curr));
+ JTextComponent.KeyBinding[] bindings =
+ (JTextComponent.KeyBinding[]) val;
+ JTextComponent.loadKeymap(keymap, bindings,
+ getComponent().getActions());
}
}
- if (bindings == null)
- bindings = new JTextComponent.KeyBinding[0];
-
- Keymap km = JTextComponent.addKeymap(getKeymapName(),
- JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP));
- JTextComponent.loadKeymap(km, bindings, textComponent.getActions());
- return km;
+ return keymap;
}
/**
@@ -688,11 +729,8 @@ public abstract class BasicTextUI extends TextUI
*/
protected void installKeyboardActions()
{
- // load key bindings for the older interface
- Keymap km = JTextComponent.getKeymap(getKeymapName());
- if (km == null)
- km = createKeymap();
- textComponent.setKeymap(km);
+ // This is only there for backwards compatibility.
+ textComponent.setKeymap(createKeymap());
// load any bindings for the newer InputMap / ActionMap interface
SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED,
@@ -793,6 +831,7 @@ public abstract class BasicTextUI extends TextUI
* this UI.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: Uninstall keyboard actions here.
}
@@ -985,6 +1024,10 @@ 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
{
// Limit p0 and p1 to sane values to prevent unfriendly
@@ -999,7 +1042,10 @@ public abstract class BasicTextUI extends TextUI
Rectangle l1 = modelToView(t, p0, firstBias);
Rectangle l2 = modelToView(t, p1, secondBias);
if (l1.y == l2.y)
- t.repaint(l1.union(l2));
+ {
+ SwingUtilities.computeUnion(l2.x, l2.y, l2.width, l2.height, l1);
+ t.repaint(l1);
+ }
else
{
// The two rectangles lie on different lines and we need a
@@ -1107,7 +1153,12 @@ public abstract class BasicTextUI extends TextUI
Position.Bias[] biasRet)
throws BadLocationException
{
- return 0; // TODO: Implement me.
+ // A comment in the spec of NavigationFilter.getNextVisualPositionFrom()
+ // suggests that this method should be implemented by forwarding the call
+ // the root view.
+ return rootView.getNextVisualPositionFrom(pos, b,
+ getVisibleEditorRect(),
+ direction, biasRet);
}
/**
@@ -1163,7 +1214,10 @@ public abstract class BasicTextUI extends TextUI
public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias)
throws BadLocationException
{
- return rootView.modelToView(pos, getVisibleEditorRect(), bias).getBounds();
+ Rectangle r = getVisibleEditorRect();
+
+ return (r != null) ? rootView.modelToView(pos, r, bias).getBounds()
+ : null;
}
/**
@@ -1240,8 +1294,9 @@ public abstract class BasicTextUI extends TextUI
int width = textComponent.getWidth();
int height = textComponent.getHeight();
+ // Return null if the component has no valid size.
if (width <= 0 || height <= 0)
- return new Rectangle(0, 0, 0, 0);
+ return null;
Insets insets = textComponent.getInsets();
return new Rectangle(insets.left, insets.top,
diff --git a/javax/swing/plaf/basic/BasicToolBarUI.java b/javax/swing/plaf/basic/BasicToolBarUI.java
index 5d718876f..80fec6a77 100644
--- a/javax/swing/plaf/basic/BasicToolBarUI.java
+++ b/javax/swing/plaf/basic/BasicToolBarUI.java
@@ -38,6 +38,8 @@ 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;
@@ -604,6 +606,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* by the look and feel.
*/
protected void installKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
@@ -900,6 +903,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* This method uninstalls keyboard actions installed by the UI.
*/
protected void uninstallKeyboardActions()
+ throws NotImplementedException
{
// FIXME: implement.
}
diff --git a/javax/swing/plaf/basic/BasicTreeUI.java b/javax/swing/plaf/basic/BasicTreeUI.java
index 1c6e6c5e5..a143a962b 100644
--- a/javax/swing/plaf/basic/BasicTreeUI.java
+++ b/javax/swing/plaf/basic/BasicTreeUI.java
@@ -1,5 +1,5 @@
/* BasicTreeUI.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,6 +38,8 @@
package javax.swing.plaf.basic;
+import gnu.javax.swing.tree.GnuPath;
+
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
@@ -55,6 +57,7 @@ import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
+import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
@@ -76,7 +79,6 @@ import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
-import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
@@ -96,17 +98,17 @@ import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TreeUI;
-import javax.swing.text.Caret;
+import javax.swing.plaf.metal.MetalIconFactory;
import javax.swing.tree.AbstractLayoutCache;
import javax.swing.tree.DefaultTreeCellEditor;
import javax.swing.tree.DefaultTreeCellRenderer;
-import javax.swing.tree.FixedHeightLayoutCache;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
+import javax.swing.tree.VariableHeightLayoutCache;
/**
* A delegate providing the user interface for <code>JTree</code> according to
@@ -117,16 +119,17 @@ import javax.swing.tree.TreeSelectionModel;
* @author Sascha Brawer (brawer@dandelis.ch)
* @author Audrius Meskauskas (audriusa@bioinformatics.org)
*/
-public class BasicTreeUI extends TreeUI
+public class BasicTreeUI
+ extends TreeUI
{
/**
* The tree cell editing may be started by the single mouse click on the
* selected cell. To separate it from the double mouse click, the editing
- * session starts after this time (in ms) after that single click, and only
- * no other clicks were performed during that time.
+ * session starts after this time (in ms) after that single click, and only no
+ * other clicks were performed during that time.
*/
- static int WAIT_TILL_EDITING = 900;
-
+ static int WAIT_TILL_EDITING = 900;
+
/** Collapse Icon for the tree. */
protected transient Icon collapsedIcon;
@@ -251,39 +254,45 @@ public class BasicTreeUI extends TreeUI
int maxHeight = 0;
/** Listeners */
- private PropertyChangeListener propertyChangeListener;
+ PropertyChangeListener propertyChangeListener;
- private FocusListener focusListener;
+ FocusListener focusListener;
- private TreeSelectionListener treeSelectionListener;
+ TreeSelectionListener treeSelectionListener;
- private MouseListener mouseListener;
+ MouseListener mouseListener;
- private KeyListener keyListener;
+ KeyListener keyListener;
- private PropertyChangeListener selectionModelPropertyChangeListener;
+ PropertyChangeListener selectionModelPropertyChangeListener;
- private ComponentListener componentListener;
+ ComponentListener componentListener;
CellEditorListener cellEditorListener;
- private TreeExpansionListener treeExpansionListener;
+ TreeExpansionListener treeExpansionListener;
+
+ TreeModelListener treeModelListener;
- private TreeModelListener treeModelListener;
-
/**
* This timer fires the editing action after about 1200 ms if not reset during
- * that time. It handles the editing start with the single mouse click
- * (and not the double mouse click) on the selected tree node.
+ * that time. It handles the editing start with the single mouse click (and
+ * not the double mouse click) on the selected tree node.
*/
Timer startEditTimer;
/**
+ * The zero size icon, used for expand controls, if they are not visible.
+ */
+ static Icon nullIcon;
+
+ /**
* The special value of the mouse event is sent indicating that this is not
* just the mouse click, but the mouse click on the selected node. Sending
* such event forces to start the cell editing session.
*/
- static final MouseEvent EDIT = new MouseEvent(new Label(), 7,7,7,7,7,7, false);
+ static final MouseEvent EDIT = new MouseEvent(new Label(), 7, 7, 7, 7, 7, 7,
+ false);
/**
* Creates a new BasicTreeUI object.
@@ -306,22 +315,21 @@ public class BasicTreeUI extends TreeUI
treeExpansionListener = createTreeExpansionListener();
treeModelListener = createTreeModelListener();
- editingRow = -1;
- lastSelectedRow = -1;
+ editingRow = - 1;
+ lastSelectedRow = - 1;
}
/**
* Returns an instance of the UI delegate for the specified component.
*
- * @param c
- * the <code>JComponent</code> for which we need a UI delegate for.
+ * @param c the <code>JComponent</code> for which we need a UI delegate for.
* @return the <code>ComponentUI</code> for c.
*/
public static ComponentUI createUI(JComponent c)
{
return new BasicTreeUI();
}
-
+
/**
* Returns the Hash color.
*
@@ -335,8 +343,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the Hash color.
*
- * @param color
- * the <code>Color</code> to set the Hash to.
+ * @param color the <code>Color</code> to set the Hash to.
*/
protected void setHashColor(Color color)
{
@@ -347,8 +354,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the left child's indent value.
*
- * @param newAmount
- * is the new indent value for the left child.
+ * @param newAmount is the new indent value for the left child.
*/
public void setLeftChildIndent(int newAmount)
{
@@ -368,8 +374,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the right child's indent value.
*
- * @param newAmount
- * is the new indent value for the right child.
+ * @param newAmount is the new indent value for the right child.
*/
public void setRightChildIndent(int newAmount)
{
@@ -389,8 +394,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the expanded icon.
*
- * @param newG
- * is the new expanded icon.
+ * @param newG is the new expanded icon.
*/
public void setExpandedIcon(Icon newG)
{
@@ -410,8 +414,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the collapsed icon.
*
- * @param newG
- * is the new collapsed icon.
+ * @param newG is the new collapsed icon.
*/
public void setCollapsedIcon(Icon newG)
{
@@ -431,8 +434,7 @@ public class BasicTreeUI extends TreeUI
/**
* Updates the componentListener, if necessary.
*
- * @param largeModel
- * sets this.largeModel to it.
+ * @param largeModel sets this.largeModel to it.
*/
protected void setLargeModel(boolean largeModel)
{
@@ -457,13 +459,12 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the row height.
*
- * @param rowHeight
- * is the height to set this.rowHeight to.
+ * @param rowHeight is the height to set this.rowHeight to.
*/
protected void setRowHeight(int rowHeight)
{
if (rowHeight == 0)
- rowHeight = Math.max(getMaxHeight(tree), 20);
+ rowHeight = getMaxHeight(tree);
treeState.setRowHeight(rowHeight);
}
@@ -474,15 +475,14 @@ public class BasicTreeUI extends TreeUI
*/
protected int getRowHeight()
{
- return treeState.getRowHeight();
+ return tree.getRowHeight();
}
/**
* Sets the TreeCellRenderer to <code>tcr</code>. This invokes
* <code>updateRenderer</code>.
*
- * @param tcr
- * is the new TreeCellRenderer.
+ * @param tcr is the new TreeCellRenderer.
*/
protected void setCellRenderer(TreeCellRenderer tcr)
{
@@ -507,13 +507,13 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the tree's model.
*
- * @param model
- * to set the treeModel to.
+ * @param model to set the treeModel to.
*/
protected void setModel(TreeModel model)
{
tree.setModel(model);
treeModel = tree.getModel();
+ treeState.setModel(treeModel);
}
/**
@@ -529,8 +529,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the root to being visible.
*
- * @param newValue
- * sets the visibility of the root
+ * @param newValue sets the visibility of the root
*/
protected void setRootVisible(boolean newValue)
{
@@ -550,8 +549,7 @@ public class BasicTreeUI extends TreeUI
/**
* Determines whether the node handles are to be displayed.
*
- * @param newValue
- * sets whether or not node handles should be displayed.
+ * @param newValue sets whether or not node handles should be displayed.
*/
protected void setShowsRootHandles(boolean newValue)
{
@@ -571,8 +569,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the cell editor.
*
- * @param editor
- * to set the cellEditor to.
+ * @param editor to set the cellEditor to.
*/
protected void setCellEditor(TreeCellEditor editor)
{
@@ -593,8 +590,7 @@ public class BasicTreeUI extends TreeUI
/**
* Configures the receiver to allow, or not allow, editing.
*
- * @param newValue
- * sets the receiver to allow editing if true.
+ * @param newValue sets the receiver to allow editing if true.
*/
protected void setEditable(boolean newValue)
{
@@ -615,8 +611,7 @@ public class BasicTreeUI extends TreeUI
* Resets the selection model. The appropriate listeners are installed on the
* model.
*
- * @param newLSM
- * resets the selection model.
+ * @param newLSM resets the selection model.
*/
protected void setSelectionModel(TreeSelectionModel newLSM)
{
@@ -642,35 +637,23 @@ public class BasicTreeUI extends TreeUI
* path will be drawn to. Will return null if any component in path is
* currently valid.
*
- * @param tree
- * is the current tree the path will be drawn to.
- * @param path
- * is the current path the tree to draw to.
+ * @param tree is the current tree the path will be drawn to.
+ * @param path is the current path the tree to draw to.
* @return the Rectangle enclosing the label portion that the last item in the
* path will be drawn to.
*/
public Rectangle getPathBounds(JTree tree, TreePath path)
{
- int row = -1;
- Object cell = null;
- if (path != null)
- {
- row = getRowForPath(tree, path);
- cell = path.getLastPathComponent();
- }
- return nodeDimensions.getNodeDimensions(cell, row, getLevel(cell),
- tree.isExpanded(path),
- new Rectangle());
+ return treeState.getBounds(path, new Rectangle());
}
/**
* Returns the max height of all the nodes in the tree.
*
- * @param tree -
- * the current tree
+ * @param tree - the current tree
* @return the max height.
*/
- private int getMaxHeight(JTree tree)
+ int getMaxHeight(JTree tree)
{
if (maxHeight != 0)
return maxHeight;
@@ -692,72 +675,61 @@ public class BasicTreeUI extends TreeUI
maxHeight = Math.max(maxHeight, iconHeight + gap);
}
-
+
+ treeState.setRowHeight(maxHeight);
return maxHeight;
}
+
+ /**
+ * Get the tree node icon.
+ */
+ Icon getNodeIcon(TreePath path)
+ {
+ Object node = path.getLastPathComponent();
+ if (treeModel.isLeaf(node))
+ return UIManager.getIcon("Tree.leafIcon");
+ else if (treeState.getExpandedState(path))
+ return UIManager.getIcon("Tree.openIcon");
+ else
+ return UIManager.getIcon("Tree.closedIcon");
+ }
/**
* Returns the path for passed in row. If row is not visible null is returned.
*
- * @param tree
- * is the current tree to return path for.
- * @param row
- * is the row number of the row to return.
+ * @param tree is the current tree to return path for.
+ * @param row is the row number of the row to return.
* @return the path for passed in row. If row is not visible null is returned.
*/
public TreePath getPathForRow(JTree tree, int row)
{
- if (treeModel != null && currentVisiblePath != null)
- {
- Object[] nodes = currentVisiblePath.getPath();
- if (row < nodes.length)
- return new TreePath(getPathToRoot(nodes[row], 0));
- }
- return null;
+ return treeState.getPathForRow(row);
}
/**
* Returns the row that the last item identified in path is visible at. Will
* return -1 if any of the elments in the path are not currently visible.
*
- * @param tree
- * is the current tree to return the row for.
- * @param path
- * is the path used to find the row.
+ * @param tree is the current tree to return the row for.
+ * @param path is the path used to find the row.
* @return the row that the last item identified in path is visible at. Will
* return -1 if any of the elments in the path are not currently
* visible.
*/
public int getRowForPath(JTree tree, TreePath path)
{
- int row = 0;
- Object dest = path.getLastPathComponent();
- int rowCount = getRowCount(tree);
- if (currentVisiblePath != null)
- {
- Object[] nodes = currentVisiblePath.getPath();
- while (row < rowCount)
- {
- if (dest.equals(nodes[row]))
- return row;
- row++;
- }
- }
- return -1;
+ return treeState.getRowForPath(path);
}
/**
* Returns the number of rows that are being displayed.
*
- * @param tree
- * is the current tree to return the number of rows for.
+ * @param tree is the current tree to return the number of rows for.
* @return the number of rows being displayed.
*/
public int getRowCount(JTree tree)
{
- if (currentVisiblePath != null)
- return currentVisiblePath.getPathCount();
- return 0;
+ return treeState.getRowCount();
}
/**
@@ -766,35 +738,21 @@ public class BasicTreeUI extends TreeUI
* valid path. If you need to test if the returned object is exactly at x,y
* you should get the bounds for the returned path and test x,y against that.
*
- * @param tree
- * the tree to search for the closest path
- * @param x
- * is the x coordinate of the location to search
- * @param y
- * is the y coordinate of the location to search
+ * @param tree the tree to search for the closest path
+ * @param x is the x coordinate of the location to search
+ * @param y is the y coordinate of the location to search
* @return the tree path closes to x,y.
*/
public TreePath getClosestPathForLocation(JTree tree, int x, int y)
{
- int row = Math.round(y / getMaxHeight(tree));
- TreePath path = getPathForRow(tree, row);
-
- // no row is visible at this node
- while (row > 0 && path == null)
- {
- --row;
- path = getPathForRow(tree, row);
- }
-
- return path;
+ return treeState.getPathClosestTo(x, y);
}
/**
* Returns true if the tree is being edited. The item that is being edited can
* be returned by getEditingPath().
*
- * @param tree
- * is the tree to check for editing.
+ * @param tree is the tree to check for editing.
* @return true if the tree is being edited.
*/
public boolean isEditing(JTree tree)
@@ -807,8 +765,7 @@ public class BasicTreeUI extends TreeUI
* being edited. Returns true if the editor allows the editing session to
* stop.
*
- * @param tree
- * is the tree to stop the editing on
+ * @param tree is the tree to stop the editing on
* @return true if the editor allows the editing session to stop.
*/
public boolean stopEditing(JTree tree)
@@ -818,32 +775,29 @@ public class BasicTreeUI extends TreeUI
completeEditing(false, false, true);
finish();
}
- return !isEditing(tree);
+ return ! isEditing(tree);
}
/**
* Cancels the current editing session.
*
- * @param tree
- * is the tree to cancel the editing session on.
+ * @param tree is the tree to cancel the editing session on.
*/
public void cancelEditing(JTree tree)
- {
- // There is no need to send the cancel message to the editor,
- // as the cancellation event itself arrives from it. This would
- // only be necessary when cancelling the editing programatically.
- completeEditing(false, false, false);
- finish();
+ {
+ // There is no need to send the cancel message to the editor,
+ // as the cancellation event itself arrives from it. This would
+ // only be necessary when cancelling the editing programatically.
+ completeEditing(false, false, false);
+ finish();
}
/**
* Selects the last item in path and tries to edit it. Editing will fail if
* the CellEditor won't allow it for the selected item.
*
- * @param tree
- * is the tree to edit on.
- * @param path
- * is the path in tree to edit on.
+ * @param tree is the tree to edit on.
+ * @param path is the path in tree to edit on.
*/
public void startEditingAtPath(JTree tree, TreePath path)
{
@@ -853,8 +807,7 @@ public class BasicTreeUI extends TreeUI
/**
* Returns the path to the element that is being editted.
*
- * @param tree
- * is the tree to get the editing path from.
+ * @param tree is the tree to get the editing path from.
* @return the path that is being edited.
*/
public TreePath getEditingPath(JTree tree)
@@ -902,7 +855,8 @@ public class BasicTreeUI extends TreeUI
/**
* Creates an instance of NodeDimensions that is able to determine the size of
- * a given node in the tree.
+ * a given node in the tree. The node dimensions must be created before
+ * configuring the layout cache.
*
* @return the NodeDimensions of a given node in the tree
*/
@@ -1018,7 +972,7 @@ public class BasicTreeUI extends TreeUI
*/
protected AbstractLayoutCache createLayoutCache()
{
- return new FixedHeightLayoutCache();
+ return new VariableHeightLayoutCache();
}
/**
@@ -1152,8 +1106,7 @@ public class BasicTreeUI extends TreeUI
* by getting the expanded descendants from the tree and forwarding to the
* tree state.
*
- * @param path
- * the path used to update the expanded states
+ * @param path the path used to update the expanded states
*/
protected void updateExpandedDescendants(TreePath path)
{
@@ -1165,8 +1118,7 @@ public class BasicTreeUI extends TreeUI
/**
* Returns a path to the last child of <code>parent</code>
*
- * @param parent
- * is the topmost path to specified
+ * @param parent is the topmost path to specified
* @return a path to the last child of parent
*/
protected TreePath getLastChildPath(TreePath parent)
@@ -1200,23 +1152,21 @@ public class BasicTreeUI extends TreeUI
protected void updateRenderer()
{
if (tree != null)
- {
- if (tree.getCellRenderer() == null)
- {
- if (currentCellRenderer == null)
- currentCellRenderer = createDefaultCellRenderer();
- tree.setCellRenderer(currentCellRenderer);
- }
- }
+ currentCellRenderer = tree.getCellRenderer();
+
+ if (currentCellRenderer == null)
+ currentCellRenderer = createDefaultCellRenderer();
}
/**
* Resets the treeState instance based on the tree we're providing the look
- * and feel for.
+ * and feel for. The node dimensions handler is required and must be created
+ * in advance.
*/
protected void configureLayoutCache()
{
treeState = createLayoutCache();
+ treeState.setNodeDimensions(nodeDimensions);
}
/**
@@ -1236,42 +1186,19 @@ public class BasicTreeUI extends TreeUI
*/
protected void updateCachedPreferredSize()
{
- int maxWidth = 0;
- updateCurrentVisiblePath();
- boolean isLeaf = false;
- if (currentVisiblePath != null)
- {
- Object[] path = currentVisiblePath.getPath();
- for (int i = 0; i < path.length; i++)
- {
- TreePath curr = new TreePath(getPathToRoot(path[i], 0));
- Rectangle bounds = getPathBounds(tree, curr);
- if (treeModel != null)
- isLeaf = treeModel.isLeaf(path[i]);
- if (!isLeaf && hasControlIcons())
- bounds.width += getCurrentControlIcon(curr).getIconWidth();
- maxWidth = Math.max(maxWidth, bounds.x + bounds.width);
- }
-
- maxHeight = 0;
- maxHeight = getMaxHeight(tree);
- preferredSize = new Dimension(maxWidth, (maxHeight * path.length));
- }
- else
- preferredSize = new Dimension(0, 0);
- validCachedPreferredSize = true;
+ validCachedPreferredSize = false;
}
/**
* Messaged from the VisibleTreeNode after it has been expanded.
*
- * @param path
- * is the path that has been expanded.
+ * @param path is the path that has been expanded.
*/
protected void pathWasExpanded(TreePath path)
{
validCachedPreferredSize = false;
- tree.repaint();
+ treeState.setExpandedState(path, true);
+ tree.repaint();
}
/**
@@ -1280,6 +1207,7 @@ public class BasicTreeUI extends TreeUI
protected void pathWasCollapsed(TreePath path)
{
validCachedPreferredSize = false;
+ treeState.setExpandedState(path, false);
tree.repaint();
}
@@ -1294,6 +1222,7 @@ public class BasicTreeUI extends TreeUI
rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
+ totalChildIndent = rightChildIndent + leftChildIndent;
setRowHeight(UIManager.getInt("Tree.rowHeight"));
tree.setRowHeight(getRowHeight());
tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
@@ -1345,8 +1274,7 @@ public class BasicTreeUI extends TreeUI
/**
* Converts the modifiers.
*
- * @param mod -
- * modifier to convert
+ * @param mod - modifier to convert
* @returns the new modifier
*/
private int convertModifiers(int mod)
@@ -1354,27 +1282,27 @@ public class BasicTreeUI extends TreeUI
if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
{
mod |= KeyEvent.SHIFT_MASK;
- mod &= ~KeyEvent.SHIFT_DOWN_MASK;
+ mod &= ~ KeyEvent.SHIFT_DOWN_MASK;
}
if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
{
mod |= KeyEvent.CTRL_MASK;
- mod &= ~KeyEvent.CTRL_DOWN_MASK;
+ mod &= ~ KeyEvent.CTRL_DOWN_MASK;
}
if ((mod & KeyEvent.META_DOWN_MASK) != 0)
{
mod |= KeyEvent.META_MASK;
- mod &= ~KeyEvent.META_DOWN_MASK;
+ mod &= ~ KeyEvent.META_DOWN_MASK;
}
if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
{
mod |= KeyEvent.ALT_MASK;
- mod &= ~KeyEvent.ALT_DOWN_MASK;
+ mod &= ~ KeyEvent.ALT_DOWN_MASK;
}
if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
{
mod |= KeyEvent.ALT_GRAPH_MASK;
- mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK;
+ mod &= ~ KeyEvent.ALT_GRAPH_DOWN_MASK;
}
return mod;
}
@@ -1399,16 +1327,16 @@ public class BasicTreeUI extends TreeUI
/**
* Install the UI for the component
*
- * @param c
- * the component to install UI for
+ * @param c the component to install UI for
*/
public void installUI(JComponent c)
{
tree = (JTree) c;
+ treeModel = tree.getModel();
+
prepareForUIInstall();
super.installUI(c);
installDefaults();
-
installComponents();
installKeyboardActions();
installListeners();
@@ -1419,10 +1347,13 @@ public class BasicTreeUI extends TreeUI
setModel(tree.getModel());
treeSelectionModel = tree.getSelectionModel();
+ setRootVisible(tree.isRootVisible());
+ treeState.setRootVisible(tree.isRootVisible());
+ updateExpandedDescendants(new TreePath(new Object[] { treeModel.getRoot() }));
completeUIInstall();
}
-
+
/**
* Uninstall the defaults for the tree
*/
@@ -1436,8 +1367,7 @@ public class BasicTreeUI extends TreeUI
/**
* Uninstall the UI for the component
*
- * @param c
- * the component to uninstall UI for
+ * @param c the component to uninstall UI for
*/
public void uninstallUI(JComponent c)
{
@@ -1456,51 +1386,103 @@ public class BasicTreeUI extends TreeUI
* component is being painted. Subclasses should override this method and use
* the specified Graphics object to render the content of the component.
*
- * @param g
- * the Graphics context in which to paint
- * @param c
- * the component being painted; this argument is often ignored, but
+ * @param g the Graphics context in which to paint
+ * @param c the component being painted; this argument is often ignored, but
* might be used if the UI object is stateless and shared by multiple
* components
*/
public void paint(Graphics g, JComponent c)
{
JTree tree = (JTree) c;
- updateCurrentVisiblePath();
+
+ int rows = treeState.getRowCount();
+
+ if (rows == 0)
+ // There is nothing to do if the tree is empty.
+ return;
Rectangle clip = g.getClipBounds();
+
Insets insets = tree.getInsets();
- if (clip != null && treeModel != null && currentVisiblePath != null)
+ if (clip != null && treeModel != null)
{
int startIndex = tree.getClosestRowForLocation(clip.x, clip.y);
int endIndex = tree.getClosestRowForLocation(clip.x + clip.width,
clip.y + clip.height);
- paintVerticalPartOfLeg(g, clip, insets, currentVisiblePath);
- for (int i = startIndex; i <= endIndex; i++)
+ // Also paint dashes to the invisible nodes below.
+ // These should be painted first, otherwise they may cover
+ // the control icons.
+ if (endIndex < rows)
+ for (int i = endIndex + 1; i < rows; i++)
+ {
+ TreePath path = treeState.getPathForRow(i);
+ if (isLastChild(path))
+ paintVerticalPartOfLeg(g, clip, insets, path);
+ }
+
+ // The two loops are required to ensure that the lines are not
+ // painted over the other tree components.
+
+ int n = endIndex - startIndex + 1;
+ Rectangle[] bounds = new Rectangle[n];
+ boolean[] isLeaf = new boolean[n];
+ boolean[] isExpanded = new boolean[n];
+ TreePath[] path = new TreePath[n];
+ int k;
+
+ k = 0;
+ for (int i = startIndex; i <= endIndex; i++, k++)
{
- Object curr = currentVisiblePath.getPathComponent(i);
- boolean isLeaf = treeModel.isLeaf(curr);
- TreePath path = new TreePath(getPathToRoot(curr, 0));
-
- boolean isExpanded = tree.isExpanded(path);
- Rectangle bounds = getPathBounds(tree, path);
- paintHorizontalPartOfLeg(g, clip, insets, bounds, path, i,
- isExpanded, false, isLeaf);
- paintRow(g, clip, insets, bounds, path, i, isExpanded, false,
- isLeaf);
+ path[k] = treeState.getPathForRow(i);
+ isLeaf[k] = treeModel.isLeaf(path[k].getLastPathComponent());
+ isExpanded[k] = tree.isExpanded(path[k]);
+ bounds[k] = getPathBounds(tree, path[k]);
+
+ paintHorizontalPartOfLeg(g, clip, insets, bounds[k], path[k], i,
+ isExpanded[k], false, isLeaf[k]);
+ if (isLastChild(path[k]))
+ paintVerticalPartOfLeg(g, clip, insets, path[k]);
+ }
+
+ k = 0;
+ for (int i = startIndex; i <= endIndex; i++, k++)
+ {
+ paintRow(g, clip, insets, bounds[k], path[k], i, isExpanded[k],
+ false, isLeaf[k]);
}
}
}
/**
+ * Check if the path is referring to the last child of some parent.
+ */
+ private boolean isLastChild(TreePath path)
+ {
+ if (path instanceof GnuPath)
+ {
+ // Except the seldom case when the layout cache is changed, this
+ // optimized code will be executed.
+ return ((GnuPath) path).isLastChild;
+ }
+ else
+ {
+ // Non optimized general case.
+ TreePath parent = path.getParentPath();
+ if (parent == null)
+ return false;
+ int childCount = treeState.getVisibleChildCount(parent);
+ int p = treeModel.getIndexOfChild(parent, path.getLastPathComponent());
+ return p == childCount - 1;
+ }
+ }
+
+ /**
* Ensures that the rows identified by beginRow through endRow are visible.
*
- * @param beginRow
- * is the first row
- * @param endRow
- * is the last row
+ * @param beginRow is the first row
+ * @param endRow is the last row
*/
protected void ensureRowsAreVisible(int beginRow, int endRow)
{
@@ -1514,7 +1496,7 @@ public class BasicTreeUI extends TreeUI
for (int i = beginRow; i < endRow; i++)
{
TreePath path = getPathForRow(tree, i);
- if (!tree.isVisible(path))
+ if (! tree.isVisible(path))
tree.makeVisible(path);
}
}
@@ -1522,8 +1504,7 @@ public class BasicTreeUI extends TreeUI
/**
* Sets the preferred minimum size.
*
- * @param newSize
- * is the new preferred minimum size.
+ * @param newSize is the new preferred minimum size.
*/
public void setPreferredMinSize(Dimension newSize)
{
@@ -1537,15 +1518,17 @@ public class BasicTreeUI extends TreeUI
*/
public Dimension getPreferredMinSize()
{
- return preferredMinSize;
+ if (preferredMinSize == null)
+ return getPreferredSize(tree);
+ else
+ return preferredMinSize;
}
/**
* Returns the preferred size to properly display the tree, this is a cover
* method for getPreferredSize(c, false).
*
- * @param c
- * the component whose preferred size is being queried; this argument
+ * @param c the component whose preferred size is being queried; this argument
* is often ignored but might be used if the UI object is stateless
* and shared by multiple components
* @return the preferred size
@@ -1559,17 +1542,20 @@ public class BasicTreeUI extends TreeUI
* Returns the preferred size to represent the tree in c. If checkConsistancy
* is true, checkConsistancy is messaged first.
*
- * @param c
- * the component whose preferred size is being queried.
- * @param checkConsistancy
- * if true must check consistancy
+ * @param c the component whose preferred size is being queried.
+ * @param checkConsistancy if true must check consistancy
* @return the preferred size
*/
public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
{
- // FIXME: checkConsistancy not implemented, c not used
- if (!validCachedPreferredSize)
- updateCachedPreferredSize();
+ if (! validCachedPreferredSize)
+ {
+ Rectangle size = tree.getBounds();
+ // Add the scrollbar dimensions to the preferred size.
+ preferredSize = new Dimension(treeState.getPreferredWidth(size),
+ treeState.getPreferredHeight());
+ validCachedPreferredSize = true;
+ }
return preferredSize;
}
@@ -1577,31 +1563,24 @@ public class BasicTreeUI extends TreeUI
* Returns the minimum size for this component. Which will be the min
* preferred size or (0,0).
*
- * @param c
- * the component whose min size is being queried.
+ * @param c the component whose min size is being queried.
* @returns the preferred size or null
*/
public Dimension getMinimumSize(JComponent c)
{
- Dimension min = getPreferredMinSize();
- if (min == null)
- return new Dimension();
- return min;
+ return preferredMinSize = getPreferredSize(c);
}
/**
* Returns the maximum size for the component, which will be the preferred
* size if the instance is currently in JTree or (0,0).
*
- * @param c
- * the component whose preferred size is being queried
+ * @param c the component whose preferred size is being queried
* @return the max size or null
*/
public Dimension getMaximumSize(JComponent c)
{
- if (c instanceof JTree)
- return ((JTree) c).getPreferredSize();
- return new Dimension();
+ return getPreferredSize(c);
}
/**
@@ -1622,12 +1601,9 @@ public class BasicTreeUI extends TreeUI
* cancelEditing. If messageTree is true, the treeModel is messaged with
* valueForPathChanged.
*
- * @param messageStop
- * message to stop editing
- * @param messageCancel
- * message to cancel editing
- * @param messageTree
- * message to treeModel
+ * @param messageStop message to stop editing
+ * @param messageCancel message to cancel editing
+ * @param messageTree message to treeModel
*/
protected void completeEditing(boolean messageStop, boolean messageCancel,
boolean messageTree)
@@ -1659,25 +1635,16 @@ public class BasicTreeUI extends TreeUI
* Will start editing for node if there is a cellEditor and shouldSelectCall
* returns true. This assumes that path is valid and visible.
*
- * @param path
- * is the path to start editing
- * @param event
- * is the MouseEvent performed on the path
+ * @param path is the path to start editing
+ * @param event is the MouseEvent performed on the path
* @return true if successful
*/
protected boolean startEditing(TreePath path, MouseEvent event)
{
- // Force to recalculate the maximal row height.
- maxHeight = 0;
-
- // Force to recalculate the cached preferred size.
- validCachedPreferredSize = false;
-
updateCellEditor();
TreeCellEditor ed = getCellEditor();
- if (ed != null
- && (event == EDIT || ed.shouldSelectCell(event))
+ if (ed != null && (event == EDIT || ed.shouldSelectCell(event))
&& ed.isCellEditable(event))
{
Rectangle bounds = getPathBounds(tree, path);
@@ -1718,12 +1685,9 @@ public class BasicTreeUI extends TreeUI
* If the <code>mouseX</code> and <code>mouseY</code> are in the expand or
* collapse region of the row, this will toggle the row.
*
- * @param path
- * the path we are concerned with
- * @param mouseX
- * is the cursor's x position
- * @param mouseY
- * is the cursor's y position
+ * @param path the path we are concerned with
+ * @param mouseX is the cursor's x position
+ * @param mouseY is the cursor's y position
*/
protected void checkForClickInExpandControl(TreePath path, int mouseX,
int mouseY)
@@ -1737,12 +1701,9 @@ public class BasicTreeUI extends TreeUI
* the area of row that is used to expand/collpse the node and the node at row
* does not represent a leaf.
*
- * @param path
- * the path we are concerned with
- * @param mouseX
- * is the cursor's x position
- * @param mouseY
- * is the cursor's y position
+ * @param path the path we are concerned with
+ * @param mouseX is the cursor's x position
+ * @param mouseY is the cursor's y position
* @return true if the <code>mouseX</code> and <code>mouseY</code> fall in
* the area of row that is used to expand/collpse the node and the
* node at row does not represent a leaf.
@@ -1753,7 +1714,7 @@ public class BasicTreeUI extends TreeUI
boolean cntlClick = false;
int row = getRowForPath(tree, path);
- if (!isLeaf(row))
+ if (! isLeaf(row))
{
Rectangle bounds = getPathBounds(tree, path);
@@ -1769,12 +1730,9 @@ public class BasicTreeUI extends TreeUI
* Messaged when the user clicks the particular row, this invokes
* toggleExpandState.
*
- * @param path
- * the path we are concerned with
- * @param mouseX
- * is the cursor's x position
- * @param mouseY
- * is the cursor's y position
+ * @param path the path we are concerned with
+ * @param mouseX is the cursor's x position
+ * @param mouseY is the cursor's y position
*/
protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
{
@@ -1787,8 +1745,7 @@ public class BasicTreeUI extends TreeUI
* invoked to scroll as many of the children to visible as possible (tries to
* scroll to last visible descendant of path).
*
- * @param path
- * the path we are concerned with
+ * @param path the path we are concerned with
*/
protected void toggleExpandState(TreePath path)
{
@@ -1800,30 +1757,40 @@ public class BasicTreeUI extends TreeUI
/**
* Returning true signifies a mouse event on the node should toggle the
- * selection of only the row under the mouse.
+ * selection of only the row under the mouse. The BasisTreeUI treats the
+ * event as "toggle selection event" if the CTRL button was pressed while
+ * clicking. The event is not counted as toggle event if the associated
+ * tree does not support the multiple selection.
*
- * @param event
- * is the MouseEvent performed on the row.
+ * @param event is the MouseEvent performed on the row.
* @return true signifies a mouse event on the node should toggle the
* selection of only the row under the mouse.
*/
protected boolean isToggleSelectionEvent(MouseEvent event)
{
- return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION);
+ return
+ (tree.getSelectionModel().getSelectionMode() !=
+ TreeSelectionModel.SINGLE_TREE_SELECTION) &&
+ ((event.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0);
}
/**
* Returning true signifies a mouse event on the node should select from the
- * anchor point.
+ * anchor point. The BasisTreeUI treats the event as "multiple selection
+ * event" if the SHIFT button was pressed while clicking. The event is not
+ * counted as multiple selection event if the associated tree does not support
+ * the multiple selection.
*
- * @param event
- * is the MouseEvent performed on the node.
+ * @param event is the MouseEvent performed on the node.
* @return true signifies a mouse event on the node should select from the
* anchor point.
*/
protected boolean isMultiSelectEvent(MouseEvent event)
{
- return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
+ return
+ (tree.getSelectionModel().getSelectionMode() !=
+ TreeSelectionModel.SINGLE_TREE_SELECTION) &&
+ ((event.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0);
}
/**
@@ -1831,8 +1798,7 @@ public class BasicTreeUI extends TreeUI
* the event. This is invoked after checkForClickInExpandControl, implying the
* location is not in the expand (toggle) control.
*
- * @param event
- * is the MouseEvent performed on the row.
+ * @param event is the MouseEvent performed on the row.
* @return true indicates the row under the mouse should be toggled based on
* the event.
*/
@@ -1846,17 +1812,19 @@ public class BasicTreeUI extends TreeUI
* row. If the even is a toggle selection event, the row is either selected,
* or deselected. If the event identifies a multi selection event, the
* selection is updated from the anchor point. Otherwise, the row is selected,
- * and if the even specified a toggle event the row is expanded/collapsed.
+ * and the previous selection is cleared.</p>
*
- * @param path
- * is the path selected for an event
- * @param event
- * is the MouseEvent performed on the path.
+ * @param path is the path selected for an event
+ * @param event is the MouseEvent performed on the path.
+ *
+ * @see #isToggleSelectionEvent(MouseEvent)
+ * @see #isMultiSelectEvent(MouseEvent)
*/
protected void selectPathForEvent(TreePath path, MouseEvent event)
{
if (isToggleSelectionEvent(event))
{
+ // The event selects or unselects the clicked row.
if (tree.isPathSelected(path))
tree.removeSelectionPath(path);
else
@@ -1867,6 +1835,7 @@ public class BasicTreeUI extends TreeUI
}
else if (isMultiSelectEvent(event))
{
+ // The event extends selection form anchor till the clicked row.
TreePath anchor = tree.getAnchorSelectionPath();
if (anchor != null)
{
@@ -1877,14 +1846,17 @@ public class BasicTreeUI extends TreeUI
tree.addSelectionPath(path);
}
else
- tree.addSelectionPath(path);
+ {
+ // This is an ordinary event that just selects the clicked row.
+ tree.setSelectionPath(path);
+ tree.setAnchorSelectionPath(path);
+ }
}
/**
* Returns true if the node at <code>row</code> is a leaf.
*
- * @param row
- * is the row we are concerned with.
+ * @param row is the row we are concerned with.
* @return true if the node at <code>row</code> is a leaf.
*/
protected boolean isLeaf(int row)
@@ -1902,46 +1874,38 @@ public class BasicTreeUI extends TreeUI
* are pressed for the JTree. The actionPerformed method is called when a key
* that has been registered for the JTree is received.
*/
- class TreeAction extends AbstractAction
+ class TreeAction
+ extends AbstractAction
{
/**
* What to do when this action is called.
*
- * @param e
- * the ActionEvent that caused this action.
+ * @param e the ActionEvent that caused this action.
*/
public void actionPerformed(ActionEvent e)
{
+ String command = e.getActionCommand();
TreePath lead = tree.getLeadSelectionPath();
- if (e.getActionCommand().equals("selectPreviousChangeLead")
- || e.getActionCommand().equals("selectPreviousExtendSelection")
- || e.getActionCommand().equals("selectPrevious")
- || e.getActionCommand().equals("selectNext")
- || e.getActionCommand().equals("selectNextExtendSelection")
- || e.getActionCommand().equals("selectNextChangeLead"))
+ 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 (e.getActionCommand().equals("selectParent")
- || e.getActionCommand().equals("selectChild"))
+ else if (command.equals("selectParent") || command.equals("selectChild"))
(new TreeTraverseAction(0, "")).actionPerformed(e);
- else if (e.getActionCommand().equals("selectAll"))
+ else if (command.equals("selectAll"))
{
- TreePath[] paths = new TreePath[tree.getVisibleRowCount()];
-
- Object curr = getNextVisibleNode(treeModel.getRoot());
- int i = 0;
- while (curr != null && i < paths.length)
- {
- paths[i] = new TreePath(getPathToRoot(curr, 0));
- i++;
- }
-
+ TreePath[] paths = new TreePath[treeState.getRowCount()];
+ for (int i = 0; i < paths.length; i++)
+ paths[i] = treeState.getPathForRow(i);
tree.addSelectionPaths(paths);
}
- else if (e.getActionCommand().equals("startEditing"))
+ else if (command.equals("startEditing"))
tree.startEditingAtPath(lead);
- else if (e.getActionCommand().equals("toggle"))
+ else if (command.equals("toggle"))
{
if (tree.isEditing())
tree.stopEditing();
@@ -1949,17 +1913,17 @@ public class BasicTreeUI extends TreeUI
{
Object last = lead.getLastPathComponent();
TreePath path = new TreePath(getPathToRoot(last, 0));
- if (!treeModel.isLeaf(last))
+ if (! treeModel.isLeaf(last))
toggleExpandState(path);
}
}
- else if (e.getActionCommand().equals("clearSelection"))
+ else if (command.equals("clearSelection"))
tree.clearSelection();
- if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
+ if (tree.isEditing() && ! command.equals("startEditing"))
tree.stopEditing();
- tree.scrollPathToVisible(lead);
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
}
@@ -1970,7 +1934,8 @@ public class BasicTreeUI extends TreeUI
* to the true receiver after altering the actionCommand property of the
* event.
*/
- private static class ActionListenerProxy extends AbstractAction
+ private static class ActionListenerProxy
+ extends AbstractAction
{
ActionListener target;
@@ -1992,11 +1957,12 @@ public class BasicTreeUI extends TreeUI
}
}
- /**
+ /**
* Updates the preferred size when scrolling, if necessary.
*/
- public class ComponentHandler extends ComponentAdapter implements
- ActionListener
+ public class ComponentHandler
+ extends ComponentAdapter
+ implements ActionListener
{
/**
* Timer used when inside a scrollpane and the scrollbar is adjusting
@@ -2017,8 +1983,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when the component's position changes.
*
- * @param e
- * the event that occurs when moving the component
+ * @param e the event that occurs when moving the component
*/
public void componentMoved(ComponentEvent e)
{
@@ -2048,8 +2013,7 @@ public class BasicTreeUI extends TreeUI
* Public as a result of Timer. If the scrollBar is null, or not adjusting,
* this stops the timer and updates the sizing.
*
- * @param ae
- * is the action performed
+ * @param ae is the action performed
*/
public void actionPerformed(ActionEvent ae)
{
@@ -2061,7 +2025,8 @@ public class BasicTreeUI extends TreeUI
* Listener responsible for getting cell editing events and updating the tree
* accordingly.
*/
- public class CellEditorHandler implements CellEditorListener
+ public class CellEditorHandler
+ implements CellEditorListener
{
/**
* Constructor
@@ -2075,8 +2040,7 @@ public class BasicTreeUI extends TreeUI
* Messaged when editing has stopped in the tree. Tells the listeners
* editing has stopped.
*
- * @param e
- * is the notification event
+ * @param e is the notification event
*/
public void editingStopped(ChangeEvent e)
{
@@ -2087,8 +2051,7 @@ public class BasicTreeUI extends TreeUI
* Messaged when editing has been canceled in the tree. This tells the
* listeners the editor has canceled editing.
*
- * @param e
- * is the notification event
+ * @param e is the notification event
*/
public void editingCanceled(ChangeEvent e)
{
@@ -2099,7 +2062,8 @@ public class BasicTreeUI extends TreeUI
/**
* Repaints the lead selection row when focus is lost/grained.
*/
- public class FocusHandler implements FocusListener
+ public class FocusHandler
+ implements FocusListener
{
/**
* Constructor
@@ -2111,26 +2075,38 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when focus is activated on the tree we're in, redraws the lead
- * row. Invoked when a component gains the keyboard focus.
+ * row. Invoked when a component gains the keyboard focus. The method
+ * repaints the lead row that is shown differently when the tree is in
+ * focus.
*
- * @param e
- * is the focus event that is activated
+ * @param e is the focus event that is activated
*/
public void focusGained(FocusEvent e)
{
- // TODO: Implement this properly.
+ repaintLeadRow();
}
/**
* Invoked when focus is deactivated on the tree we're in, redraws the lead
- * row. Invoked when a component loses the keyboard focus.
+ * row. Invoked when a component loses the keyboard focus. The method
+ * repaints the lead row that is shown differently when the tree is in
+ * focus.
*
- * @param e
- * is the focus event that is deactivated
+ * @param e is the focus event that is deactivated
*/
public void focusLost(FocusEvent e)
{
- // TODO: Implement this properly.
+ repaintLeadRow();
+ }
+
+ /**
+ * Repaint the lead row.
+ */
+ void repaintLeadRow()
+ {
+ TreePath lead = tree.getLeadSelectionPath();
+ if (lead!=null)
+ tree.repaint(tree.getPathBounds(lead));
}
}
@@ -2138,7 +2114,8 @@ public class BasicTreeUI extends TreeUI
* This is used to get multiple key down events to appropriately genereate
* events.
*/
- public class KeyHandler extends KeyAdapter
+ public class KeyHandler
+ extends KeyAdapter
{
/** Key code that is being generated for. */
protected Action repeatKeyAction;
@@ -2160,8 +2137,7 @@ public class BasicTreeUI extends TreeUI
* user. Subsequent same key presses move the keyboard focus to the next
* object that starts with the same letter.
*
- * @param e
- * the key typed
+ * @param e the key typed
*/
public void keyTyped(KeyEvent e)
{
@@ -2171,8 +2147,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when a key has been pressed.
*
- * @param e
- * the key pressed
+ * @param e the key pressed
*/
public void keyPressed(KeyEvent e)
{
@@ -2182,8 +2157,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when a key has been released
*
- * @param e
- * the key released
+ * @param e the key released
*/
public void keyReleased(KeyEvent e)
{
@@ -2195,7 +2169,9 @@ public class BasicTreeUI extends TreeUI
* MouseListener is responsible for updating the selection based on mouse
* events.
*/
- public class MouseHandler extends MouseAdapter implements MouseMotionListener
+ public class MouseHandler
+ extends MouseAdapter
+ implements MouseMotionListener
{
/**
* Constructor
@@ -2208,11 +2184,10 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when a mouse button has been pressed on a component.
*
- * @param e
- * is the mouse event that occured
+ * @param e is the mouse event that occured
*/
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)
@@ -2220,7 +2195,7 @@ public class BasicTreeUI extends TreeUI
startEditTimer.stop();
startEditTimer = null;
}
-
+
Point click = e.getPoint();
TreePath path = getClosestPathForLocation(tree, click.x, click.y);
@@ -2228,6 +2203,11 @@ public class BasicTreeUI extends TreeUI
{
Rectangle bounds = getPathBounds(tree, path);
int row = getRowForPath(tree, path);
+
+ // Cancel the editing session if clicked on the different row.
+ if (tree.isEditing() && row != editingRow)
+ cancelEditing(tree);
+
boolean cntlClick = isLocationInExpandControl(path, click.x, click.y);
boolean isLeaf = isLeaf(row);
@@ -2258,35 +2238,32 @@ public class BasicTreeUI extends TreeUI
if (inBounds)
{
TreePath currentLead = tree.getLeadSelectionPath();
- if (
- currentLead != null &&
- currentLead.equals(path) &&
- e.getClickCount() == 1 &&
- tree.isEditable()
- )
+ if (currentLead != null && currentLead.equals(path)
+ && e.getClickCount() == 1 && tree.isEditable())
{
// Schedule the editing session.
final TreePath editPath = path;
-
+
if (startEditTimer != null)
startEditTimer.stop();
-
- startEditTimer = new Timer(WAIT_TILL_EDITING,
- new ActionListener()
- {
+
+ startEditTimer = new Timer(WAIT_TILL_EDITING,
+ new ActionListener()
+ {
public void actionPerformed(ActionEvent e)
- {
- startEditing(editPath, EDIT);
- }
+ {
+ startEditing(editPath, EDIT);
+ }
});
- startEditTimer.setRepeats(false);
- startEditTimer.start();
+ startEditTimer.setRepeats(false);
+ startEditTimer.start();
}
else
{
- selectPath(tree, path);
- if (e.getClickCount() == 2 && !isLeaf(row))
+ if (e.getClickCount() == 2 && ! isLeaf(row))
toggleExpandState(path);
+ else
+ selectPathForEvent(path, e);
}
}
@@ -2309,8 +2286,7 @@ public class BasicTreeUI extends TreeUI
* the drag originated until the mouse button is released (regardless of
* whether the mouse position is within the bounds of the component).
*
- * @param e
- * is the mouse event that occured
+ * @param e is the mouse event that occured
*/
public void mouseDragged(MouseEvent e)
{
@@ -2321,8 +2297,7 @@ public class BasicTreeUI extends TreeUI
* Invoked when the mouse button has been moved on a component (with no
* buttons no down).
*
- * @param e
- * the mouse event that occured
+ * @param e the mouse event that occured
*/
public void mouseMoved(MouseEvent e)
{
@@ -2332,8 +2307,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when a mouse button has been released on a component.
*
- * @param e
- * is the mouse event that occured
+ * @param e is the mouse event that occured
*/
public void mouseReleased(MouseEvent e)
{
@@ -2346,7 +2320,8 @@ public class BasicTreeUI extends TreeUI
* events, until the mouse is released to the destination it is constructed
* with.
*/
- public class MouseInputHandler implements MouseInputListener
+ public class MouseInputHandler
+ implements MouseInputListener
{
/** Source that events are coming from */
protected Component source;
@@ -2357,12 +2332,9 @@ public class BasicTreeUI extends TreeUI
/**
* Constructor
*
- * @param source
- * that events are coming from
- * @param destination
- * that receives all events
- * @param e
- * is the event received
+ * @param source that events are coming from
+ * @param destination that receives all events
+ * @param e is the event received
*/
public MouseInputHandler(Component source, Component destination,
MouseEvent e)
@@ -2375,8 +2347,7 @@ public class BasicTreeUI extends TreeUI
* Invoked when the mouse button has been clicked (pressed and released) on
* a component.
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mouseClicked(MouseEvent e)
{
@@ -2386,8 +2357,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when a mouse button has been pressed on a component.
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mousePressed(MouseEvent e)
{
@@ -2397,8 +2367,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when a mouse button has been released on a component.
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mouseReleased(MouseEvent e)
{
@@ -2408,8 +2377,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when the mouse enters a component.
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mouseEntered(MouseEvent e)
{
@@ -2419,8 +2387,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when the mouse exits a component.
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mouseExited(MouseEvent e)
{
@@ -2433,8 +2400,7 @@ public class BasicTreeUI extends TreeUI
* the drag originated until the mouse button is released (regardless of
* whether the mouse position is within the bounds of the component).
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mouseDragged(MouseEvent e)
{
@@ -2445,8 +2411,7 @@ public class BasicTreeUI extends TreeUI
* Invoked when the mouse cursor has been moved onto a component but no
* buttons have been pushed.
*
- * @param e
- * mouse event that occured
+ * @param e mouse event that occured
*/
public void mouseMoved(MouseEvent e)
{
@@ -2467,7 +2432,8 @@ public class BasicTreeUI extends TreeUI
* BasicTreeUI method. X location does not include insets, that is handled in
* getPathBounds.
*/
- public class NodeDimensionsHandler extends AbstractLayoutCache.NodeDimensions
+ public class NodeDimensionsHandler
+ extends AbstractLayoutCache.NodeDimensions
{
/**
* Constructor
@@ -2483,16 +2449,11 @@ public class BasicTreeUI extends TreeUI
* bounds is null, a newly created Rectangle should be returned, otherwise
* the value should be placed in bounds and returned.
*
- * @param cell
- * the value to be represented
- * @param row
- * row being queried
- * @param depth
- * the depth of the row
- * @param expanded
- * true if row is expanded
- * @param size
- * a Rectangle containing the size needed to represent value
+ * @param cell the value to be represented
+ * @param row row being queried
+ * @param depth the depth of the row
+ * @param expanded true if row is expanded
+ * @param size a Rectangle containing the size needed to represent value
* @return containing the node dimensions, or null if node has no dimension
*/
public Rectangle getNodeDimensions(Object cell, int row, int depth,
@@ -2507,8 +2468,11 @@ public class BasicTreeUI extends TreeUI
if (s != null)
{
+ TreePath path = treeState.getPathForRow(row);
size.x = getRowX(row, depth);
size.width = SwingUtilities.computeStringWidth(fm, s);
+ size.width = size.width + getCurrentControlIcon(path).getIconWidth()
+ + gap + getNodeIcon(path).getIconWidth();
size.height = getMaxHeight(tree);
size.y = size.height * row;
}
@@ -2523,17 +2487,16 @@ public class BasicTreeUI extends TreeUI
*/
protected int getRowX(int row, int depth)
{
- if (row == 0)
- return 0;
- return depth * rightChildIndent;
+ return depth * totalChildIndent;
}
}// NodeDimensionsHandler
/**
- * PropertyChangeListener for the tree. Updates the appropriate varaible, or
+ * PropertyChangeListener for the tree. Updates the appropriate variable, or
* TreeState, based on what changes.
*/
- public class PropertyChangeHandler implements PropertyChangeListener
+ public class PropertyChangeHandler
+ implements PropertyChangeListener
{
/**
@@ -2547,17 +2510,28 @@ public class BasicTreeUI extends TreeUI
/**
* This method gets called when a bound property is changed.
*
- * @param event
- * A PropertyChangeEvent object describing the event source and the
- * property that has changed.
+ * @param event A PropertyChangeEvent object describing the event source and
+ * the property that has changed.
*/
public void propertyChange(PropertyChangeEvent event)
{
- if ((event.getPropertyName()).equals("rootVisible"))
+ String property = event.getPropertyName();
+ if (property.equals(JTree.ROOT_VISIBLE_PROPERTY))
{
validCachedPreferredSize = false;
+ treeState.setRootVisible(tree.isRootVisible());
tree.repaint();
}
+ else if (property.equals(JTree.SELECTION_MODEL_PROPERTY))
+ {
+ treeSelectionModel = tree.getSelectionModel();
+ treeSelectionModel.setRowMapper(treeState);
+ }
+ else if (property.equals(JTree.TREE_MODEL_PROPERTY))
+ {
+ treeModel = tree.getModel();
+ treeModel.addTreeModelListener(treeModelListener);
+ }
}
}
@@ -2565,8 +2539,8 @@ public class BasicTreeUI extends TreeUI
* Listener on the TreeSelectionModel, resets the row selection if any of the
* properties of the model change.
*/
- public class SelectionModelPropertyChangeHandler implements
- PropertyChangeListener
+ public class SelectionModelPropertyChangeHandler
+ implements PropertyChangeListener
{
/**
@@ -2580,9 +2554,8 @@ public class BasicTreeUI extends TreeUI
/**
* This method gets called when a bound property is changed.
*
- * @param event
- * A PropertyChangeEvent object describing the event source and the
- * property that has changed.
+ * @param event A PropertyChangeEvent object describing the event source and
+ * the property that has changed.
*/
public void propertyChange(PropertyChangeEvent event)
{
@@ -2593,7 +2566,8 @@ public class BasicTreeUI extends TreeUI
/**
* ActionListener that invokes cancelEditing when action performed.
*/
- public class TreeCancelEditingAction extends AbstractAction
+ public class TreeCancelEditingAction
+ extends AbstractAction
{
/**
@@ -2607,8 +2581,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when an action occurs.
*
- * @param e
- * event that occured
+ * @param e event that occured
*/
public void actionPerformed(ActionEvent e)
{
@@ -2630,7 +2603,8 @@ public class BasicTreeUI extends TreeUI
/**
* Updates the TreeState in response to nodes expanding/collapsing.
*/
- public class TreeExpansionHandler implements TreeExpansionListener
+ public class TreeExpansionHandler
+ implements TreeExpansionListener
{
/**
@@ -2644,24 +2618,30 @@ public class BasicTreeUI extends TreeUI
/**
* Called whenever an item in the tree has been expanded.
*
- * @param event
- * is the event that occured
+ * @param event is the event that occured
*/
public void treeExpanded(TreeExpansionEvent event)
{
validCachedPreferredSize = false;
+ treeState.setExpandedState(event.getPath(), true);
+ // The maximal cell height may change
+ maxHeight = 0;
+ tree.revalidate();
tree.repaint();
}
/**
* Called whenever an item in the tree has been collapsed.
*
- * @param event
- * is the event that occured
+ * @param event is the event that occured
*/
public void treeCollapsed(TreeExpansionEvent event)
{
validCachedPreferredSize = false;
+ treeState.setExpandedState(event.getPath(), false);
+ // The maximal cell height may change
+ maxHeight = 0;
+ tree.revalidate();
tree.repaint();
}
}// TreeExpansionHandler
@@ -2670,7 +2650,8 @@ public class BasicTreeUI extends TreeUI
* TreeHomeAction is used to handle end/home actions. Scrolls either the first
* or last cell to be visible based on direction.
*/
- public class TreeHomeAction extends AbstractAction
+ public class TreeHomeAction
+ extends AbstractAction
{
/** The direction, either home or end */
@@ -2679,10 +2660,8 @@ public class BasicTreeUI extends TreeUI
/**
* Constructor
*
- * @param direction -
- * it is home or end
- * @param name
- * is the name of the direction
+ * @param direction - it is home or end
+ * @param name is the name of the direction
*/
public TreeHomeAction(int direction, String name)
{
@@ -2692,8 +2671,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when an action occurs.
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void actionPerformed(ActionEvent e)
{
@@ -2716,7 +2694,8 @@ public class BasicTreeUI extends TreeUI
* TreeIncrementAction is used to handle up/down actions. Selection is moved
* up or down based on direction.
*/
- public class TreeIncrementAction extends AbstractAction
+ public class TreeIncrementAction
+ extends AbstractAction
{
/** Specifies the direction to adjust the selection by. */
@@ -2725,10 +2704,8 @@ public class BasicTreeUI extends TreeUI
/**
* Constructor
*
- * @param direction
- * up or down
- * @param name
- * is the name of the direction
+ * @param direction up or down
+ * @param name is the name of the direction
*/
public TreeIncrementAction(int direction, String name)
{
@@ -2738,73 +2715,79 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when an action occurs.
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void actionPerformed(ActionEvent e)
{
- Object last = tree.getLeadSelectionPath().getLastPathComponent();
+ TreePath currentPath = tree.getLeadSelectionPath();
+ int currentRow;
- if (e.getActionCommand().equals("selectPreviousChangeLead"))
- {
- Object prev = getPreviousVisibleNode(last);
+ if (currentPath != null)
+ currentRow = treeState.getRowForPath(currentPath);
+ else
+ currentRow = 0;
- if (prev != null)
- {
- TreePath newPath = new TreePath(getPathToRoot(prev, 0));
- selectPath(tree, newPath);
- tree.setLeadSelectionPath(newPath);
- }
- }
- else if (e.getActionCommand().equals("selectPreviousExtendSelection"))
+ int rows = treeState.getRowCount();
+
+ int nextRow = currentRow + 1;
+ int prevRow = currentRow - 1;
+ boolean hasNext = nextRow < rows;
+ boolean hasPrev = prevRow >= 0 && rows > 0;
+ TreePath newPath;
+ String command = e.getActionCommand();
+
+ if (command.equals("selectPreviousChangeLead") && hasPrev)
{
- Object prev = getPreviousVisibleNode(last);
- if (prev != null)
- {
- TreePath newPath = new TreePath(getPathToRoot(prev, 0));
- tree.addSelectionPath(newPath);
- tree.setLeadSelectionPath(newPath);
- }
+ newPath = treeState.getPathForRow(prevRow);
+ tree.setSelectionPath(newPath);
+ tree.setAnchorSelectionPath(newPath);
+ tree.setLeadSelectionPath(newPath);
}
- else if (e.getActionCommand().equals("selectPrevious"))
+ else if (command.equals("selectPreviousExtendSelection") && hasPrev)
{
- Object prev = getPreviousVisibleNode(last);
+ newPath = treeState.getPathForRow(prevRow);
- if (prev != null)
- {
- TreePath newPath = new TreePath(getPathToRoot(prev, 0));
- selectPath(tree, newPath);
- }
+ // If the new path is already selected, the selection shrinks,
+ // unselecting the previously current path.
+ if (tree.isPathSelected(newPath))
+ tree.getSelectionModel().removeSelectionPath(currentPath);
+
+ // This must be called in any case because it updates the model
+ // lead selection index.
+ tree.addSelectionPath(newPath);
+ tree.setLeadSelectionPath(newPath);
}
- else if (e.getActionCommand().equals("selectNext"))
+ else if (command.equals("selectPrevious") && hasPrev)
{
- Object next = getNextVisibleNode(last);
-
- if (next != null)
- {
- TreePath newPath = new TreePath(getPathToRoot(next, 0));
- selectPath(tree, newPath);
- }
+ newPath = treeState.getPathForRow(prevRow);
+ tree.setSelectionPath(newPath);
}
- else if (e.getActionCommand().equals("selectNextExtendSelection"))
+ else if (command.equals("selectNext") && hasNext)
{
- Object next = getNextVisibleNode(last);
- if (next != null)
- {
- TreePath newPath = new TreePath(getPathToRoot(next, 0));
- tree.addSelectionPath(newPath);
- tree.setLeadSelectionPath(newPath);
- }
+ newPath = treeState.getPathForRow(nextRow);
+ tree.setSelectionPath(newPath);
}
- else if (e.getActionCommand().equals("selectNextChangeLead"))
+ else if (command.equals("selectNextExtendSelection") && hasNext)
{
- Object next = getNextVisibleNode(last);
- if (next != null)
- {
- TreePath newPath = new TreePath(getPathToRoot(next, 0));
- selectPath(tree, newPath);
- tree.setLeadSelectionPath(newPath);
- }
+ newPath = treeState.getPathForRow(nextRow);
+
+ // If the new path is already selected, the selection shrinks,
+ // unselecting the previously current path.
+ if (tree.isPathSelected(newPath))
+ tree.getSelectionModel().removeSelectionPath(currentPath);
+
+ // This must be called in any case because it updates the model
+ // lead selection index.
+ tree.addSelectionPath(newPath);
+
+ tree.setLeadSelectionPath(newPath);
+ }
+ else if (command.equals("selectNextChangeLead") && hasNext)
+ {
+ newPath = treeState.getPathForRow(nextRow);
+ tree.setSelectionPath(newPath);
+ tree.setAnchorSelectionPath(newPath);
+ tree.setLeadSelectionPath(newPath);
}
}
@@ -2823,7 +2806,8 @@ public class BasicTreeUI extends TreeUI
/**
* Forwards all TreeModel events to the TreeState.
*/
- public class TreeModelHandler implements TreeModelListener
+ public class TreeModelHandler
+ implements TreeModelListener
{
/**
* Constructor
@@ -2843,12 +2827,12 @@ public class BasicTreeUI extends TreeUI
* node(s). e.getChildIndices() returns the index(es) of the changed
* node(s).
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void treeNodesChanged(TreeModelEvent e)
{
validCachedPreferredSize = false;
+ treeState.treeNodesChanged(e);
tree.repaint();
}
@@ -2857,12 +2841,12 @@ public class BasicTreeUI extends TreeUI
* get the parent of the new node(s). e.getChildIndices() returns the
* index(es) of the new node(s) in ascending order.
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void treeNodesInserted(TreeModelEvent e)
{
validCachedPreferredSize = false;
+ treeState.treeNodesInserted(e);
tree.repaint();
}
@@ -2874,12 +2858,12 @@ public class BasicTreeUI extends TreeUI
* node(s). e.getChildIndices() returns, in ascending order, the index(es)
* the node(s) had before being deleted.
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void treeNodesRemoved(TreeModelEvent e)
{
validCachedPreferredSize = false;
+ treeState.treeNodesRemoved(e);
tree.repaint();
}
@@ -2890,15 +2874,15 @@ public class BasicTreeUI extends TreeUI
* should become the new root of the tree. Use e.getPath() to get the path
* to the node. e.getChildIndices() returns null.
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void treeStructureChanged(TreeModelEvent e)
{
if (e.getPath().length == 1
- && !e.getPath()[0].equals(treeModel.getRoot()))
+ && ! e.getPath()[0].equals(treeModel.getRoot()))
tree.expandPath(new TreePath(treeModel.getRoot()));
validCachedPreferredSize = false;
+ treeState.treeStructureChanged(e);
tree.repaint();
}
}// TreeModelHandler
@@ -2906,7 +2890,8 @@ public class BasicTreeUI extends TreeUI
/**
* TreePageAction handles page up and page down events.
*/
- public class TreePageAction extends AbstractAction
+ public class TreePageAction
+ extends AbstractAction
{
/** Specifies the direction to adjust the selection by. */
protected int direction;
@@ -2914,10 +2899,8 @@ public class BasicTreeUI extends TreeUI
/**
* Constructor
*
- * @param direction
- * up or down
- * @param name
- * is the name of the direction
+ * @param direction up or down
+ * @param name is the name of the direction
*/
public TreePageAction(int direction, String name)
{
@@ -2927,8 +2910,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when an action occurs.
*
- * @param e
- * is the event that occured
+ * @param e is the event that occured
*/
public void actionPerformed(ActionEvent e)
{
@@ -2950,7 +2932,8 @@ public class BasicTreeUI extends TreeUI
* Listens for changes in the selection model and updates the display
* accordingly.
*/
- public class TreeSelectionHandler implements TreeSelectionListener
+ public class TreeSelectionHandler
+ implements TreeSelectionListener
{
/**
* Constructor
@@ -2964,26 +2947,42 @@ public class BasicTreeUI extends TreeUI
* Messaged when the selection changes in the tree we're displaying for.
* Stops editing, messages super and displays the changed paths.
*
- * @param event
- * the event that characterizes the change.
+ * @param event the event that characterizes the change.
*/
public void valueChanged(TreeSelectionEvent event)
{
if (tree.isEditing())
- tree.stopEditing();
+ tree.cancelEditing();
+
+ TreePath op = event.getOldLeadSelectionPath();
+ TreePath np = event.getNewLeadSelectionPath();
+
+ // Repaint of the changed lead selection path.
+ if (op != np)
+ {
+ Rectangle o = treeState.getBounds(event.getOldLeadSelectionPath(),
+ new Rectangle());
+ Rectangle n = treeState.getBounds(event.getNewLeadSelectionPath(),
+ new Rectangle());
+
+ if (o!=null)
+ tree.repaint(o);
+ if (n!=null)
+ tree.repaint(n);
+ }
}
}// TreeSelectionHandler
/**
* For the first selected row expandedness will be toggled.
*/
- public class TreeToggleAction extends AbstractAction
+ public class TreeToggleAction
+ extends AbstractAction
{
/**
* Constructor
*
- * @param name
- * is the name of <code>Action</code> field
+ * @param name is the name of <code>Action</code> field
*/
public TreeToggleAction(String name)
{
@@ -2993,8 +2992,7 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when an action occurs.
*
- * @param e
- * the event that occured
+ * @param e the event that occured
*/
public void actionPerformed(ActionEvent e)
{
@@ -3016,7 +3014,8 @@ public class BasicTreeUI extends TreeUI
* TreeTraverseAction is the action used for left/right keys. Will toggle the
* expandedness of a node, as well as potentially incrementing the selection.
*/
- public class TreeTraverseAction extends AbstractAction
+ public class TreeTraverseAction
+ extends AbstractAction
{
/**
* Determines direction to traverse, 1 means expand, -1 means collapse.
@@ -3026,10 +3025,8 @@ public class BasicTreeUI extends TreeUI
/**
* Constructor
*
- * @param direction
- * to traverse
- * @param name
- * is the name of the direction
+ * @param direction to traverse
+ * @param name is the name of the direction
*/
public TreeTraverseAction(int direction, String name)
{
@@ -3039,35 +3036,49 @@ public class BasicTreeUI extends TreeUI
/**
* Invoked when an action occurs.
*
- * @param e
- * the event that occured
+ * @param e the event that occured
*/
public void actionPerformed(ActionEvent e)
{
- Object last = tree.getLeadSelectionPath().getLastPathComponent();
+ TreePath current = tree.getLeadSelectionPath();
+ if (current == null)
+ return;
if (e.getActionCommand().equals("selectParent"))
{
- TreePath path = new TreePath(getPathToRoot(last, 0));
- Object p = getParent(treeModel.getRoot(), last);
+ if (current == null)
+ return;
- if (!treeModel.isLeaf(last))
- toggleExpandState(path);
- else if (p != null)
- selectPath(tree, new TreePath(getPathToRoot(p, 0)));
+ if (tree.isExpanded(current))
+ {
+ tree.collapsePath(current);
+ }
+ else
+ {
+ // If the node is not expanded (also, if it is a leaf node),
+ // we just select the parent. We do not select the root if it
+ // is not visible.
+ TreePath parent = current.getParentPath();
+ if (parent != null &&
+ !(parent.getPathCount()==1 && !tree.isRootVisible()) )
+ tree.setSelectionPath(parent);
+ }
}
else if (e.getActionCommand().equals("selectChild"))
{
- TreePath path = new TreePath(getPathToRoot(last, 0));
-
- if (!treeModel.isLeaf(last))
- toggleExpandState(path);
+ Object node = current.getLastPathComponent();
+ int nc = treeModel.getChildCount(node);
+ if (nc == 0 || treeState.isExpanded(current))
+ {
+ // If the node is leaf or it is already expanded,
+ // we just select the next row.
+ int nextRow = tree.getLeadSelectionRow() + 1;
+ if (nextRow <= tree.getRowCount())
+ tree.setSelectionRow(nextRow);
+ }
else
{
- Object next = getNextVisibleNode(last);
-
- if (next != null)
- selectPath(tree, new TreePath(getPathToRoot(next, 0)));
+ tree.expandPath(current);
}
}
}
@@ -3105,18 +3116,42 @@ public class BasicTreeUI extends TreeUI
*/
Icon getCurrentControlIcon(TreePath path)
{
- if (tree.isExpanded(path))
- return expandedIcon;
- return collapsedIcon;
+ if (hasControlIcons())
+ {
+ if (tree.isExpanded(path))
+ return expandedIcon;
+ else
+ return collapsedIcon;
+ }
+ else
+ {
+ if (nullIcon == null)
+ nullIcon = new Icon()
+ {
+ public int getIconHeight()
+ {
+ return 0;
+ }
+
+ public int getIconWidth()
+ {
+ return 0;
+ }
+
+ public void paintIcon(Component c, Graphics g, int x, int y)
+ {
+ // No action here.
+ }
+ };
+ return nullIcon;
+ }
}
/**
* Returns the parent of the current node
*
- * @param root
- * is the root of the tree
- * @param node
- * is the current node
+ * @param root is the root of the tree
+ * @param node is the current node
* @return is the parent of the current node
*/
Object getParent(Object root, Object node)
@@ -3132,15 +3167,13 @@ public class BasicTreeUI extends TreeUI
/**
* Recursively checks the tree for the specified node, starting at the root.
*
- * @param root
- * is starting node to start searching at.
- * @param node
- * is the node to search for
+ * @param root is starting node to start searching at.
+ * @param node is the node to search for
* @return the parent node of node
*/
private Object findNode(Object root, Object node)
{
- if (!treeModel.isLeaf(root) && !root.equals(node))
+ if (! treeModel.isLeaf(root) && ! root.equals(node))
{
int size = treeModel.getChildCount(root);
for (int j = 0; j < size; j++)
@@ -3158,167 +3191,20 @@ public class BasicTreeUI extends TreeUI
}
/**
- * Get previous visible node in the tree. Package private for use in inner
- * classes.
- *
- * @param node -
- * current node
- * @return the next visible node in the JTree. Return null if there are no
- * more.
- */
- Object getPreviousVisibleNode(Object node)
- {
- if (currentVisiblePath != null)
- {
- Object[] nodes = currentVisiblePath.getPath();
- int i = 0;
- while (i < nodes.length && !node.equals(nodes[i]))
- i++;
- // return the next node
- if (i - 1 >= 0)
- return nodes[i - 1];
- }
- return null;
- }
-
- /**
- * Returns the next node in the tree Package private for use in inner classes.
- *
- * @param curr -
- * current node
- * @return the next node in the tree
- */
- Object getNextNode(Object curr)
- {
- if (!treeModel.isLeaf(curr) && treeModel.getChildCount(curr) > 0)
- return treeModel.getChild(curr, 0);
-
- Object node = curr;
- Object sibling = null;
- do
- {
- sibling = getNextSibling(node);
- node = getParent(treeModel.getRoot(), node);
- }
- while (sibling == null && node != null);
-
- return sibling;
- }
-
- /**
- * Returns the previous node in the tree Package private for use in inner
- * classes.
- *
- * @param node
- * current node
- * @return the previous node in the tree
- */
- Object getPreviousNode(Object node)
- {
- Object parent = getParent(treeModel.getRoot(), node);
- if (parent == null)
- return null;
-
- Object sibling = getPreviousSibling(node);
-
- if (sibling == null)
- return parent;
-
- int size = 0;
- if (!treeModel.isLeaf(sibling))
- size = treeModel.getChildCount(sibling);
- while (size > 0)
- {
- sibling = treeModel.getChild(sibling, size - 1);
- if (!treeModel.isLeaf(sibling))
- size = treeModel.getChildCount(sibling);
- else
- size = 0;
- }
-
- return sibling;
- }
-
- /**
- * Returns the next sibling in the tree Package private for use in inner
- * classes.
- *
- * @param node -
- * current node
- * @return the next sibling in the tree
- */
- Object getNextSibling(Object node)
- {
- Object parent = getParent(treeModel.getRoot(), node);
- if (parent == null)
- return null;
-
- int index = treeModel.getIndexOfChild(parent, node) + 1;
-
- int size = 0;
- if (!treeModel.isLeaf(parent))
- size = treeModel.getChildCount(parent);
- if (index == 0 || index >= size)
- return null;
-
- return treeModel.getChild(parent, index);
- }
-
- /**
- * Returns the previous sibling in the tree Package private for use in inner
- * classes.
- *
- * @param node -
- * current node
- * @return the previous sibling in the tree
- */
- Object getPreviousSibling(Object node)
- {
- Object parent = getParent(treeModel.getRoot(), node);
- if (parent == null)
- return null;
-
- int index = treeModel.getIndexOfChild(parent, node) - 1;
-
- int size = 0;
- if (!treeModel.isLeaf(parent))
- size = treeModel.getChildCount(parent);
- if (index < 0 || index >= size)
- return null;
-
- return treeModel.getChild(parent, index);
- }
-
- /**
* Selects the specified path in the tree depending on modes. Package private
* for use in inner classes.
*
- * @param tree
- * is the tree we are selecting the path in
- * @param path
- * is the path we are selecting
+ * @param tree is the tree we are selecting the path in
+ * @param path is the path we are selecting
*/
void selectPath(JTree tree, TreePath path)
{
if (path != null)
{
- if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION)
- {
- tree.getSelectionModel().clearSelection();
- tree.addSelectionPath(path);
- tree.setLeadSelectionPath(path);
- }
- else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
- {
- // TODO
- }
- else
- {
- tree.addSelectionPath(path);
- tree.setLeadSelectionPath(path);
- tree.getSelectionModel().setSelectionMode(
- TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
- }
+ tree.setSelectionPath(path);
+ tree.setLeadSelectionPath(path);
+ tree.makeVisible(path);
+ tree.scrollPathToVisible(path);
}
}
@@ -3326,10 +3212,8 @@ public class BasicTreeUI extends TreeUI
* Returns the path from node to the root. Package private for use in inner
* classes.
*
- * @param node
- * the node to get the path to
- * @param depth
- * the depth of the tree to return a path for
+ * @param node the node to get the path to
+ * @param depth the depth of the tree to return a path for
* @return an array of tree nodes that represent the path to node.
*/
Object[] getPathToRoot(Object node, int depth)
@@ -3349,47 +3233,13 @@ public class BasicTreeUI extends TreeUI
}
/**
- * Returns the level of the node in the tree.
- *
- * @param node -
- * current node
- * @return the number of the level
- */
- int getLevel(Object node)
- {
- int count = -1;
-
- Object current = node;
-
- if (treeModel != null)
- {
- Object root = treeModel.getRoot();
- if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root)))
- count--;
-
- do
- {
- current = getParent(root, current);
- count++;
- }
- while (current != null);
- }
- return count;
- }
-
- /**
* Draws a vertical line using the given graphic context
*
- * @param g
- * is the graphic context
- * @param c
- * is the component the new line will belong to
- * @param x
- * is the horizonal position
- * @param top
- * specifies the top of the line
- * @param bottom
- * specifies the bottom of the line
+ * @param g is the graphic context
+ * @param c is the component the new line will belong to
+ * @param x is the horizonal position
+ * @param top specifies the top of the line
+ * @param bottom specifies the bottom of the line
*/
protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
int bottom)
@@ -3402,16 +3252,11 @@ public class BasicTreeUI extends TreeUI
/**
* Draws a horizontal line using the given graphic context
*
- * @param g
- * is the graphic context
- * @param c
- * is the component the new line will belong to
- * @param y
- * is the vertical position
- * @param left
- * specifies the left point of the line
- * @param right
- * specifies the right point of the line
+ * @param g is the graphic context
+ * @param c is the component the new line will belong to
+ * @param y is the vertical position
+ * @param left specifies the left point of the line
+ * @param right specifies the right point of the line
*/
protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
int right)
@@ -3424,16 +3269,11 @@ public class BasicTreeUI extends TreeUI
/**
* Draws an icon at around a specific position
*
- * @param c
- * is the component the new line will belong to
- * @param g
- * is the graphic context
- * @param icon
- * is the icon which will be drawn
- * @param x
- * is the center position in x-direction
- * @param y
- * is the center position in y-direction
+ * @param c is the component the new line will belong to
+ * @param g is the graphic context
+ * @param icon is the icon which will be drawn
+ * @param x is the center position in x-direction
+ * @param y is the center position in y-direction
*/
protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
{
@@ -3451,14 +3291,10 @@ public class BasicTreeUI extends TreeUI
/**
* Draws a dashed horizontal line.
*
- * @param g -
- * the graphics configuration.
- * @param y -
- * the y location to start drawing at
- * @param x1 -
- * the x location to start drawing at
- * @param x2 -
- * the x location to finish drawing at
+ * @param g - the graphics configuration.
+ * @param y - the y location to start drawing at
+ * @param x1 - the x location to start drawing at
+ * @param x2 - the x location to finish drawing at
*/
protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
{
@@ -3470,14 +3306,10 @@ public class BasicTreeUI extends TreeUI
/**
* Draws a dashed vertical line.
*
- * @param g -
- * the graphics configuration.
- * @param x -
- * the x location to start drawing at
- * @param y1 -
- * the y location to start drawing at
- * @param y2 -
- * the y location to finish drawing at
+ * @param g - the graphics configuration.
+ * @param x - the x location to start drawing at
+ * @param y1 - the y location to start drawing at
+ * @param y2 - the y location to finish drawing at
*/
protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
{
@@ -3490,22 +3322,15 @@ public class BasicTreeUI extends TreeUI
* Paints the expand (toggle) part of a row. The receiver should NOT modify
* clipBounds, or insets.
*
- * @param g -
- * the graphics configuration
+ * @param g - the graphics configuration
* @param clipBounds -
* @param insets -
- * @param bounds -
- * bounds of expand control
- * @param path -
- * path to draw control for
- * @param row -
- * row to draw control for
- * @param isExpanded -
- * is the row expanded
- * @param hasBeenExpanded -
- * has the row already been expanded
- * @param isLeaf -
- * is the path a leaf
+ * @param bounds - bounds of expand control
+ * @param path - path to draw control for
+ * @param row - row to draw control for
+ * @param isExpanded - is the row expanded
+ * @param hasBeenExpanded - has the row already been expanded
+ * @param isLeaf - is the path a leaf
*/
protected void paintExpandControl(Graphics g, Rectangle clipBounds,
Insets insets, Rectangle bounds,
@@ -3516,9 +3341,7 @@ public class BasicTreeUI extends TreeUI
{
Icon icon = getCurrentControlIcon(path);
int iconW = icon.getIconWidth();
- int x = bounds.x - rightChildIndent + iconW / 2;
- if (x + iconW > bounds.x)
- x = bounds.x - rightChildIndent - gap;
+ int x = bounds.x - iconW - gap;
icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2
- icon.getIconHeight() / 2);
}
@@ -3529,22 +3352,15 @@ public class BasicTreeUI extends TreeUI
* clipBounds, or insets. NOTE: parentRow can be -1 if the root is not
* visible.
*
- * @param g -
- * the graphics configuration
+ * @param g - the graphics configuration
* @param clipBounds -
* @param insets -
- * @param bounds -
- * bounds of the cell
- * @param path -
- * path to draw leg for
- * @param row -
- * row to start drawing at
- * @param isExpanded -
- * is the row expanded
- * @param hasBeenExpanded -
- * has the row already been expanded
- * @param isLeaf -
- * is the path a leaf
+ * @param bounds - bounds of the cell
+ * @param path - path to draw leg for
+ * @param row - row to start drawing at
+ * @param isExpanded - is the row expanded
+ * @param hasBeenExpanded - has the row already been expanded
+ * @param isLeaf - is the path a leaf
*/
protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
Insets insets, Rectangle bounds,
@@ -3554,45 +3370,32 @@ public class BasicTreeUI extends TreeUI
boolean isLeaf)
{
if (row != 0)
- paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, bounds.x - gap
- - 2, bounds.x);
+ {
+ paintHorizontalLine(g, tree, bounds.y + bounds.height / 2,
+ bounds.x - leftChildIndent - gap, bounds.x - gap);
+ }
}
/**
* Paints the vertical part of the leg. The receiver should NOT modify
* clipBounds, insets.
*
- * @param g -
- * the graphics configuration.
+ * @param g - the graphics configuration.
* @param clipBounds -
* @param insets -
- * @param path -
- * the path to draw the vertical part for.
+ * @param path - the path to draw the vertical part for.
*/
protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
Insets insets, TreePath path)
{
- int max = tree.getVisibleRowCount();
- for (int i = 0; i < max; i++)
+ Rectangle bounds = getPathBounds(tree, path);
+ TreePath parent = path.getParentPath();
+ if (parent != null)
{
- Object curr = path.getPathComponent(i);
- TreePath currPath = new TreePath(getPathToRoot(curr, 0));
- int numChild = treeModel.getChildCount(curr);
- if (numChild > 0 && tree.isExpanded(currPath))
- {
- Rectangle bounds = getPathBounds(tree, currPath);
- Rectangle lastChildBounds = getPathBounds(
- tree,
- new TreePath(
- getPathToRoot(
- treeModel.getChild(
- curr,
- numChild - 1),
- 0)));
- paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y
- + bounds.height - 2,
- lastChildBounds.y + lastChildBounds.height / 2);
- }
+ Rectangle parentBounds = getPathBounds(tree, parent);
+ paintVerticalLine(g, tree, parentBounds.x + 2* gap,
+ parentBounds.y + parentBounds.height / 2,
+ bounds.y + bounds.height / 2);
}
}
@@ -3600,22 +3403,15 @@ public class BasicTreeUI extends TreeUI
* Paints the renderer part of a row. The receiver should NOT modify
* clipBounds, or insets.
*
- * @param g -
- * the graphics configuration
+ * @param g - the graphics configuration
* @param clipBounds -
* @param insets -
- * @param bounds -
- * bounds of expand control
- * @param path -
- * path to draw control for
- * @param row -
- * row to draw control for
- * @param isExpanded -
- * is the row expanded
- * @param hasBeenExpanded -
- * has the row already been expanded
- * @param isLeaf -
- * is the path a leaf
+ * @param bounds - bounds of expand control
+ * @param path - path to draw control for
+ * @param row - row to draw control for
+ * @param isExpanded - is the row expanded
+ * @param hasBeenExpanded - has the row already been expanded
+ * @param isLeaf - is the path a leaf
*/
protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets,
Rectangle bounds, TreePath path, int row,
@@ -3626,26 +3422,21 @@ public class BasicTreeUI extends TreeUI
boolean hasIcons = false;
Object node = path.getLastPathComponent();
- if (tree.isVisible(path))
- {
- if (!validCachedPreferredSize)
- updateCachedPreferredSize();
-
- paintExpandControl(g, clipBounds, insets, bounds, path, row,
- isExpanded, hasBeenExpanded, isLeaf);
-
- if (row != 0)
- bounds.x += gap;
- bounds.width = preferredSize.width + bounds.x;
- TreeCellRenderer dtcr = tree.getCellRenderer();
- if (dtcr == null)
- dtcr = createDefaultCellRenderer();
-
- Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
- isExpanded, isLeaf,
- row, tree.hasFocus());
- rendererPane.paintComponent(g, c, c.getParent(), bounds);
- }
+ paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded,
+ hasBeenExpanded, isLeaf);
+
+ TreeCellRenderer dtcr = currentCellRenderer;
+
+ boolean focused = false;
+ if (treeSelectionModel != null)
+ focused = treeSelectionModel.getLeadSelectionRow() == row
+ && tree.isFocusOwner();
+
+ Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
+ isExpanded, isLeaf, row,
+ focused);
+
+ rendererPane.paintComponent(g, c, c.getParent(), bounds);
}
/**
@@ -3660,16 +3451,11 @@ public class BasicTreeUI extends TreeUI
* Returns true if the expand (toggle) control should be drawn for the
* specified row.
*
- * @param path -
- * current path to check for.
- * @param row -
- * current row to check for.
- * @param isExpanded -
- * true if the path is expanded
- * @param hasBeenExpanded -
- * true if the path has been expanded already
- * @param isLeaf -
- * true if the row is a lead
+ * @param path - current path to check for.
+ * @param row - current row to check for.
+ * @param isExpanded - true if the path is expanded
+ * @param hasBeenExpanded - true if the path has been expanded already
+ * @param isLeaf - true if the row is a lead
*/
protected boolean shouldPaintExpandControl(TreePath path, int row,
boolean isExpanded,
@@ -3677,121 +3463,25 @@ public class BasicTreeUI extends TreeUI
boolean isLeaf)
{
Object node = path.getLastPathComponent();
- return (!isLeaf && getLevel(node) != 0 && hasControlIcons());
+ return (! isLeaf && hasControlIcons());
}
/**
- * Updates the cached current TreePath of all visible nodes in the tree.
+ * Finish the editing session.
*/
- void updateCurrentVisiblePath()
- {
- if (treeModel == null)
- return;
-
- Object next = treeModel.getRoot();
- if (next == null)
- return;
-
- TreePath rootPath = new TreePath(next);
- Rectangle bounds = getPathBounds(tree, rootPath);
-
- // If root is not a valid size to be visible, or is
- // not visible and the tree is expanded, then the next node acts
- // as the root
- if ((bounds.width == 0 && bounds.height == 0)
- || (!isRootVisible() && tree.isExpanded(new TreePath(next))))
- {
- next = getNextNode(next);
- rootPath = new TreePath(next);
- }
-
- Object root = next;
- TreePath current = null;
- while (next != null)
- {
- if (current == null)
- current = rootPath;
- else
- current = current.pathByAddingChild(next);
-
- do
- {
- TreePath path = new TreePath(getPathToRoot(next, 0));
- if ((tree.isVisible(path) && tree.isExpanded(path))
- || treeModel.isLeaf(next))
- next = getNextNode(next);
- else
- {
- Object pNext = next;
- next = getNextSibling(pNext);
- // if no next sibling, check parent's next sibling.
- if (next == null)
- {
- Object parent = getParent(root, pNext);
- while (next == null && parent != null)
- {
- next = getNextSibling(parent);
- if (next == null)
- parent = getParent(root, parent);
- }
- }
- }
- }
- while (next != null
- && !tree.isVisible(new TreePath(getPathToRoot(next, 0))));
- }
-
- currentVisiblePath = current;
- tree.setVisibleRowCount(getRowCount(tree));
-
- if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0
- && currentVisiblePath != null)
- selectPath(
- tree,
- new TreePath(
- getPathToRoot(
- currentVisiblePath.getPathComponent(0),
- 0)));
- }
-
- /**
- * Get next visible node in the currentVisiblePath. Package private for use in
- * inner classes.
- *
- * @param node
- * current node
- * @return the next visible node in the JTree. Return null if there are no
- * more.
- */
- Object getNextVisibleNode(Object node)
- {
- if (currentVisiblePath != null)
- {
- Object[] nodes = currentVisiblePath.getPath();
- int i = 0;
- while (i < nodes.length && !node.equals(nodes[i]))
- i++;
- // return the next node
- if (i + 1 < nodes.length)
- return nodes[i + 1];
- }
- return null;
- }
-
- /**
- * Finish the editing session.
- */
void finish()
{
+ treeState.invalidatePathBounds(treeState.getPathForRow(editingRow));
editingPath = null;
- editingRow = -1;
+ editingRow = - 1;
stopEditingInCompleteEditing = false;
isEditing = false;
+ Rectangle bounds = editingComponent.getParent().getBounds();
tree.removeAll();
validCachedPreferredSize = false;
-
// Repaint the region, where was the editing component.
- tree.repaint(editingComponent.getParent().getBounds());
+ tree.repaint(bounds);
editingComponent = null;
+ tree.requestFocus();
}
} // BasicTreeUI
diff --git a/javax/swing/plaf/metal/MetalBorders.java b/javax/swing/plaf/metal/MetalBorders.java
index 77e684127..98a00ee0a 100644
--- a/javax/swing/plaf/metal/MetalBorders.java
+++ b/javax/swing/plaf/metal/MetalBorders.java
@@ -139,24 +139,59 @@ public class MetalBorders
if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
paintOceanButtonBorder(c, g, x, y, w, h);
else
- {
- ButtonModel bmodel = null;
-
- if (c instanceof AbstractButton)
- bmodel = ((AbstractButton) c).getModel();
+ paintDefaultButtonBorder(c, g, x, y, w, h);
+ }
- Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
- Color shadow = MetalLookAndFeel.getControlShadow();
- Color light = MetalLookAndFeel.getControlHighlight();
- Color middle = MetalLookAndFeel.getControl();
+ /**
+ * Paints the button border for the DefaultMetalTheme.
+ *
+ * @param c the component (button)
+ * @param g the graphics object to use
+ * @param x the upper left corner of the component, X coordinate
+ * @param y the upper left corner of the component, Y coordinate
+ * @param w the width of the component
+ * @param h the height of the component
+ */
+ private void paintDefaultButtonBorder(Component c, Graphics g, int x,
+ int y, int w, int h)
+ {
+ ButtonModel bmodel = null;
- if (c.isEnabled())
- {
- // draw dark border
- g.setColor(darkShadow);
- g.drawRect(x, y, w - 2, h - 2);
+ if (c instanceof AbstractButton)
+ bmodel = ((AbstractButton) c).getModel();
+
+ Color darkShadow = MetalLookAndFeel.getControlDarkShadow();
+ Color shadow = MetalLookAndFeel.getControlShadow();
+ Color light = MetalLookAndFeel.getControlHighlight();
+ Color middle = MetalLookAndFeel.getControl();
- if (!bmodel.isPressed())
+ if (c.isEnabled())
+ {
+ // draw dark border
+ g.setColor(darkShadow);
+ g.drawRect(x, y, w - 2, h - 2);
+
+ // If the button is the default button, we paint a special border,
+ // regardless of the pressed state.
+ if (c instanceof JButton && ((JButton) c).isDefaultButton())
+ {
+ g.drawRect(x + 1, y + 1, w - 4, h - 4);
+ // Draw white highlight.
+ g.setColor(light);
+ g.drawLine(x + 2, y + 2, x + w - 4, y + 2);
+ g.drawLine(x + 2, y + 2, x + 2, y + h - 4);
+ g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
+ g.drawLine(x + w - 1, y + 2, x + w - 1, y + h - 1);
+ // Draw crossing pixels.
+ g.setColor(middle);
+ g.fillRect(x + w - 2, y + 2, 1, 1);
+ g.fillRect(x + 2, y + h - 2, 1, 1);
+ }
+ else
+ {
+ // The normal border. This is used when the button is not
+ // pressed or the button is not armed.
+ if (! (bmodel.isPressed() && bmodel.isArmed()) )
{
// draw light border
g.setColor(light);
@@ -167,6 +202,8 @@ public class MetalBorders
g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2);
g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
}
+ // The pressed border. This border is painted only when
+ // the button is both pressed and armed.
else
{
// draw light border
@@ -185,12 +222,12 @@ public class MetalBorders
g.drawRect(x + w - 2, y + 1, 0, 0);
}
}
- else
- {
- // draw disabled border
- g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
- g.drawRect(x, y, w - 2, h - 2);
- }
+ }
+ else
+ {
+ // draw disabled border
+ g.setColor(MetalLookAndFeel.getInactiveControlTextColor());
+ g.drawRect(x, y, w - 2, h - 2);
}
}
@@ -219,11 +256,16 @@ public class MetalBorders
if (c.isEnabled())
{
- if (bmodel.isPressed())
+ // Paint the pressed border if the button is pressed, or if
+ // the button is the default button. In the OceanTheme, the default
+ // button has the same border as a pressed button.
+ if (bmodel.isPressed() || ((c instanceof JButton)
+ && ((JButton) c).isDefaultButton()))
{
- // draw fat border
- g.drawLine(x + 1, y + 1, x + w - 2, y + 1);
- g.drawLine(x + 1, y + 1, x + 1, y + h - 2);
+ // Draw fat border.
+ g.setColor(darkShadow);
+ g.drawRect(x, y, w - 1, h - 1);
+ g.drawRect(x + 1, y + 1, w - 3, h - 3);
}
else if (bmodel.isRollover())
{
diff --git a/javax/swing/plaf/metal/MetalButtonUI.java b/javax/swing/plaf/metal/MetalButtonUI.java
index 485424cda..83cd33662 100644
--- a/javax/swing/plaf/metal/MetalButtonUI.java
+++ b/javax/swing/plaf/metal/MetalButtonUI.java
@@ -45,11 +45,13 @@ import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
import javax.swing.plaf.basic.BasicButtonUI;
@@ -159,8 +161,8 @@ public class MetalButtonUI
}
/**
- * Paints the background of the button to indicate that it is in the "pressed"
- * state.
+ * Paints the background of the button to indicate that it is in the
+ * "pressed" state.
*
* @param g the graphics context.
* @param b the button.
@@ -233,9 +235,12 @@ public class MetalButtonUI
public void update(Graphics g, JComponent c)
{
AbstractButton b = (AbstractButton) c;
+ ButtonModel m = b.getModel();
if (b.isContentAreaFilled()
- && UIManager.get(getPropertyPrefix() + "gradient") != null
- && !b.getModel().isPressed() && b.isEnabled())
+ && (UIManager.get(getPropertyPrefix() + "gradient") != null)
+ && ! m.isPressed() && ! m.isArmed()
+ && b.isEnabled()
+ && (b.getBackground() instanceof UIResource))
{
MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(),
SwingConstants.VERTICAL,
diff --git a/javax/swing/plaf/metal/MetalComboBoxButton.java b/javax/swing/plaf/metal/MetalComboBoxButton.java
index b8dd95098..3787a98c3 100644
--- a/javax/swing/plaf/metal/MetalComboBoxButton.java
+++ b/javax/swing/plaf/metal/MetalComboBoxButton.java
@@ -112,6 +112,7 @@ public class MetalComboBoxButton
iconOnly = onlyIcon;
listBox = list;
rendererPane = pane;
+ setRolloverEnabled(false);
setEnabled(comboBox.isEnabled());
setFocusable(comboBox.isEnabled());
}
@@ -187,7 +188,7 @@ public class MetalComboBoxButton
*/
public boolean isFocusTraversable()
{
- return !comboBox.isEditable() && comboBox.isEnabled();
+ return false;
}
/**
@@ -198,8 +199,16 @@ public class MetalComboBoxButton
public void setEnabled(boolean enabled)
{
super.setEnabled(enabled);
- // TODO: figure out what this might need to be used for
- // perhaps it has something to do with the button's icon and/or border?
+ if (enabled)
+ {
+ setBackground(comboBox.getBackground());
+ setForeground(comboBox.getForeground());
+ }
+ else
+ {
+ setBackground(UIManager.getColor("ComboBox.disabledBackground"));
+ setForeground(UIManager.getColor("ComboBox.disabledForeground"));
+ }
}
/**
diff --git a/javax/swing/plaf/metal/MetalComboBoxEditor.java b/javax/swing/plaf/metal/MetalComboBoxEditor.java
index fb25644fa..11e415103 100644
--- a/javax/swing/plaf/metal/MetalComboBoxEditor.java
+++ b/javax/swing/plaf/metal/MetalComboBoxEditor.java
@@ -39,6 +39,7 @@ exception statement from your version. */
package javax.swing.plaf.metal;
import java.awt.Component;
+import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
@@ -79,16 +80,31 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor
int h)
{
g.translate(x, y);
- g.setColor(MetalLookAndFeel.getControlDarkShadow());
- g.drawLine(0, 0, w - 1, 0);
- g.drawLine(0, 0, 0, h - 2);
- g.drawLine(0, h - 2, w - 1, h - 2);
- g.setColor(MetalLookAndFeel.getControlHighlight());
- g.drawLine(1, 1, w - 1, 1);
- g.drawLine(1, 1, 1, h - 1);
- g.drawLine(1, h - 1, w - 1, h - 1);
- g.setColor(MetalLookAndFeel.getControl());
- g.drawLine(1, h - 2, 1, h - 2);
+ if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)
+ {
+ g.setColor(MetalLookAndFeel.getControlDarkShadow());
+ g.drawLine(0, 0, w - 1, 0);
+ g.drawLine(0, 0, 0, h - 1);
+ g.drawLine(0, h - 1, w - 1, h - 1);
+ g.setColor(MetalLookAndFeel.getControlShadow());
+ g.drawLine(1, 1, w - 2, 1);
+ g.drawLine(1, 1, 1, h - 2);
+ g.drawLine(1, h - 2, w - 1, h - 2);
+ g.drawLine(w - 1, 1, w - 1, h - 2);
+ }
+ else
+ {
+ g.setColor(MetalLookAndFeel.getControlDarkShadow());
+ g.drawLine(0, 0, w - 1, 0);
+ g.drawLine(0, 0, 0, h - 2);
+ g.drawLine(0, h - 2, w - 1, h - 2);
+ g.setColor(MetalLookAndFeel.getControlHighlight());
+ g.drawLine(1, 1, w - 1, 1);
+ g.drawLine(1, 1, 1, h - 1);
+ g.drawLine(1, h - 1, w - 1, h - 1);
+ g.setColor(MetalLookAndFeel.getControl());
+ g.drawLine(1, h - 2, 1, h - 2);
+ }
g.translate(-x, -y);
}
@@ -125,7 +141,40 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor
// Nothing to do here.
}
}
-
+
+ /**
+ * A special textfield implementation for the MetalComboBoxEditor.
+ */
+ private class EditorTextField extends JTextField
+ {
+ EditorTextField(String s, int columns)
+ {
+ super(s, columns);
+ }
+
+ /**
+ * Tests seem to show that the textfield in MetalComboBoxEditors have
+ * a height + 4.
+ */
+ public Dimension getPreferredSize()
+ {
+ Dimension size = super.getPreferredSize();
+ size.height += 4;
+ return size;
+ }
+
+ /**
+ * Tests seem to show that the textfield in MetalComboBoxEditors have
+ * a height + 4.
+ */
+ public Dimension getMinimumSize()
+ {
+ Dimension size = super.getMinimumSize();
+ size.height += 4;
+ return size;
+ }
+ }
+
/** The editor's border insets. */
protected static Insets editorBorderInsets = new Insets(2, 2, 2, 0);
@@ -134,7 +183,7 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor
*/
public MetalComboBoxEditor()
{
- super();
+ editor = new EditorTextField("", 9);
editor.setBorder(new MetalComboBoxEditorBorder());
}
diff --git a/javax/swing/plaf/metal/MetalComboBoxUI.java b/javax/swing/plaf/metal/MetalComboBoxUI.java
index 0266d34f8..c24c08505 100644
--- a/javax/swing/plaf/metal/MetalComboBoxUI.java
+++ b/javax/swing/plaf/metal/MetalComboBoxUI.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing.plaf.metal;
+import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -130,7 +131,7 @@ public class MetalComboBoxUI extends BasicComboBoxUI
String name = e.getPropertyName();
if (name.equals("editable"))
editablePropertyChanged(e);
- if (name.equals("enabled"))
+ else if (name.equals("enabled"))
{
if (arrowButton instanceof MetalComboBoxButton)
{
@@ -139,6 +140,18 @@ public class MetalComboBoxUI extends BasicComboBoxUI
comboBox.repaint();
}
}
+ else if (name.equals("background"))
+ {
+ Color c = (Color) e.getNewValue();
+ arrowButton.setBackground(c);
+ listBox.setBackground(c);
+ }
+ else if (name.equals("foreground"))
+ {
+ Color c = (Color) e.getNewValue();
+ arrowButton.setForeground(c);
+ listBox.setForeground(c);
+ }
}
}
@@ -306,14 +319,8 @@ public class MetalComboBoxUI extends BasicComboBoxUI
{
d = super.getMinimumSize(c);
Insets arrowMargin = arrowButton.getMargin();
- Insets comboInsets = comboBox.getInsets();
- if (editor instanceof JComponent)
- {
- Insets editorInsets = ((JComponent) editor).getInsets();
- d.height += editorInsets.top + editorInsets.bottom;
- }
d.height += arrowMargin.top + arrowMargin.bottom;
- d.height += comboInsets.top + comboInsets.bottom;
+ d.width += arrowMargin.left + arrowMargin.right;
}
else
{
diff --git a/javax/swing/plaf/metal/MetalDesktopIconUI.java b/javax/swing/plaf/metal/MetalDesktopIconUI.java
index ecbb76e6e..0c1163a8e 100644
--- a/javax/swing/plaf/metal/MetalDesktopIconUI.java
+++ b/javax/swing/plaf/metal/MetalDesktopIconUI.java
@@ -1,5 +1,5 @@
/* MetalDesktopIconUI.java
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -50,10 +50,6 @@ public class MetalDesktopIconUI
extends BasicDesktopIconUI
{
- // FIXME: maybe replace by a Map of instances when this becomes stateful
- /** The shared UI instance for MetalDesktopIcons */
- private static MetalDesktopIconUI instance = null;
-
/**
* Constructs a new instance of <code>MetalDesktopIconUI</code>.
*/
@@ -63,16 +59,14 @@ public class MetalDesktopIconUI
}
/**
- * Returns a shared instance of <code>MetalDesktopIconUI</code>.
+ * Returns a new <code>MetalDesktopIconUI</code> instance.
*
- * @param component the component for which we return an UI instance
+ * @param component the component (ignored).
*
- * @return A shared instance of <code>MetalDesktopIconUI</code>.
+ * @return A new <code>MetalDesktopIconUI</code> instance.
*/
public static ComponentUI createUI(JComponent component)
{
- if (instance == null)
- instance = new MetalDesktopIconUI();
- return instance;
+ return new MetalDesktopIconUI();
}
}
diff --git a/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java
index 534f0ca34..f74828e56 100644
--- a/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java
+++ b/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java
@@ -93,7 +93,11 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane
public void propertyChange(PropertyChangeEvent e)
{
String propName = e.getPropertyName();
- if (propName.equals("JInternalFrame.isPalette"))
+ if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY))
+ {
+ title.setIcon( frame.getFrameIcon() );
+ }
+ else if (propName.equals("JInternalFrame.isPalette"))
{
if (e.getNewValue().equals(Boolean.TRUE))
setPalette(true);
@@ -262,7 +266,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane
paletteTitleHeight = UIManager.getInt("InternalFrame.paletteTitleHeight");
paletteCloseIcon = UIManager.getIcon("InternalFrame.paletteCloseIcon");
minIcon = MetalIconFactory.getInternalFrameAltMaximizeIcon(16);
-
+
title = new JLabel(frame.getTitle(),
MetalIconFactory.getInternalFrameDefaultMenuIcon(),
SwingConstants.LEFT);
@@ -383,8 +387,8 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane
paintPalette(g);
else
{
- paintTitleBackground(g);
- paintChildren(g);
+ paintTitleBackground(g);
+ paintChildren(g);
Dimension d = getSize();
if (frame.isSelected())
g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow());
diff --git a/javax/swing/plaf/metal/MetalLookAndFeel.java b/javax/swing/plaf/metal/MetalLookAndFeel.java
index 38b357219..7a973d46e 100644
--- a/javax/swing/plaf/metal/MetalLookAndFeel.java
+++ b/javax/swing/plaf/metal/MetalLookAndFeel.java
@@ -1204,7 +1204,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"Table.focusCellForeground", getControlTextColor(),
"Table.foreground", getControlTextColor(),
"Table.focusCellHighlightBorder",
- new BorderUIResource.LineBorderUIResource(getControlShadow()),
+ new BorderUIResource.LineBorderUIResource(getFocusColor()),
"Table.focusCellBackground", getWindowBackground(),
"Table.gridColor", getControlDarkShadow(),
"Table.selectionBackground", new ColorUIResource(204, 204, 255),
diff --git a/javax/swing/plaf/metal/MetalRootPaneUI.java b/javax/swing/plaf/metal/MetalRootPaneUI.java
index 23051e9bc..6cabc7e86 100644
--- a/javax/swing/plaf/metal/MetalRootPaneUI.java
+++ b/javax/swing/plaf/metal/MetalRootPaneUI.java
@@ -47,11 +47,11 @@ import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
+import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
-import java.awt.event.WindowEvent;
-import java.awt.event.WindowFocusListener;
+import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import javax.swing.AbstractAction;
@@ -70,6 +70,7 @@ import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.AbstractBorder;
+import javax.swing.event.MouseInputAdapter;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicRootPaneUI;
@@ -191,6 +192,50 @@ public class MetalRootPaneUI
*/
private static class MetalTitlePane extends JComponent
{
+
+ /**
+ * Handles dragging of the title pane and moves the window accordingly.
+ */
+ private class MouseHandler
+ extends MouseInputAdapter
+ {
+ /**
+ * The point where the dragging started.
+ */
+ Point lastDragLocation;
+
+ /**
+ * Receives notification when the mouse gets pressed on the title pane.
+ * This updates the lastDragLocation.
+ *
+ * @param ev the mouse event
+ */
+ public void mousePressed(MouseEvent ev)
+ {
+ lastDragLocation = ev.getPoint();
+ }
+
+ /**
+ * Receives notification when the mouse is dragged on the title pane.
+ * This will move the nearest window accordingly.
+ *
+ * @param ev the mouse event
+ */
+ public void mouseDragged(MouseEvent ev)
+ {
+ Point dragLocation = ev.getPoint();
+ int deltaX = dragLocation.x - lastDragLocation.x;
+ int deltaY = dragLocation.y - lastDragLocation.y;
+ Window window = SwingUtilities.getWindowAncestor(rootPane);
+ Point loc = window.getLocation();
+ window.setLocation(loc.x + deltaX, loc.y + deltaY);
+ // Note that we do not update the lastDragLocation. This is because
+ // we move the underlying window while dragging the component, which
+ // results in having the same lastDragLocation under the mouse while
+ // dragging.
+ }
+ }
+
/**
* The Action responsible for closing the JInternalFrame.
*/
@@ -255,6 +300,45 @@ public class MetalRootPaneUI
}
/**
+ * This action is performed when the iconify button is pressed.
+ */
+ private class IconifyAction
+ extends AbstractAction
+ {
+
+ public void actionPerformed(ActionEvent event)
+ {
+ Window w = SwingUtilities.getWindowAncestor(rootPane);
+ if (w instanceof Frame)
+ {
+ Frame f = (Frame) w;
+ int state = f.getExtendedState();
+ f.setExtendedState(Frame.ICONIFIED);
+ }
+ }
+
+ }
+
+ /**
+ * This action is performed when the maximize button is pressed.
+ */
+ private class MaximizeAction
+ extends AbstractAction
+ {
+
+ public void actionPerformed(ActionEvent event)
+ {
+ Window w = SwingUtilities.getWindowAncestor(rootPane);
+ if (w instanceof Frame)
+ {
+ Frame f = (Frame) w;
+ int state = f.getExtendedState();
+ f.setExtendedState(Frame.MAXIMIZED_BOTH);
+ }
+ }
+ }
+
+ /**
* This helper class is used to create the minimize, maximize and close
* buttons in the top right corner of the Title Pane. These buttons are
* special since they cannot be given focus and have no border.
@@ -499,23 +583,16 @@ public class MetalRootPaneUI
private void installListeners()
{
- Window window = SwingUtilities.getWindowAncestor(rootPane);
- window.addWindowFocusListener(new WindowFocusListener()
- {
- public void windowGainedFocus(WindowEvent ev)
- {
- repaint();
- }
- public void windowLostFocus(WindowEvent ev)
- {
- repaint();
- }
- });
+ MouseInputAdapter mouseHandler = new MouseHandler();
+ addMouseListener(mouseHandler);
+ addMouseMotionListener(mouseHandler);
}
private void createActions()
{
closeAction = new CloseAction();
+ iconifyAction = new IconifyAction();
+ maximizeAction = new MaximizeAction();
}
private void assembleSystemMenu()
@@ -699,6 +776,21 @@ public class MetalRootPaneUI
*/
private Dimension prefSize;
+ /**
+ * The title pane for l&f decorated frames.
+ */
+ private MetalTitlePane titlePane;
+
+ /**
+ * Creates a new MetalRootLayout.
+ *
+ * @param tp the title pane
+ */
+ MetalRootLayout(MetalTitlePane tp)
+ {
+ titlePane = tp;
+ }
+
public void addLayoutComponent(Component component, Object constraints)
{
// Nothing to do here.
@@ -747,12 +839,8 @@ public class MetalRootPaneUI
{
JRootPane rp = (JRootPane) parent;
JLayeredPane layeredPane = rp.getLayeredPane();
- Component contentPane = layeredPane.getComponent(0);
- Component titlePane = layeredPane.getComponent(1);
- Component menuBar = null;
- if (layeredPane.getComponentCount() > 2
- && layeredPane.getComponent(2) instanceof JMenuBar)
- menuBar = layeredPane.getComponent(2);
+ Component contentPane = rp.getContentPane();
+ Component menuBar = rp.getJMenuBar();
// We must synchronize here, otherwise we cannot guarantee that the
// prefSize is still non-null when returning.
@@ -789,12 +877,8 @@ public class MetalRootPaneUI
{
JRootPane rp = (JRootPane) parent;
JLayeredPane layeredPane = rp.getLayeredPane();
- Component contentPane = layeredPane.getComponent(0);
- Component titlePane = layeredPane.getComponent(1);
- Component menuBar = null;
- if (layeredPane.getComponentCount() > 2
- && layeredPane.getComponent(2) instanceof JMenuBar)
- menuBar = layeredPane.getComponent(2);
+ Component contentPane = rp.getContentPane();
+ Component menuBar = rp.getJMenuBar();
Component glassPane = rp.getGlassPane();
if (glassPaneBounds == null || layeredPaneBounds == null
@@ -937,6 +1021,7 @@ public class MetalRootPaneUI
*/
public void propertyChange(PropertyChangeEvent ev)
{
+ super.propertyChange(ev);
String propertyName = ev.getPropertyName();
if (propertyName.equals("windowDecorationStyle"))
{
@@ -958,12 +1043,14 @@ public class MetalRootPaneUI
private void installWindowDecorations(JRootPane rp)
{
rp.setBorder(new MetalFrameBorder());
- rp.setLayout(new MetalRootLayout());
+ MetalTitlePane titlePane = new MetalTitlePane(rp);
+ rp.setLayout(new MetalRootLayout(titlePane));
// We should have a contentPane already.
- assert rp.getLayeredPane().getComponentCount() == 1
+ assert rp.getLayeredPane().getComponentCount() > 0
: "We should have a contentPane already";
- rp.getLayeredPane().add(new MetalTitlePane(rp),
- JLayeredPane.FRAME_CONTENT_LAYER);
+
+ rp.getLayeredPane().add(titlePane,
+ JLayeredPane.FRAME_CONTENT_LAYER, 1);
}
/**
@@ -975,6 +1062,14 @@ public class MetalRootPaneUI
private void uninstallWindowDecorations(JRootPane rp)
{
rp.setBorder(null);
- rp.getLayeredPane().remove(1);
+ JLayeredPane lp = rp.getLayeredPane();
+ for (int i = lp.getComponentCount() - 1; i >= 0; --i)
+ {
+ if (lp.getComponent(i) instanceof MetalTitlePane)
+ {
+ lp.remove(i);
+ break;
+ }
+ }
}
}
diff --git a/javax/swing/plaf/metal/MetalSliderUI.java b/javax/swing/plaf/metal/MetalSliderUI.java
index 9b2f45cc7..f97717f31 100644
--- a/javax/swing/plaf/metal/MetalSliderUI.java
+++ b/javax/swing/plaf/metal/MetalSliderUI.java
@@ -1,5 +1,5 @@
/* MetalSliderUI.java
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -210,7 +210,7 @@ public class MetalSliderUI extends BasicSliderUI
{
int trackX = trackRect.x;
int trackY = trackRect.y + (trackRect.height - getTrackWidth()) / 2;
- int trackW = trackRect.width - 1;
+ int trackW = trackRect.width;
int trackH = getTrackWidth();
// draw border
@@ -264,7 +264,7 @@ public class MetalSliderUI extends BasicSliderUI
int trackX = trackRect.x + (trackRect.width - getTrackWidth()) / 2;
int trackY = trackRect.y;
int trackW = getTrackWidth();
- int trackH = trackRect.height - 1;
+ int trackH = trackRect.height;
if (slider.isEnabled())
BasicGraphicsUtils.drawEtchedRect(g, trackX, trackY, trackW, trackH,
darkShadowColor, shadowColor, darkShadowColor, highlightColor);
diff --git a/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/javax/swing/plaf/metal/MetalTabbedPaneUI.java
index c6c46ffe6..39dec3d66 100644
--- a/javax/swing/plaf/metal/MetalTabbedPaneUI.java
+++ b/javax/swing/plaf/metal/MetalTabbedPaneUI.java
@@ -47,6 +47,7 @@ import javax.swing.JComponent;
import javax.swing.JTabbedPane;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTabbedPaneUI;
/**
@@ -101,6 +102,17 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
// do nothing, because the selected tab does not have extra padding in
// the MetalLookAndFeel
}
+
+ /**
+ * Overridden because tab runs are only normalized for TOP and BOTTOM
+ * tab placement in the Metal L&F.
+ */
+ protected void normalizeTabRuns(int tabPlacement, int tabCount, int start,
+ int max)
+ {
+ if (tabPlacement == TOP || tabPlacement == BOTTOM)
+ super.normalizeTabRuns(tabPlacement, tabCount, start, max);
+ }
}
/**
@@ -125,7 +137,12 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
/** The graphics to draw the highlight below the tab. */
private Graphics hg;
-
+
+ /**
+ * Indicates if the tabs are having their background filled.
+ */
+ private boolean tabsOpaque;
+
/**
* Constructs a new instance of MetalTabbedPaneUI.
*/
@@ -153,7 +170,7 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
*/
protected LayoutManager createLayoutManager()
{
- return super.createLayoutManager();
+ return new TabbedPaneLayout();
}
/**
@@ -172,16 +189,24 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
protected void paintTabBorder(Graphics g, int tabPlacement, int tabIndex,
int x, int y, int w, int h, boolean isSelected)
{
- if (tabPlacement == TOP)
- paintTopTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected);
- else if (tabPlacement == LEFT)
- paintLeftTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected);
- else if (tabPlacement == BOTTOM)
- paintBottomTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected);
- else if (tabPlacement == RIGHT)
- paintRightTabBorder(tabIndex, g, x, y, w, h, 0, 0, isSelected);
- else
- throw new AssertionError("Unrecognised 'tabPlacement' argument.");
+ int bottom = y + h - 1;
+ int right = x + w - 1;
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ paintLeftTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ break;
+ case BOTTOM:
+ paintBottomTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ break;
+ case RIGHT:
+ paintRightTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ break;
+ case TOP:
+ default:
+ paintTopTabBorder(tabIndex, g, x, y, w, h, bottom, right, isSelected);
+ }
}
/**
@@ -194,35 +219,90 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
* @param y the y-coordinate for the tab's bounding rectangle.
* @param w the width for the tab's bounding rectangle.
* @param h the height for the tab's bounding rectangle.
- * @param btm ???
- * @param rght ???
+ * @param btm the y coordinate of the bottom border
+ * @param rght the x coordinate of the right border
* @param isSelected indicates whether the tab is selected.
*/
protected void paintTopTabBorder(int tabIndex, Graphics g, int x, int y,
int w, int h, int btm, int rght, boolean isSelected)
{
- int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex);
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ int right = w - 1;
+ int bottom = h - 1;
+
+ // Paint gap.
if (shouldFillGap(currentRun, tabIndex, x, y))
{
g.translate(x, y);
- g.setColor(getColorForGap(currentRun, x, y));
+ g.setColor(getColorForGap(currentRun, x, y + 1));
g.fillRect(1, 0, 5, 3);
g.fillRect(1, 3, 2, 2);
g.translate(-x, -y);
}
-
- if (isSelected)
- {
- g.setColor(MetalLookAndFeel.getControlHighlight());
- g.drawLine(x + 1, y + h, x + 1, y + 6);
- g.drawLine(x + 1, y + 6, x + 6, y + 1);
- g.drawLine(x + 6, y + 1, x + w - 1, y + 1);
- }
- g.setColor(MetalLookAndFeel.getControlDarkShadow());
- g.drawLine(x, y + h - 1, x, y + 6);
- g.drawLine(x, y + 6, x + 6, y);
- g.drawLine(x + 6, y, x + w, y);
- g.drawLine(x + w, y, x + w, y + h - 1);
+
+ g.translate(x, y);
+
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ g.setColor(oceanSelectedBorder);
+ else
+ g.setColor(darkShadow);
+
+ // Slant
+ g.drawLine(1, 5, 6, 0);
+ // Top.
+ g.drawLine(6, 0, right, 0);
+ // Right.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ g.drawLine(right, 1, right, bottom);
+ // Left.
+ int selectedIndex = tabPane.getSelectedIndex();
+ if (isOcean && tabIndex - 1 == selectedIndex
+ && currentRun == getRunForTab(tabCount, selectedIndex))
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ if (tabIndex != tabRuns[runCount - 1])
+ {
+ if (isOcean && isSelected)
+ {
+ g.drawLine(0, 6, 0, bottom);
+ g.setColor(darkShadow);
+ g.drawLine(0, 0, 0, 5);
+ }
+ else
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ }
+ else
+ {
+ g.drawLine(0, 6, 0, bottom);
+ }
+
+ // Paint the highlight.
+ g.setColor(isSelected ? selectHighlight : highlight);
+ // Slant.
+ g.drawLine(1, 6, 6, 1);
+ // Top.
+ g.drawLine(6, 1, right, 1);
+ // Left.
+ g.drawLine(1, 6, 1, bottom);
+ int firstIndex = tabRuns[currentRun];
+ if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1])
+ {
+ if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1])
+ g.setColor(selectHighlight);
+ else
+ g.setColor(highlight);
+ g.drawLine(1, 0, 1, 4);
+ }
+
+ g.translate(-x, -y);
}
/**
@@ -242,18 +322,115 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
protected void paintLeftTabBorder(int tabIndex, Graphics g, int x, int y,
int w, int h, int btm, int rght, boolean isSelected)
{
- if (isSelected)
- {
- g.setColor(MetalLookAndFeel.getControlHighlight());
- g.drawLine(x + 1, y + h, x + 1, y + 6);
- g.drawLine(x + 1, y + 6, x + 6, y + 1);
- g.drawLine(x + 6, y + 1, x + w - 1, y + 1);
- }
- g.setColor(MetalLookAndFeel.getControlDarkShadow());
- g.drawLine(x, y + h, x, y + 6);
- g.drawLine(x, y + 6, x + 6, y);
- g.drawLine(x + 6, y, x + w - 1, y);
- g.drawLine(x, y + h, x + w - 1, y + h);
+ g.translate(x, y);
+ int bottom = h - 1;
+ int right = w - 1;
+
+
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ int firstIndex = tabRuns[currentRun];
+
+ // Paint the part of the above tab.
+ if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque)
+ {
+ Color c;
+ if (tabPane.getSelectedIndex() == tabIndex - 1)
+ c = selectColor;
+ else
+ c = getUnselectedBackground(tabIndex - 1);
+ g.setColor(c);
+ g.fillRect(2, 0, 4, 3);
+ g.drawLine(2, 3, 2, 3);
+ }
+
+ // Paint the highlight.
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ if (isOcean)
+ {
+ g.setColor(isSelected ? selectHighlight : MetalLookAndFeel.getWhite());
+ }
+ else
+ {
+ g.setColor(isSelected ? selectHighlight : highlight);
+ }
+ // Slant.
+ g.drawLine(1, 6, 6, 1);
+ // Left.
+ g.drawLine(1, 6, 1, bottom);
+ // Top.
+ g.drawLine(6, 1, right, 1);
+ if (tabIndex != firstIndex)
+ {
+ if (isOcean)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ }
+ g.drawLine(1, 0, 1, 4);
+ }
+
+ // Paint border.
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(darkShadow);
+ }
+
+ // Slant.
+ g.drawLine(1, 5, 6, 0);
+ // Top.
+ g.drawLine(6, 0, right, 0);
+ // Bottom.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ {
+ g.drawLine(0, bottom, right, bottom);
+ }
+ // Left.
+ if (isOcean)
+ {
+ if (tabPane.getSelectedIndex() == tabIndex - 1)
+ {
+ g.drawLine(0, 5, 0, bottom);
+ g.setColor(oceanSelectedBorder);
+ g.drawLine(0, 0, 0, 5);
+ }
+ else if (isSelected)
+ {
+ g.drawLine(0, 5, 0, bottom);
+ if (tabIndex != 0)
+ {
+ g.setColor(darkShadow);
+ g.drawLine(0, 0, 0, 5);
+ }
+ }
+ else if (tabIndex != firstIndex)
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ else
+ {
+ g.drawLine(0, 6, 0, bottom);
+ }
+ }
+ else
+ {
+ if (tabIndex != firstIndex)
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ else
+ {
+ g.drawLine(0, 6, 0, bottom);
+ }
+ }
+
+ g.translate(-x, -y);
}
/**
@@ -273,17 +450,92 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
protected void paintRightTabBorder(int tabIndex, Graphics g, int x, int y,
int w, int h, int btm, int rght, boolean isSelected)
{
- if (isSelected)
- {
- g.setColor(MetalLookAndFeel.getControlHighlight());
- g.drawLine(x, y + 1, x + w - 7, y + 1);
- g.drawLine(x + w - 7, y + 1, x + w - 1, y + 7);
- }
- g.setColor(MetalLookAndFeel.getControlDarkShadow());
- g.drawLine(x, y, x + w - 7, y);
- g.drawLine(x + w - 7, y, x + w - 1, y + 6);
- g.drawLine(x + w - 1, y + 6, x + w - 1, y + h - 1);
- g.drawLine(x + w - 1, y + h, x, y + h);
+ g.translate(x, y);
+ int bottom = h - 1;
+ int right = w - 1;
+
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ int firstIndex = tabRuns[currentRun];
+
+ // Paint part of the above tab.
+ if (tabIndex != firstIndex && tabIndex > 0 && tabsOpaque)
+ {
+ Color c;
+ if (tabPane.getSelectedIndex() == tabIndex - 1)
+ c = UIManager.getColor("TabbedPane.tabAreaBackground");
+ else
+ c = getUnselectedBackground(tabIndex - 1);
+ g.fillRect(right - 5, 0, 5, 3);
+ g.fillRect(right - 2, 3, 2, 2);
+ }
+
+ // Paint highlight.
+ g.setColor(isSelected ? selectHighlight : highlight);
+
+ // Slant.
+ g.drawLine(right - 6, 1, right - 1, 6);
+ // Top.
+ g.drawLine(0, 1, right - 6, 1);
+ // Left.
+ if (! isSelected)
+ {
+ g.drawLine(0, 1, 0, bottom);
+ }
+
+ // Paint border.
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(darkShadow);
+ }
+
+ // Bottom.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ {
+ g.drawLine(0, bottom, right, bottom);
+ }
+ // Slant.
+ if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(right - 6, 0, right, 6);
+ // Top.
+ g.drawLine(0, 0, right - 6, 0);
+ // Right.
+ if (isOcean && isSelected)
+ {
+ g.drawLine(right, 6, right, bottom);
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(darkShadow);
+ g.drawLine(right, 0, right, 5);
+ }
+ }
+ else if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1)
+ {
+ g.setColor(oceanSelectedBorder);
+ g.drawLine(right, 0, right, 6);
+ g.setColor(darkShadow);
+ g.drawLine(right, 6, right, bottom);
+ }
+ else if (tabIndex != firstIndex)
+ {
+ g.drawLine(right, 0, right, bottom);
+ }
+ else
+ {
+ g.drawLine(right, 6, right, bottom);
+ }
+ g.translate(-x, -y);
}
/**
@@ -303,27 +555,94 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
protected void paintBottomTabBorder(int tabIndex, Graphics g, int x, int y,
int w, int h, int btm, int rght, boolean isSelected)
{
- int currentRun = getRunForTab(tabPane.getTabCount(), tabIndex);
+ int bottom = h - 1;
+ int right = w - 1;
+
+ int tabCount = tabPane.getTabCount();
+ int currentRun = getRunForTab(tabCount, tabIndex);
+ // Paint gap if necessary.
if (shouldFillGap(currentRun, tabIndex, x, y))
{
g.translate(x, y);
g.setColor(getColorForGap(currentRun, x, y));
- g.fillRect(1, h - 5, 3, 5);
- g.fillRect(4, h - 2, 2, 2);
+ g.fillRect(1, bottom - 4, 3, 5);
+ g.fillRect(4, bottom - 1, 2, 2);
g.translate(-x, -y);
}
-
- if (isSelected)
- {
- g.setColor(MetalLookAndFeel.getControlHighlight());
- g.drawLine(x + 1, y, x + 1, y + h - 7);
- g.drawLine(x + 1, y + h - 7, x + 7, y + h - 1);
- }
- g.setColor(MetalLookAndFeel.getControlDarkShadow());
- g.drawLine(x, y, x, y + h - 7);
- g.drawLine(x, y + h - 7, x + 6, y + h - 1);
- g.drawLine(x + 6, y + h - 1, x + w, y + h - 1);
- g.drawLine(x + w, y + h - 1, x + w, y);
+
+ g.translate(x, y);
+
+ // Paint border.
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (isOcean && isSelected)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(darkShadow);
+ }
+ // Slant.
+ g.drawLine(1, bottom - 5, 6, bottom);
+ // Bottom.
+ g.drawLine(6, bottom, right, bottom);
+ // Right.
+ int lastIndex = lastTabInRun(tabCount, currentRun);
+ if (tabIndex == lastIndex)
+ {
+ g.drawLine(right, 0, right, bottom);
+ }
+ // Left.
+ if (isOcean && isSelected)
+ {
+ g.drawLine(0, 0, 0, bottom - 5);
+ if ((currentRun == 0 && tabIndex != 0)
+ || (currentRun > 0 && tabIndex != tabRuns[currentRun - 1]))
+ {
+ g.setColor(darkShadow);
+ g.drawLine(0, bottom - 5, 0, bottom);
+ }
+ }
+ else
+ {
+ if (isOcean && tabIndex == tabPane.getSelectedIndex()+ 1)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ if (tabIndex != tabRuns[runCount- 1])
+ {
+ g.drawLine(0, 0, 0, bottom);
+ }
+ else
+ {
+ g.drawLine(0, 0, 0, bottom - 6);
+ }
+ }
+
+ // Paint highlight.
+ g.setColor(isSelected ? selectHighlight : highlight);
+ // Slant.
+ g.drawLine(1, bottom - 6, 6, bottom - 1);
+ // Left.
+ g.drawLine(1, 0, 1, bottom - 6);
+
+ int firstIndex = tabRuns[currentRun];
+ if (tabIndex == firstIndex && tabIndex != tabRuns[runCount - 1])
+ {
+ if (tabPane.getSelectedIndex() == tabRuns[currentRun + 1])
+ {
+ g.setColor(selectHighlight);
+ }
+ else
+ {
+ g.setColor(highlight);
+ }
+ g.drawLine(1, bottom - 4, 1, bottom);
+ }
+
+ g.translate(-x, -y);
}
/**
@@ -343,42 +662,29 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
int tabIndex, int x, int y, int w, int h, boolean isSelected)
{
if (isSelected)
- g.setColor(UIManager.getColor("TabbedPane.selected"));
+ g.setColor(selectColor);
else
- {
- // This is only present in the OceanTheme, so we must check if it
- // is actually there
- Color background = UIManager.getColor("TabbedPane.unselectedBackground");
- if (background == null)
- background = UIManager.getColor("TabbedPane.background");
- g.setColor(background);
- }
- int[] px, py;
- if (tabPlacement == TOP)
- {
- px = new int[] {x + 6, x + w - 1, x + w -1, x + 2, x + 2};
- py = new int[] {y + 2, y + 2, y + h - 1, y + h -1, y + 6};
- }
- else if (tabPlacement == LEFT)
- {
- px = new int[] {x + 6, x + w - 1, x + w -1, x + 2, x + 2};
- py = new int[] {y + 2, y + 2, y + h - 1, y + h -1, y + 6};
- }
- else if (tabPlacement == BOTTOM)
- {
- px = new int[] {x + 2, x + w - 1, x + w -1, x + 8, x + 2};
- py = new int[] {y, y, y + h - 1, y + h -1, y + h - 7};
- }
- else if (tabPlacement == RIGHT)
- {
- px = new int[] {x + 2, x + w - 7, x + w - 1, x + w - 1, x + 2};
- py = new int[] {y + 2, y + 2, y + 7, y + h -1, y + h - 1};
- }
- else
- throw new AssertionError("Unrecognised 'tabPlacement' argument.");
- g.fillPolygon(px, py, 5);
- hg = g;
- paintHighlightBelowTab();
+ g.setColor(getUnselectedBackground(tabIndex));
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ g.fillRect(x + 5, y + 1, w - 5, h - 1);
+ g.fillRect(x + 2, y + 4, 3, h - 4);
+ break;
+ case BOTTOM:
+ g.fillRect(x + 2, y, w - 2, h - 3);
+ g.fillRect(x + 5, y + h - 4, w - 5, 3);
+ break;
+ case RIGHT:
+ g.fillRect(x, y + 1, w - 4, h - 1);
+ g.fillRect(x + w - 4, y + 5, 3, h - 5);
+ break;
+ case TOP:
+ default:
+ g.fillRect(x + 4, y + 2, w - 4, h - 2);
+ g.fillRect(x + 2, y + 5, 2, h - 5);
+ }
}
/**
@@ -408,6 +714,7 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
selectColor = UIManager.getColor("TabbedPane.selected");
selectHighlight = UIManager.getColor("TabbedPane.selectHighlight");
tabAreaBackground = UIManager.getColor("TabbedPane.tabAreaBackground");
+ tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
minTabWidth = 0;
}
@@ -487,4 +794,354 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
// false because tab runs are not rotated in the MetalLookAndFeel
return false;
}
+
+ protected int calculateMaxTabHeight(int tabPlacement)
+ {
+ // FIXME: Why is this overridden?
+ return super.calculateMaxTabHeight(tabPlacement);
+ }
+
+ /**
+ * Returns the amount of overlay among the tabs. In
+ * the Metal L&F the overlay for LEFT and RIGHT placement
+ * is half of the maxTabHeight. For TOP and BOTTOM placement
+ * the tabs do not overlay.
+ *
+ * @param tabPlacement the placement
+ *
+ * @return the amount of overlay among the tabs
+ */
+ protected int getTabRunOverlay(int tabPlacement)
+ {
+ int overlay = 0;
+ if (tabPlacement == LEFT || tabPlacement == RIGHT)
+ {
+ int maxHeight = calculateMaxTabHeight(tabPlacement);
+ overlay = maxTabHeight / 2;
+ }
+ return overlay;
+ }
+
+ /**
+ * Paints the upper edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of the content area
+ * @param w the width of the content area
+ * @param h the height of the content area
+ */
+ protected void paintContentBorderTopEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y,
+ int w, int h)
+ {
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(selectHighlight);
+ }
+
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+
+ // If tabs are not placed on TOP, or if the selected tab is not in the
+ // run directly above the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ if (tabPlacement != TOP || selectedIndex < 0
+ || rect.y + rect.height + 1 < y || rect.x < x ||rect.x > x + w)
+ {
+ g.drawLine(x, y, x + w - 2, y);
+ if (isOcean && tabPlacement == TOP)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ g.drawLine(x, y + 1, x + w - 2, y + 1);
+ }
+ }
+ else
+ {
+ boolean isLast = isLastTabInRun(selectedIndex);
+ if (isLast)
+ {
+ g.drawLine(x, y, rect.x + 1, y);
+ }
+ else
+ {
+ g.drawLine(x, y, rect.x, y);
+ }
+
+ int right = x + w - 1;
+ if (rect.x + rect.width < right - 1)
+ {
+ if (isLast)
+ {
+ g.drawLine(rect.x + rect.width - 1, y, right - 1, y);
+ }
+ else
+ {
+ g.drawLine(rect.x + rect.width, y, right - 1, y);
+ }
+ }
+ else
+ {
+ g.setColor(shadow);
+ g.drawLine(x + w - 2, y, x + w - 2, y);
+ }
+
+ // When in OceanTheme, draw another white line.
+ if (isOcean)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ if (isLast)
+ {
+ g.drawLine(x, y + 1, rect.x + 1, y + 1);
+ }
+ else
+ {
+ g.drawLine(x, y + 1, rect.x, y + 1);
+ }
+
+ if (rect.x + rect.width < right - 1)
+ {
+ if (isLast)
+ {
+ g.drawLine(rect.x + rect.width - 1, y + 1, right - 1,
+ y + 1);
+ }
+ else
+ {
+ g.drawLine(rect.x + rect.width, y + 1, right - 1, y + 1);
+ }
+ }
+ else
+ {
+ g.setColor(shadow);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, y + 1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Paints the lower edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of the content area
+ * @param w the width of the content area
+ * @param h the height of the content area
+ */
+ protected void paintContentBorderBottomEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y,
+ int w, int h)
+ {
+ g.setColor(darkShadow);
+
+ // If tabs are not placed on BOTTOM, or if the selected tab is not in the
+ // run directly below the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ if (tabPlacement != BOTTOM || selectedIndex < 0 || rect.y - 1 > h
+ || rect.x < x || rect.x > x + w)
+ {
+ if (isOcean && tabPlacement == BOTTOM)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
+ }
+ else
+ {
+ boolean isLast = isLastTabInRun(selectedIndex);
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+
+ int bottom = y + h - 1;
+ int right = x + w - 1;
+ if (isLast)
+ {
+ g.drawLine(x, bottom, rect.x, bottom);
+ }
+ else
+ {
+ g.drawLine(x, bottom, rect.x - 1, bottom);
+ }
+
+ if (rect.x + rect.width < x + w - 2)
+ {
+ if (isLast)
+ {
+ g.drawLine(rect.x + rect.width - 1, bottom, right, bottom);
+ }
+ else
+ {
+ g.drawLine(rect.x + rect.width, bottom, right, bottom);
+ }
+ }
+ }
+ }
+
+ /**
+ * Paints the left edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of the content area
+ * @param w the width of the content area
+ * @param h the height of the content area
+ */
+ protected void paintContentBorderLeftEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y,
+ int w, int h)
+ {
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ else
+ {
+ g.setColor(selectHighlight);
+ }
+
+ // If tabs are not placed on LEFT, or if the selected tab is not in the
+ // run directly left to the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ if (tabPlacement != LEFT || selectedIndex < 0
+ || rect.x + rect.width + 1 < x || rect.y < y || rect.y > y + h)
+ {
+ g.drawLine(x, y + 1, x, y + h - 2);
+ if (isOcean && tabPlacement == LEFT)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ g.drawLine(x, y + 1, x, y + h - 2);
+ }
+ }
+ else
+ {
+ g.drawLine(x, y, x, rect.y + 1);
+ if (rect.y + rect.height < y + h - 2)
+ {
+ g.drawLine(x, rect.y + rect.height + 1, x, y + h + 2);
+ }
+ if (isOcean)
+ {
+ g.setColor(MetalLookAndFeel.getWhite());
+ g.drawLine(x + 1, y + 1, x + 1, rect.y + 1);
+ if (rect.y + rect.height < y + h - 2)
+ {
+ g.drawLine(x + y, rect.y + rect.height + 1, x + 1, y + h + 2);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Paints the right edge of the content border.
+ *
+ * @param g the graphics to use for painting
+ * @param tabPlacement the tab placement
+ * @param selectedIndex the index of the selected tab
+ * @param x the upper left coordinate of the content area
+ * @param y the upper left coordinate of the content area
+ * @param w the width of the content area
+ * @param h the height of the content area
+ */
+ protected void paintContentBorderRightEdge(Graphics g, int tabPlacement,
+ int selectedIndex, int x, int y,
+ int w, int h)
+ {
+ g.setColor(darkShadow);
+ Rectangle rect = selectedIndex < 0 ? null :
+ getTabBounds(selectedIndex, calcRect);
+ boolean isOcean = MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme;
+ Color oceanSelectedBorder =
+ UIManager.getColor("TabbedPane.borderHightlightColor");
+
+ // If tabs are not placed on RIGHT, or if the selected tab is not in the
+ // run directly right to the content or the selected tab is not visible,
+ // then we draw an unbroken line.
+ if (tabPlacement != RIGHT || selectedIndex < 0 || rect.x - 1 > w
+ || rect.y < y || rect.y > y + h)
+ {
+ if (isOcean && tabPlacement == RIGHT)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(x + w - 1, y, x + w - 1, y + h - 1);
+ }
+ else
+ {
+ if (isOcean)
+ {
+ g.setColor(oceanSelectedBorder);
+ }
+ g.drawLine(x + w - 1, y, x + w - 1, rect.y);
+
+ if (rect.y + rect.height < y + h - 2)
+ {
+ g.drawLine(x + w - 1, rect.y + rect.height, x + w - 1, y + h - 2);
+ }
+ }
+ }
+
+ /**
+ * Determines if the specified tab is the last tab in its tab run.
+ *
+ * @param tabIndex the index of the tab
+ *
+ * @return if the specified tab is the last tab in its tab run
+ */
+ private boolean isLastTabInRun(int tabIndex)
+ {
+ int count = tabPane.getTabCount();
+ int run = getRunForTab(count, tabIndex);
+ int lastIndex = lastTabInRun(count, run);
+ return tabIndex == lastIndex;
+ }
+
+ /**
+ * Returns the background for an unselected tab. This first asks the
+ * JTabbedPane for the background at the specified tab index, if this
+ * is an UIResource (that means, it is inherited from the JTabbedPane)
+ * and the TabbedPane.unselectedBackground UI property is not null,
+ * this returns the value of the TabbedPane.unselectedBackground property,
+ * otherwise the value returned by the JTabbedPane.
+ *
+ * @param tabIndex the index of the tab for which we query the background
+ *
+ * @return the background for an unselected tab
+ */
+ private Color getUnselectedBackground(int tabIndex)
+ {
+ Color bg = tabPane.getBackgroundAt(tabIndex);
+ Color unselectedBackground =
+ UIManager.getColor("TabbedPane.unselectedBackground");
+ if (bg instanceof UIResource && unselectedBackground != null)
+ bg = unselectedBackground;
+ return bg;
+ }
}
diff --git a/javax/swing/plaf/metal/MetalToggleButtonUI.java b/javax/swing/plaf/metal/MetalToggleButtonUI.java
index b1ed33236..8c7a46e3a 100644
--- a/javax/swing/plaf/metal/MetalToggleButtonUI.java
+++ b/javax/swing/plaf/metal/MetalToggleButtonUI.java
@@ -45,12 +45,14 @@ import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
+import javax.swing.ButtonModel;
import javax.swing.JComponent;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.basic.BasicToggleButtonUI;
@@ -209,7 +211,12 @@ public class MetalToggleButtonUI
*/
public void update(Graphics g, JComponent c)
{
- if (c.isOpaque() && UIManager.get(getPropertyPrefix() + "gradient") != null)
+ AbstractButton b = (AbstractButton) c;
+ ButtonModel m = b.getModel();
+ if (b.getBackground() instanceof UIResource
+ && b.isContentAreaFilled()
+ && b.isEnabled() && ! m.isArmed() && ! m.isPressed()
+ && UIManager.get(getPropertyPrefix() + "gradient") != null)
{
MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(),
SwingConstants.VERTICAL,
diff --git a/javax/swing/plaf/metal/MetalToolBarUI.java b/javax/swing/plaf/metal/MetalToolBarUI.java
index 797567d55..1848c1f16 100644
--- a/javax/swing/plaf/metal/MetalToolBarUI.java
+++ b/javax/swing/plaf/metal/MetalToolBarUI.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing.plaf.metal;
+import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ContainerListener;
import java.awt.event.MouseEvent;
@@ -46,6 +47,7 @@ import java.beans.PropertyChangeListener;
import javax.swing.JComponent;
import javax.swing.JToolBar;
+import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.MouseInputListener;
@@ -259,4 +261,38 @@ public class MetalToolBarUI extends BasicToolBarUI
}
super.uninstallUI(c);
}
+
+ /**
+ * Paints the background of the component if necessary and then calls
+ * <code>paint(g, c)</code>.
+ *
+ * This is overridden to implement the OceanTheme gradient when an OceanTheme
+ * is installed.
+ *
+ * @param g the graphics to use
+ * @param c the component to paint.
+ *
+ * @since 1.5
+ */
+ public void update(Graphics g, JComponent c)
+ {
+ // TODO: Sun's implementation uses the MenuBar.gradient here.
+ // I would consider this a bug, but implement it like this
+ // for compatibility.
+ if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme
+ && UIManager.get("MenuBar.gradient") != null)
+ {
+ if (c.isOpaque())
+ {
+ MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(),
+ SwingConstants.VERTICAL,
+ "MenuBar.gradient");
+ }
+ paint(g, c);
+ }
+ else
+ {
+ super.update(g, c);
+ }
+ }
}
diff --git a/javax/swing/plaf/metal/MetalTreeUI.java b/javax/swing/plaf/metal/MetalTreeUI.java
index 24432a2b5..3ea37c82f 100644
--- a/javax/swing/plaf/metal/MetalTreeUI.java
+++ b/javax/swing/plaf/metal/MetalTreeUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.metal;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
@@ -133,6 +135,7 @@ public class MetalTreeUI extends BasicTreeUI
* @param lineStyleFlag - String representation
*/
protected void decodeLineStyle(Object lineStyleFlag)
+ throws NotImplementedException
{
// FIXME: not implemented
}
@@ -176,6 +179,7 @@ public class MetalTreeUI extends BasicTreeUI
* @param c - the current component to draw
*/
protected void paintHorizontalSeparators(Graphics g, JComponent c)
+ throws NotImplementedException
{
// FIXME: not implemented
}
diff --git a/javax/swing/plaf/metal/OceanTheme.java b/javax/swing/plaf/metal/OceanTheme.java
index cfba4b5ff..9d76ff7e8 100644
--- a/javax/swing/plaf/metal/OceanTheme.java
+++ b/javax/swing/plaf/metal/OceanTheme.java
@@ -43,6 +43,7 @@ import java.util.Arrays;
import javax.swing.UIDefaults;
import javax.swing.plaf.ColorUIResource;
+import javax.swing.plaf.BorderUIResource.LineBorderUIResource;
/**
* A modern theme for the Metal Look &amp; Feel.
@@ -264,6 +265,10 @@ public class OceanTheme extends DefaultMetalTheme
defaults.put("ToolBar.borderColor", c3);
defaults.put("Tree.selectionBorderColor", PRIMARY1);
+ // Borders.
+ defaults.put("Table.focusCellHighlightBorder",
+ new LineBorderUIResource(getPrimary1()));
+
// Insets.
defaults.put("TabbedPane.contentBorderInsets", new Insets(4, 2, 3, 3));
defaults.put("TabbedPane.tabAreaInsets", new Insets(2, 2, 0, 6));
diff --git a/javax/swing/plaf/synth/ColorType.java b/javax/swing/plaf/synth/ColorType.java
index 954e309e1..ced1efc02 100644
--- a/javax/swing/plaf/synth/ColorType.java
+++ b/javax/swing/plaf/synth/ColorType.java
@@ -78,7 +78,12 @@ public class ColorType
/**
* The maximum number of color types.
*/
- public static final int MAX_COUNT = 5;
+ public static final int MAX_COUNT;
+ static
+ {
+ // This is not a constant in the JDK.
+ MAX_COUNT = 5;
+ }
/**
* A counter used to assign an ID to the created color types.
diff --git a/javax/swing/plaf/synth/SynthGraphicsUtils.java b/javax/swing/plaf/synth/SynthGraphicsUtils.java
index a68b6f6ec..1907d754f 100644
--- a/javax/swing/plaf/synth/SynthGraphicsUtils.java
+++ b/javax/swing/plaf/synth/SynthGraphicsUtils.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.synth;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
@@ -159,6 +161,7 @@ public class SynthGraphicsUtils
Icon icon, int hAlign, int vAlign,
int hTextPosition,int vTextPosition,
int iconTextGap,int mnemonicIndex)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return new Dimension(0, 0);
@@ -187,6 +190,7 @@ public class SynthGraphicsUtils
Icon icon, int hAlign, int vAlign,
int hTextPosition,int vTextPosition,
int iconTextGap,int mnemonicIndex)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return new Dimension(0, 0);
@@ -215,6 +219,7 @@ public class SynthGraphicsUtils
Icon icon, int hAlign, int vAlign,
int hTextPosition,int vTextPosition,
int iconTextGap,int mnemonicIndex)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return new Dimension(0, 0);
@@ -277,6 +282,7 @@ public class SynthGraphicsUtils
int hAlign, int vAlign, int hTextPosition,
int vTextPosition, int iconTextGap, int mnemonicIndex,
int textOffset)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
}
diff --git a/javax/swing/plaf/synth/SynthLookAndFeel.java b/javax/swing/plaf/synth/SynthLookAndFeel.java
index ed5a5b053..1a2489e7e 100644
--- a/javax/swing/plaf/synth/SynthLookAndFeel.java
+++ b/javax/swing/plaf/synth/SynthLookAndFeel.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.synth;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Component;
import java.io.InputStream;
import java.text.ParseException;
@@ -119,6 +121,7 @@ public class SynthLookAndFeel
* @param c the componenent for which to update the style
*/
public static void updateStyles(Component c)
+ throws NotImplementedException
{
// FIXME: Implement this properly.
}
@@ -131,6 +134,7 @@ public class SynthLookAndFeel
* @return the region for a given Swing component
*/
public static Region getRegion(JComponent c)
+ throws NotImplementedException
{
// FIXME: This can be implemented as soon as we have the component UI
// classes in place, since this region will be matched via the UI classes.
@@ -147,6 +151,7 @@ public class SynthLookAndFeel
* component
*/
public static ComponentUI createUI(JComponent c)
+ throws NotImplementedException
{
// FIXME: This can be implemented as soon as we have the component UI
// classes in place.
@@ -157,6 +162,7 @@ public class SynthLookAndFeel
* Initializes this look and feel.
*/
public void initialize()
+ throws NotImplementedException
{
super.initialize();
// TODO: Implement at least the following here:
@@ -168,6 +174,7 @@ public class SynthLookAndFeel
* Uninitializes the look and feel.
*/
public void uninitialize()
+ throws NotImplementedException
{
super.uninitialize();
// TODO: What to do here?
@@ -179,6 +186,7 @@ public class SynthLookAndFeel
* @return the UI defaults of this look and feel
*/
public UIDefaults getDefaults()
+ throws NotImplementedException
{
// FIXME: This is certainly wrong. The defaults should be fetched/merged
// from the file from which the l&f is loaded.
@@ -191,6 +199,7 @@ public class SynthLookAndFeel
* @return FIXME
*/
public boolean shouldUpdateStyleOnAncestorChanged()
+ throws NotImplementedException
{
return false;
}
@@ -210,7 +219,7 @@ public class SynthLookAndFeel
// FIXME: The signature in the JDK has a Class<?> here. Should be fixed as
// soon as we switch to the generics branch.
public void load(InputStream in, Class resourceBase)
- throws ParseException, IllegalArgumentException
+ throws ParseException, IllegalArgumentException, NotImplementedException
{
// FIXME: Implement this correctly.
}
diff --git a/javax/swing/plaf/synth/SynthPainter.java b/javax/swing/plaf/synth/SynthPainter.java
index 4d7f18ee4..fa1f6f572 100644
--- a/javax/swing/plaf/synth/SynthPainter.java
+++ b/javax/swing/plaf/synth/SynthPainter.java
@@ -1100,9 +1100,10 @@ public abstract class SynthPainter
* @param y the Y coordinate of the area to paint
* @param w the width of the area to paint
* @param h the height of the area to paint
+ * @param orientation orientation of the scrollbar
*/
public void paintScrollBarThumbBackground(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
+ int y, int w, int h, int orientation)
{
// Nothing to do here.
}
@@ -1117,9 +1118,10 @@ public abstract class SynthPainter
* @param y the Y coordinate of the area to paint
* @param w the width of the area to paint
* @param h the height of the area to paint
+ * @param orientation orientation of the scrollbar
*/
public void paintScrollBarThumbBorder(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
+ int y, int w, int h, int orientation)
{
// Nothing to do here.
}
@@ -1270,9 +1272,10 @@ public abstract class SynthPainter
* @param y the Y coordinate of the area to paint
* @param w the width of the area to paint
* @param h the height of the area to paint
+ * @param orientation orientation of the slider
*/
public void paintSliderThumbBackground(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
+ int y, int w, int h, int orientation)
{
// Nothing to do here.
}
@@ -1287,9 +1290,10 @@ public abstract class SynthPainter
* @param y the Y coordinate of the area to paint
* @param w the width of the area to paint
* @param h the height of the area to paint
+ * @param orientation orientation of the slider
*/
public void paintSliderThumbBorder(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
+ int y, int w, int h, int orientation)
{
// Nothing to do here.
}
@@ -1414,23 +1418,6 @@ public abstract class SynthPainter
}
/**
- * Paints the border of a split pane's divider.
- *
- * @param ctx the synth context identifying the component and region for
- * painting
- * @param g the graphics context to use for painting
- * @param x the X coordinate of the area to paint
- * @param y the Y coordinate of the area to paint
- * @param w the width of the area to paint
- * @param h the height of the area to paint
- */
- public void paintSplitPaneDividerBorder(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
- {
- // Nothing to do here.
- }
-
- /**
* Paints the background of a tabbed pane.
*
* @param ctx the synth context identifying the component and region for
@@ -1542,9 +1529,10 @@ public abstract class SynthPainter
* @param y the Y coordinate of the area to paint
* @param w the width of the area to paint
* @param h the height of the area to paint
+ * @param index the index of the tab to paint
*/
public void paintTabbedPaneTabBackground(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
+ int y, int w, int h, int index)
{
// Nothing to do here.
}
@@ -1559,9 +1547,10 @@ public abstract class SynthPainter
* @param y the Y coordinate of the area to paint
* @param w the width of the area to paint
* @param h the height of the area to paint
+ * @param index the index of the tab to paint
*/
public void paintTabbedPaneTabBorder(SynthContext ctx, Graphics g, int x,
- int y, int w, int h)
+ int y, int w, int h, int index)
{
// Nothing to do here.
}
diff --git a/javax/swing/plaf/synth/SynthStyle.java b/javax/swing/plaf/synth/SynthStyle.java
index e0a8dbcc7..f5ab3df3b 100644
--- a/javax/swing/plaf/synth/SynthStyle.java
+++ b/javax/swing/plaf/synth/SynthStyle.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.synth;
+import gnu.classpath.NotImplementedException;
+
import java.awt.Color;
import java.awt.Font;
import java.awt.Insets;
@@ -58,87 +60,144 @@ public abstract class SynthStyle
* Creates a new <code>SynthStyle</code> object.
*/
public SynthStyle()
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
}
public SynthGraphicsUtils getGraphicsUtils(SynthContext ctx)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return null;
}
public Color getColor(SynthContext ctx, ColorType type)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return null;
}
- public abstract Color getColorForState(SynthContext ctx, ColorType type);
+ protected abstract Color getColorForState(SynthContext ctx, ColorType type);
public Font getFont(SynthContext ctx)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return null;
}
- public abstract Font getFontForState(SynthContext ctx);
+ protected abstract Font getFontForState(SynthContext ctx);
- public Insets getInsets(SynthContext ctx)
+ public Insets getInsets(SynthContext ctx, Insets result)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return null;
}
- public SynthPainter getPainted(SynthContext ctx)
+ public SynthPainter getPainter(SynthContext ctx)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return null;
}
public boolean isOpaque(SynthContext ctx)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return true;
}
public Object get(SynthContext ctx, Object key)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
return null;
}
public void installDefaults(SynthContext ctx)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
}
public void uninstallDefaults(SynthContext ctx)
+ throws NotImplementedException
{
// FIXME: Implement this correctly.
}
+ /**
+ * A convenience method to fetch an integer property.
+ * If the property's value is a {@link Number}, then the
+ * integer value is returned. Otherwise, the default value
+ * is returned.
+ * @param ctx the context
+ * @param key the key to fetch
+ * @param defaultValue the default value
+ * @return the integer value of the property, or the default value
+ */
public int getInt(SynthContext ctx, Object key, int defaultValue)
{
- // FIXME: Implement this correctly.
- return -1;
+ Object obj = get(ctx, key);
+ if (obj instanceof Number)
+ return ((Number) obj).intValue();
+ return defaultValue;
}
- public boolean getBoolean(SynthContext ctx, Object key, boolean defaultValue)
+ /**
+ * A convenience method to fetch an integer property.
+ * If the property's value is a {@link Boolean}, then the
+ * value is returned. Otherwise, the default value
+ * is returned.
+ * @param ctx the context
+ * @param key the key to fetch
+ * @param defaultValue the default value
+ * @return the boolean value of the property, or the default value
+ */
+ public boolean getBoolean(SynthContext ctx, Object key,
+ boolean defaultValue)
{
- // FIXME: Implement this correctly.
- return false;
+ Object obj = get(ctx, key);
+ if (obj instanceof Boolean)
+ return ((Boolean) obj).booleanValue();
+ return defaultValue;
}
+ /**
+ * A convenience method to fetch an Icon-valued property.
+ * If the property's value is an {@link Icon}, then the
+ * value is returned. Otherwise, null is returned.
+ * @param ctx the context
+ * @param key the key to fetch
+ * @return the icon, or null
+ */
public Icon getIcon(SynthContext ctx, Object key)
{
- // FIXME: Implement this correctly.
+ Object obj = get(ctx, key);
+ if (key instanceof Icon)
+ return (Icon) obj;
return null;
}
+ /**
+ * A convenience method to fetch a String property.
+ * If the property's value is a {@link String}, then the
+ * value is returned. Otherwise, the default value
+ * is returned.
+ * @param ctx the context
+ * @param key the key to fetch
+ * @param defaultValue the default value
+ * @return the String value of the property, or the default value
+ */
public String getString(SynthContext ctx, Object key, String defaultValue)
{
- // FIXME: Implement this correctly.
- return null;
+ Object obj = get(ctx, key);
+ if (obj instanceof String)
+ return (String) obj;
+ return defaultValue;
}
}