diff options
Diffstat (limited to 'libjava/classpath/javax/swing/plaf')
59 files changed, 7073 insertions, 3095 deletions
diff --git a/libjava/classpath/javax/swing/plaf/ComboBoxUI.java b/libjava/classpath/javax/swing/plaf/ComboBoxUI.java index 3e81ed7..58f6e81 100644 --- a/libjava/classpath/javax/swing/plaf/ComboBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/ComboBoxUI.java @@ -1,5 +1,5 @@ /* ComboBoxUI.java -- - Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,9 +41,7 @@ import javax.swing.JComboBox; /** * An abstract base class for delegates that implement the pluggable - * look and feel for a <code>JButton</code>. - * - * @see javax.swing.JComboBox + * look and feel for a {@link JComboBox}. * * @author Andrew Selkirk * @author Sascha Brawer (brawer@dandelis.ch) @@ -57,8 +55,7 @@ public abstract class ComboBoxUI extends ComponentUI { // Nothing to do here. } - - + /** * Sets the visibility of the popup button. * @@ -70,7 +67,6 @@ public abstract class ComboBoxUI extends ComponentUI */ public abstract void setPopupVisible(JComboBox c, boolean visible); - /** * Determines whether the popup button is currently visible. * @@ -82,15 +78,15 @@ public abstract class ComboBoxUI extends ComponentUI */ public abstract boolean isPopupVisible(JComboBox c); - /** * Determines whether the combo box can receive input focus. * * @param c <code>JComboBox</code> whose focus traversability * is to be retrieved. * - * @returns <code>true</code> if <code>c</code> can receive + * @return <code>true</code> if <code>c</code> can receive * input focus, <code>false</code> otherwise. */ public abstract boolean isFocusTraversable(JComboBox c); + } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java index 1fca694..89e99a2 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java index 7a63331..7dbcb91 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java @@ -156,7 +156,8 @@ public class BasicButtonUI extends ButtonUI LookAndFeel.installColorsAndFont(b, prefix + "background", prefix + "foreground", prefix + "font"); LookAndFeel.installBorder(b, prefix + "border"); - b.setMargin(UIManager.getInsets(prefix + "margin")); + if (b.getMargin() == null || b.getMargin() instanceof UIResource) + b.setMargin(UIManager.getInsets(prefix + "margin")); b.setIconTextGap(UIManager.getInt(prefix + "textIconGap")); b.setInputMap(JComponent.WHEN_FOCUSED, (InputMap) UIManager.get(prefix + "focusInputMap")); @@ -171,11 +172,15 @@ public class BasicButtonUI extends ButtonUI { if (b.getFont() instanceof UIResource) b.setFont(null); - b.setForeground(null); - b.setBackground(null); - b.setBorder(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); - b.setMargin(null); + if (b.getMargin() instanceof UIResource) + b.setMargin(null); } protected BasicButtonListener listener; @@ -308,7 +313,7 @@ public class BasicButtonUI extends ButtonUI * @param c The component to paint the state of */ public void paint(Graphics g, JComponent c) - { + { AbstractButton b = (AbstractButton) c; Rectangle tr = new Rectangle(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java index 831dde8..d879261 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java @@ -1,5 +1,5 @@ /* BasicComboBoxEditor.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. @@ -177,4 +177,5 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor, // Nothing to do here. } } + } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java index 8115605..48195ff 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxRenderer.java @@ -40,15 +40,13 @@ package javax.swing.plaf.basic; import java.awt.Component; import java.awt.Dimension; -import java.awt.FontMetrics; import java.io.Serializable; +import javax.swing.Icon; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.ListCellRenderer; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; @@ -64,14 +62,14 @@ public class BasicComboBoxRenderer /** * A shared border instance for all renderers. */ - protected static Border noFocusBorder = new EmptyBorder(0, 0, 0, 0); + protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); /** * Creates a new <code>BasicComboBoxRenderer</code> object. */ public BasicComboBoxRenderer() { - setHorizontalAlignment(SwingConstants.LEFT); + setOpaque(true); setBorder(noFocusBorder); } @@ -103,32 +101,7 @@ public class BasicComboBoxRenderer int index, boolean isSelected, boolean cellHasFocus) { - String s = value.toString(); - - // String maybe larger than comboBox. - FontMetrics fm = getToolkit().getFontMetrics(list.getFont()); - int strWidth = SwingUtilities.computeStringWidth(fm, s); - int cbWidth = getSize().width; - if (cbWidth != 0 && strWidth > cbWidth) - { - char[] str = s.toCharArray(); - int currWidth = 0; - int i = 0; - String postStr = "... "; - cbWidth -= SwingUtilities.computeStringWidth(fm, postStr); - while (i < str.length && currWidth < cbWidth) - { - ++i; - currWidth = SwingUtilities.computeStringWidth(fm, new String(str, 0, i)); - } - setText(new String(str, 0, i) + postStr); - } - else - setText(s); - - setOpaque(true); - - if (isSelected || cellHasFocus) + if (isSelected) { setBackground(list.getSelectionBackground()); setForeground(list.getSelectionForeground()); @@ -138,9 +111,13 @@ public class BasicComboBoxRenderer setBackground(list.getBackground()); setForeground(list.getForeground()); } - - setEnabled(list.isEnabled()); setFont(list.getFont()); + + if (value instanceof Icon) + setIcon((Icon) value); + else + setText(value == null ? "" : value.toString()); + return this; } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java index 288a8d8..557eea9 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -38,12 +38,13 @@ 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; import java.awt.Dimension; import java.awt.Font; -import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; @@ -55,8 +56,6 @@ import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.beans.PropertyChangeEvent; @@ -66,13 +65,13 @@ import javax.accessibility.Accessible; import javax.swing.CellRendererPane; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; +import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; 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; @@ -129,11 +128,6 @@ public class BasicComboBoxUI extends ComboBoxUI protected KeyListener keyListener; /** - * A listener listening to mouse events occuring in the {@link JComboBox}. - */ - private MouseListener mouseListener; - - /** * List used when rendering selected item of the combo box. The selection * and foreground colors for combo box renderer are configured from this * list. @@ -161,36 +155,14 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected PropertyChangeListener propertyChangeListener; - /** - * The button background. - * @see #installDefaults() - */ - private Color buttonBackground; - - /** - * The button shadow. - * @see #installDefaults() - */ - private Color buttonShadow; - - /** - * The button dark shadow. - * @see #installDefaults() - */ - private Color buttonDarkShadow; - - /** - * The button highlight. - * @see #installDefaults() - */ - private Color buttonHighlight; - /* Size of the largest item in the comboBox * This is package-private to avoid an accessor method. */ - Dimension displaySize; + Dimension displaySize = new Dimension(); - // FIXME: This field isn't used anywhere at this moment. + /** + * Used to render the combo box values. + */ protected CellRendererPane currentValuePane; /** @@ -209,7 +181,8 @@ public class BasicComboBoxUI extends ComboBoxUI */ public BasicComboBoxUI() { - // Nothing to do here. + currentValuePane = new CellRendererPane(); + cachedMinimumSize = new Dimension(); } /** @@ -238,12 +211,33 @@ public class BasicComboBoxUI extends ComboBoxUI if (c instanceof JComboBox) { + isMinimumSizeDirty = true; comboBox = (JComboBox) c; - comboBox.setOpaque(true); - comboBox.setLayout(createLayoutManager()); installDefaults(); + + // Set editor and renderer for the combo box. Editor is used + // only if combo box becomes editable, otherwise renderer is used + // to paint the selected item; combobox is not editable by default. + ListCellRenderer renderer = comboBox.getRenderer(); + if (renderer == null || renderer instanceof UIResource) + comboBox.setRenderer(createRenderer()); + + ComboBoxEditor currentEditor = comboBox.getEditor(); + if (currentEditor == null || currentEditor instanceof UIResource) + { + currentEditor = createEditor(); + comboBox.setEditor(currentEditor); + } + editor = currentEditor.getEditorComponent(); + installComponents(); installListeners(); + if (arrowButton != null) + configureArrowButton(); + if (editor != null) + configureEditor(); + comboBox.setLayout(createLayoutManager()); + comboBox.setFocusable(true); installKeyboardActions(); } } @@ -257,9 +251,12 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void uninstallUI(JComponent c) { + setPopupVisible(comboBox, false); + popup.uninstallingUI(); uninstallKeyboardActions(); - uninstallListeners(); + comboBox.setLayout(null); uninstallComponents(); + uninstallListeners(); uninstallDefaults(); comboBox = null; } @@ -274,12 +271,7 @@ public class BasicComboBoxUI extends ComboBoxUI { LookAndFeel.installColorsAndFont(comboBox, "ComboBox.background", "ComboBox.foreground", "ComboBox.font"); - - // fetch the button color scheme - buttonBackground = UIManager.getColor("ComboBox.buttonBackground"); - buttonShadow = UIManager.getColor("ComboBox.buttonShadow"); - buttonDarkShadow = UIManager.getColor("ComboBox.buttonDarkShadow"); - buttonHighlight = UIManager.getColor("ComboBox.buttonHighlight"); + LookAndFeel.installBorder(comboBox, "ComboBox.border"); } /** @@ -302,12 +294,19 @@ public class BasicComboBoxUI extends ComboBoxUI keyListener = createKeyListener(); comboBox.addKeyListener(keyListener); - mouseListener = createMouseListener(); - arrowButton.addMouseListener(mouseListener); - // install listeners that listen to combo box model listDataListener = createListDataListener(); comboBox.getModel().addListDataListener(listDataListener); + + // Install mouse and key listeners from the popup. + popupMouseListener = popup.getMouseListener(); + comboBox.addMouseListener(popupMouseListener); + + popupMouseMotionListener = popup.getMouseMotionListener(); + comboBox.addMouseMotionListener(popupMouseMotionListener); + + popupKeyListener = popup.getKeyListener(); + comboBox.addKeyListener(popupKeyListener); } /** @@ -327,10 +326,7 @@ public class BasicComboBoxUI extends ComboBoxUI if (comboBox.getBackground() instanceof UIResource) comboBox.setBackground(null); - buttonBackground = null; - buttonShadow = null; - buttonDarkShadow = null; - buttonHighlight = null; + LookAndFeel.uninstallBorder(comboBox); } /** @@ -353,11 +349,20 @@ public class BasicComboBoxUI extends ComboBoxUI comboBox.removeKeyListener(keyListener); keyListener = null; - arrowButton.removeMouseListener(mouseListener); - mouseListener = null; - comboBox.getModel().removeListDataListener(listDataListener); listDataListener = null; + + if (popupMouseListener != null) + comboBox.removeMouseListener(popupMouseListener); + popupMouseListener = null; + + if (popupMouseMotionListener != null) + comboBox.removeMouseMotionListener(popupMouseMotionListener); + popupMouseMotionListener = null; + + if (popupKeyListener != null) + comboBox.removeKeyListener(popupKeyListener); + popupKeyListener = null; } /** @@ -381,17 +386,6 @@ public class BasicComboBoxUI extends ComboBoxUI } /** - * Creates a {@link MouseListener} that will listen to mouse events occurring - * in the combo box. - * - * @return the MouseListener - */ - private MouseListener createMouseListener() - { - return new MouseHandler(); - } - - /** * Creates the {@link FocusListener} that will listen to changes in this * JComboBox's focus. * @@ -453,7 +447,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected ListCellRenderer createRenderer() { - return new BasicComboBoxRenderer(); + return new BasicComboBoxRenderer.UIResource(); } /** @@ -480,25 +474,14 @@ public class BasicComboBoxUI extends ComboBoxUI popup = createPopup(); listBox = popup.getList(); - // set editor and renderer for the combo box. Editor is used - // only if combo box becomes editable, otherwise renderer is used - // to paint the selected item; combobox is not editable by default. - comboBox.setRenderer(createRenderer()); - // create and install arrow button arrowButton = createArrowButton(); - configureArrowButton(); comboBox.add(arrowButton); - ComboBoxEditor currentEditor = comboBox.getEditor(); - if (currentEditor == null || currentEditor instanceof UIResource) - { - currentEditor = createEditor(); - comboBox.setEditor(currentEditor); - } - editor = currentEditor.getEditorComponent(); + if (comboBox.isEditable()) + addEditor(); - comboBox.revalidate(); + comboBox.add(currentValuePane); } /** @@ -513,10 +496,10 @@ public class BasicComboBoxUI extends ComboBoxUI comboBox.remove(arrowButton); arrowButton = null; - listBox = null; popup = null; - comboBox.setRenderer(null); + if (comboBox.getRenderer() instanceof UIResource) + comboBox.setRenderer(null); // if the editor is not an instanceof UIResource, it was not set by the // UI delegate, so don't clear it... @@ -533,6 +516,8 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void addEditor() { + removeEditor(); + editor = comboBox.getEditor().getEditorComponent(); comboBox.add(editor); } @@ -541,7 +526,11 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void removeEditor() { - comboBox.remove(editor); + if (editor != null) + { + unconfigureEditor(); + comboBox.remove(editor); + } } /** @@ -550,8 +539,10 @@ public class BasicComboBoxUI extends ComboBoxUI protected void configureEditor() { editor.setFont(comboBox.getFont()); - comboBox.getEditor().setItem(comboBox.getSelectedItem()); - // FIXME: Need to implement. Set font and add listeners. + if (popupKeyListener != null) + editor.addKeyListener(popupKeyListener); + comboBox.configureEditor(comboBox.getEditor(), + comboBox.getSelectedItem()); } /** @@ -559,7 +550,8 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected void unconfigureEditor() { - // FIXME: Need to implement + if (popupKeyListener != null) + editor.removeKeyListener(popupKeyListener); } /** @@ -569,9 +561,15 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void configureArrowButton() { - arrowButton.setEnabled(comboBox.isEnabled()); - arrowButton.setFont(comboBox.getFont()); - arrowButton.setFocusable(false); + if (arrowButton != null) + { + arrowButton.setEnabled(comboBox.isEnabled()); + arrowButton.setFocusable(false); + if (popupMouseListener != null) + arrowButton.addMouseListener(popupMouseListener); + if (popupMouseMotionListener != null) + arrowButton.addMouseMotionListener(popupMouseMotionListener); + } } /** @@ -584,7 +582,13 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void unconfigureArrowButton() { - // Nothing to do here yet. + if (arrowButton != null) + { + if (popupMouseListener != null) + arrowButton.removeMouseListener(popupMouseListener); + if (popupMouseMotionListener != null) + arrowButton.removeMouseMotionListener(popupMouseMotionListener); + } } /** @@ -596,8 +600,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected JButton createArrowButton() { - return new BasicArrowButton(BasicArrowButton.SOUTH, buttonBackground, - buttonShadow, buttonDarkShadow, buttonHighlight); + return new BasicArrowButton(BasicArrowButton.SOUTH); } /** @@ -627,11 +630,6 @@ public class BasicComboBoxUI extends ComboBoxUI popup.show(); else popup.hide(); - - if (comboBox.isEditable()) - editor.requestFocus(); - else - comboBox.requestFocus(); } /** @@ -657,9 +655,13 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void paint(Graphics g, JComponent c) { - Rectangle rect = rectangleForCurrentValue(); - paintCurrentValueBackground(g, rect, hasFocus); - paintCurrentValue(g, rect, hasFocus); + hasFocus = comboBox.hasFocus(); + if (! comboBox.isEditable()) + { + Rectangle rect = rectangleForCurrentValue(); + paintCurrentValueBackground(g, rect, hasFocus); + paintCurrentValue(g, rect, hasFocus); + } } /** @@ -671,9 +673,6 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension getPreferredSize(JComponent c) { - // note: overriding getMinimumSize() (for example in the MetalComboBoxUI - // class) affects the getPreferredSize() result, so it seems logical that - // this method is implemented by delegating to the getMinimumSize() method return getMinimumSize(c); } @@ -689,18 +688,15 @@ public class BasicComboBoxUI extends ComboBoxUI { if (isMinimumSizeDirty) { - Dimension d = getDisplaySize(); - int arrowButtonWidth = d.height; - cachedMinimumSize = new Dimension(d.width + arrowButtonWidth, - d.height); - isMinimumSizeDirty = false; + Insets i = getInsets(); + Dimension d = getDisplaySize(); + 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); } - /** The value returned by the getMaximumSize() method. */ - private static final Dimension MAXIMUM_SIZE = new Dimension(32767, 32767); - /** * Returns the maximum size for this {@link JComboBox} for this * look and feel. @@ -711,7 +707,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension getMaximumSize(JComponent c) { - return MAXIMUM_SIZE; + return new Dimension(32767, 32767); } public int getAccessibleChildrenCount(JComponent c) @@ -779,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)); } /** @@ -793,7 +794,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Insets getInsets() { - return new Insets(0, 0, 0, 0); + return comboBox.getInsets(); } /** @@ -807,34 +808,52 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus) { - if (! comboBox.isEditable()) + Object currentValue = comboBox.getSelectedItem(); + boolean isPressed = arrowButton.getModel().isPressed(); + + /* Gets the component to be drawn for the current value. + * If there is currently no selected item we will take an empty + * String as replacement. + */ + ListCellRenderer renderer = comboBox.getRenderer(); + if (comboBox.getSelectedIndex() != -1) { - Object currentValue = comboBox.getSelectedItem(); - boolean isPressed = arrowButton.getModel().isPressed(); - - /* Gets the component to be drawn for the current value. - * If there is currently no selected item we will take an empty - * String as replacement. - */ - Component comp = comboBox.getRenderer().getListCellRendererComponent( - listBox, (currentValue != null ? currentValue : ""), -1, - isPressed, hasFocus); - if (! comboBox.isEnabled()) + Component comp; + if (hasFocus && ! isPopupVisible(comboBox)) + { + comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), + -1, true, false); + } + else { - comp.setBackground(UIManager.getColor( - "ComboBox.disabledBackground")); - comp.setForeground(UIManager.getColor( - "ComboBox.disabledForeground")); - comp.setEnabled(false); + comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), + -1, false, false); + Color bg = UIManager.getColor("ComboBox.disabledForeground"); + comp.setBackground(bg); } - comp.setBounds(0, 0, bounds.width, bounds.height); comp.setFont(comboBox.getFont()); - comp.paint(g); - - comboBox.revalidate(); + if (hasFocus && ! isPopupVisible(comboBox)) + { + comp.setForeground(listBox.getSelectionForeground()); + comp.setBackground(listBox.getSelectionBackground()); + } + else if (comboBox.isEnabled()) + { + comp.setForeground(comboBox.getForeground()); + comp.setBackground(comboBox.getBackground()); + } + else + { + Color fg = UIManager.getColor("ComboBox.disabledForeground"); + comp.setForeground(fg); + Color bg = UIManager.getColor("ComboBox.disabledBackground"); + comp.setBackground(bg); + } + currentValuePane.paintComponent(g, comp, comboBox, bounds.x, bounds.y, + bounds.width, bounds.height); } - else - comboBox.getEditor().setItem(comboBox.getSelectedItem()); } /** @@ -850,10 +869,22 @@ public class BasicComboBoxUI extends ComboBoxUI public void paintCurrentValueBackground(Graphics g, Rectangle bounds, boolean hasFocus) { - // background is painted by renderer, so it seems that nothing - // should be done here. + Color saved = g.getColor(); + if (comboBox.isEnabled()) + { + g.setColor(UIManager.getColor("UIManager.background")); + } + else + { + g.setColor(UIManager.getColor("UIManager.disabledBackground")); + } + g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height); + g.setColor(saved); } + private static final ListCellRenderer DEFAULT_RENDERER + = new DefaultListCellRenderer(); + /** * Returns the default size for the display area of a combo box that does * not contain any elements. This method returns the width and height of @@ -865,14 +896,15 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Dimension getDefaultSize() { - // There is nothing in the spec to say how this method should be - // implemented...so I've done some guessing, written some Mauve tests, - // and written something that gives dimensions that are close to the - // reference implementation. - FontMetrics fm = comboBox.getFontMetrics(comboBox.getFont()); - int w = fm.charWidth(' ') + 2; - int h = fm.getHeight() + 2; - return new Dimension(w, h); + Component comp = DEFAULT_RENDERER.getListCellRendererComponent(listBox, + " ", -1, + false, + false); + currentValuePane.add(comp); + comp.setFont(comboBox.getFont()); + Dimension d = comp.getPreferredSize(); + currentValuePane.remove(comp); + return d; } /** @@ -883,70 +915,58 @@ public class BasicComboBoxUI extends ComboBoxUI */ protected Dimension getDisplaySize() { - if (!comboBox.isEditable()) + Dimension dim = new Dimension(); + ListCellRenderer renderer = comboBox.getRenderer(); + if (renderer == null) + { + renderer = DEFAULT_RENDERER; + } + + Object prototype = comboBox.getPrototypeDisplayValue(); + if (prototype != null) { - 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(); + if (size > 0) { - // calculate result based on prototype - ListCellRenderer renderer = comboBox.getRenderer(); - Component comp = renderer.getListCellRendererComponent(listBox, - prototype, -1, false, false); - Dimension compSize = comp.getPreferredSize(); - compSize.width += 2; // add 1 pixel margin around area - compSize.height += 2; - return compSize; + 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); + } } else { - ComboBoxModel model = comboBox.getModel(); - int numItems = model.getSize(); - - // if combo box doesn't have any items then simply - // return its default size - if (numItems == 0) - { - displaySize = getDefaultSize(); - return displaySize; - } - - Dimension size = new Dimension(0, 0); - - // ComboBox's display size should be equal to the - // size of the largest item in the combo box. - ListCellRenderer renderer = comboBox.getRenderer(); - - for (int i = 0; i < numItems; i++) - { - Object item = model.getElementAt(i); - Component comp = renderer.getListCellRendererComponent(listBox, - item, -1, false, false); - - Dimension compSize = comp.getPreferredSize(); - if (compSize.width + 2 > size.width) - size.width = compSize.width + 2; - if (compSize.height + 2 > size.height) - size.height = compSize.height + 2; - } - displaySize = size; - return displaySize; + dim = getDefaultSize(); + if (comboBox.isEditable()) + dim.width = 100; } } - else // an editable combo, + if (comboBox.isEditable()) { - Component comp = comboBox.getEditor().getEditorComponent(); - Dimension prefSize = comp.getPreferredSize(); - int width = prefSize.width; - int height = prefSize.height + 2; - Object prototype = comboBox.getPrototypeDisplayValue(); - if (prototype != null) - { - FontMetrics fm = comboBox.getFontMetrics(comboBox.getFont()); - width = Math.max(width, fm.stringWidth(prototype.toString()) + 2); - } - displaySize = new Dimension(width, height); - return displaySize; + 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; } /** @@ -954,6 +974,7 @@ public class BasicComboBoxUI extends ComboBoxUI * by the look and feel. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement. } @@ -963,6 +984,7 @@ public class BasicComboBoxUI extends ComboBoxUI * installed by in {@link #installListeners}. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement. } @@ -1016,7 +1038,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension preferredLayoutSize(Container parent) { - return getPreferredSize((JComponent) parent); + return parent.getPreferredSize(); } /** @@ -1028,7 +1050,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public Dimension minimumLayoutSize(Container parent) { - return preferredLayoutSize(parent); + return parent.getMinimumSize(); } /** @@ -1043,14 +1065,15 @@ public class BasicComboBoxUI extends ComboBoxUI { // Position editor component to the left of arrow button if combo box is // editable - int arrowSize = comboBox.getHeight(); + Insets i = getInsets(); + int arrowSize = comboBox.getHeight() - (i.top + i.bottom); int editorWidth = comboBox.getBounds().width - arrowSize; - if (comboBox.isEditable()) - editor.setBounds(0, 0, editorWidth, comboBox.getBounds().height); - - arrowButton.setBounds(editorWidth, 0, arrowSize, arrowSize); - comboBox.revalidate(); + if (arrowButton != null) + arrowButton.setBounds(comboBox.getWidth() - (i.right + arrowSize), + i.top, arrowSize, arrowSize); + if (editor != null) + editor.setBounds(rectangleForCurrentValue()); } } @@ -1078,9 +1101,6 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void focusGained(FocusEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - hasFocus = true; comboBox.repaint(); } @@ -1093,11 +1113,9 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void focusLost(FocusEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - hasFocus = false; - setPopupVisible(comboBox, false); + if (! e.isTemporary() && comboBox.isLightWeightPopupEnabled()) + setPopupVisible(comboBox, false); comboBox.repaint(); } } @@ -1124,11 +1142,12 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void itemStateChanged(ItemEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - - if (e.getStateChange() == ItemEvent.SELECTED && comboBox.isEditable()) - comboBox.getEditor().setItem(e.getItem()); + ComboBoxModel model = comboBox.getModel(); + Object v = model.getSelectedItem(); + if (editor != null) + { + comboBox.configureEditor(comboBox.getEditor(), v); + } comboBox.repaint(); } } @@ -1173,10 +1192,17 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void contentsChanged(ListDataEvent e) { - // if the item is selected or deselected - - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; + if (e.getIndex0() != -1 || e.getIndex1() != -1) + { + isMinimumSizeDirty = true; + comboBox.revalidate(); + } + if (editor != null) + { + comboBox.configureEditor(comboBox.getEditor(), + comboBox.getSelectedItem()); + } + comboBox.repaint(); } /** @@ -1186,20 +1212,51 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void intervalAdded(ListDataEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - - ComboBoxModel model = comboBox.getModel(); - ListCellRenderer renderer = comboBox.getRenderer(); - - if (displaySize == null) - displaySize = getDisplaySize(); - if (displaySize.width < getDefaultSize().width) - displaySize.width = getDefaultSize().width; - if (displaySize.height < getDefaultSize().height) - displaySize.height = getDefaultSize().height; - - comboBox.repaint(); + int start = e.getIndex0(); + int end = e.getIndex1(); + if (start == 0 && comboBox.getItemCount() - (end - start + 1) == 0) + { + contentsChanged(e); + } + else if (start != -1 || end != -1) + { + ListCellRenderer renderer = comboBox.getRenderer(); + ComboBoxModel model = comboBox.getModel(); + int w = displaySize.width; + int h = displaySize.height; + // TODO: Optimize using prototype here. + for (int i = start; i <= end; ++i) + { + Component comp = + renderer.getListCellRendererComponent(listBox, + model.getElementAt(i), + -1, false, false); + currentValuePane.add(comp); + comp.setFont(comboBox.getFont()); + Dimension dim = comp.getPreferredSize(); + w = Math.max(w, dim.width); + h = Math.max(h, dim.height); + currentValuePane.remove(comp); + } + if (displaySize.width < w || displaySize.height < h) + { + if (displaySize.width < w) + { + displaySize.width = w; + } + if (displaySize.height < h) + { + displaySize.height = h; + } + comboBox.revalidate(); + if (editor != null) + { + comboBox.configureEditor(comboBox.getEditor(), + comboBox.getSelectedItem()); + } + } + } + } /** @@ -1210,12 +1267,7 @@ public class BasicComboBoxUI extends ComboBoxUI */ public void intervalRemoved(ListDataEvent e) { - // Lets assume every change invalidates the minimumsize. - isMinimumSizeDirty = true; - - // recalculate display size of the JComboBox. - displaySize = getDisplaySize(); - comboBox.repaint(); + contentsChanged(e); } } @@ -1291,22 +1343,4 @@ public class BasicComboBoxUI extends ComboBoxUI } } - /** - * A handler for mouse events occurring in the combo box. An instance of - * this class is returned by the <code>createMouseListener()</code> method. - */ - private class MouseHandler extends MouseAdapter - { - /** - * Invoked when mouse is pressed over the combo box. It toggles the - * visibility of the popup list. - * - * @param e the event - */ - public void mousePressed(MouseEvent e) - { - if (comboBox.isEnabled()) - toggleOpenClose(); - } - } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java index 798101d..d4eabc6 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java +++ b/libjava/classpath/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; @@ -59,13 +62,13 @@ import java.beans.PropertyChangeListener; import javax.swing.BorderFactory; import javax.swing.ComboBoxModel; import javax.swing.JComboBox; -import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPopupMenu; import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; +import javax.swing.MenuSelectionManager; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; @@ -165,9 +168,17 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public BasicComboPopup(JComboBox comboBox) { this.comboBox = comboBox; - installComboBoxListeners(); + mouseListener = createMouseListener(); + mouseMotionListener = createMouseMotionListener(); + keyListener = createKeyListener(); + + list = createList(); + configureList(); + scroller = createScroller(); + configureScroller(); configurePopup(); - setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); + installComboBoxListeners(); + installKeyboardActions(); } /** @@ -175,42 +186,23 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void show() { - Rectangle cbBounds = comboBox.getBounds(); - - // popup should have same width as the comboBox and should be hight anough - // to display number of rows equal to 'maximumRowCount' property - int popupHeight = getPopupHeightForRowCount(comboBox.getMaximumRowCount()); - - scroller.setPreferredSize(new Dimension(cbBounds.width, popupHeight)); - pack(); + 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); - // Highlight selected item in the combo box's drop down list - if (comboBox.getSelectedIndex() != -1) - list.setSelectedIndex(comboBox.getSelectedIndex()); + scroller.setMaximumSize(bounds.getSize()); + scroller.setPreferredSize(bounds.getSize()); + scroller.setMinimumSize(bounds.getSize()); + list.invalidate(); - //scroll scrollbar s.t. selected item is visible - JScrollBar scrollbar = scroller.getVerticalScrollBar(); - int selectedIndex = comboBox.getSelectedIndex(); - if (selectedIndex > comboBox.getMaximumRowCount()) - scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); - - // We put the autoclose-registration inside an InvocationEvent, so that - // the same event that triggered this show() call won't hide the popup - // immediately. - SwingUtilities.invokeLater - (new Runnable() - { - public void run() - { - // Register this popup to be autoclosed when user clicks outside the - // popup. - BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel(); - laf.registerForAutoClose(BasicComboPopup.this); - }}); - - // location specified is relative to comboBox - super.show(comboBox, 0, cbBounds.height); + syncListSelection(); + list.ensureIndexIsVisible(list.getSelectedIndex()); + setLightWeightPopupEnabled(comboBox.isLightWeightPopupEnabled()); + show(comboBox, bounds.x, bounds.y); } /** @@ -218,7 +210,19 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void hide() { - super.setVisible(false); + MenuSelectionManager menuSelectionManager = + MenuSelectionManager.defaultManager(); + javax.swing.MenuElement[] menuElements = + menuSelectionManager.getSelectedPath(); + for (int i = 0; i < menuElements.length; i++) + { + if (menuElements[i] == this) + { + menuSelectionManager.clearSelectedPath(); + break; + } + } + comboBox.repaint(); } /** @@ -270,7 +274,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public void uninstallingUI() { uninstallComboBoxModelListeners(comboBox.getModel()); - uninstallListeners(); uninstallKeyboardActions(); } @@ -291,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 } @@ -446,7 +450,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup protected JList createList() { JList l = new JList(comboBox.getModel()); - l.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); return l; } @@ -456,9 +459,18 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void configureList() { - list.setModel(comboBox.getModel()); - list.setVisibleRowCount(comboBox.getMaximumRowCount()); + list.setFont(comboBox.getFont()); + list.setForeground(comboBox.getForeground()); + list.setBackground(comboBox.getBackground()); + Color sfg = UIManager.getColor("ComboBox.selectionForeground"); + list.setSelectionForeground(sfg); + Color sbg = UIManager.getColor("ComboBox.selectionBackground"); + list.setSelectionBackground(sbg); + list.setBorder(null); + list.setCellRenderer(comboBox.getRenderer()); list.setFocusable(false); + syncListSelection(); + list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION); installListListeners(); } @@ -489,7 +501,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected JScrollPane createScroller() { - return new JScrollPane(); + return new JScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, + JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); } /** @@ -498,8 +511,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup protected void configureScroller() { scroller.setBorder(null); - scroller.getViewport().setView(list); - scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scroller.setFocusable(false); + scroller.getVerticalScrollBar().setFocusable(false); } /** @@ -508,18 +521,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void configurePopup() { + setBorderPainted(true); setBorder(BorderFactory.createLineBorder(Color.BLACK)); - // initialize list that will be used to display combo box's items - this.list = createList(); - ((JLabel) list.getCellRenderer()).setHorizontalAlignment(SwingConstants.LEFT); - configureList(); - - // initialize scroller. Add list to the scroller. - scroller = createScroller(); - configureScroller(); - - // add scroller with list inside of it to JPopupMenu - super.add(scroller); + setOpaque(false); + add(scroller); + setFocusable(false); } /* @@ -528,20 +534,14 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void installComboBoxListeners() { - // mouse listener that listens to mouse event in combo box - mouseListener = createMouseListener(); - comboBox.addMouseListener(mouseListener); - - // mouse listener that listens to mouse dragging events in the combo box - mouseMotionListener = createMouseMotionListener(); - comboBox.addMouseMotionListener(mouseMotionListener); - // item listener listenening to selection events in the combo box itemListener = createItemListener(); comboBox.addItemListener(itemListener); propertyChangeListener = createPropertyChangeListener(); comboBox.addPropertyChangeListener(propertyChangeListener); + + installComboBoxModelListeners(comboBox.getModel()); } /** @@ -562,6 +562,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup * DOCUMENT ME! */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -651,7 +652,10 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void delegateFocus(MouseEvent e) { - // FIXME: Need to implement + if (comboBox.isEditable()) + comboBox.getEditor().getEditorComponent().requestFocus(); + else + comboBox.requestFocus(); } /** @@ -660,7 +664,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected void togglePopup() { - if (BasicComboPopup.this.isVisible()) + if (isVisible()) hide(); else show(); @@ -675,7 +679,14 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ protected MouseEvent convertMouseEvent(MouseEvent e) { - return null; + Point point = SwingUtilities.convertPoint((Component) e.getSource(), + e.getPoint(), list); + MouseEvent newEvent= new MouseEvent((Component) e.getSource(), + e.getID(), e.getWhen(), + e.getModifiers(), point.x, point.y, + e.getModifiers(), + e.isPopupTrigger()); + return newEvent; } /** @@ -707,7 +718,7 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup totalHeight += dim.height; } - return totalHeight; + return totalHeight == 0 ? 100 : totalHeight; } /** @@ -735,11 +746,24 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup protected void updateListBoxSelectionForEvent(MouseEvent anEvent, boolean shouldScroll) { - // TODO: We need to handle the shouldScroll parameter somehow. - int index = list.locationToIndex(anEvent.getPoint()); - // Check for valid index. - if (index >= 0) - list.setSelectedIndex(index); + Point point = anEvent.getPoint(); + if (list != null) + { + int index = list.locationToIndex(point); + if (index == -1) + { + if (point.y < 0) + index = 0; + else + index = comboBox.getModel().getSize() - 1; + } + if (list.getSelectedIndex() != index) + { + list.setSelectedIndex(index); + if (shouldScroll) + list.ensureIndexIsVisible(index); + } + } } /** @@ -769,8 +793,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void mousePressed(MouseEvent e) { - if (comboBox.isEnabled()) - togglePopup(); + if (SwingUtilities.isLeftMouseButton(e) && comboBox.isEnabled()) + { + delegateFocus(e); + togglePopup(); + } } /** @@ -782,28 +809,27 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void mouseReleased(MouseEvent e) { - // Get component over which mouse was released - Component src = (Component) e.getSource(); - int x = e.getX(); - int y = e.getY(); - Component releasedComponent = SwingUtilities.getDeepestComponentAt(src, - x, y); - - // if mouse was released inside the bounds of combo box then do nothing, + Component component = (Component) e.getSource(); + Dimension size = component.getSize(); + Rectangle bounds = new Rectangle(0, 0, size.width - 1, size.height - 1); + // If mouse was released inside the bounds of combo box then do nothing, // Otherwise if mouse was released inside the list of combo box items // then change selection and close popup - if (! (releasedComponent instanceof JComboBox)) + if (! bounds.contains(e.getPoint())) { - // List model contains the item over which mouse is released, - // since it is updated every time the mouse is moved over a different - // item in the list. Now that the mouse is released we need to - // update model of the combo box as well. - comboBox.setSelectedIndex(list.getSelectedIndex()); - - if (isAutoScrolling) - stopAutoScrolling(); + MouseEvent convEvent = convertMouseEvent(e); + Point point = convEvent.getPoint(); + Rectangle visRect = new Rectangle(); + list.computeVisibleRect(visRect); + if (visRect.contains(point)) + { + updateListBoxSelectionForEvent(convEvent, false); + comboBox.setSelectedIndex(list.getSelectedIndex()); + } hide(); } + hasEntered = false; + stopAutoScrolling(); } } @@ -827,58 +853,42 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void mouseDragged(MouseEvent e) { - // convert point of the drag event relative to combo box list component - // figure out over which list cell the mouse is currently being dragged - // and highlight the cell. The list model is changed but the change has - // no effect on combo box's data model. The list model is changed so - // that the appropriate item would be highlighted in the combo box's - // list. - if (BasicComboPopup.this.isVisible()) + if (isVisible()) { - int cbHeight = (int) comboBox.getPreferredSize().getHeight(); - int popupHeight = BasicComboPopup.this.getSize().height; - - // if mouse is dragged inside the the combo box's items list. - if (e.getY() > cbHeight && ! (e.getY() - cbHeight >= popupHeight)) - { - int index = list.locationToIndex(new Point(e.getX(), - (int) (e.getY() - - cbHeight))); - - int firstVisibleIndex = list.getFirstVisibleIndex(); - - // list.locationToIndex returns item's index that would - // be located at the specified point if the first item that - // is visible is item 0. However in the JComboBox it is not - // necessarily the case since list is contained in the - // JScrollPane so we need to adjust the index returned. - if (firstVisibleIndex != 0) - // FIXME: adjusted index here is off by one. I am adding one - // here to compensate for that. This should be - // index += firstVisibleIndex. Remove +1 once the bug is fixed. - index += firstVisibleIndex + 1; - - list.setSelectedIndex(index); - } - else - { - // if mouse is being dragged at the bottom of combo box's list - // of items or at the very top then scroll the list in the - // desired direction. - boolean movingUP = e.getY() < cbHeight; - boolean movingDown = e.getY() > cbHeight; - - if (movingUP) - { - scrollDirection = SCROLL_UP; - startAutoScrolling(SCROLL_UP); - } - else if (movingDown) - { - scrollDirection = SCROLL_DOWN; - startAutoScrolling(SCROLL_DOWN); - } - } + MouseEvent convEvent = convertMouseEvent(e); + Rectangle visRect = new Rectangle(); + list.computeVisibleRect(visRect); + if (convEvent.getPoint().y >= visRect.y + && (convEvent.getPoint().y <= visRect.y + visRect.height - 1)) + { + hasEntered = true; + if (isAutoScrolling) + stopAutoScrolling(); + Point point = convEvent.getPoint(); + if (visRect.contains(point)) + { + valueIsAdjusting = true; + updateListBoxSelectionForEvent(convEvent, false); + valueIsAdjusting = false; + } + } + else if (hasEntered) + { + int dir = convEvent.getPoint().y < visRect.y ? SCROLL_UP + : SCROLL_DOWN; + if (isAutoScrolling && scrollDirection != dir) + { + stopAutoScrolling(); + startAutoScrolling(dir); + } + else if (!isAutoScrolling) + startAutoScrolling(dir); + } + else if (e.getPoint().y < 0) + { + hasEntered = true; + startAutoScrolling(SCROLL_UP); + } } } } @@ -905,7 +915,13 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ public void itemStateChanged(ItemEvent e) { - // TODO: What should be done here? + if (e.getStateChange() == ItemEvent.SELECTED && ! valueIsAdjusting) + { + valueIsAdjusting = true; + syncListSelection(); + valueIsAdjusting = false; + list.ensureIndexIsVisible(comboBox.getSelectedIndex()); + } } } @@ -924,15 +940,12 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public void mousePressed(MouseEvent e) { - // TODO: What should be do here? + // Nothing to do here. } public void mouseReleased(MouseEvent anEvent) { - int index = list.locationToIndex(anEvent.getPoint()); - // Check for valid index. - if (index >= 0) - comboBox.setSelectedIndex(index); + comboBox.setSelectedIndex(list.getSelectedIndex()); hide(); } } @@ -951,7 +964,15 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup public void mouseMoved(MouseEvent anEvent) { - updateListBoxSelectionForEvent(anEvent, false); + Point point = anEvent.getPoint(); + Rectangle visRect = new Rectangle(); + list.computeVisibleRect(visRect); + if (visRect.contains(point)) + { + valueIsAdjusting = true; + updateListBoxSelectionForEvent(anEvent, false); + valueIsAdjusting = false; + } } } @@ -971,15 +992,21 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup { if (e.getPropertyName().equals("renderer")) { - list.setCellRenderer((ListCellRenderer) e.getNewValue()); - revalidate(); - repaint(); + list.setCellRenderer(comboBox.getRenderer()); + if (isVisible()) + hide(); } - if (e.getPropertyName().equals("dataModel")) + if (e.getPropertyName().equals("model")) { - list.setModel((ComboBoxModel) e.getNewValue()); - revalidate(); - repaint(); + ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue(); + uninstallComboBoxModelListeners(oldModel); + ComboBoxModel newModel = (ComboBoxModel) e.getNewValue(); + list.setModel(newModel); + installComboBoxModelListeners(newModel); + if (comboBox.getItemCount() > 0) + comboBox.setSelectedIndex(0); + if (isVisible()) + hide(); } } } @@ -991,7 +1018,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ private void uninstallListeners() { - uninstallListListeners(); uninstallComboBoxListeners(); uninstallComboBoxModelListeners(comboBox.getModel()); } @@ -1015,12 +1041,6 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup */ private void uninstallComboBoxListeners() { - comboBox.removeMouseListener(mouseListener); - mouseListener = null; - - comboBox.removeMouseMotionListener(mouseMotionListener); - mouseMotionListener = null; - comboBox.removeItemListener(itemListener); itemListener = null; @@ -1028,6 +1048,15 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup propertyChangeListener = null; } + void syncListSelection() + { + int index = comboBox.getSelectedIndex(); + if (index == -1) + list.clearSelection(); + else + list.setSelectedIndex(index); + } + // -------------------------------------------------------------------- // The following classes are here only for backwards API compatibility // They aren't used. diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java index 30e3156..daa9770 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java index 56022f3..11980f6 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java @@ -301,27 +301,27 @@ public class BasicInternalFrameTitlePane extends JComponent { String propName = evt.getPropertyName(); if (propName.equals("closable")) - { - if (evt.getNewValue().equals(Boolean.TRUE)) - closeButton.setVisible(true); - else - closeButton.setVisible(false); - } - else if (propName.equals("iconifiable")) - { - if (evt.getNewValue().equals(Boolean.TRUE)) - iconButton.setVisible(true); - else - iconButton.setVisible(false); - } + { + if (evt.getNewValue().equals(Boolean.TRUE)) + closeButton.setVisible(true); + else + closeButton.setVisible(false); + } + else if (propName.equals("iconable")) + { + if (evt.getNewValue().equals(Boolean.TRUE)) + iconButton.setVisible(true); + else + iconButton.setVisible(false); + } else if (propName.equals("maximizable")) - { - if (evt.getNewValue().equals(Boolean.TRUE)) - maxButton.setVisible(true); - else - maxButton.setVisible(false); - } - + { + if (evt.getNewValue().equals(Boolean.TRUE)) + maxButton.setVisible(true); + else + maxButton.setVisible(false); + } + enableActions(); } } @@ -340,7 +340,7 @@ public class BasicInternalFrameTitlePane extends JComponent * * @return True if this Component can receive focus. */ - public boolean isFocusTransversable() + public boolean isFocusTraversable() { return true; } @@ -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/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java index f6cbeec..7ec3aa0 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/libjava/classpath/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; @@ -255,7 +264,7 @@ public class BasicInternalFrameUI extends InternalFrameUI else if (e.getSource() == titlePane) { Rectangle fBounds = frame.getBounds(); - + frame.putClientProperty("bufferedDragging", Boolean.TRUE); dm.dragFrame(frame, e.getX() - xOffset + b.x, e.getY() - yOffset + b.y); } @@ -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; + } } /** @@ -326,7 +379,10 @@ public class BasicInternalFrameUI extends InternalFrameUI if (e.getSource() == frame && frame.isResizable()) dm.endResizingFrame(frame); else if (e.getSource() == titlePane) - dm.endDraggingFrame(frame); + { + dm.endDraggingFrame(frame); + frame.putClientProperty("bufferedDragging", null); + } } /** @@ -1119,12 +1175,8 @@ public class BasicInternalFrameUI extends InternalFrameUI installComponents(); installKeyboardActions(); - ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); if (! frame.isSelected()) - frame.getRootPane().getGlassPane().setVisible(true); - - frame.setOpaque(true); - frame.invalidate(); + frame.getGlassPane().setVisible(true); } } @@ -1140,9 +1192,7 @@ public class BasicInternalFrameUI extends InternalFrameUI uninstallListeners(); uninstallDefaults(); - ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(true); frame.getRootPane().getGlassPane().setVisible(false); - frame = null; } @@ -1155,12 +1205,22 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.setLayout(internalFrameLayout); LookAndFeel.installBorder(frame, "InternalFrame.border"); frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon")); + + // Let the content pane inherit the background color from its + // frame by setting the background to null. + Component contentPane = frame.getContentPane(); + if (contentPane != null + && contentPane.getBackground() instanceof UIResource) + { + contentPane.setBackground(null); + } } /** * This method installs the keyboard actions for the JInternalFrame. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Implement. } @@ -1243,6 +1303,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/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java index d0964f4..60e3a98 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java index 19dfe21..d9bc067 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java @@ -1,5 +1,5 @@ /* BasicListUI.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 @@ 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; @@ -179,7 +181,8 @@ public class BasicListUI extends ListUI int index1 = e.getFirstIndex(); int index2 = e.getLastIndex(); Rectangle damaged = getCellBounds(list, index1, index2); - list.repaint(damaged); + if (damaged != null) + list.repaint(damaged); } } @@ -716,7 +719,8 @@ public class BasicListUI extends ListUI * @param index2 The last row to incude in the bounds * * @return A rectangle encompassing the range of rows between - * <code>index1</code> and <code>index2</code> inclusive + * <code>index1</code> and <code>index2</code> inclusive, or null + * such a rectangle couldn't be calculated for the given indexes. */ public Rectangle getCellBounds(JList l, int index1, int index2) { @@ -1023,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. } @@ -1182,7 +1187,7 @@ public class BasicListUI extends ListUI for (int row = startIndex; row <= endIndex; ++row) { Rectangle bounds = getCellBounds(list, row, row); - if (bounds.intersects(clip)) + if (bounds != null && bounds.intersects(clip)) paintCell(g, row, bounds, render, model, sel, lead); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java index 3451224..78c16ef 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/libjava/classpath/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 "#C0C0C0", 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/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java index daa9b0d..f258ebe 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java +++ b/libjava/classpath/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; @@ -68,7 +70,7 @@ public class BasicMenuBarUI extends MenuBarUI protected ContainerListener containerListener; /*Property change listeners that listener to PropertyChangeEvent from menu bar*/ - protected PropertyChangeListener propertyChangeListener; + private PropertyChangeListener propertyChangeListener; /* menu bar for which this UI delegate is for*/ protected JMenuBar menuBar; @@ -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. } @@ -252,7 +256,7 @@ public class BasicMenuBarUI extends MenuBarUI menuBar = null; } - protected class ChangeHandler implements ChangeListener + private class ChangeHandler implements ChangeListener { public void stateChanged(ChangeEvent event) { @@ -264,7 +268,7 @@ public class BasicMenuBarUI extends MenuBarUI * This class handles ContainerEvents fired by JMenuBar. It revalidates * and repaints menu bar whenever menu is added or removed from it. */ - protected class ContainerHandler implements ContainerListener + private class ContainerHandler implements ContainerListener { /** * This method is called whenever menu is added to the menu bar @@ -292,7 +296,7 @@ public class BasicMenuBarUI extends MenuBarUI /** * This class handles PropertyChangeEvents fired from the JMenuBar */ - protected class PropertyChangeHandler implements PropertyChangeListener + private class PropertyChangeHandler implements PropertyChangeListener { /** * This method is called whenever one of the properties of the MenuBar diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java index 9166c49..69c9c45 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java index e638b68..f8936be 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java @@ -38,10 +38,11 @@ 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; -import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.JComponent; @@ -219,6 +220,7 @@ public class BasicMenuUI extends BasicMenuItemUI * */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -263,6 +265,7 @@ public class BasicMenuUI extends BasicMenuItemUI * Basic look and feel's defaults. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Need to implement } @@ -391,7 +394,7 @@ public class BasicMenuUI extends BasicMenuItemUI /** * This class handles MenuEvents fired by the JMenu */ - protected class MenuHandler implements MenuListener + private class MenuHandler implements MenuListener { /** * This method is called when menu is cancelled. The menu is cancelled @@ -440,24 +443,7 @@ public class BasicMenuUI extends BasicMenuItemUI } /** - * This class handles PropertyChangeEvents fired from the JMenu - */ - protected class PropertyChangeHandler implements PropertyChangeListener - { - /** - * This method is called whenever one of the properties of the menu item - * changes. - * - * @param e The PropertyChangeEvent. - */ - public void propertyChange(PropertyChangeEvent e) - { - // TODO: Implement this properly. - } - } - - /** - * @deprecated + * Obsolete as of JDK1.4. */ public class ChangeHandler implements ChangeListener { @@ -501,7 +487,7 @@ public class BasicMenuUI extends BasicMenuItemUI /** * This class handles mouse dragged events occuring in the menu. */ - protected class MenuDragMouseHandler implements MenuDragMouseListener + private class MenuDragMouseHandler implements MenuDragMouseListener { /** * This method is invoked when mouse is dragged over the menu item. @@ -553,7 +539,7 @@ public class BasicMenuUI extends BasicMenuItemUI * This class handles key events occuring when menu item is visible on the * screen. */ - protected class MenuKeyHandler implements MenuKeyListener + private class MenuKeyHandler implements MenuKeyListener { /** * This method is invoked when key has been pressed diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java index 005a3b3..88bca3b 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java index 783cec4..4f535f6 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java @@ -61,11 +61,10 @@ public class BasicPanelUI extends PanelUI } } - public void installDefaults(JPanel p) + protected void installDefaults(JPanel p) { LookAndFeel.installColorsAndFont(p, "Panel.background", "Panel.foreground", "Panel.font"); - p.setOpaque(true); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java index 6ecd06b..a26a5c7 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java index 66e5380..a66fa28 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java index 28e3b67..933db4c 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java index c8713c9..f244854 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/libjava/classpath/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; @@ -383,7 +385,7 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, * * @return Whether the thumb should keep scrolling. */ - public boolean shouldScroll(int direction) + boolean shouldScroll(int direction) { int value; if (scrollbar.getOrientation() == HORIZONTAL) @@ -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/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java index 71671b7..e6a4eaf 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java index 26f5805..137ab55 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java +++ b/libjava/classpath/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); } /** @@ -364,17 +373,20 @@ public class BasicSliderUI extends SliderUI */ public void mouseDragged(MouseEvent e) { - currentMouseX = e.getX(); - currentMouseY = e.getY(); - if (slider.getValueIsAdjusting()) + if (slider.isEnabled()) { - int value; - if (slider.getOrientation() == JSlider.HORIZONTAL) - value = valueForXPosition(currentMouseX) - offset; - else - value = valueForYPosition(currentMouseY) - offset; - - slider.setValue(value); + currentMouseX = e.getX(); + currentMouseY = e.getY(); + if (slider.getValueIsAdjusting()) + { + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX) - offset; + else + value = valueForYPosition(currentMouseY) - offset; + + slider.setValue(value); + } } } @@ -399,32 +411,36 @@ public class BasicSliderUI extends SliderUI */ public void mousePressed(MouseEvent e) { - currentMouseX = e.getX(); - currentMouseY = e.getY(); - - int value; - if (slider.getOrientation() == JSlider.HORIZONTAL) - value = valueForXPosition(currentMouseX); - else - value = valueForYPosition(currentMouseY); - - if (slider.getSnapToTicks()) - value = findClosestTick(value); - - // If the thumb is hit, then we don't need to set the timers to move it. - if (! thumbRect.contains(e.getPoint())) - { - // The mouse has hit some other part of the slider. - // The value moves no matter where in the slider you hit. - if (value > slider.getValue()) - scrollDueToClickInTrack(POSITIVE_SCROLL); - else - scrollDueToClickInTrack(NEGATIVE_SCROLL); - } - else + if (slider.isEnabled()) { - slider.setValueIsAdjusting(true); - offset = value - slider.getValue(); + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + int value; + if (slider.getOrientation() == JSlider.HORIZONTAL) + value = valueForXPosition(currentMouseX); + else + value = valueForYPosition(currentMouseY); + + if (slider.getSnapToTicks()) + value = findClosestTick(value); + + // If the thumb is hit, then we don't need to set the timers to + // move it. + if (! thumbRect.contains(e.getPoint())) + { + // The mouse has hit some other part of the slider. + // The value moves no matter where in the slider you hit. + if (value > slider.getValue()) + scrollDueToClickInTrack(POSITIVE_SCROLL); + else + scrollDueToClickInTrack(NEGATIVE_SCROLL); + } + else + { + slider.setValueIsAdjusting(true); + offset = value - slider.getValue(); + } } } @@ -436,17 +452,20 @@ public class BasicSliderUI extends SliderUI */ public void mouseReleased(MouseEvent e) { - currentMouseX = e.getX(); - currentMouseY = e.getY(); - - if (slider.getValueIsAdjusting()) + if (slider.isEnabled()) { - slider.setValueIsAdjusting(false); - if (slider.getSnapToTicks()) - slider.setValue(findClosestTick(slider.getValue())); + currentMouseX = e.getX(); + currentMouseY = e.getY(); + + if (slider.getValueIsAdjusting()) + { + slider.setValueIsAdjusting(false); + if (slider.getSnapToTicks()) + slider.setValue(findClosestTick(slider.getValue())); + } + if (scrollTimer != null) + scrollTimer.stop(); } - if (scrollTimer != null) - scrollTimer.stop(); } /** @@ -460,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()); } } @@ -643,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(); } } @@ -856,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); } /** @@ -868,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. @@ -899,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. @@ -1120,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() { @@ -1135,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() { @@ -1163,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 @@ -1207,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 { @@ -1222,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; } } @@ -1252,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; } } @@ -1280,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; } } @@ -1312,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; } @@ -1340,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. */ @@ -1391,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. */ @@ -1406,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(); } /** @@ -1437,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)) @@ -1451,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() { @@ -1466,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)) @@ -1490,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(); @@ -1599,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); @@ -1647,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. */ @@ -1819,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); + } + } } } @@ -1918,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()); } /** @@ -1957,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()); } /** @@ -1997,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); @@ -2071,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); @@ -2091,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); @@ -2126,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); } /** @@ -2279,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 @@ -2307,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/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java index 6f7a41a..465374b 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java index 8a7c9d2..694baad 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/libjava/classpath/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; @@ -101,6 +103,16 @@ public class BasicSplitPaneUI extends SplitPaneUI protected int[] sizes = new int[3]; /** + * Creates a new instance. This is package private because the reference + * implementation has no public constructor either. Still, we need to + * call it from BasicVerticalLayoutManager. + */ + BasicHorizontalLayoutManager() + { + // Nothing to do here. + } + + /** * This method adds the component given to the JSplitPane. The position of * the component is given by the constraints object. * @@ -1037,6 +1049,7 @@ public class BasicSplitPaneUI extends SplitPaneUI * This method installs the keyboard actions for the JSplitPane. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -1045,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/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 5b1e1ff..6d9bed3 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java index 1e8e39f..cfbebda 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/libjava/classpath/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; @@ -96,7 +98,12 @@ public class BasicTableHeaderUI extends TableHeaderUI /** * The header cell border. */ - protected Border cellBorder; + 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/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java index 8360a9e..ef491cb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java index 36854e0..93e119b 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextAreaUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java index 4e2ca9f..89c4e5a 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java index beb1a6d..3b620f0 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java +++ b/libjava/classpath/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()); } @@ -546,7 +559,6 @@ public abstract class BasicTextUI extends TextUI public void installUI(final JComponent c) { super.installUI(c); - c.setOpaque(true); textComponent = (JTextComponent) c; Document doc = textComponent.getDocument(); @@ -608,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. + } + } } }; @@ -655,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; } /** @@ -689,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, @@ -794,6 +831,7 @@ public abstract class BasicTextUI extends TextUI * this UI. */ protected void uninstallKeyboardActions() + throws NotImplementedException { // FIXME: Uninstall keyboard actions here. } @@ -986,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 @@ -1000,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 @@ -1023,7 +1068,11 @@ public abstract class BasicTextUI extends TextUI // we should stop searching for one. int posBelow = Utilities.getPositionBelow(t, p0, l1.x); - if (posBelow < p1 && posBelow != -1 && posBelow != p0) + int p1RowStart = Utilities.getRowStart(t, p1); + + if (posBelow != -1 + && posBelow != p0 + && Utilities.getRowStart(t, posBelow) != p1RowStart) { // Take the rectangle of the offset we just found and grow it // to the maximum width. Retain y because this is our start @@ -1034,10 +1083,15 @@ public abstract class BasicTextUI extends TextUI // Find further lines which have to be damaged completely. int nextPosBelow = posBelow; - while (nextPosBelow < p1 && nextPosBelow != -1 && posBelow != nextPosBelow) + while (nextPosBelow != -1 + && posBelow != nextPosBelow + && Utilities.getRowStart(t, nextPosBelow) != p1RowStart) { posBelow = nextPosBelow; nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x); + + if (posBelow == nextPosBelow) + break; } // Now posBelow is an offset on the last line which has to be damaged // completely. (newPosBelow is on the same line as p1) @@ -1099,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); } /** @@ -1155,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; } /** @@ -1232,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/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java index 261db68..80fec6a 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/libjava/classpath/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; @@ -60,6 +62,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Hashtable; +import javax.swing.AbstractButton; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; @@ -72,8 +75,8 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; +import javax.swing.border.EtchedBorder; import javax.swing.event.MouseInputListener; -import javax.swing.plaf.BorderUIResource.EtchedBorderUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ToolBarUI; import javax.swing.plaf.UIResource; @@ -307,7 +310,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createNonRolloverBorder() { - return new EtchedBorderUIResource(); + return new EtchedBorder(); } /** @@ -328,7 +331,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createRolloverBorder() { - return new EtchedBorderUIResource() + return new EtchedBorder() { public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) @@ -577,6 +580,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants rolloverBorder = createRolloverBorder(); borders = new Hashtable(); + setRolloverBorders(toolBar.isRollover()); fillHashtable(); } @@ -595,7 +599,6 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants floatingBorderColor = UIManager.getColor("ToolBar.floatingForeground"); floatingColor = UIManager.getColor("ToolBar.floatingBackground"); - setRolloverBorders(toolBar.isRollover()); } /** @@ -603,6 +606,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants * by the look and feel. */ protected void installKeyboardActions() + throws NotImplementedException { // FIXME: implement. } @@ -707,9 +711,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants if (c instanceof JToolBar) { toolBar = (JToolBar) c; - toolBar.setOpaque(true); - installDefaults(); - installComponents(); + installDefaults(); + installComponents(); installListeners(); installKeyboardActions(); } @@ -754,9 +757,9 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected void setBorderToNonRollover(Component c) { - if (c instanceof JButton) + if (c instanceof AbstractButton) { - JButton b = (JButton) c; + AbstractButton b = (AbstractButton) c; b.setRolloverEnabled(false); b.setBorder(nonRolloverBorder); } @@ -875,8 +878,6 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants { installNormalBorders(toolBar); borders = null; - rolloverBorder = null; - nonRolloverBorder = null; cachedBounds = null; floatFrame = null; @@ -902,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. } @@ -1231,8 +1233,8 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants public void propertyChange(PropertyChangeEvent e) { // FIXME: need name properties so can change floatFrame title. - if (e.getPropertyName().equals("rollover")) - setRolloverBorders(toolBar.isRollover()); + if (e.getPropertyName().equals("rollover") && toolBar != null) + setRolloverBorders(toolBar.isRollover()); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java index 1c6e6c5..be61cca 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java +++ b/libjava/classpath/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,16 @@ 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.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 +118,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 +253,40 @@ 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 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 +309,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 +337,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 +348,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 +368,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 +388,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 +408,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 +428,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 +453,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 +469,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 +501,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 +523,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 +543,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 +563,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 +584,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 +605,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 +631,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 +669,47 @@ public class BasicTreeUI extends TreeUI maxHeight = Math.max(maxHeight, iconHeight + gap); } - + + treeState.setRowHeight(maxHeight); return maxHeight; } /** * 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 +718,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 +745,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 +755,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 +787,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 +835,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 +952,7 @@ public class BasicTreeUI extends TreeUI */ protected AbstractLayoutCache createLayoutCache() { - return new FixedHeightLayoutCache(); + return new VariableHeightLayoutCache(); } /** @@ -1152,8 +1086,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 +1098,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) @@ -1212,11 +1144,13 @@ public class BasicTreeUI extends TreeUI /** * 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 +1170,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 +1191,7 @@ public class BasicTreeUI extends TreeUI protected void pathWasCollapsed(TreePath path) { validCachedPreferredSize = false; + treeState.setExpandedState(path, false); tree.repaint(); } @@ -1345,8 +1257,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 +1265,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 +1310,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,6 +1330,8 @@ public class BasicTreeUI extends TreeUI setModel(tree.getModel()); treeSelectionModel = tree.getSelectionModel(); + setRootVisible(tree.isRootVisible()); + treeState.setRootVisible(tree.isRootVisible()); completeUIInstall(); } @@ -1436,8 +1349,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 +1368,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++) + { + 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++) { - 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); + 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 +1478,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 +1486,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 +1500,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 +1524,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 +1545,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 +1583,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 +1617,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 +1667,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 +1683,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 +1696,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 +1712,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 +1727,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 +1739,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 +1780,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 +1794,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 +1817,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 +1828,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 +1856,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 +1895,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 +1916,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 +1939,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 +1965,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 +1995,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 +2007,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 +2022,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 +2033,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 +2044,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 +2057,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 +2096,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 +2119,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 +2129,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 +2139,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 +2151,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 +2166,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 +2177,7 @@ public class BasicTreeUI extends TreeUI startEditTimer.stop(); startEditTimer = null; } - + Point click = e.getPoint(); TreePath path = getClosestPathForLocation(tree, click.x, click.y); @@ -2228,6 +2185,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 +2220,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 +2268,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 +2279,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 +2289,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 +2302,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 +2314,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 +2329,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 +2339,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 +2349,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 +2359,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 +2369,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 +2382,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 +2393,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 +2414,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 +2431,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, @@ -2509,6 +2452,8 @@ public class BasicTreeUI extends TreeUI { size.x = getRowX(row, depth); size.width = SwingUtilities.computeStringWidth(fm, s); + size.width = size.width + getCurrentControlIcon(null).getIconWidth() + + gap; size.height = getMaxHeight(tree); size.y = size.height * row; } @@ -2523,17 +2468,17 @@ public class BasicTreeUI extends TreeUI */ protected int getRowX(int row, int depth) { - if (row == 0) - return 0; - return depth * rightChildIndent; + int iw = getCurrentControlIcon(null).getIconWidth(); + return depth * (rightChildIndent + iw/2); } }// 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 +2492,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 +2521,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 +2536,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 +2548,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 +2563,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 +2585,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 +2600,26 @@ 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); + 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); + tree.revalidate(); tree.repaint(); } }// TreeExpansionHandler @@ -2670,7 +2628,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 +2638,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 +2649,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 +2672,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 +2682,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 +2693,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 +2784,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 +2805,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 +2819,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 +2836,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 +2852,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 +2868,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 +2877,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 +2888,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 +2910,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 +2925,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 +2970,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 +2992,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 +3003,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 +3014,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); } } } @@ -3113,10 +3102,8 @@ public class BasicTreeUI extends TreeUI /** * 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 +3119,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 +3143,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 +3164,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 +3185,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 +3204,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 +3221,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 +3243,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 +3258,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 +3274,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 +3293,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 +3304,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 +3322,34 @@ public class BasicTreeUI extends TreeUI boolean isLeaf) { if (row != 0) - paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, bounds.x - gap - - 2, bounds.x); + { + Icon icon = getCurrentControlIcon(path); + int iconW = icon.getIconWidth(); + paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, + bounds.x - iconW/2 - 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 +3357,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 +3376,23 @@ 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 = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + 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 +3407,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 +3419,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/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java index 99c90ac..98a00ee 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalBorders.java @@ -59,6 +59,7 @@ import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.border.AbstractBorder; import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicBorders; @@ -138,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 (c.isEnabled()) + { + // draw dark border + g.setColor(darkShadow); + g.drawRect(x, y, w - 2, h - 2); - if (!bmodel.isPressed()) + // 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); @@ -166,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 @@ -184,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); } } @@ -218,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()) { @@ -1025,14 +1068,10 @@ public class MetalBorders public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { - boolean mouseIsOver = false; - if (c instanceof AbstractButton) - { - ButtonModel bmodel = ((AbstractButton) c).getModel(); - mouseIsOver = bmodel.isRollover(); - } - if (mouseIsOver) - super.paintBorder(c, g, x, y, w, h); + // TODO: What should be done here? Obviously the ButtonBorder already + // handles the rollover state in Sun's impl. Maybe this is only there + // for backwards compatibility. + super.paintBorder(c, g, x, y, w, h); } } @@ -1520,8 +1559,7 @@ public class MetalBorders { Border outer = new ButtonBorder(); Border inner = new RolloverMarginBorder(); - toolbarButtonBorder = new BorderUIResource.CompoundBorderUIResource - (outer, inner); + toolbarButtonBorder = new CompoundBorder(outer, inner); } return toolbarButtonBorder; } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java index e6fb22e..f2f778f 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonListener.java @@ -41,7 +41,6 @@ package javax.swing.plaf.metal; import java.beans.PropertyChangeEvent; import javax.swing.AbstractButton; -import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicButtonListener; /** @@ -70,17 +69,6 @@ class MetalButtonListener extends BasicButtonListener public void propertyChange(PropertyChangeEvent e) { super.propertyChange(e); - if (e.getPropertyName().equals( - AbstractButton.ROLLOVER_ENABLED_CHANGED_PROPERTY)) - { - AbstractButton b = (AbstractButton) e.getSource(); - if (b.getBorder() instanceof UIResource) - { - if (Boolean.TRUE.equals(e.getNewValue())) - b.setBorder(MetalBorders.getRolloverBorder()); - else if (Boolean.FALSE.equals(e.getNewValue())) - b.setBorder(MetalBorders.getButtonBorder()); - } - } + // TODO: What should be done here? } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java index 10e5111..83cd336 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalButtonUI.java @@ -45,6 +45,7 @@ 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; @@ -160,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. @@ -234,8 +235,12 @@ public class MetalButtonUI public void update(Graphics g, JComponent c) { AbstractButton b = (AbstractButton) c; - if (b.isOpaque() && UIManager.get(getPropertyPrefix() + "gradient") != null - && !b.getModel().isPressed() && b.isEnabled()) + ButtonModel m = b.getModel(); + if (b.isContentAreaFilled() + && (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/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java index 6993e18..3787a98 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java @@ -38,22 +38,25 @@ exception statement from your version. */ package javax.swing.plaf.metal; +import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Insets; -import java.awt.Rectangle; import javax.swing.CellRendererPane; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JList; -import javax.swing.SwingUtilities; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; /** * A button used by the {@link MetalComboBoxUI} class. */ -public class MetalComboBoxButton extends JButton { +public class MetalComboBoxButton + extends JButton +{ /** A reference to the JComboBox that the button belongs to. */ protected JComboBox comboBox; @@ -61,7 +64,9 @@ public class MetalComboBoxButton extends JButton { /** A reference to the JList. */ protected JList listBox; - /** ??? */ + /** + * Used for rendering the selected item. + */ protected CellRendererPane rendererPane; /** The button icon. */ @@ -91,7 +96,7 @@ public class MetalComboBoxButton extends JButton { * @param cb the combo that the button is used for (<code>null</code> not * permitted). * @param i the icon displayed on the button. - * @parma onlyIcon a flag that specifies whether the button displays only an + * @param onlyIcon a flag that specifies whether the button displays only an * icon, or text as well. * @param pane the rendering pane. * @param list the list. @@ -107,6 +112,9 @@ public class MetalComboBoxButton extends JButton { iconOnly = onlyIcon; listBox = list; rendererPane = pane; + setRolloverEnabled(false); + setEnabled(comboBox.isEnabled()); + setFocusable(comboBox.isEnabled()); } /** @@ -191,8 +199,16 @@ public class MetalComboBoxButton extends JButton { 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")); + } } /** @@ -203,39 +219,75 @@ public class MetalComboBoxButton extends JButton { public void paintComponent(Graphics g) { super.paintComponent(g); - if (iconOnly) - { - Rectangle bounds = getBounds(); - int x = (bounds.width - comboIcon.getIconWidth()) / 2; - int y = (bounds.height - comboIcon.getIconHeight()) / 2; - comboIcon.paintIcon(comboBox, g, x, y); - } - else + Insets insets = this.getInsets(); + int w = getWidth() - (insets.left + insets.right); + int h = getHeight() - (insets.top + insets.bottom); + if (h > 0 && w > 0) { - Object selected = comboBox.getModel().getSelectedItem(); - if (selected == null) - selected = ""; - Rectangle bounds = comboBox.getBounds(); - Rectangle innerArea = SwingUtilities.calculateInnerArea(this, null); - Insets insets = comboBox.getInsets(); - Rectangle renderArea = new Rectangle(innerArea.x, innerArea.y, - innerArea.width - comboIcon.getIconWidth() - 4, innerArea.height); - Component cellRenderer - = comboBox.getRenderer().getListCellRendererComponent(this.listBox, - selected, comboBox.getSelectedIndex(), false, false); - cellRenderer.setBackground(comboBox.getBackground()); - cellRenderer.setEnabled(comboBox.isEnabled()); - rendererPane.paintComponent(g, cellRenderer, this, renderArea); - if (comboBox.hasFocus()) + int x1 = insets.left; + int y1 = insets.top; + int x2 = x1 + (w - 1); + int y2 = y1 + (h - 1); + int iconWidth = 0; + int iconX = x2; + if (comboIcon != null) + { + iconWidth = comboIcon.getIconWidth(); + int iconHeight = comboIcon.getIconHeight(); + int iconY; + if (iconOnly) + { + iconX = getWidth() / 2 - iconWidth / 2; + iconY = getHeight() / 2 - iconHeight / 2; + } + else + { + iconX = x1 + (w - 1) - iconWidth; + iconY = y1 + (y2 - y1) / 2 - iconHeight / 2; + } + comboIcon.paintIcon(this, g, iconX, iconY); + if (this.hasFocus()) + { + g.setColor(MetalLookAndFeel.getFocusColor()); + g.drawRect(x1 - 1, y1 - 1, w + 3, h + 1); + } + } + if (! iconOnly && comboBox != null) { - g.setColor(MetalLookAndFeel.getFocusColor()); - g.drawRect(innerArea.x, innerArea.y - 1, innerArea.width - 1, - innerArea.height); + ListCellRenderer renderer = comboBox.getRenderer(); + boolean pressed = this.getModel().isPressed(); + Component comp= renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), + -1, false, false); + comp.setFont(rendererPane.getFont()); + if (model.isArmed() && model.isPressed()) + { + if (isOpaque()) + { + comp.setBackground(UIManager.getColor("Button.select")); + comp.setForeground(comboBox.getForeground()); + } + } + else if (! comboBox.isEnabled()) + { + if (this.isOpaque()) + { + Color dbg = + UIManager.getColor("ComboBox.disabledBackground"); + comp.setBackground(dbg); + Color dfg = + UIManager.getColor("ComboBox.disabledForeground"); + comp.setForeground(dfg); + } + } + else + { + comp.setForeground(comboBox.getForeground()); + comp.setBackground(comboBox.getBackground()); + } + int wr = w - (insets.right + iconWidth); + rendererPane.paintComponent(g, comp, this, x1, y1, wr, h); } - int iconX = bounds.width - insets.right - comboIcon.getIconWidth() - 7; - int iconY = insets.top - + (bounds.height - comboIcon.getIconHeight()) / 2; - comboIcon.paintIcon(comboBox, g, iconX, iconY); } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java index a531079..11e4151 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxEditor.java @@ -38,15 +38,15 @@ exception statement from your version. */ package javax.swing.plaf.metal; -import java.awt.Color; import java.awt.Component; +import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import javax.swing.JTextField; +import javax.swing.border.AbstractBorder; import javax.swing.plaf.basic.BasicComboBoxEditor; import javax.swing.plaf.metal.MetalLookAndFeel; -import javax.swing.plaf.metal.MetalBorders.Flush3DBorder; /** * An editor used by the {@link MetalComboBoxUI} class. @@ -56,7 +56,7 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor /** * A border used for the {@link JTextField} component. */ - static class MetalComboBoxEditorBorder extends Flush3DBorder + static class MetalComboBoxEditorBorder extends AbstractBorder { /** * Creates a new border instance. @@ -78,20 +78,34 @@ public class MetalComboBoxEditor extends BasicComboBoxEditor */ public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) - { - Color savedColor = g.getColor(); - if (c.isEnabled()) - g.setColor(MetalLookAndFeel.getControlDarkShadow()); + { + g.translate(x, y); + 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.getControlShadow()); - g.drawLine(x, y, x + w - 1, y); - g.drawLine(x, y, x, y + h - 2); - g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2); - g.setColor(MetalLookAndFeel.getControl()); - g.drawLine(x + 1, y + h - 2, x + 1, y + h - 2); - g.setColor(MetalLookAndFeel.getWhite()); - g.drawLine(x, y + h - 1, x + w - 1, y + h - 1); - g.setColor(savedColor); + { + 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); } /** @@ -127,16 +141,49 @@ 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(4, 2, 4, 0); + protected static Insets editorBorderInsets = new Insets(2, 2, 2, 0); /** * Creates a new editor. */ public MetalComboBoxEditor() { - super(); + editor = new EditorTextField("", 9); editor.setBorder(new MetalComboBoxEditorBorder()); } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java index 0006b78..c24c085 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java @@ -38,12 +38,12 @@ 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; import java.awt.Insets; import java.awt.LayoutManager; -import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -88,14 +88,7 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public void layoutContainer(Container parent) { - JComboBox cb = (JComboBox) parent; - if (!cb.isEditable()) - { - Rectangle bounds = parent.getBounds(); - arrowButton.setBounds(0, 0, bounds.width, bounds.height); - } - else - superLayout(parent); + layoutComboBox(parent, this); } /** @@ -134,9 +127,31 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName().equals("editable")) - editablePropertyChanged(e); super.propertyChange(e); + String name = e.getPropertyName(); + if (name.equals("editable")) + editablePropertyChanged(e); + else if (name.equals("enabled")) + { + if (arrowButton instanceof MetalComboBoxButton) + { + arrowButton.setFocusable(!comboBox.isEditable() + && comboBox.isEnabled()); + 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); + } } } @@ -247,22 +262,8 @@ public class MetalComboBoxUI extends BasicComboBoxUI { MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; b.setIconOnly(comboBox.isEditable()); - } - if (comboBox.isEditable()) - { - arrowButton.setText(null); - if (editor != null) - editor.setVisible(true); - } - else - { - String text = ""; - Object selected = comboBox.getSelectedItem(); - if (selected != null) - text = selected.toString(); - arrowButton.setText(text); - if (editor != null) - editor.setVisible(true); + b.setFocusable(!comboBox.isEditable() && comboBox.isEnabled()); + comboBox.repaint(); } } @@ -295,22 +296,39 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public Dimension getMinimumSize(JComponent c) { - Dimension d = getDisplaySize(); - MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; - Insets insets = b.getInsets(); - int insetsH = insets.top + insets.bottom; - int insetsW = insets.left + insets.right; - if (!comboBox.isEditable()) + if (!isMinimumSizeDirty) + return new Dimension(cachedMinimumSize); + + Dimension d; + if (!comboBox.isEditable() && arrowButton != null + && arrowButton instanceof MetalComboBoxButton) { + MetalComboBoxButton b = (MetalComboBoxButton) arrowButton; + d = getDisplaySize(); + Insets insets = b.getInsets(); + Insets arrowInsets = b.getInsets(); + Insets comboInsets = comboBox.getInsets(); Icon icon = b.getComboIcon(); - int iconWidth = icon.getIconWidth() + 6; - return new Dimension(d.width + insetsW + iconWidth, d.height + insetsH); + d.width += comboInsets.left + comboInsets.right; + d.width += arrowInsets.left + arrowInsets.right; + d.width += arrowInsets.right + icon.getIconWidth(); + d.height += comboInsets.top + comboInsets.bottom; + d.height += arrowInsets.top + arrowInsets.bottom; + } + else if (comboBox.isEditable() && arrowButton != null && editor != null) + { + d = super.getMinimumSize(c); + Insets arrowMargin = arrowButton.getMargin(); + d.height += arrowMargin.top + arrowMargin.bottom; + d.width += arrowMargin.left + arrowMargin.right; } else - // FIXME: the following dimensions pass most of the Mauve tests, but - // I don't yet understand the logic behind this...it is probably wrong - return new Dimension(d.width + insetsW + (d.height + insetsH) - 4, - d.height + insetsH + 1); + { + d = super.getMinimumSize(c); + } + cachedMinimumSize.setSize(d.width, d.height); + isMinimumSizeDirty = false; + return new Dimension(cachedMinimumSize); } /** @@ -318,27 +336,21 @@ public class MetalComboBoxUI extends BasicComboBoxUI */ public void configureEditor() { - ComboBoxEditor cbe = comboBox.getEditor(); - if (cbe != null) - { - cbe.getEditorComponent().setFont(comboBox.getFont()); - cbe.setItem(comboBox.getSelectedItem()); - cbe.addActionListener(comboBox); - } + super.configureEditor(); + if (popupKeyListener != null) + editor.removeKeyListener(popupKeyListener); + if (focusListener != null) + editor.addFocusListener(focusListener); } - + /** * Unconfigures the editor for this combo box. */ public void unconfigureEditor() { - ComboBoxEditor cbe = comboBox.getEditor(); - if (cbe != null) - { - cbe.getEditorComponent().setFont(null); - cbe.setItem(null); - cbe.removeActionListener(comboBox); - } + super.unconfigureEditor(); + if (focusListener != null) + editor.removeFocusListener(focusListener); } /** @@ -347,6 +359,16 @@ public class MetalComboBoxUI extends BasicComboBoxUI public void layoutComboBox(Container parent, MetalComboBoxUI.MetalComboBoxLayoutManager manager) { - manager.layoutContainer(parent); + if (comboBox.isEditable()) + manager.superLayout(parent); + else if (arrowButton != null) + { + Insets comboInsets = comboBox.getInsets(); + int width = comboBox.getWidth(); + int height = comboBox.getHeight(); + arrowButton.setBounds(comboInsets.left, comboInsets.top, + width - (comboInsets.left + comboInsets.right), + height - (comboInsets.top + comboInsets.bottom)); + } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java index ecbb76e..0c1163a 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalDesktopIconUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java index 0b644f3..d24a052 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java @@ -756,6 +756,17 @@ public class MetalIconFactory implements Serializable { /** + * This is used as a mask when painting the gradient. See + * {@link MetalUtils#paintGradient(java.awt.Graphics, int, int, int, int, + * float, float, java.awt.Color, java.awt.Color, java.awt.Color, int, + * int[][])} for details. + */ + private static int[][] gradientMask = new int[][] {{3, 7}, {1, 9}, {1, 9}, + {0, 10}, {0, 10}, {0, 10}, + {0, 10}, {1, 9}, {1, 9}, + {3, 7}}; + + /** * Returns the width of the icon in pixels. * * @return the width of the icon in pixels @@ -788,12 +799,13 @@ public class MetalIconFactory implements Serializable public void paintIcon(Component c, Graphics g, int x, int y) { if (UIManager.get("RadioButton.gradient") != null) - MetalUtils.paintGradient(g, x, y, getIconWidth(), getIconHeight(), - SwingConstants.VERTICAL, "RadioButton.gradient"); + MetalUtils.paintGradient(g, x + 2, y + 2, 8, 8, + SwingConstants.VERTICAL, "RadioButton.gradient", + gradientMask); Color savedColor = g.getColor(); JRadioButton b = (JRadioButton) c; - + // draw outer circle if (b.isEnabled()) g.setColor(MetalLookAndFeel.getControlDarkShadow()); @@ -951,6 +963,14 @@ public class MetalIconFactory implements Serializable { /** + * This mask is used to paint the gradient in the shape of the thumb. + */ + int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12}, + {0, 12}, {0, 12}, {0, 12}, {1, 12}, + {2, 10}, {3, 9}, {4, 8}, {5, 7}, + {6, 6}}; + + /** * Creates a new instance. */ public HorizontalSliderThumbIcon() @@ -1008,21 +1028,37 @@ public class MetalIconFactory implements Serializable g.drawLine(x + 6, y + 14, x, y + 8); g.drawLine(x, y + 7, x, y + 1); - // fill the icon - if (focus) - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + // Fill the icon. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme + && enabled) + { + String gradient; + if (focus) + gradient = "Slider.focusGradient"; + else + gradient = "Slider.gradient"; + MetalUtils.paintGradient(g, x + 1, y + 2, 12, 13, + SwingConstants.VERTICAL, gradient, + gradientMask); + } else - g.setColor(MetalLookAndFeel.getControl()); - g.fillRect(x + 1, y + 2, 13, 7); - g.drawLine(x + 2, y + 9, x + 12, y + 9); - g.drawLine(x + 3, y + 10, x + 11, y + 10); - g.drawLine(x + 4, y + 11, x + 10, y + 11); - g.drawLine(x + 5, y + 12, x + 9, y + 12); - g.drawLine(x + 6, y + 13, x + 8, y + 13); - g.drawLine(x + 7, y + 14, x + 7, y + 14); - - // if the slider is enabled, draw dots and highlights - if (c.isEnabled()) + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x + 1, y + 2, 13, 7); + g.drawLine(x + 2, y + 9, x + 12, y + 9); + g.drawLine(x + 3, y + 10, x + 11, y + 10); + g.drawLine(x + 4, y + 11, x + 10, y + 11); + g.drawLine(x + 5, y + 12, x + 9, y + 12); + g.drawLine(x + 6, y + 13, x + 8, y + 13); + g.drawLine(x + 7, y + 14, x + 7, y + 14); + } + + // If the slider is enabled, draw dots and highlights. + if (c.isEnabled() + && !(MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) { if (focus) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); @@ -1039,7 +1075,7 @@ public class MetalIconFactory implements Serializable g.drawLine(x + 7, y + 7, x + 7, y + 7); g.drawLine(x + 11, y + 7, x + 11, y + 7); - // draw highlights + // Draw highlights if (focus) g.setColor(MetalLookAndFeel.getPrimaryControl()); else @@ -1583,6 +1619,14 @@ public class MetalIconFactory implements Serializable private static class VerticalSliderThumbIcon implements Icon, Serializable { /** + * This mask is used to paint the gradient in the shape of the thumb. + */ + int[][] gradientMask = new int[][] { {0, 12}, {0, 12}, {0, 12}, {0, 12}, + {0, 12}, {0, 12}, {0, 12}, {1, 12}, + {2, 10}, {3, 9}, {4, 8}, {5, 7}, + {6, 6}}; + + /** * Creates a new instance. */ public VerticalSliderThumbIcon() @@ -1641,21 +1685,37 @@ public class MetalIconFactory implements Serializable g.drawLine(x + 8, y + 14, x + 1, y + 14); g.drawLine(x, y + 13, x, y + 1); - // fill the icon - if (focus) - g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + // Fill the icon. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme + && enabled) + { + String gradient; + if (focus) + gradient = "Slider.focusGradient"; + else + gradient = "Slider.gradient"; + MetalUtils.paintGradient(g, x + 2, y + 1, 13, 12, + SwingConstants.HORIZONTAL, gradient, + gradientMask); + } else - g.setColor(MetalLookAndFeel.getControl()); - g.fillRect(x + 2, y + 1, 7, 13); - g.drawLine(x + 9, y + 2, x + 9, y + 12); - g.drawLine(x + 10, y + 3, x + 10, y + 11); - g.drawLine(x + 11, y + 4, x + 11, y + 10); - g.drawLine(x + 12, y + 5, x + 12, y + 9); - g.drawLine(x + 13, y + 6, x + 13, y + 8); - g.drawLine(x + 14, y + 7, x + 14, y + 7); - + { + if (focus) + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + else + g.setColor(MetalLookAndFeel.getControl()); + g.fillRect(x + 2, y + 1, 7, 13); + g.drawLine(x + 9, y + 2, x + 9, y + 12); + g.drawLine(x + 10, y + 3, x + 10, y + 11); + g.drawLine(x + 11, y + 4, x + 11, y + 10); + g.drawLine(x + 12, y + 5, x + 12, y + 9); + g.drawLine(x + 13, y + 6, x + 13, y + 8); + g.drawLine(x + 14, y + 7, x + 14, y + 7); + } + // if the slider is enabled, draw dots and highlights - if (enabled) + if (enabled + && ! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) { if (focus) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java index 2cf5f67..f74828e 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java +++ b/libjava/classpath/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); @@ -329,9 +333,10 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane } /** - * Creates a new instance of {@link MetalTitlePaneLayout}. + * Creates a new instance of <code>MetalTitlePaneLayout</code> (not part of + * the public API). * - * @return A new instance of {@link MetalTitlePaneLayout}. + * @return A new instance of <code>MetalTitlePaneLayout</code>. */ protected LayoutManager createLayout() { @@ -382,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/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java index e846446..7a973d4 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -1,5 +1,5 @@ /* MetalLookAndFeel.java - Copyright (C) 2002, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -90,7 +90,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel protected void createDefaultTheme() { if (theme == null) - setCurrentTheme(new DefaultMetalTheme()); + setCurrentTheme(new OceanTheme()); } /** @@ -899,7 +899,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "CheckBoxMenuItem.acceleratorForeground", getAcceleratorForeground(), "CheckBoxMenuItem.acceleratorSelectionForeground", getAcceleratorSelectedForeground(), "CheckBoxMenuItem.background", getMenuBackground(), - "CheckBoxMenuItem.borderPainted", new Boolean(true), + "CheckBoxMenuItem.borderPainted", Boolean.TRUE, "CheckBoxMenuItem.commandSound", "sounds/MenuItemCommand.wav", "CheckBoxMenuItem.checkIcon", MetalIconFactory.getCheckBoxMenuItemIcon(), "CheckBoxMenuItem.disabledForeground", getMenuDisabledForeground(), @@ -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/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java index 23051e9..6cabc7e 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalRootPaneUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java index 155bb81..c7dfd11 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -349,10 +349,15 @@ public class MetalScrollBarUI extends BasicScrollBarUI else paintThumbVertical(g, c, thumbBounds); - // draw the pattern - MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3, - thumbBounds.width - 6, thumbBounds.height - 6, - thumbHighlightColor, thumbLightShadowColor); + // Draw the pattern when the theme is not Ocean. + if (! (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme)) + { + MetalUtils.fillMetalPattern(c, g, thumbBounds.x + 3, thumbBounds.y + 3, + thumbBounds.width - 6, + thumbBounds.height - 6, + thumbHighlightColor, + thumbLightShadowColor); + } } /** @@ -370,13 +375,24 @@ public class MetalScrollBarUI extends BasicScrollBarUI int w = thumbBounds.width; int h = thumbBounds.height; - // first we fill the background - g.setColor(thumbColor); - if (isFreeStanding) - g.fillRect(x, y, w, h - 1); + // First we fill the background. + MetalTheme theme = MetalLookAndFeel.getCurrentTheme(); + if (theme instanceof OceanTheme + && UIManager.get("ScrollBar.gradient") != null) + { + MetalUtils.paintGradient(g, x + 2, y + 2, w - 4, h - 2, + SwingConstants.VERTICAL, + "ScrollBar.gradient"); + } else - g.fillRect(x, y, w, h); - + { + g.setColor(thumbColor); + if (isFreeStanding) + g.fillRect(x, y, w, h - 1); + else + g.fillRect(x, y, w, h); + } + // then draw the dark box g.setColor(thumbLightShadowColor); if (isFreeStanding) @@ -405,6 +421,19 @@ public class MetalScrollBarUI extends BasicScrollBarUI g.setColor(UIManager.getColor("ScrollBar.shadow")); g.drawLine(x + w, y + 1, x + w, y + h - 1); + // For the OceanTheme, draw the 3 lines in the middle. + if (theme instanceof OceanTheme) + { + g.setColor(thumbLightShadowColor); + int middle = x + w / 2; + g.drawLine(middle - 2, y + 4, middle - 2, y + h - 5); + g.drawLine(middle, y + 4, middle, y + h - 5); + g.drawLine(middle + 2, y + 4, middle + 2, y + h - 5); + g.setColor(UIManager.getColor("ScrollBar.highlight")); + g.drawLine(middle - 1, y + 5, middle - 1, y + h - 4); + g.drawLine(middle + 1, y + 5, middle + 1, y + h - 4); + g.drawLine(middle + 3, y + 5, middle + 3, y + h - 4); + } } /** @@ -422,13 +451,24 @@ public class MetalScrollBarUI extends BasicScrollBarUI int w = thumbBounds.width; int h = thumbBounds.height; - // first we fill the background - g.setColor(thumbColor); - if (isFreeStanding) - g.fillRect(x, y, w - 1, h); + // First we fill the background. + MetalTheme theme = MetalLookAndFeel.getCurrentTheme(); + if (theme instanceof OceanTheme + && UIManager.get("ScrollBar.gradient") != null) + { + MetalUtils.paintGradient(g, x + 2, y + 2, w - 2, h - 4, + SwingConstants.HORIZONTAL, + "ScrollBar.gradient"); + } else - g.fillRect(x, y, w, h); - + { + g.setColor(thumbColor); + if (isFreeStanding) + g.fillRect(x, y, w - 1, h); + else + g.fillRect(x, y, w, h); + } + // then draw the dark box g.setColor(thumbLightShadowColor); if (isFreeStanding) @@ -456,6 +496,20 @@ public class MetalScrollBarUI extends BasicScrollBarUI // draw the shadow line g.setColor(UIManager.getColor("ScrollBar.shadow")); g.drawLine(x + 1, y + h, x + w - 2, y + h); + + // For the OceanTheme, draw the 3 lines in the middle. + if (theme instanceof OceanTheme) + { + g.setColor(thumbLightShadowColor); + int middle = y + h / 2; + g.drawLine(x + 4, middle - 2, x + w - 5, middle - 2); + g.drawLine(x + 4, middle, x + w - 5, middle); + g.drawLine(x + 4, middle + 2, x + w - 5, middle + 2); + g.setColor(UIManager.getColor("ScrollBar.highlight")); + g.drawLine(x + 5, middle - 1, x + w - 4, middle - 1); + g.drawLine(x + 5, middle + 1, x + w - 4, middle + 1); + g.drawLine(x + 5, middle + 3, x + w - 4, middle + 3); + } } /** diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java index 08fb99d..f97717f 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalSliderUI.java +++ b/libjava/classpath/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 @@ -224,29 +224,47 @@ public class MetalSliderUI extends BasicSliderUI } // fill track (if required) - if (filledSlider) - { - int xPos = xPositionForValue(slider.getValue()); - int x = (slider.getInverted() ? xPos : trackRect.x); - int w = (slider.getInverted() ? trackX + trackW - xPos - : xPos - trackRect.x); - g.setColor(MetalLookAndFeel.getControlShadow()); - g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); - if (slider.isEnabled()) - { - g.setColor(MetalLookAndFeel.getControl()); - g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); - g.drawLine(x + 1, trackY + 1, x + 1, - trackY + getTrackWidth() - 3); - } - } + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + if (slider.isEnabled()) + { + int xPos = xPositionForValue(slider.getValue()); + int x = (slider.getInverted() ? xPos : trackRect.x); + int w = (slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x); + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); + g.setColor(UIManager.getColor("Slider.altTrackColor")); + g.drawLine(x + 1, trackY + 2, x + w - 3, trackY + 2); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(x + 1, trackY + 3, x + w - 3, trackY + 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(x + 1, trackY + 4, x + w - 3, trackY + 4); + } + } + else if (filledSlider) + { + int xPos = xPositionForValue(slider.getValue()); + int x = (slider.getInverted() ? xPos : trackRect.x); + int w = (slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); + if (slider.isEnabled()) + { + g.setColor(MetalLookAndFeel.getControl()); + g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); + g.drawLine(x + 1, trackY + 1, x + 1, + trackY + getTrackWidth() - 3); + } + } } else { 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); @@ -255,8 +273,28 @@ public class MetalSliderUI extends BasicSliderUI g.setColor(MetalLookAndFeel.getControlShadow()); g.drawRect(trackX, trackY, trackW - 2, trackH - 2); } - - if (filledSlider) + + // Fill track if necessary. + if (MetalLookAndFeel.getCurrentTheme() instanceof OceanTheme) + { + if (slider.isEnabled()) + { + int yPos = yPositionForValue(slider.getValue()); + int y = (slider.getInverted() ? trackY : yPos); + int h = (slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos); + + g.setColor(MetalLookAndFeel.getWhite()); + g.drawLine(trackX + 1, y + 1, trackX + 1, y + h - 3); + g.setColor(UIManager.getColor("Slider.altTrackColor")); + g.drawLine(trackX + 2, y + 1, trackX + 2, y + h - 3); + g.setColor(MetalLookAndFeel.getControlShadow()); + g.drawLine(trackX + 3, y + 1, trackX + 3, y + h - 3); + g.setColor(MetalLookAndFeel.getPrimaryControlShadow()); + g.drawLine(trackX + 4, y + 1, trackX + 4, y + h - 3); + } + } + else if (filledSlider) { int yPos = yPositionForValue(slider.getValue()); int y = (slider.getInverted() ? trackY : yPos); diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java index c6c46ff..39dec3d 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java index 0b56d59..8c7a46e 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalToggleButtonUI.java +++ b/libjava/classpath/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; @@ -157,13 +159,15 @@ public class MetalToggleButtonUI /** * Paints the text for the button. * + * As of JDK 1.4 this method is obsolete. + * Use {@link BasicButtonUI#paintText(java.awt.Graphics, + * javax.swing.AbstractButton, java.awt.Rectangle, java.lang.String)}. + * * @param g the graphics device. * @param c the component. * @param textRect the bounds for the text. * @param text the text. * - * @deprecated 1.4 Use {@link BasicButtonUI#paintText(java.awt.Graphics, - * javax.swing.AbstractButton, java.awt.Rectangle, java.lang.String)}. */ protected void paintText(Graphics g, JComponent c, Rectangle textRect, String text) @@ -207,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/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java index 16e22ac..1848c1f 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalToolBarUI.java +++ b/libjava/classpath/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,8 @@ 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; import javax.swing.plaf.ComponentUI; @@ -225,4 +228,71 @@ public class MetalToolBarUI extends BasicToolBarUI super.mouseDragged(e); } } + + /** + * Installs the UI on the toolbar. This calls super and sets the rollover + * property according to the <code>UIManager</code> property + * "ToolBar.isRollover". + * + * @param c the component to install the UI on + */ + public void installUI(JComponent c) + { + super.installUI(c); + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + tb.setRollover(UIManager.getBoolean("ToolBar.isRollover")); + } + } + + /** + * Uninstalls the UI from the toolbar. This calls super and resets the + * rollover property. + * + * @param c the component to uninstall the UI from + */ + public void uninstallUI(JComponent c) + { + if (c instanceof JToolBar) + { + JToolBar tb = (JToolBar) c; + tb.setRollover(false); + } + 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/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java index 24432a2..3ea37c8 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalTreeUI.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java index b9d5ea7..03617aa 100644 --- a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java +++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java @@ -91,7 +91,7 @@ class MetalUtils Color light, Color dark) { if (g instanceof Graphics2D - && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null) + && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null) fillMetalPattern2D((Graphics2D) g, x, y, w, h, light, dark); else { @@ -161,14 +161,35 @@ class MetalUtils /** * Paints the typical Metal gradient. See {@link #paintGradient(Graphics, - * int, int, int, int, double, double, Color, Color, Color, int)} + * int, int, int, int, float, float, Color, Color, Color, int, int[][])} + * for more details. + * + * This variant paints a gradient without a mask. + * + * @param g the graphics context to use + * @param x the X coordinate of the upper left corner of the rectangle + * @param y the Y coordinate of the upper left corner of the rectangle + * @param w the width of the rectangle + * @param h the height of the rectangle + * @param dir the direction of the gradient, either + * @param uiProp the key of the UIManager property that has the parameters + */ + static void paintGradient(Graphics g, int x, int y, int w, int h, + int dir, String uiProp) + { + paintGradient(g, x, y, w, h, dir, uiProp, null); + } + + /** + * Paints the typical Metal gradient. See {@link #paintGradient(Graphics, + * int, int, int, int, float, float, Color, Color, Color, int, int[][])} * for more details. * * The parameters are fetched from the UIManager using the key * <code>uiProp</code>. The value is expected to be a {@link List} that * contains 4 values: two {@link Double}s and 3 {@link Color} object that * together make up the parameters passed to the painting method. - * + * * @param g the graphics context to use * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -176,17 +197,19 @@ class MetalUtils * @param h the height of the rectangle * @param dir the direction of the gradient, either * @param uiProp the key of the UIManager property that has the parameters + * @param mask the mask that should be used when painting the gradient as + * described above */ static void paintGradient(Graphics g, int x, int y, int w, int h, - int dir, String uiProp) + int dir, String uiProp, int[][] mask) { List params = (List) UIManager.get(uiProp); - double g1 = ((Double) params.get(0)).doubleValue(); - double g2 = ((Double) params.get(1)).doubleValue(); + float g1 = ((Float) params.get(0)).floatValue(); + float g2 = ((Float) params.get(1)).floatValue(); Color c1 = (Color) params.get(2); Color c2 = (Color) params.get(3); Color c3 = (Color) params.get(4); - paintGradient(g, x, y, w, h, g1, g2, c1, c2, c3, dir); + paintGradient(g, x, y, w, h, g1, g2, c1, c2, c3, dir, mask); } /** @@ -209,6 +232,33 @@ class MetalUtils * <li>A gradient from color 2 to color 1 with the relative width specified * by <code>g1</code></li> * + * The <code>mask</code> parameter is an array if int arrays, where the first + * index specifies the row (in the gradient direction), and the second index + * is the starting and end offset of that line. This way you can specify a + * mask that should be laid over the gradient for paintint non-rectangular + * gradients. The following example should demonstrate this for painting + * a circular shaped gradient (note that the first and last line should not + * be drawn at all, they are only here to show the circular shape more + * clearly). Everything <em>inside</code> the surrounded area is filled by + * the gradient: + * + * <pre> + * 012345678 + * xxx + * 0 x x { {4, 7}, + * 1 x x {3, 8}, + * 2 x x {3, 8}, + * 3 x x {3, 8}, + * 4 x x {4, 7} } + * xxx + * </pre> + * + * The <code>mask</code> array is expected to have <code>w</code> or + * <code>h</code> array elements, depending on the direction. + * + * If the <code>mask</code> parameter is null, then the gradient is painted + * without a mask. + * * @param g the graphics context to use * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -221,19 +271,23 @@ class MetalUtils * @param c3 the color 3 * @param dir the direction of the gradient, either * {@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL} + * @param mask the mask that should be used when painting the gradient as + * described above */ - static void paintGradient(Graphics g, int x, int y, int w, int h, double g1, - double g2, Color c1, Color c2, Color c3, int dir) + static void paintGradient(Graphics g, int x, int y, int w, int h, float g1, + float g2, Color c1, Color c2, Color c3, int dir, + int[][] mask) { if (dir == SwingConstants.HORIZONTAL) - paintHorizontalGradient(g, x, y, w, h, g1, g2, c1, c2, c3); + paintHorizontalGradient(g, x, y, w, h, g1, g2, c1, c2, c3, mask); else - paintVerticalGradient(g, x, y, w, h, g1, g2, c1, c2, c3); + paintVerticalGradient(g, x, y, w, h, g1, g2, c1, c2, c3, mask); } /** * Paints a horizontal gradient. See {@link #paintGradient(Graphics, int, - * int, int, int, double, double, Color, Color, Color, int)} for details. + * int, int, int, float, float, Color, Color, Color, int, int[][])} + * for details. * * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -244,12 +298,16 @@ class MetalUtils * @param c1 the color 1 * @param c2 the color 2 * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above */ static void paintHorizontalGradient(Graphics g, int x, int y, int w, int h, - double g1, double g2, Color c1, Color c2, - Color c3) + float g1, float g2, Color c1, Color c2, + Color c3, int[][] mask) { // Calculate the coordinates. + int y0 = y; + int y1 = y + h; // The size of the first gradient area (c1->2). int w1 = (int) (w * g1); // The size of the solid c2 area. @@ -276,11 +334,28 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(xc, y, xc, y + h); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); } // Paint solid c2 area. g.setColor(c2); - g.fillRect(x1, y, x2 - x1, h); + if (mask == null) + { + g.fillRect(x1, y, x2 - x1, h); + } + else + { + for (xc = x1; xc < x2; xc++) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + g.drawLine(xc, y0, xc, y1); + } + } // Paint second gradient area (c2->c1). for (xc = x2; xc < x3; xc++) @@ -297,7 +372,12 @@ class MetalUtils + c2.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(xc, y, xc, y + h); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); } // Paint third gradient area (c1->c3). @@ -315,13 +395,18 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(xc, y, xc, y + h); + if (mask != null) + { + y0 = mask[xc - x0][0] + y; + y1 = mask[xc - x0][1] + y; + } + g.drawLine(xc, y0, xc, y1); } } /** * Paints a vertical gradient. See {@link #paintGradient(Graphics, int, int, - * int, int, double, double, Color, Color, Color, int)} for details. + * int, int, float, float, Color, Color, Color, int, int[][])} for details. * * @param x the X coordinate of the upper left corner of the rectangle * @param y the Y coordinate of the upper left corner of the rectangle @@ -332,12 +417,16 @@ class MetalUtils * @param c1 the color 1 * @param c2 the color 2 * @param c3 the color 3 + * @param mask the mask that should be used when painting the gradient as + * described above */ static void paintVerticalGradient(Graphics g, int x, int y, int w, int h, double g1, double g2, Color c1, Color c2, - Color c3) + Color c3, int[][] mask) { // Calculate the coordinates. + int x0 = x; + int x1 = x + w; // The size of the first gradient area (c1->2). int w1 = (int) (h * g1); // The size of the solid c2 area. @@ -364,11 +453,28 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(x, yc, x + w, yc); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.drawLine(x0, yc, x1, yc); } // Paint solid c2 area. g.setColor(c2); - g.fillRect(x, y1, w, y2 - y1); + if (mask == null) + { + g.fillRect(x, y1, w, y2 - y1); + } + else + { + for (yc = y1; yc < y2; yc++) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + g.drawLine(x0, yc, x1, yc); + } + } // Paint second gradient area (c2->c1). for (yc = y2; yc < y3; yc++) @@ -385,7 +491,12 @@ class MetalUtils + c2.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(x, yc, x + w, yc); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.drawLine(x0, yc, x1, yc); } // Paint third gradient area (c1->c3). @@ -403,7 +514,12 @@ class MetalUtils + c1.getBlue()); Color interpolated = new Color(rInt, gInt, bInt); g.setColor(interpolated); - g.drawLine(x, yc, x + w, yc); + if (mask != null) + { + x0 = mask[yc - y0][0] + x; + x1 = mask[yc - y0][1] + x; + } + g.drawLine(x0, yc, x1, yc); } } } diff --git a/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java b/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java index d1fc4cf..9d76ff7 100644 --- a/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java +++ b/libjava/classpath/javax/swing/plaf/metal/OceanTheme.java @@ -38,10 +38,12 @@ exception statement from your version. */ package javax.swing.plaf.metal; import java.awt.Color; +import java.awt.Insets; 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 & Feel. @@ -207,41 +209,108 @@ public class OceanTheme extends DefaultMetalTheme */ public void addCustomEntriesToTable(UIDefaults defaults) { + // Gradients. defaults.put("Button.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("CheckBox.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("CheckBoxMenuItem.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("MenuBar.gradient", Arrays.asList(new Object[] - {new Double(1.0), new Double(0.0), new ColorUIResource(Color.WHITE), + {new Float(1.0), new Float(0.0), new ColorUIResource(Color.WHITE), new ColorUIResource(218, 218, 218), new ColorUIResource(218, 218, 218)})); defaults.put("RadioButton.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("RadioButtonMenuItem.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("ScrollBar.gradient", Arrays.asList(new Object[] - {new Double(1.0), new Double(0.0), new ColorUIResource(Color.WHITE), - new ColorUIResource(218, 218, 218), new ColorUIResource(218, 218, 218)})); + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("Slider.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.2), new ColorUIResource(200, 221, 242), + {new Float(0.3), new Float(0.2), new ColorUIResource(200, 221, 242), + new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); + defaults.put("Slider.focusGradient", Arrays.asList(new Object[] + {new Float(0.3), new Float(0.2), new ColorUIResource(200, 221, 242), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("ToggleButton.gradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); defaults.put("InternalFrame.activeTitleGradient", Arrays.asList(new Object[] - {new Double(0.3), new Double(0.0), new ColorUIResource(221, 232, 243), + {new Float(0.3), new Float(0.0), new ColorUIResource(221, 232, 243), new ColorUIResource(Color.WHITE), new ColorUIResource(184, 207, 229)})); - + // Colors. + ColorUIResource c1 = new ColorUIResource(200, 221, 242); + ColorUIResource c2 = new ColorUIResource(153, 153, 153); + ColorUIResource c3 = new ColorUIResource(204, 204, 204); + ColorUIResource c4 = new ColorUIResource(210, 226, 239); + ColorUIResource c5 = new ColorUIResource(218, 218, 218); + defaults.put("Button.disabledToolBarBorderBackground", c3); + defaults.put("Button.toolBarBorderBackground", c2); + defaults.put("Label.disabledForeground", c2); + defaults.put("MenuBar.borderColor", c3); + defaults.put("Slider.altTrackColor", c4); + defaults.put("SplitPane.dividerFocusColor", c1); + defaults.put("TabbedPane.contentAreaColor", c1); + defaults.put("TabbedPane.borderHightlightColor", PRIMARY1); + defaults.put("TabbedPane.selected", c1); + defaults.put("TabbedPane.tabAreaBackground", c5); + defaults.put("TabbedPane.unselectedBackground", SECONDARY3); + defaults.put("Table.gridColor", SECONDARY1); + 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)); + + // Flags. + defaults.put("SplitPane.oneTouchButtonsOpaque", Boolean.FALSE); + defaults.put("Menu.opaque", Boolean.FALSE); + defaults.put("ToolBar.isRollover", Boolean.TRUE); + defaults.put("RadioButton.rollover", Boolean.TRUE); + defaults.put("CheckBox.rollover", Boolean.TRUE); defaults.put("Button.rollover", Boolean.TRUE); - defaults.put("TabbedPane.selected", new ColorUIResource(200, 221, 242)); - defaults.put("TabbedPane.unselectedBackground", SECONDARY3); + // Icons. + // FIXME: Add OceanTheme icons. +// defaults.put("Tree.leafIcon", XXX); +// defaults.put("Tree.expandedIcon", XXX); +// defaults.put("Tree.openIcon", XXX); +// defaults.put("Tree.closedIcon", XXX); +// defaults.put("Tree.collapsedIcon", XXX); +// defaults.put("FileChooser.newFolderIcon", XXX); +// defaults.put("FileChooser.homeFolderIcon", XXX); +// defaults.put("FileChooser.upFolderIcon", XXX); +// defaults.put("FileView.hardDriveIcon", XXX); +// defaults.put("FileView.floppyDriveIcon", XXX); +// defaults.put("FileView.fileIcon", XXX); +// defaults.put("FileView.computerIcon", XXX); +// defaults.put("FileView.directoryIcon", XXX); +// defaults.put("OptionPane.questionIcon", XXX); +// defaults.put("OptionPane.errorIcon", XXX); +// defaults.put("OptionPane.warningIcon", XXX); +// defaults.put("OptionPane.informationIcon", XXX); +// defaults.put("InternalFrame.icon", XXX); +// defaults.put("InternalFrame.closeIcon", XXX); +// defaults.put("InternalFrame.iconifyIcon", XXX); +// defaults.put("InternalFrame.minimizeIcon", XXX); +// defaults.put("InternalFrame.maximizeIcon", XXX); +// defaults.put("InternalFrame.paletteCloseIcon", XXX); + + // UI classes. + defaults.put("MenuBarUI", "javax.swing.plaf.metal.MetalMenuBarUI"); + + // Others. + defaults.put("Button.rolloverIconType", "ocean"); } } diff --git a/libjava/classpath/javax/swing/plaf/synth/ColorType.java b/libjava/classpath/javax/swing/plaf/synth/ColorType.java index 954e309..ced1efc 100644 --- a/libjava/classpath/javax/swing/plaf/synth/ColorType.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/synth/Region.java b/libjava/classpath/javax/swing/plaf/synth/Region.java index 7ede65f..25d1a11 100644 --- a/libjava/classpath/javax/swing/plaf/synth/Region.java +++ b/libjava/classpath/javax/swing/plaf/synth/Region.java @@ -108,13 +108,13 @@ public class Region /** * Specifies the region of a file chooser. */ - public static final Region FILECHOOSER = + public static final Region FILE_CHOOSER = new Region("FileChooser", "FileChooserUI", false); /** * Specifies the region of a formatted text field. */ - public static final Region FormattedTextField = + public static final Region FORMATTED_TEXT_FIELD = new Region("FormattedTextField", "FormattedTextFieldUI", false); /** diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java index a68b6f6..1907d75 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthGraphicsUtils.java +++ b/libjava/classpath/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/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java b/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java index 8d0596d..1a2489e 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthLookAndFeel.java +++ b/libjava/classpath/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,14 +219,14 @@ 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. } /** * Returns a textual description of the Synth look and feel. This returns - * "Synt look and feel". + * "Synth look and feel". * * @return a textual description of the Synth look and feel */ @@ -238,7 +247,7 @@ public class SynthLookAndFeel /** * Returns the name of the Synth look and feel. This returns - * "Synt look and feel". + * "Synth look and feel". * * @return the name of the Synth look and feel */ diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java index 0d63c6d..fa1f6f5 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java +++ b/libjava/classpath/javax/swing/plaf/synth/SynthPainter.java @@ -62,6 +62,117 @@ public abstract class SynthPainter } /** + * Paints the foreground of an arrow button. + * + * @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 + * @param dir the orientation of the arrow + */ + public void paintArrowButtonForeground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int dir) + { + // Nothing to do here. + } + + /** + * Paints the foreground of a progress bar. + * + * @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 + * @param dir the orientation of the progress bar + */ + public void paintProgressBarForeground(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints the foreground of a separator. + * + * @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 + * @param dir the orientation of the separator + */ + public void paintSeparatorForeground(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints the foreground 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 + * @param dir the orientation of the divider + */ + public void paintSplitPaneDividerForeground(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints a split pane's divider, when it is being dragged. + * + * @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 + * @param dir the orientation of the divider + */ + public void paintSplitPaneDragDivider(SynthContext ctx, Graphics g, + int x, int y, int w, int h, + int dir) + { + // Nothing to do here. + } + + /** + * Paints the indicator for a tree cell which has the focus. + * + * @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 paintTreeCellFocus(SynthContext ctx, Graphics g, + int x, int y, int w, int h) + { + // Nothing to do here. + } + + /** * Paints the background of an arrow button. * * @param ctx the synth context identifying the component and region for @@ -73,7 +184,1815 @@ public abstract class SynthPainter * @param h the height of the area to paint */ public void paintArrowButtonBackground(SynthContext ctx, Graphics g, int x, - int y, int w, int h) + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an arrow button. + * + * @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 paintArrowButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a button. + * + * @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 paintButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a button. + * + * @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 paintButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a check box. + * + * @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 paintCheckBoxBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a check box. + * + * @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 paintCheckBoxBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a check box menu item. + * + * @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 paintCheckBoxMenuItemBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a check box menu item. + * + * @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 paintCheckBoxMenuItemBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a color chooser. + * + * @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 paintColorChooserBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a color chooser. + * + * @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 paintColorChooserBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a combo box. + * + * @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 paintComboBoxBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a combo box. + * + * @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 paintComboBoxBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a desktop icon. + * + * @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 paintDesktopIconBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a desktop icon. + * + * @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 paintDesktopIconBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a desktop pane. + * + * @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 paintDesktopPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a desktop pane. + * + * @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 paintDesktopPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an editor pane. + * + * @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 paintEditorPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an editor pane. + * + * @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 paintEditorPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a file chooser. + * + * @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 paintFileChooserBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a file chooser. + * + * @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 paintFileChooserBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a formatted text field. + * + * @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 paintFormattedTextFieldBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a formatted text field. + * + * @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 paintFormattedTextFieldBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an internal frame. + * + * @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 paintInternalFrameBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an internal frame. + * + * @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 paintInternalFrameBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an internal frame's title pane. + * + * @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 paintInternalFrameTitlePaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an internal frame's title pane. + * + * @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 paintInternalFrameTitlePaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a label. + * + * @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 paintLabelBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a label. + * + * @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 paintLabelBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a list. + * + * @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 paintListBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a list. + * + * @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 paintListBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a menu. + * + * @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 paintMenuBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a menu. + * + * @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 paintMenuBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a menu bar. + * + * @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 paintMenuBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a menu bar. + * + * @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 paintMenuBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a menu item. + * + * @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 paintMenuItemBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a menu item. + * + * @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 paintMenuItemBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of an option pane. + * + * @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 paintOptionPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of an option pane. + * + * @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 paintOptionPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a panel. + * + * @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 paintPanelBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a panel. + * + * @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 paintPanelBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a password field. + * + * @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 paintPasswordFieldBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a password field. + * + * @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 paintPasswordFieldBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a popup menu. + * + * @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 paintPopupMenuBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a popup menu. + * + * @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 paintPopupMenuBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a progress bar. + * + * @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 paintProgressBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a progress bar. + * + * @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 paintProgressBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a radio button. + * + * @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 paintRadioButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a radio button. + * + * @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 paintRadioButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a radio button menu item. + * + * @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 paintRadioButtonMenuItemBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a radio button menu item. + * + * @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 paintRadioButtonMenuItemBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a root pane. + * + * @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 paintRootPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a root pane. + * + * @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 paintRootPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a scrollbar. + * + * @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 paintScrollBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a scrollbar. + * + * @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 paintScrollBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a scrollbar's thumb. + * + * @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 + * @param orientation orientation of the scrollbar + */ + public void paintScrollBarThumbBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the border of a scrollbar's thumb. + * + * @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 + * @param orientation orientation of the scrollbar + */ + public void paintScrollBarThumbBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the background of a scrollbar's track. + * + * @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 paintScrollBarTrackBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a scrollbar's track. + * + * @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 paintScrollBarTrackBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a scroll pane. + * + * @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 paintScrollPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a scroll pane. + * + * @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 paintScrollPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a separator. + * + * @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 paintSeparatorBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a separator. + * + * @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 paintSeparatorBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a slider. + * + * @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 paintSliderBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a slider. + * + * @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 paintSliderBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a slider's thumb. + * + * @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 + * @param orientation orientation of the slider + */ + public void paintSliderThumbBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the border of a slider's thumb. + * + * @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 + * @param orientation orientation of the slider + */ + public void paintSliderThumbBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h, int orientation) + { + // Nothing to do here. + } + + /** + * Paints the background of a slider's track. + * + * @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 paintSliderTrackBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a slider's track. + * + * @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 paintSliderTrackBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a spinner. + * + * @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 paintSpinnerBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a spinner. + * + * @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 paintSpinnerBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a split pane. + * + * @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 paintSplitPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a split pane. + * + * @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 paintSplitPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background 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 paintSplitPaneDividerBackground(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 + * 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 paintTabbedPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a tabbed pane. + * + * @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 paintTabbedPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the contents of a tabbed pane. + * + * @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 paintTabbedPaneContentBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the contents of a tabbed pane. + * + * @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 paintTabbedPaneContentBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the tab area of a tabbed pane. + * + * @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 paintTabbedPaneTabAreaBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the tab area of a tabbed pane. + * + * @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 paintTabbedPaneTabAreaBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tab of a tabbed pane. + * + * @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 + * @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 index) + { + // Nothing to do here. + } + + /** + * Paints the border of a tab of a tabbed pane. + * + * @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 + * @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 index) + { + // Nothing to do here. + } + + /** + * Paints the background of a table. + * + * @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 paintTableBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a table. + * + * @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 paintTableBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a table's header. + * + * @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 paintTableHeaderBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a table's header. + * + * @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 paintTableHeaderBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a text area. + * + * @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 paintTextAreaBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a text area. + * + * @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 paintTextAreaBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a text field. + * + * @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 paintTextFieldBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a text field. + * + * @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 paintTextFieldBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a text pane. + * + * @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 paintTextPaneBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a text pane. + * + * @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 paintTextPaneBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a toggle button. + * + * @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 paintToggleButtonBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a toggle button. + * + * @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 paintToggleButtonBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a toolbar. + * + * @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 paintToolBarBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a toolbar. + * + * @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 paintToolBarBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the contents of a toolbar. + * + * @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 paintToolBarContentBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the contents of a toolbar. + * + * @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 paintToolBarContentBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of the window of a detached toolbar. + * + * @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 paintToolBarDragWindowBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of the window of a detached toolbar. + * + * @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 paintToolBarDragWindowBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tool tip. + * + * @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 paintToolTipBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a tool tip. + * + * @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 paintToolTipBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a tree. + * + * @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 paintTreeBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a tree. + * + * @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 paintTreeBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a cell in a tree. + * + * @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 paintTreeCellBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a cell in a tree. + * + * @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 paintTreeCellBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the background of a viewport. + * + * @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 paintViewportBackground(SynthContext ctx, Graphics g, int x, + int y, int w, int h) + { + // Nothing to do here. + } + + /** + * Paints the border of a viewport. + * + * @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 paintViewportBorder(SynthContext ctx, Graphics g, int x, + int y, int w, int h) { // Nothing to do here. } diff --git a/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java b/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java index e0a8dbc..f5ab3df 100644 --- a/libjava/classpath/javax/swing/plaf/synth/SynthStyle.java +++ b/libjava/classpath/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; } } |