diff options
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic')
32 files changed, 5463 insertions, 3274 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java index 4da4691f6d8..836ef223494 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java @@ -56,7 +56,7 @@ import javax.swing.border.Border; public class BasicArrowButton extends JButton implements SwingConstants { /** The default size of the Arrow buttons. */ - private static int defaultSize = 10; + private static int defaultSize = 12; /** The Polygon that points up. */ private static Polygon upIcon = new Polygon(new int[] { 0, 5, 9 }, diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java index d893c5d0a1b..6c80f14b6fc 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java @@ -115,21 +115,21 @@ public class BasicButtonUI extends ButtonUI */ protected String getPropertyPrefix() { - return "Button"; + return "Button."; } protected void installDefaults(AbstractButton b) { UIDefaults defaults = UIManager.getLookAndFeelDefaults(); String prefix = getPropertyPrefix(); - focusColor = defaults.getColor(prefix + ".focus"); - b.setForeground(defaults.getColor(prefix + ".foreground")); - b.setBackground(defaults.getColor(prefix + ".background")); - b.setMargin(defaults.getInsets(prefix + ".margin")); - b.setBorder(defaults.getBorder(prefix + ".border")); - b.setIconTextGap(defaults.getInt(prefix + ".textIconGap")); + focusColor = defaults.getColor(prefix + "focus"); + b.setForeground(defaults.getColor(prefix + "foreground")); + b.setBackground(defaults.getColor(prefix + "background")); + b.setMargin(defaults.getInsets(prefix + "margin")); + b.setBorder(defaults.getBorder(prefix + "border")); + b.setIconTextGap(defaults.getInt(prefix + "textIconGap")); b.setInputMap(JComponent.WHEN_FOCUSED, - (InputMap) defaults.get(prefix + ".focusInputMap")); + (InputMap) defaults.get(prefix + "focusInputMap")); b.setOpaque(true); } @@ -285,7 +285,8 @@ public class BasicButtonUI extends ButtonUI paintIcon(g, c, ir); if (text != null) paintText(g, b, tr, text); - paintFocus(g, b, vr, tr, ir); + if (b.isFocusOwner()) + paintFocus(g, b, vr, tr, ir); } /** @@ -306,15 +307,8 @@ public class BasicButtonUI extends ButtonUI protected void paintFocus(Graphics g, AbstractButton b, Rectangle vr, Rectangle tr, Rectangle ir) { - if (b.hasFocus() && b.isFocusPainted()) - { - Color saved_color = g.getColor(); - g.setColor(focusColor); - Rectangle focusRect = ir.union(tr); - g.drawRect(focusRect.x, focusRect.y, - focusRect.width, focusRect.height); - g.setColor(saved_color); - } + // In the BasicLookAndFeel no focus border is drawn. This can be + // overridden in subclasses to implement such behaviour. } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java index da11898bf0b..945aea53dc3 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java @@ -67,13 +67,13 @@ public class BasicCheckBoxMenuItemUI extends BasicMenuItemUI } /** - * DOCUMENT ME! + * Returns the prefix for entries in the {@link UIDefaults} table. * - * @return $returnType$ DOCUMENT ME! + * @return "CheckBoxMenuItem" */ protected String getPropertyPrefix() { - return null; + return "CheckBoxMenuItem"; } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java index e3167327c3a..3cf02a00156 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxUI.java @@ -57,14 +57,14 @@ public class BasicCheckBoxUI extends BasicRadioButtonUI return defaults.getIcon("CheckBox.icon"); } - public void installUI(final JComponent c) { - super.installUI(c); - } - - // Overridden to change method access. + /** + * Returns the prefix for entries in the {@link UIDefaults} table. + * + * @return "CheckBox." + */ public String getPropertyPrefix() { - return super.getPropertyPrefix(); + return "CheckBox."; } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java index 04296df0a85..dd867f0dc55 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxEditor.java @@ -91,7 +91,10 @@ public class BasicComboBoxEditor extends Object implements ComboBoxEditor, */ public void setItem(Object item) { - editor.setText(item.toString()); + if (item == null) + editor.setText(""); + else + editor.setText(item.toString()); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java index b15700d6fc8..b59261b17f3 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicDesktopPaneUI.java @@ -363,7 +363,7 @@ public class BasicDesktopPaneUI extends DesktopPaneUI { UIDefaults defaults = UIManager.getLookAndFeelDefaults(); - desktop.setBackground(defaults.getColor("Desktop.background")); + desktop.setBackground(defaults.getColor("desktop")); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java index 6dd15a8f982..d5b34d9eef6 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicEditorPaneUI.java @@ -39,30 +39,69 @@ exception statement from your version. */ package javax.swing.plaf.basic; import javax.swing.JComponent; +import javax.swing.JEditorPane; import javax.swing.plaf.ComponentUI; +import javax.swing.text.EditorKit; import javax.swing.text.Element; +import javax.swing.text.JTextComponent; import javax.swing.text.PlainView; import javax.swing.text.View; +/** + * The UI class for {@link JEditorPane}s. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public class BasicEditorPaneUI extends BasicTextUI { + /** + * Creates an instance of <code>BasicEditorPaneUI</code> for the text + * component <code>comp</code>. + * + * @param comp the component for which to create an UI + * + * @return the UI for <code>comp</code> + */ public static ComponentUI createUI(JComponent comp) { return new BasicEditorPaneUI(); } + /** + * Creates a new <code>BasicEditorPaneUI</code> + */ public BasicEditorPaneUI() { // Do nothing here. } + // FIXME: Should not be overridden here but instead be handled by the + // JEditorPane's EditorKit. However, as long as we don't have styles in + // place this doesn't make much sense. public View create(Element elem) { return new PlainView(elem); } + /** + * Returns the property prefix to be used by this UI class. This is + * <code>EditorPane</code> in this case. + * + * @return <code>EditorPane</code> + */ protected String getPropertyPrefix() { return "EditorPane"; } + + /** + * Gets the EditorKit for the text component. + * + * @param textComponent the text component for which to fetch the editor kit + */ + public EditorKit getEditorKit(JTextComponent textComponent) + { + return ((JEditorPane) textComponent).getEditorKit(); + } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java index fd34fbd6227..f74e9229893 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java @@ -1090,7 +1090,9 @@ public class BasicFileChooserUI extends FileChooserUI } // FIXME: Indent the entries in the combobox - private void boxEntries() + // Made this method package private to access it from within inner classes + // with better performance + void boxEntries() { ArrayList parentFiles = new ArrayList(); File parent = filechooser.getCurrentDirectory(); @@ -1098,12 +1100,12 @@ public class BasicFileChooserUI extends FileChooserUI parent = filechooser.getFileSystemView().getDefaultDirectory(); while (parent != null) { - String name = parent.getName(); - if (name.equals("")) - name = parent.getAbsolutePath(); + String name = parent.getName(); + if (name.equals("")) + name = parent.getAbsolutePath(); - parentFiles.add(parentFiles.size(), name); - parent = parent.getParentFile(); + parentFiles.add(parentFiles.size(), name); + parent = parent.getParentFile(); } if (parentFiles.size() == 0) @@ -1509,12 +1511,12 @@ public class BasicFileChooserUI extends FileChooserUI } else if (e.getPropertyName().equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) { - //boxEntries(); filelist.clearSelection(); filelist.revalidate(); filelist.repaint(); setDirectorySelected(false); setDirectory(filechooser.getCurrentDirectory()); + boxEntries(); } else if (e.getPropertyName().equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) || e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java index 78ee62f95f8..757ac47c903 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java @@ -609,7 +609,7 @@ public class BasicGraphicsUtils * LineMetrics, not a FontMetrics argument. But fixing this that * would change the public API. */ - SwingUtilities.layoutCompoundLabel( + SwingUtilities.layoutCompoundLabel( b, // for the component orientation b.getToolkit().getFontMetrics(b.getFont()), // see comment above b.getText(), @@ -630,10 +630,10 @@ public class BasicGraphicsUtils */ contentRect = textRect.union(iconRect); - + return new Dimension(insets.left + contentRect.width - + insets.right, + + insets.right + b.getHorizontalAlignment(), insets.top + contentRect.height + insets.bottom); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java b/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java index e7aad8964ba..56a67b02935 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicIconFactory.java @@ -1,5 +1,5 @@ /* BasicIconFactory.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,13 +44,11 @@ import java.awt.Graphics; import java.awt.Polygon; import java.io.Serializable; -import javax.swing.AbstractButton; import javax.swing.Icon; -import javax.swing.UIDefaults; -import javax.swing.UIManager; +import javax.swing.JCheckBoxMenuItem; /** - * STUBBED + * Creates icons for the {@link BasicLookAndFeel}. */ public class BasicIconFactory implements Serializable { @@ -70,13 +68,174 @@ public class BasicIconFactory implements Serializable } } + /** + * The icon used for CheckBoxes in the BasicLookAndFeel. This is an empty + * icon with a size of 13x13 pixels. + */ + static class CheckBoxIcon + implements Icon + { + /** + * Returns the height of the icon. The BasicLookAndFeel CheckBox icon + * has a height of 13 pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 13; + } - public BasicIconFactory() + /** + * Returns the width of the icon. The BasicLookAndFeel CheckBox icon + * has a width of 13 pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 13; + } + + /** + * Paints the icon. The BasicLookAndFeel CheckBox icon is empty and does + * not need to be painted. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // The icon is empty and needs no painting. + } + } + + /** + * The icon used for {@link JCheckBoxMenuItem}s in the + * {@link BasicLookAndFeel}. This icon has a size of 9x9 pixels. + */ + static class CheckBoxMenuItemIcon + implements Icon { + /** + * Returns the height of the icon in pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 9; + } + + /** + * Returns the width of the icon in pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 9; + } + + /** + * Paints the icon. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + JCheckBoxMenuItem item = (JCheckBoxMenuItem) c; + if (item.isSelected()) + { + // paint the check... + g.setColor(Color.black); + g.drawLine(x + 1, y + 3, x + 1, y + 4); + g.drawLine(x + 2, y + 4, x + 2, y + 5); + for (int i = 0; i < 5; i++) + g.drawLine(x + 3 + i, y + 5 - i, x + 3 + i, y + 6 - i); + } + } } + + /** + * The icon used for RadioButtons in the BasicLookAndFeel. This is an empty + * icon with a size of 13x13 pixels. + */ + static class RadioButtonIcon + implements Icon + { + /** + * Returns the height of the icon. The BasicLookAndFeel RadioButton icon + * has a height of 13 pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 13; + } + + /** + * Returns the width of the icon. The BasicLookAndFeel RadioButton icon + * has a width of 13 pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 13; + } + + /** + * Paints the icon. The BasicLookAndFeel RadioButton icon is empty and does + * not need to be painted. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // The icon is empty and needs no painting. + } + } + /** The cached CheckBoxIcon instance. */ + private static CheckBoxIcon checkBoxIcon; + + /** The cached RadioButtonIcon instance. */ + private static RadioButtonIcon radioButtonIcon; + public static Icon getMenuItemCheckIcon() { - return new DummyIcon(); + return new Icon() + { + public int getIconHeight() + { + return 13; + } + + public int getIconWidth() + { + return 13; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color saved = g.getColor(); + g.setColor(Color.BLACK); + g.drawLine(3 + x, 5 + y, 3 + x, 9 + y); + g.drawLine(4 + x, 5 + y, 4 + x, 9 + y); + g.drawLine(5 + x, 7 + y, 9 + x, 3 + y); + g.drawLine(5 + x, 8 + y, 9 + x, 4 + y); + g.setColor(saved); + } + }; } public static Icon getMenuItemArrowIcon() { @@ -114,123 +273,50 @@ public class BasicIconFactory implements Serializable }; } + /** + * Returns an icon for CheckBoxes in the BasicLookAndFeel. CheckBox icons + * in the Basic L&F are empty and have a size of 13x13 pixels. + * This method returns a shared single instance of this icon. + * + * @return an icon for CheckBoxes in the BasicLookAndFeel + */ public static Icon getCheckBoxIcon() { - return new Icon() - { - public int getIconHeight() - { - return 10; - } - public int getIconWidth() - { - return 10; - } - public void paintIcon(Component c, Graphics g, int x, int y) - { - if (c instanceof AbstractButton) - { - UIDefaults defaults; - defaults = UIManager.getLookAndFeelDefaults(); - Color hi = defaults.getColor("CheckBox.highlight"); - Color low = defaults.getColor("CheckBox.darkShadow"); - Color sel = defaults.getColor("CheckBox.foreground"); - Color dim = defaults.getColor("CheckBox.shadow"); - Polygon check = new Polygon(new int[] {x+3, x+3, x+8}, - new int[] {y+5, y+9, y+3}, 3); - AbstractButton b = (AbstractButton) c; - Color saved = g.getColor(); - if (b.isEnabled()) - { - g.setColor(low); - g.drawRect(x, y, 10, 10); - g.setColor(hi); - g.drawRect(x+1, y+1, 10, 10); - if (b.isSelected()) - { - g.setColor(sel); - if (b.isSelected()) - { - g.drawLine(x+3, y+5, x+3, y+8); - g.drawLine(x+4, y+5, x+4, y+8); - g.drawLine(x+3, y+8, x+8, y+3); - g.drawLine(x+4, y+8, x+8, y+3); - } - } - } - else - { - g.setColor(hi); - g.drawRect(x, y, 10, 10); - if (b.isSelected()) - { - g.drawLine(x+3, y+5, x+3, y+9); - g.drawLine(x+3, y+9, x+8, y+3); - } - } - g.setColor(saved); - } - } - }; + if (checkBoxIcon == null) + checkBoxIcon = new CheckBoxIcon(); + return checkBoxIcon; } + /** + * Returns an icon for RadioButtons in the BasicLookAndFeel. RadioButton + * icons in the Basic L&F are empty and have a size of 13x13 pixels. + * This method returns a shared single instance of this icon. + * + * @return an icon for RadioButtons in the BasicLookAndFeel + */ public static Icon getRadioButtonIcon() { - return new Icon() - { - public int getIconHeight() - { - return 12; - } - public int getIconWidth() - { - return 12; - } - public void paintIcon(Component c, Graphics g, int x, int y) - { - UIDefaults defaults; - defaults = UIManager.getLookAndFeelDefaults(); - Color hi = defaults.getColor("RadioButton.highlight"); - Color low = defaults.getColor("RadioButton.darkShadow"); - Color sel = defaults.getColor("RadioButton.foreground"); - Color dim = defaults.getColor("RadioButton.shadow"); - - if (c instanceof AbstractButton) - { - AbstractButton b = (AbstractButton) c; - Color saved = g.getColor(); - if (b.isEnabled()) - { - g.setColor(low); - g.drawOval(x, y, 12, 12); - g.setColor(hi); - g.drawOval(x+1, y+1, 12, 12); - if (b.isSelected()) - { - g.setColor(sel); - g.fillOval(x+4, y+4, 6, 6); - } - } - else - { - g.setColor(hi); - g.drawOval(x, y, 12, 12); - if (b.isSelected()) - g.fillOval(x+4, y+4, 6, 6); - } - g.setColor(saved); - } - } - }; + if (radioButtonIcon == null) + radioButtonIcon = new RadioButtonIcon(); + return radioButtonIcon; } + + /** + * Creates and returns an icon used when rendering {@link JCheckBoxMenuItem} + * components. + * + * @return An icon. + */ public static Icon getCheckBoxMenuItemIcon() { - return getCheckBoxIcon(); + return new CheckBoxMenuItemIcon(); } + public static Icon getRadioButtonMenuItemIcon() { return getRadioButtonIcon(); } + public static Icon createEmptyFrameIcon() { return new DummyIcon(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java index 91db0cbeb7c..cc262948ded 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameTitlePane.java @@ -47,7 +47,6 @@ import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; -import java.awt.Polygon; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; @@ -514,18 +513,6 @@ public class BasicInternalFrameTitlePane extends JComponent /** The button that maximizes the JInternalFrame. */ protected JButton maxButton; - /** Active background color. */ - protected Color activeBGColor; - - /** Active foreground color. */ - protected Color activeFGColor; - - /** Inactive background color. */ - protected Color inactiveBGColor; - - /** Inactive foreground color. */ - protected Color inactiveFGColor; - /** The icon displayed in the restore button. */ protected Icon minIcon = BasicIconFactory.createEmptyFrameIcon(); @@ -592,6 +579,7 @@ public class BasicInternalFrameTitlePane extends JComponent setOpaque(true); setBackground(Color.LIGHT_GRAY); + setOpaque(true); installTitlePane(); } @@ -679,10 +667,10 @@ public class BasicInternalFrameTitlePane extends JComponent UIDefaults defaults = UIManager.getLookAndFeelDefaults(); setFont(defaults.getFont("InternalFrame.titleFont")); - activeFGColor = defaults.getColor("InternalFrame.activeTitleForeground"); - activeBGColor = defaults.getColor("InternalFrame.activeTitleBackground"); - inactiveFGColor = defaults.getColor("InternalFrame.inactiveTitleForeground"); - inactiveBGColor = defaults.getColor("InternalFrame.inactiveTitleBackground"); + selectedTextColor = defaults.getColor("InternalFrame.activeTitleForeground"); + selectedTitleColor = defaults.getColor("InternalFrame.activeTitleBackground"); + notSelectedTextColor = defaults.getColor("InternalFrame.inactiveTitleForeground"); + notSelectedTitleColor = defaults.getColor("InternalFrame.inactiveTitleBackground"); } /** @@ -691,10 +679,10 @@ public class BasicInternalFrameTitlePane extends JComponent protected void uninstallDefaults() { setFont(null); - activeFGColor = null; - activeBGColor = null; - inactiveFGColor = null; - inactiveBGColor = null; + selectedTextColor = null; + selectedTitleColor = null; + notSelectedTextColor = null; + notSelectedTitleColor = null; } /** @@ -714,12 +702,19 @@ public class BasicInternalFrameTitlePane extends JComponent } /** - * This method sets the icons in the buttons. This is a no-op method here, it - * can be overridden by subclasses to set icons for the minimize-, maximize- - * and close-buttons. + * Set icons for the minimize-, maximize- and close-buttons. */ protected void setButtonIcons() { + Icon icon = UIManager.getIcon("InternalFrame.closeIcon"); + if (icon != null) + closeButton.setIcon(icon); + icon = UIManager.getIcon("InternalFrame.iconifyIcon"); + if (icon != null) + iconButton.setIcon(icon); + icon = UIManager.getIcon("InternalFrame.maximizeIcon"); + if (icon != null) + maxButton.setIcon(icon); } /** @@ -827,9 +822,9 @@ public class BasicInternalFrameTitlePane extends JComponent { Color saved = g.getColor(); if (frame.isSelected()) - g.setColor(activeFGColor); + g.setColor(selectedTextColor); else - g.setColor(inactiveFGColor); + g.setColor(notSelectedTextColor); title.setText(getTitle(frame.getTitle(), fm, title.getBounds().width)); SwingUtilities.paintComponent(g, title, null, title.getBounds()); g.setColor(saved); @@ -848,9 +843,9 @@ public class BasicInternalFrameTitlePane extends JComponent Color bg = getBackground(); if (frame.isSelected()) - bg = activeBGColor; + bg = selectedTitleColor; else - bg = inactiveBGColor; + bg = notSelectedTitleColor; g.setColor(bg); g.fillRect(0, 0, dims.width, dims.height); g.setColor(saved); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java index 16379668278..8f76ea0cc19 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -74,7 +74,6 @@ import javax.swing.event.InternalFrameEvent; import javax.swing.event.InternalFrameListener; import javax.swing.event.MouseInputAdapter; import javax.swing.event.MouseInputListener; -import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.InternalFrameUI; import javax.swing.plaf.UIResource; @@ -1150,7 +1149,6 @@ public class BasicInternalFrameUI extends InternalFrameUI installKeyboardActions(); frame.setOpaque(true); - titlePane.setOpaque(true); frame.invalidate(); } } @@ -1179,28 +1177,10 @@ public class BasicInternalFrameUI extends InternalFrameUI */ protected void installDefaults() { - // This is the border of InternalFrames in the BasicLookAndFeel. - // Note that there exist entries for various border colors in - // BasicLookAndFeel's defaults, but obviously they differ - // from the colors that are actually used by the JDK. UIDefaults defaults = UIManager.getLookAndFeelDefaults(); - Color borderColor = defaults.getColor("InternalFrame.borderColor"); - Border inner = BorderFactory.createLineBorder(borderColor, 1); - Color borderDarkShadow = defaults.getColor - ("InternalFrame.borderDarkShadow"); - Color borderHighlight = defaults.getColor - ("InternalFrame.borderHighlight"); - Color borderShadow = defaults.getColor("InternalFrame.borderShadow"); - Color borderLight = defaults.getColor("InternalFrame.borderLight"); - Border outer = BorderFactory.createBevelBorder(BevelBorder.RAISED, - borderShadow, - borderHighlight, - borderDarkShadow, - borderShadow); - Border border = new BorderUIResource.CompoundBorderUIResource(outer, - inner); + Border border = defaults.getBorder("InternalFrame.border"); frame.setBorder(border); - + frame.setFrameIcon(defaults.getIcon("InternalFrame.icon")); // InternalFrames are invisible by default. frame.setVisible(false); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java index e71e82f03d1..bb9ce6cb1d9 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java @@ -1,39 +1,39 @@ /* BasicLabelUI.java - Copyright (C) 2002, 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ package javax.swing.plaf.basic; @@ -56,12 +56,13 @@ import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.LabelUI; - /** * This is the Basic Look and Feel class for the JLabel. One BasicLabelUI * object is used to paint all JLabels that utilize the Basic Look and Feel. */ -public class BasicLabelUI extends LabelUI implements PropertyChangeListener +public class BasicLabelUI + extends LabelUI + implements PropertyChangeListener { /** The labelUI that is shared by all labels. */ protected static BasicLabelUI labelUI; @@ -99,20 +100,20 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * * @return The preferred size. */ - public Dimension getPreferredSize(JComponent c) + public Dimension getPreferredSize(JComponent c) { - JLabel lab = (JLabel)c; + JLabel lab = (JLabel) c; Rectangle vr = new Rectangle(); Rectangle ir = new Rectangle(); Rectangle tr = new Rectangle(); - Insets insets = lab.getInsets(); + Insets insets = lab.getInsets(); FontMetrics fm = lab.getToolkit().getFontMetrics(lab.getFont()); layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr); Rectangle cr = tr.union(ir); - return new Dimension(insets.left + cr.width + insets.right, - insets.top + cr.height + insets.bottom); - - } + return new Dimension(insets.left + cr.width + insets.right, insets.top + + cr.height + insets.bottom); + + } /** * This method returns the minimum size of the {@link JComponent} given. If @@ -144,7 +145,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener /** * The method that paints the label according to its current state. - * + * * @param g The {@link Graphics} object to paint with. * @param c The {@link JComponent} to paint. */ @@ -169,26 +170,28 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener vr.width = 0; if (vr.height < 0) vr.height = 0; - + Icon icon = (b.isEnabled()) ? b.getIcon() : b.getDisabledIcon(); String text = layoutCL(b, fm, b.getText(), icon, vr, ir, tr); - + if (icon != null) - icon.paintIcon(b, g, ir.x, ir.y); - if (text != null && ! text.equals("")) - { - if (b.isEnabled()) - paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); - else - paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); - } + icon.paintIcon(b, g, ir.x, ir.y); + + if (text != null && !text.equals("")) + { + if (b.isEnabled()) + paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + else + paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + } + g.setFont(saved_font); } /** * This method is simply calls SwingUtilities's layoutCompoundLabel. - * + * * @param label The label to lay out. * @param fontMetrics The FontMetrics for the font used. * @param text The text to paint. @@ -196,20 +199,16 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * @param viewR The entire viewable rectangle. * @param iconR The icon bounds rectangle. * @param textR The text bounds rectangle. - * + * * @return A possibly clipped version of the text. */ - protected String layoutCL(JLabel label, FontMetrics fontMetrics, - String text, Icon icon, Rectangle viewR, - Rectangle iconR, Rectangle textR) + protected String layoutCL(JLabel label, FontMetrics fontMetrics, String text, + Icon icon, Rectangle viewR, Rectangle iconR, Rectangle textR) { return SwingUtilities.layoutCompoundLabel(label, fontMetrics, text, icon, - label.getVerticalAlignment(), - label.getHorizontalAlignment(), - label.getVerticalTextPosition(), - label.getHorizontalTextPosition(), - viewR, iconR, textR, - label.getIconTextGap()); + label.getVerticalAlignment(), label.getHorizontalAlignment(), label + .getVerticalTextPosition(), label.getHorizontalTextPosition(), + viewR, iconR, textR, label.getIconTextGap()); } /** @@ -225,7 +224,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * @param textY The y coordinate of the start of the baseline. */ protected void paintDisabledText(JLabel l, Graphics g, String s, int textX, - int textY) + int textY) { Color saved_color = g.getColor(); @@ -235,14 +234,14 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, - textY); + textY); else g.drawString(s, textX, textY); g.setColor(l.getBackground().darker()); if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX + 1, - textY + 1); + textY + 1); else g.drawString(s, textX + 1, textY + 1); @@ -260,7 +259,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener * @param textY The y coordinate of the start of the baseline. */ protected void paintEnabledText(JLabel l, Graphics g, String s, int textX, - int textY) + int textY) { Color saved_color = g.getColor(); g.setColor(l.getForeground()); @@ -269,7 +268,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener if (mnemIndex != -1) BasicGraphicsUtils.drawStringUnderlineCharAt(g, s, mnemIndex, textX, - textY); + textY); else g.drawString(s, textX, textY); @@ -287,14 +286,14 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener { super.installUI(c); if (c instanceof JLabel) - { - JLabel l = (JLabel) c; - - installComponents(l); - installDefaults(l); - installListeners(l); - installKeyboardActions(l); - } + { + JLabel l = (JLabel) c; + + installComponents(l); + installDefaults(l); + installListeners(l); + installKeyboardActions(l); + } } /** @@ -308,14 +307,14 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener { super.uninstallUI(c); if (c instanceof JLabel) - { - JLabel l = (JLabel) c; - - uninstallKeyboardActions(l); - uninstallListeners(l); - uninstallDefaults(l); - uninstallComponents(l); - } + { + JLabel l = (JLabel) c; + + uninstallKeyboardActions(l); + uninstallListeners(l); + uninstallDefaults(l); + uninstallComponents(l); + } } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java index 24c6cd20b61..841bd670f67 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java @@ -49,6 +49,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.MouseEvent; @@ -208,12 +209,12 @@ public class BasicListUI extends ListUI if ((evt.getKeyCode() == KeyEvent.VK_DOWN) || (evt.getKeyCode() == KeyEvent.VK_KP_DOWN)) { - if (!evt.isShiftDown()) + if (evt.getModifiers() == 0) { BasicListUI.this.list.clearSelection(); BasicListUI.this.list.setSelectedIndex(Math.min(lead+1,max)); } - else + else if (evt.getModifiers() == InputEvent.SHIFT_MASK) { BasicListUI.this.list.getSelectionModel(). setLeadSelectionIndex(Math.min(lead+1,max)); @@ -222,12 +223,12 @@ public class BasicListUI extends ListUI else if ((evt.getKeyCode() == KeyEvent.VK_UP) || (evt.getKeyCode() == KeyEvent.VK_KP_UP)) { - if (!evt.isShiftDown()) + if (evt.getModifiers() == 0) { BasicListUI.this.list.clearSelection(); BasicListUI.this.list.setSelectedIndex(Math.max(lead-1,0)); } - else + else if (evt.getModifiers() == InputEvent.SHIFT_MASK) { BasicListUI.this.list.getSelectionModel(). setLeadSelectionIndex(Math.max(lead-1,0)); @@ -235,20 +236,53 @@ public class BasicListUI extends ListUI } else if (evt.getKeyCode() == KeyEvent.VK_PAGE_UP) { - // FIXME: implement, need JList.ensureIndexIsVisible to work + int target; + if (lead == BasicListUI.this.list.getFirstVisibleIndex()) + { + target = Math.max + (0, lead - (BasicListUI.this.list.getLastVisibleIndex() - + BasicListUI.this.list.getFirstVisibleIndex() + 1)); + } + else + { + target = BasicListUI.this.list.getFirstVisibleIndex(); + } + if (evt.getModifiers() == 0) + BasicListUI.this.list.setSelectedIndex(target); + else if (evt.getModifiers() == InputEvent.SHIFT_MASK) + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(target); } else if (evt.getKeyCode() == KeyEvent.VK_PAGE_DOWN) { - // FIXME: implement, need JList.ensureIndexIsVisible to work + int target; + if (lead == BasicListUI.this.list.getLastVisibleIndex()) + { + target = Math.min + (max, lead + (BasicListUI.this.list.getLastVisibleIndex() - + BasicListUI.this.list.getFirstVisibleIndex() + 1)); + } + else + { + target = BasicListUI.this.list.getLastVisibleIndex(); + } + if (evt.getModifiers() == 0) + BasicListUI.this.list.setSelectedIndex(target); + else if (evt.getModifiers() == InputEvent.SHIFT_MASK) + BasicListUI.this.list.getSelectionModel(). + setLeadSelectionIndex(target); } else if (evt.getKeyCode() == KeyEvent.VK_BACK_SLASH - && evt.isControlDown()) + && (evt.getModifiers() == InputEvent.CTRL_MASK)) { BasicListUI.this.list.clearSelection(); } else if ((evt.getKeyCode() == KeyEvent.VK_HOME) || evt.getKeyCode() == KeyEvent.VK_END) { + if (evt.getModifiers() != 0 && + evt.getModifiers() != InputEvent.SHIFT_MASK) + return; // index is either 0 for HOME, or last cell for END int index = (evt.getKeyCode() == KeyEvent.VK_HOME) ? 0 : max; @@ -264,16 +298,23 @@ public class BasicListUI extends ListUI setLeadSelectionIndex(index); } else if ((evt.getKeyCode() == KeyEvent.VK_A || evt.getKeyCode() - == KeyEvent.VK_SLASH) && evt.isControlDown()) + == KeyEvent.VK_SLASH) && (evt.getModifiers() == + InputEvent.CTRL_MASK)) { BasicListUI.this.list.setSelectionInterval(0, max); + // this next line is to restore the lead selection index to the old + // position, because select-all should not change the lead index + BasicListUI.this.list.addSelectionInterval(lead, lead); } - else if (evt.getKeyCode() == KeyEvent.VK_SPACE && evt.isControlDown()) + else if (evt.getKeyCode() == KeyEvent.VK_SPACE && + (evt.getModifiers() == InputEvent.CTRL_MASK)) { BasicListUI.this.list.getSelectionModel(). setLeadSelectionIndex(Math.min(lead+1,max)); } - + + BasicListUI.this.list.ensureIndexIsVisible + (BasicListUI.this.list.getLeadSelectionIndex()); } } @@ -295,17 +336,7 @@ public class BasicListUI extends ListUI int index = BasicListUI.this.locationToIndex(list, click); if (index == -1) return; - if (event.isControlDown()) - { - if (BasicListUI.this.list.getSelectionMode() == - ListSelectionModel.SINGLE_SELECTION) - BasicListUI.this.list.setSelectedIndex(index); - else if (BasicListUI.this.list.isSelectedIndex(index)) - BasicListUI.this.list.removeSelectionInterval(index,index); - else - BasicListUI.this.list.addSelectionInterval(index,index); - } - else if (event.isShiftDown()) + if (event.isShiftDown()) { if (BasicListUI.this.list.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION) @@ -329,8 +360,21 @@ public class BasicListUI extends ListUI BasicListUI.this.list.getSelectionModel(). setLeadSelectionIndex(index); } + else if (event.isControlDown()) + { + if (BasicListUI.this.list.getSelectionMode() == + ListSelectionModel.SINGLE_SELECTION) + BasicListUI.this.list.setSelectedIndex(index); + else if (BasicListUI.this.list.isSelectedIndex(index)) + BasicListUI.this.list.removeSelectionInterval(index,index); + else + BasicListUI.this.list.addSelectionInterval(index,index); + } else BasicListUI.this.list.setSelectedIndex(index); + + BasicListUI.this.list.ensureIndexIsVisible + (BasicListUI.this.list.getLeadSelectionIndex()); } /** @@ -843,11 +887,11 @@ public class BasicListUI extends ListUI ListCellRenderer rend, ListModel data, ListSelectionModel sel, int lead) { - boolean is_sel = list.isSelectedIndex(row); - boolean has_focus = false; + boolean isSel = list.isSelectedIndex(row); + boolean hasFocus = (list.getLeadSelectionIndex() == row) && BasicListUI.this.list.hasFocus(); Component comp = rend.getListCellRendererComponent(list, data.getElementAt(row), - 0, is_sel, has_focus); + 0, isSel, hasFocus); //comp.setBounds(new Rectangle(0, 0, bounds.width, bounds.height)); //comp.paint(g); rendererPane.paintComponent(g, comp, list, bounds); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java index 14fe28f7110..d35ac9eb926 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -57,6 +57,7 @@ import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.DimensionUIResource; import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.IconUIResource; import javax.swing.plaf.InsetsUIResource; import javax.swing.text.JTextComponent; @@ -276,7 +277,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Button.shadow", new ColorUIResource(Color.GRAY), "Button.textIconGap", new Integer(4), "Button.textShiftOffset", new Integer(0), - "CheckBox.background", new ColorUIResource(light), + "CheckBox.background", new ColorUIResource(new Color(204, 204, 204)), "CheckBox.border", new BorderUIResource.CompoundBorderUIResource(null, null), "CheckBox.focusInputMap", new UIDefaults.LazyInputMap(new Object[] { @@ -285,21 +286,43 @@ public abstract class BasicLookAndFeel extends LookAndFeel }), "CheckBox.font", new FontUIResource("Dialog", Font.PLAIN, 12), "CheckBox.foreground", new ColorUIResource(darkShadow), - "CheckBox.icon", BasicIconFactory.getCheckBoxIcon(), + "CheckBox.icon", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults def) + { + return BasicIconFactory.getCheckBoxIcon(); + } + }, + "CheckBox.checkIcon", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults def) + { + return BasicIconFactory.getMenuItemCheckIcon(); + } + }, "CheckBox.margin",new InsetsUIResource(2, 2, 2, 2), "CheckBox.textIconGap", new Integer(4), "CheckBox.textShiftOffset", new Integer(0), "CheckBoxMenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12), "CheckBoxMenuItem.acceleratorForeground", - new ColorUIResource(darkShadow), + new ColorUIResource(new Color(16, 16, 16)), "CheckBoxMenuItem.acceleratorSelectionForeground", new ColorUIResource(Color.white), "CheckBoxMenuItem.arrowIcon", BasicIconFactory.getMenuItemArrowIcon(), "CheckBoxMenuItem.background", new ColorUIResource(light), "CheckBoxMenuItem.border", new BasicBorders.MarginBorder(), "CheckBoxMenuItem.borderPainted", Boolean.FALSE, - "CheckBoxMenuItem.checkIcon", BasicIconFactory.getCheckBoxMenuItemIcon(), + "CheckBoxMenuItem.checkIcon", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults def) + { + return BasicIconFactory.getCheckBoxMenuItemIcon(); + } + }, "CheckBoxMenuItem.font", new FontUIResource("Dialog", Font.PLAIN, 12), "CheckBoxMenuItem.foreground", new ColorUIResource(darkShadow), "CheckBoxMenuItem.margin", new InsetsUIResource(2, 2, 2, 2), @@ -371,7 +394,6 @@ public abstract class BasicLookAndFeel extends LookAndFeel "ctrl F10", "maximize", "ctrl alt shift F6","selectPreviousFrame" }), - "Desktop.background", new ColorUIResource(0, 92, 92), "DesktopIcon.border", new BorderUIResource.CompoundBorderUIResource(null, null), "EditorPane.background", new ColorUIResource(Color.white), @@ -480,15 +502,22 @@ public abstract class BasicLookAndFeel extends LookAndFeel "InternalFrame.borderLight", new ColorUIResource(Color.LIGHT_GRAY), "InternalFrame.borderShadow", new ColorUIResource(Color.GRAY), "InternalFrame.closeIcon", BasicIconFactory.createEmptyFrameIcon(), - // XXX Don't use gif -// "InternalFrame.icon", new IconUIResource(new ImageIcon("icons/JavaCup.gif")), + // FIXME: Set a nice icon for InternalFrames here. + "InternalFrame.icon", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults def) + { + return new IconUIResource(BasicIconFactory.createEmptyFrameIcon()); + } + }, "InternalFrame.iconifyIcon", BasicIconFactory.createEmptyFrameIcon(), "InternalFrame.inactiveTitleBackground", new ColorUIResource(Color.gray), "InternalFrame.inactiveTitleForeground", new ColorUIResource(Color.lightGray), "InternalFrame.maximizeIcon", BasicIconFactory.createEmptyFrameIcon(), "InternalFrame.minimizeIcon", BasicIconFactory.createEmptyFrameIcon(), - "InternalFrame.titleFont", new FontUIResource("Dialog", Font.PLAIN, 12), + "InternalFrame.titleFont", new FontUIResource("Dialog", Font.BOLD, 12), "InternalFrame.windowBindings", new Object[] { "shift ESCAPE", "showSystemMenu", "ctrl SPACE", "showSystemMenu", @@ -524,6 +553,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel "List.foreground", new ColorUIResource(darkShadow), "List.selectionBackground", new ColorUIResource(Color.black), "List.selectionForeground", new ColorUIResource(Color.white), + "List.focusCellHighlightBorder", + new BorderUIResource. + LineBorderUIResource(new ColorUIResource(Color.yellow)), "Menu.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 12), "Menu.acceleratorForeground", new ColorUIResource(darkShadow), "Menu.acceleratorSelectionForeground", new ColorUIResource(Color.white), @@ -613,7 +645,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel null, null), "PasswordField.caretBlinkRate", new Integer(500), "PasswordField.caretForeground", new ColorUIResource(Color.black), - "PasswordField.font", new FontUIResource("MonoSpaced", Font.PLAIN, 12), + "PasswordField.font", new FontUIResource("Dialog", Font.PLAIN, 12), "PasswordField.foreground", new ColorUIResource(Color.black), "PasswordField.inactiveBackground", new ColorUIResource(light), "PasswordField.inactiveForeground", new ColorUIResource(Color.gray), @@ -649,7 +681,14 @@ public abstract class BasicLookAndFeel extends LookAndFeel "RadioButton.font", new FontUIResource("Dialog", Font.PLAIN, 12), "RadioButton.foreground", new ColorUIResource(darkShadow), "RadioButton.highlight", new ColorUIResource(highLight), - "RadioButton.icon", BasicIconFactory.getRadioButtonIcon(), + "RadioButton.icon", + new UIDefaults.LazyValue() + { + public Object createValue(UIDefaults def) + { + return BasicIconFactory.getRadioButtonIcon(); + } + }, "RadioButton.light", new ColorUIResource(highLight), "RadioButton.margin", new InsetsUIResource(2, 2, 2, 2), "RadioButton.shadow", new ColorUIResource(shadow), @@ -748,7 +787,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Slider.highlight", new ColorUIResource(highLight), "Slider.shadow", new ColorUIResource(shadow), "Slider.thumbHeight", new Integer(20), - "Slider.thumbWidth", new Integer(10), + "Slider.thumbWidth", new Integer(11), "Slider.tickHeight", new Integer(12), "Spinner.background", new ColorUIResource(light), "Spinner.foreground", new ColorUIResource(light), @@ -838,13 +877,24 @@ public abstract class BasicLookAndFeel extends LookAndFeel "shift KP_DOWN", "selectNextRowExtendSelection", "shift KP_LEFT", "selectPreviousColumnExtendSelection", "ESCAPE", "cancel", - "ctrl shift PAGE_UP", "scrollRightExtendSelection", - "shift KP_RIGHT", " selectNextColumnExtendSelection", + "ctrl shift PAGE_UP", "scrollLeftExtendSelection", + "shift KP_RIGHT", "selectNextColumnExtendSelection", "ctrl PAGE_UP", "scrollLeftChangeSelection", "shift PAGE_UP", "scrollUpExtendSelection", - "ctrl shift PAGE_DOWN", "scrollLeftExtendSelection", + "ctrl shift PAGE_DOWN", "scrollRightExtendSelection", "ctrl PAGE_DOWN", "scrollRightChangeSelection", - "PAGE_UP", "scrollUpChangeSelection" + "PAGE_UP", "scrollUpChangeSelection", + "ctrl shift LEFT", "selectPreviousColumnExtendSelection", + "shift KP_UP", "selectPreviousRowExtendSelection", + "ctrl shift UP", "selectPreviousRowExtendSelection", + "ctrl shift RIGHT", "selectNextColumnExtendSelection", + "ctrl shift KP_RIGHT", "selectNextColumnExtendSelection", + "ctrl shift DOWN", "selectNextRowExtendSelection", + "ctrl BACK_SLASH", "clearSelection", + "ctrl shift KP_UP", "selectPreviousRowExtendSelection", + "ctrl shift KP_LEFT", "selectPreviousColumnExtendSelection", + "ctrl SLASH", "selectAll", + "ctrl shift KP_DOWN", "selectNextRowExtendSelection", }), "Table.background", new ColorUIResource(light), "Table.focusCellBackground", new ColorUIResource(light), @@ -1000,7 +1050,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel "shift END", "selectLastExtendSelection", "HOME", "selectFirst", "ctrl END", "selectLastChangeLead", - "ctrl /", "selectAll", + "ctrl SLASH", "selectAll", "LEFT", "selectParent", "shift HOME", "selectFirstExtendSelection", "UP", "selectPrevious", @@ -1027,7 +1077,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel "shift KP_DOWN","selectNextExtendSelection", "ctrl SPACE", "toggleSelectionPreserveAnchor", "ctrl shift PAGE_UP", "scrollUpExtendSelection", - "ctrl \\", "clearSelection", + "ctrl BACK_SLASH", "clearSelection", "shift SPACE", "extendSelection", "ctrl PAGE_UP", "scrollUpChangeLead", "shift PAGE_UP","scrollUpExtendSelection", @@ -1046,6 +1096,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel "Tree.selectionBackground", new ColorUIResource(Color.black), "Tree.nonSelectionBackground", new ColorUIResource(new Color(239, 235, 231)), "Tree.selectionBorderColor", new ColorUIResource(Color.black), + "Tree.selectionBorder", new BorderUIResource.LineBorderUIResource(Color.black), "Tree.selectionForeground", new ColorUIResource(new Color(255, 255, 255)), "Tree.textBackground", new ColorUIResource(new Color(255, 255, 255)), "Tree.textForeground", new ColorUIResource(Color.black), diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java index a5bf0822ac5..8aa1193bcc4 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -295,7 +295,7 @@ public class BasicMenuItemUI extends MenuItemUI * Returns preferred size for the given menu item. * * @param c menu item for which to get preferred size - * @param checkIcon chech icon displayed in the given menu item + * @param checkIcon check icon displayed in the given menu item * @param arrowIcon arrow icon displayed in the given menu item * @param defaultTextIconGap space between icon and text in the given menuItem * @@ -355,12 +355,18 @@ public class BasicMenuItemUI extends MenuItemUI */ public Dimension getPreferredSize(JComponent c) { - return getPreferredMenuItemSize(c, checkIcon, arrowIcon, defaultTextIconGap); + return getPreferredMenuItemSize(c, checkIcon, arrowIcon, + defaultTextIconGap); } + /** + * Returns the prefix for entries in the {@link UIDefaults} table. + * + * @return "MenuItem" + */ protected String getPropertyPrefix() { - return null; + return "MenuItem"; } /** @@ -507,7 +513,8 @@ public class BasicMenuItemUI extends MenuItemUI br.height += insets.top + insets.bottom; // Menu item is considered to be highlighted when it is selected. - if (m.isSelected() || m.getModel().isArmed() && + // But we don't want to paint the background of JCheckBoxMenuItems + if ((m.isSelected() && checkIcon == null) || m.getModel().isArmed() && (m.getParent() instanceof MenuElement)) { if (m.isContentAreaFilled()) @@ -531,8 +538,7 @@ public class BasicMenuItemUI extends MenuItemUI SwingUtilities.layoutCompoundLabel(m, fm, null, checkIcon, vertAlign, horAlign, vertTextPos, horTextPos, vr, cr, tr, defaultTextIconGap); - checkIcon.paintIcon(m, g, cr.x, cr.y); - + 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 @@ -561,7 +567,6 @@ public class BasicMenuItemUI extends MenuItemUI defaultTextIconGap); if (i != null) i.paintIcon(c, g, ir.x, ir.y); - paintText(g, m, tr, m.getText()); // paint accelerator @@ -605,7 +610,8 @@ public class BasicMenuItemUI extends MenuItemUI if (menuItem.isEnabled()) { // Menu item is considered to be highlighted when it is selected. - if (menuItem.isSelected() || menuItem.getModel().isArmed() && + // But not if it's a JCheckBoxMenuItem + if ((menuItem.isSelected() && checkIcon == null) || menuItem.getModel().isArmed() && (menuItem.getParent() instanceof MenuElement)) g.setColor(selectionForeground); else diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java index 6bd15ede2c5..30be592ee79 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java @@ -46,6 +46,7 @@ import java.beans.PropertyChangeListener; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; +import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; @@ -179,12 +180,23 @@ public class BasicMenuUI extends BasicMenuItemUI */ public Dimension getMaximumSize(JComponent c) { + // If this menu is in a popup menu, treat it like a regular JMenuItem + if (!((JMenu)c).isTopLevelMenu()) + { + JMenuItem menuItem = new JMenuItem(((JMenu)c).getText(), ((JMenu)c).getIcon()); + return menuItem.getMaximumSize(); + } return c.getPreferredSize(); } + /** + * Returns the prefix for entries in the {@link UIDefaults} table. + * + * @return "Menu" + */ protected String getPropertyPrefix() { - return null; + return "Menu"; } /** @@ -294,14 +306,17 @@ public class BasicMenuUI extends BasicMenuItemUI private boolean popupVisible() { - JMenuBar mb = (JMenuBar) ((JMenu)menuItem).getParent(); + JMenuBar mb = (JMenuBar) ((JMenu) menuItem).getParent(); // check if mb.isSelected because if no menus are selected // we don't have to look through the list for popup menus if (!mb.isSelected()) return false; - for (int i=0;i<mb.getMenuCount();i++) - if (((JMenu)mb.getComponent(i)).isPopupMenuVisible()) + for (int i = 0; i < mb.getMenuCount(); i++) + { + JMenu m = mb.getMenu(i); + if (m != null && m.isPopupMenuVisible()) return true; + } return false; } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java index ce29f24b42a..c9f623259ba 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java @@ -910,7 +910,9 @@ public class BasicOptionPaneUI extends OptionPaneUI */ protected Container createSeparator() { - return (Container) Box.createVerticalStrut(17); + // FIXME: Figure out what this method is supposed to return and where + // this should be added to the OptionPane. + return null; } /** @@ -1115,6 +1117,10 @@ public class BasicOptionPaneUI extends OptionPaneUI optionPane.add(msg); } + // FIXME: Figure out if the separator should be inserted here or what + // this thing is supposed to do. Note: The JDK does NOT insert another + // component at this place. The JOptionPane only has two panels in it + // and there actually are applications that depend on this beeing so. Container sep = createSeparator(); if (sep != null) optionPane.add(sep); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java index 0896721ca99..b715c57b360 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPanelUI.java @@ -40,6 +40,8 @@ package javax.swing.plaf.basic; import javax.swing.JComponent; import javax.swing.JPanel; +import javax.swing.UIDefaults; +import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.PanelUI; @@ -62,6 +64,8 @@ public class BasicPanelUI extends PanelUI public void installDefaults(JPanel p) { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + p.setBackground(defaults.getColor("Panel.background")); p.setOpaque(true); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java index d5cd7f4488e..fa74a008bae 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java @@ -77,13 +77,13 @@ public class BasicRadioButtonMenuItemUI extends BasicMenuItemUI } /** - * DOCUMENT ME! + * Returns the prefix for entries in the {@link UIDefaults} table. * - * @return $returnType$ DOCUMENT ME! + * @return "RadioButtonMenuItem" */ protected String getPropertyPrefix() { - return null; + return "RadioButtonMenuItem"; } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java index 38e117b18b2..fbd21241a0d 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -38,50 +38,125 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Rectangle; + import javax.swing.AbstractButton; import javax.swing.Icon; import javax.swing.JComponent; +import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +/** + * The BasicLookAndFeel UI implementation for + * {@link javax.swing.JRadioButton}s. + */ public class BasicRadioButtonUI extends BasicToggleButtonUI { - + /** + * The default icon for JRadioButtons. The default icon displays the usual + * RadioButton and is sensible to the selection state of the button, + * and can be used both as normal icon as well as selectedIcon. + */ protected Icon icon; + /** + * Creates and returns a new instance of <code>BasicRadioButtonUI</code>. + * + * @return a new instance of <code>BasicRadioButtonUI</code> + */ public static ComponentUI createUI(final JComponent c) { return new BasicRadioButtonUI(); } + /** + * Creates a new instance of <code>BasicButtonUI</code>. + */ public BasicRadioButtonUI() { icon = getDefaultIcon(); } - public void installUI(final JComponent c) { - super.installUI(c); - if (c instanceof AbstractButton) - { - AbstractButton b = (AbstractButton) c; - b.setIcon(icon); - } + /** + * Installs defaults from the Look & Feel table on the specified + * button. + * + * @param b the button on which to install the defaults + */ + protected void installDefaults(AbstractButton b) + { + super.installDefaults(b); + if (b.getIcon() == null) + b.setIcon(icon); + if (b.getSelectedIcon() == null) + b.setSelectedIcon(icon); } + /** + * Returns the prefix used for UIDefaults properties. This is + * <code>RadioButton</code> in this case. + * + * @return the prefix used for UIDefaults properties + */ + protected String getPropertyPrefix() + { + return "RadioButton."; + } + + /** + * Returns the default icon for JRadioButtons. + * The default icon displays the usual + * RadioButton and is sensible to the selection state of the button, + * and can be used both as normal icon as well as selectedIcon. + * + * @return the default icon for JRadioButtons + */ public Icon getDefaultIcon() { UIDefaults defaults = UIManager.getLookAndFeelDefaults(); - return defaults.getIcon("RadioButton.icon"); + return defaults.getIcon(getPropertyPrefix() + "icon"); } - -} - - - - + /** + * Paints the RadioButton. + * + * @param g the Graphics context to paint with + * @param c the button to paint + */ + public void paint(Graphics g, JComponent c) + { + AbstractButton b = (AbstractButton) c; + Rectangle tr = new Rectangle(); + Rectangle ir = new Rectangle(); + Rectangle vr = new Rectangle(); + Font f = c.getFont(); + g.setFont(f); + Icon currentIcon = null; + if (b.isSelected()) + currentIcon = b.getSelectedIcon(); + else + currentIcon = b.getIcon(); + SwingUtilities.calculateInnerArea(b, vr); + String text = SwingUtilities.layoutCompoundLabel + (c, g.getFontMetrics(f), b.getText(), currentIcon, + b.getVerticalAlignment(), b.getHorizontalAlignment(), + b.getVerticalTextPosition(), b.getHorizontalTextPosition(), + vr, ir, tr, b.getIconTextGap() + defaultTextShiftOffset); + + if (currentIcon != null) + { + currentIcon.paintIcon(c, g, ir.x, ir.y); + } + if (text != null) + paintText(g, b, tr, text); + paintFocus(g, b, vr, tr, ir); + } +} diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java index 892db2b031b..22242afcd8a 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -659,7 +659,6 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, height = Math.max(incrButton.getPreferredSize().height, decrButton.getPreferredSize().height); height = Math.max(getMinimumThumbSize().height, height); - height = Math.max(20, height); height = Math.min(getMaximumThumbSize().height, height); } else @@ -672,7 +671,6 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, width = Math.max(incrButton.getPreferredSize().width, decrButton.getPreferredSize().width); width = Math.max(getMinimumThumbSize().width, width); - width = Math.max(20, width); width = Math.min(getMaximumThumbSize().width, width); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java index 7bb7acffb8d..bd1576f37a5 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollPaneUI.java @@ -102,14 +102,6 @@ public class BasicScrollPaneUI extends ScrollPaneUI return sl.minimumLayoutSize(c); } - public Dimension getPreferredSize(JComponent c) - { - JScrollPane p = (JScrollPane ) c; - ScrollPaneLayout sl = (ScrollPaneLayout) p.getLayout(); - return sl.preferredLayoutSize(c); - } - - public void paint(Graphics g, JComponent c) { // do nothing; the normal painting-of-children algorithm, along with diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java index 0a72a62ff9c..0b4058429c5 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java @@ -470,15 +470,6 @@ public class BasicSliderUI extends SliderUI } } - /** The preferred height of the thumb. */ - private transient int thumbHeight; - - /** The preferred width of the thumb. */ - private transient int thumbWidth; - - /** The preferred height of the tick rectangle. */ - private transient int tickHeight; - /** Listener for changes from the model. */ protected ChangeListener changeListener; @@ -698,11 +689,6 @@ public class BasicSliderUI extends SliderUI focusColor = defaults.getColor("Slider.focus"); slider.setBorder(defaults.getBorder("Slider.border")); slider.setOpaque(true); - - thumbHeight = defaults.getInt("Slider.thumbHeight"); - thumbWidth = defaults.getInt("Slider.thumbWidth"); - tickHeight = defaults.getInt("Slider.tickHeight"); - focusInsets = defaults.getInsets("Slider.focusInsets"); } @@ -899,11 +885,11 @@ public class BasicSliderUI extends SliderUI width += insets.left + insets.right + focusInsets.left + focusInsets.right; // Height is determined by the thumb, the ticks and the labels. - int height = thumbHeight; + int height = getThumbSize().height; if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 || slider.getMinorTickSpacing() > 0) - height += tickHeight; + height += getTickLength(); if (slider.getPaintLabels()) height += getHeightOfTallestLabel(); @@ -934,11 +920,11 @@ public class BasicSliderUI extends SliderUI height += insets.top + insets.bottom + focusInsets.top + focusInsets.bottom; - int width = thumbHeight; + int width = getThumbSize().width; if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 || slider.getMinorTickSpacing() > 0) - width += tickHeight; + width += getTickLength(); if (slider.getPaintLabels()) width += getWidthOfWidestLabel(); @@ -956,7 +942,21 @@ public class BasicSliderUI extends SliderUI */ public Dimension getMinimumHorizontalSize() { - return getPreferredHorizontalSize(); + Insets insets = slider.getInsets(); + // Height is determined by the thumb, the ticks and the labels. + int height = getThumbSize().height; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 + || slider.getMinorTickSpacing() > 0) + height += getTickLength(); + + if (slider.getPaintLabels()) + height += getHeightOfTallestLabel(); + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + return new Dimension(36, height); } /** @@ -967,7 +967,19 @@ public class BasicSliderUI extends SliderUI */ public Dimension getMinimumVerticalSize() { - return getPreferredVerticalSize(); + Insets insets = slider.getInsets(); + int width = getThumbSize().width; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 + || slider.getMinorTickSpacing() > 0) + width += getTickLength(); + + if (slider.getPaintLabels()) + width += getWidthOfWidestLabel(); + + width += insets.left + insets.right + focusInsets.left + focusInsets.right; + + return new Dimension(width, 36); } /** @@ -999,15 +1011,14 @@ public class BasicSliderUI extends SliderUI public Dimension getMinimumSize(JComponent c) { if (slider.getOrientation() == JSlider.HORIZONTAL) - return getPreferredHorizontalSize(); + return getMinimumHorizontalSize(); else - return getPreferredVerticalSize(); + return getMinimumVerticalSize(); } /** * This method returns the maximum size for this {@link JSlider} for this - * look and feel. If it returns null, then it is up to the Layout Manager - * to give the {@link JComponent} a size. + * look and feel. * * @param c The {@link JComponent} to find a maximum size for. * @@ -1015,10 +1026,40 @@ public class BasicSliderUI extends SliderUI */ public Dimension getMaximumSize(JComponent c) { + Insets insets = slider.getInsets(); if (slider.getOrientation() == JSlider.HORIZONTAL) - return getPreferredHorizontalSize(); + { + // Height is determined by the thumb, the ticks and the labels. + int height = getThumbSize().height; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 + || slider.getMinorTickSpacing() > 0) + height += getTickLength(); + + if (slider.getPaintLabels()) + height += getHeightOfTallestLabel(); + + height += insets.top + insets.bottom + focusInsets.top + + focusInsets.bottom; + + return new Dimension(32767, height); + } else - return getPreferredVerticalSize(); + { + int width = getThumbSize().width; + + if (slider.getPaintTicks() && slider.getMajorTickSpacing() > 0 + || slider.getMinorTickSpacing() > 0) + width += getTickLength(); + + if (slider.getPaintLabels()) + width += getWidthOfWidestLabel(); + + width += insets.left + insets.right + focusInsets.left + + focusInsets.right; + + return new Dimension(width, 32767); + } } /** @@ -1045,7 +1086,6 @@ public class BasicSliderUI extends SliderUI { insetCache = slider.getInsets(); focusRect = SwingUtilities.calculateInnerArea(slider, focusRect); - if (focusRect.width < 0) focusRect.width = 0; if (focusRect.height < 0) @@ -1058,30 +1098,13 @@ public class BasicSliderUI extends SliderUI */ protected void calculateThumbSize() { + Dimension d = getThumbSize(); + thumbRect.width = d.width; + thumbRect.height = d.height; if (slider.getOrientation() == JSlider.HORIZONTAL) - { - if (thumbWidth > contentRect.width) - thumbRect.width = contentRect.width / 4; - else - thumbRect.width = thumbWidth; - if (thumbHeight > contentRect.height) - thumbRect.height = contentRect.height; - else - thumbRect.height = thumbHeight; - } + thumbRect.y = trackRect.y; else - { - // The thumb gets flipped when inverted, so thumbWidth - // actually is the height and vice versa. - if (thumbWidth > contentRect.height) - thumbRect.height = contentRect.height / 4; - else - thumbRect.height = thumbWidth; - if (thumbHeight > contentRect.width) - thumbRect.width = contentRect.width; - else - thumbRect.width = thumbHeight; - } + thumbRect.x = trackRect.x; } /** @@ -1092,9 +1115,10 @@ public class BasicSliderUI extends SliderUI { contentRect.x = focusRect.x + focusInsets.left; contentRect.y = focusRect.y + focusInsets.top; + contentRect.width = focusRect.width - focusInsets.left - focusInsets.right; - contentRect.height = focusRect.height - focusInsets.top - - focusInsets.bottom; + contentRect.height = focusRect.height - focusInsets.top + - focusInsets.bottom; if (contentRect.width < 0) contentRect.width = 0; @@ -1113,11 +1137,11 @@ public class BasicSliderUI extends SliderUI if (slider.getOrientation() == JSlider.HORIZONTAL) { thumbRect.x = xPositionForValue(value) - thumbRect.width / 2; - thumbRect.y = contentRect.y; + thumbRect.y = trackRect.y; } else { - thumbRect.x = contentRect.x; + thumbRect.x = trackRect.x; thumbRect.y = yPositionForValue(value) - thumbRect.height / 2; } } @@ -1129,9 +1153,9 @@ public class BasicSliderUI extends SliderUI protected void calculateTrackBuffer() { if (slider.getOrientation() == JSlider.HORIZONTAL) - trackBuffer = thumbRect.width; + trackBuffer = thumbRect.width / 2; else - trackBuffer = thumbRect.height; + trackBuffer = thumbRect.height / 2; } /** @@ -1141,9 +1165,11 @@ public class BasicSliderUI extends SliderUI */ protected Dimension getThumbSize() { - // This is really just the bounds box for the thumb. - // The thumb will actually be pointed (like a rectangle + triangle at bottom) - return thumbRect.getSize(); + // TODO: shouldn't create new objects every time + if (slider.getOrientation() == JSlider.HORIZONTAL) + return new Dimension(11, 20); + else + return new Dimension(20, 11); } /** @@ -1155,13 +1181,21 @@ public class BasicSliderUI extends SliderUI if (slider.getOrientation() == JSlider.HORIZONTAL) { trackRect.x = contentRect.x + trackBuffer; - trackRect.y = contentRect.y; + 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; } else { - trackRect.x = contentRect.x; + int w = getThumbSize().width; + 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; @@ -1180,7 +1214,7 @@ public class BasicSliderUI extends SliderUI */ protected int getTickLength() { - return tickHeight; + return 8; } /** @@ -1536,9 +1570,6 @@ public class BasicSliderUI extends SliderUI Point c = new Point(a); Point d = new Point(a); - Polygon high; - Polygon shadow; - if (slider.getOrientation() == JSlider.HORIZONTAL) { width = trackRect.width; @@ -1591,74 +1622,78 @@ public class BasicSliderUI extends SliderUI { if (slider.getOrientation() == JSlider.HORIZONTAL) { - double loc = tickRect.x; + double loc = tickRect.x + 0.5; double increment = (max == min) ? 0 - : majorSpace * (double) tickRect.width / (max - - min); - if (drawInverted()) + : majorSpace * (double) (tickRect.width - 1) / (max - min); + if (drawInverted()) { loc += tickRect.width; increment *= -1; } + g.translate(0, tickRect.y); for (int i = min; i <= max; i += majorSpace) { paintMajorTickForHorizSlider(g, tickRect, (int) loc); loc += increment; } + g.translate(0, -tickRect.y); } else { - double loc = tickRect.height + tickRect.y; + double loc = tickRect.height + tickRect.y + 0.5; double increment = (max == min) ? 0 - : -majorSpace * (double) tickRect.height / (max - - min); + : -majorSpace * (double) (tickRect.height - 1) / (max - min); if (drawInverted()) { - loc = tickRect.y; + loc = tickRect.y + 0.5; increment *= -1; } + g.translate(tickRect.x, 0); for (int i = min; i <= max; i += majorSpace) { paintMajorTickForVertSlider(g, tickRect, (int) loc); loc += increment; } + g.translate(-tickRect.x, 0); } } if (minorSpace > 0) { if (slider.getOrientation() == JSlider.HORIZONTAL) { - double loc = tickRect.x; + double loc = tickRect.x + 0.5; double increment = (max == min) ? 0 - : minorSpace * (double) tickRect.width / (max - - min); + : minorSpace * (double) (tickRect.width - 1) / (max - min); if (drawInverted()) { loc += tickRect.width; increment *= -1; } + g.translate(0, tickRect.y); for (int i = min; i <= max; i += minorSpace) { paintMinorTickForHorizSlider(g, tickRect, (int) loc); loc += increment; } + g.translate(0, -tickRect.y); } else { - double loc = tickRect.height + tickRect.y; + double loc = tickRect.height + tickRect.y + 0.5; double increment = (max == min) ? 0 - : -minorSpace * (double) tickRect.height / (max - - min); + : -minorSpace * (double) (tickRect.height - 1) / (max - min); if (drawInverted()) { - loc = tickRect.y; + loc = tickRect.y + 0.5; increment *= -1; } + g.translate(tickRect.x, 0); for (int i = min; i <= max; i += minorSpace) { paintMinorTickForVertSlider(g, tickRect, (int) loc); loc += increment; } + g.translate(-tickRect.x, 0); } } } @@ -1680,7 +1715,7 @@ public class BasicSliderUI extends SliderUI protected void paintMinorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x) { - int y = tickRect.y + tickRect.height / 4; + int y = tickRect.height / 4; Color saved = g.getColor(); g.setColor(Color.BLACK); @@ -1699,7 +1734,7 @@ public class BasicSliderUI extends SliderUI protected void paintMajorTickForHorizSlider(Graphics g, Rectangle tickBounds, int x) { - int y = tickRect.y + tickRect.height / 4; + int y = tickRect.height / 4; Color saved = g.getColor(); g.setColor(Color.BLACK); @@ -1718,7 +1753,7 @@ public class BasicSliderUI extends SliderUI protected void paintMinorTickForVertSlider(Graphics g, Rectangle tickBounds, int y) { - int x = tickRect.x + tickRect.width / 4; + int x = tickRect.width / 4; Color saved = g.getColor(); g.setColor(Color.BLACK); @@ -1737,7 +1772,7 @@ public class BasicSliderUI extends SliderUI protected void paintMajorTickForVertSlider(Graphics g, Rectangle tickBounds, int y) { - int x = tickRect.x + tickRect.width / 4; + int x = tickRect.width / 4; Color saved = g.getColor(); g.setColor(Color.BLACK); @@ -1924,8 +1959,6 @@ public class BasicSliderUI extends SliderUI { Color saved_color = g.getColor(); - Polygon thumb = new Polygon(); - Point a = new Point(thumbRect.x, thumbRect.y); Point b = new Point(a); Point c = new Point(a); @@ -1933,7 +1966,8 @@ public class BasicSliderUI extends SliderUI Point e = new Point(a); Polygon bright; - Polygon dark; + Polygon light; // light shadow + Polygon dark; // dark shadow Polygon all; // This will be in X-dimension if the slider is inverted and y if it isn't. @@ -1943,36 +1977,42 @@ public class BasicSliderUI extends SliderUI { turnPoint = thumbRect.height * 3 / 4; - b.translate(thumbRect.width, 0); - c.translate(thumbRect.width, turnPoint); - d.translate(thumbRect.width / 2, thumbRect.height); + 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, a.x, e.x, d.x }, + 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 }, - new int[] { b.y, c.y, d.y }, 3); - all = new Polygon(new int[] { a.x + 1, b.x, c.x, d.x, e.x + 1 }, - new int[] { a.y + 1, b.y + 1, c.y, d.y + 1, e.y }, 5); + 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); } else { - turnPoint = thumbRect.width * 3 / 4; + turnPoint = thumbRect.width * 3 / 4 - 1; b.translate(turnPoint, 0); - c.translate(thumbRect.width, thumbRect.height / 2); - d.translate(turnPoint, thumbRect.height); - e.translate(0, thumbRect.height); + 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, b.x, a.x, e.x }, - new int[] { c.y, b.y, a.y, e.y }, 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 + 1 }, + dark = new Polygon(new int[] { c.x, d.x, e.x }, new int[] { c.y, d.y, e.y }, 3); - all = new Polygon(new int[] { a.x + 1, b.x, c.x - 1, d.x, e.x + 1 }, - new int[] { a.y + 1, b.y + 1, c.y, d.y, e.y }, 5); + 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); } g.setColor(Color.WHITE); @@ -1982,6 +2022,10 @@ public class BasicSliderUI extends SliderUI g.drawPolyline(dark.xpoints, dark.ypoints, dark.npoints); g.setColor(Color.GRAY); + g.drawPolyline(light.xpoints, light.ypoints, light.npoints); + + g.setColor(Color.LIGHT_GRAY); + g.drawPolyline(all.xpoints, all.ypoints, all.npoints); g.fillPolygon(all); g.setColor(saved_color); @@ -2065,8 +2109,7 @@ public class BasicSliderUI extends SliderUI { int min = slider.getMinimum(); int max = slider.getMaximum(); - int extent = slider.getExtent(); - int len = trackRect.width; + int len = trackRect.width - 1; int xPos = (max == min) ? 0 : (value - min) * len / (max - min); @@ -2074,7 +2117,7 @@ public class BasicSliderUI extends SliderUI xPos += trackRect.x; else { - xPos = trackRect.width - xPos; + xPos = len - xPos; xPos += trackRect.x; } return xPos; @@ -2091,14 +2134,13 @@ public class BasicSliderUI extends SliderUI { int min = slider.getMinimum(); int max = slider.getMaximum(); - int extent = slider.getExtent(); - int len = trackRect.height; + int len = trackRect.height - 1; int yPos = (max == min) ? 0 : (value - min) * len / (max - min); if (! drawInverted()) { - yPos = trackRect.height - yPos; + yPos = len - yPos; yPos += trackRect.y; } else @@ -2123,8 +2165,9 @@ public class BasicSliderUI extends SliderUI int value; - // If the length is 0, you shouldn't be able to even see where the slider is. - // This really shouldn't ever happen, but just in case, we'll return the middle. + // If the length is 0, you shouldn't be able to even see where the slider + // is. This really shouldn't ever happen, but just in case, we'll return + // the middle. if (len == 0) return ((max - min) / 2); @@ -2158,8 +2201,9 @@ public class BasicSliderUI extends SliderUI int value; - // If the length is 0, you shouldn't be able to even see where the slider is. - // This really shouldn't ever happen, but just in case, we'll return the middle. + // If the length is 0, you shouldn't be able to even see where the slider + // is. This really shouldn't ever happen, but just in case, we'll return + // the middle. if (len == 0) return ((max - min) / 2); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java index ff7e8acfbb6..ef8e2282349 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -870,7 +870,8 @@ public class BasicSplitPaneUI extends SplitPaneUI transient int lastDragLocation = -1; /** The distance the divider is moved when moved by keyboard actions. */ - protected static int KEYBOARD_DIVIDER_MOVE_OFFSET; + // Sun defines this as 3 + protected static int KEYBOARD_DIVIDER_MOVE_OFFSET = 3; /** The divider that divides this JSplitPane. */ protected BasicSplitPaneDivider divider; @@ -1337,9 +1338,11 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public int getMinimumDividerLocation(JSplitPane jc) { - int value = layoutManager.getInitialLocation(jc.getInsets()); - if (layoutManager.components[0] != null) - value += layoutManager.minimumSizeOfComponent(0); + int value = layoutManager.getInitialLocation(jc.getInsets()) + - layoutManager.getAvailableSize(jc.getSize(), jc.getInsets()) + + splitPane.getDividerSize(); + if (layoutManager.components[1] != null) + value += layoutManager.minimumSizeOfComponent(1); return value; } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 8a27f98a3c9..7e9d9b9820c 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -1680,18 +1680,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } /** - * This method returns the preferred size of the JTabbedPane. - * - * @param c The JComponent to find a size for. - * - * @return The preferred size. - */ - public Dimension getPreferredSize(JComponent c) - { - return layoutManager.preferredLayoutSize(tabPane); - } - - /** * This method returns the minimum size of the JTabbedPane. * * @param c The JComponent to find a size for. diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java index 778743619bc..4559937eb69 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java @@ -40,26 +40,37 @@ package javax.swing.plaf.basic; import java.awt.Color; import java.awt.Component; +import java.awt.ComponentOrientation; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; +import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; +import javax.swing.AbstractAction; +import javax.swing.ActionMap; import javax.swing.BorderFactory; import javax.swing.CellRendererPane; +import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JTable; +import javax.swing.JTextField; +import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.Border; +import javax.swing.event.ChangeEvent; import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TableUI; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; @@ -85,6 +96,9 @@ public class BasicTableUI /** The cell border for selected/highlighted cells. */ Border highlightCellBorder; + /** The action bound to KeyStrokes. */ + TableAction action; + class FocusHandler implements FocusListener { public void focusGained(FocusEvent e) @@ -95,54 +109,37 @@ public class BasicTableUI } } - class KeyHandler implements KeyListener - { - public void keyPressed(KeyEvent e) - { - } - public void keyReleased(KeyEvent e) - { - } - public void keyTyped(KeyEvent e) - { - } - } - class MouseInputHandler implements MouseInputListener { Point begin, curr; private void updateSelection(boolean controlPressed) { - if (table.getRowSelectionAllowed()) + // Update the rows + int lo_row = table.rowAtPoint(begin); + int hi_row = table.rowAtPoint(curr); + ListSelectionModel rowModel = table.getSelectionModel(); + if (lo_row != -1 && hi_row != -1) { - int lo_row = table.rowAtPoint(begin); - int hi_row = table.rowAtPoint(curr); - ListSelectionModel rowModel = table.getSelectionModel(); - if (lo_row != -1 && hi_row != -1) - { - if (controlPressed && rowModel.getSelectionMode() - != ListSelectionModel.SINGLE_SELECTION) - rowModel.addSelectionInterval(lo_row, hi_row); - else - rowModel.setSelectionInterval(lo_row, hi_row); - } + if (controlPressed && rowModel.getSelectionMode() + != ListSelectionModel.SINGLE_SELECTION) + rowModel.addSelectionInterval(lo_row, hi_row); + else + rowModel.setSelectionInterval(lo_row, hi_row); } - - if (table.getColumnSelectionAllowed()) + + // Update the columns + int lo_col = table.columnAtPoint(begin); + int hi_col = table.columnAtPoint(curr); + ListSelectionModel colModel = table.getColumnModel(). + getSelectionModel(); + if (lo_col != -1 && hi_col != -1) { - int lo_col = table.columnAtPoint(begin); - int hi_col = table.columnAtPoint(curr); - ListSelectionModel colModel = table.getColumnModel(). - getSelectionModel(); - if (lo_col != -1 && hi_col != -1) - { - if (controlPressed && colModel.getSelectionMode() != - ListSelectionModel.SINGLE_SELECTION) - colModel.addSelectionInterval(lo_col, hi_col); - else - colModel.setSelectionInterval(lo_col, hi_col); - } + if (controlPressed && colModel.getSelectionMode() != + ListSelectionModel.SINGLE_SELECTION) + colModel.addSelectionInterval(lo_col, hi_col); + else + colModel.setSelectionInterval(lo_col, hi_col); } } @@ -165,6 +162,11 @@ public class BasicTableUI } public void mousePressed(MouseEvent e) { + ListSelectionModel rowModel = table.getSelectionModel(); + ListSelectionModel colModel = table.getColumnModel().getSelectionModel(); + int rowLead = rowModel.getLeadSelectionIndex(); + int colLead = colModel.getLeadSelectionIndex(); + begin = new Point(e.getX(), e.getY()); curr = new Point(e.getX(), e.getY()); //if control is pressed and the cell is already selected, deselect it @@ -180,7 +182,12 @@ public class BasicTableUI } else updateSelection(e.isControlDown()); - + + // If we were editing, but the moved to another cell, stop editing + if (rowLead != rowModel.getLeadSelectionIndex() || + colLead != colModel.getLeadSelectionIndex()) + if (table.isEditing()) + table.editingStopped(new ChangeEvent(e)); } public void mouseReleased(MouseEvent e) { @@ -193,23 +200,50 @@ public class BasicTableUI { return new FocusHandler(); } - protected KeyListener createKeyListener() - { - return new KeyHandler(); - } + protected MouseInputListener createMouseInputListener() { return new MouseInputHandler(); } + /** + * Return the maximum size of the table. The maximum height is the row + * height times the number of rows. The maximum width is the sum of + * the maximum widths of each column. + * + * @param comp the component whose maximum size is being queried, + * this is ignored. + * @return a Dimension object representing the maximum size of the table, + * or null if the table has no elements. + */ public Dimension getMaximumSize(JComponent comp) { - return getPreferredSize(comp); + int maxTotalColumnWidth = 0; + for (int i = 0; i < table.getColumnCount(); i++) + maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth(); + if (maxTotalColumnWidth == 0 || table.getRowCount() == 0) + return null; + return new Dimension(maxTotalColumnWidth, table.getRowCount()*table.getRowHeight()); } + /** + * Return the minimum size of the table. The minimum height is the row + * height times the number of rows. The minimum width is the sum of + * the minimum widths of each column. + * + * @param comp the component whose minimum size is being queried, + * this is ignored. + * @return a Dimension object representing the minimum size of the table, + * or null if the table has no elements. + */ public Dimension getMinimumSize(JComponent comp) { - return getPreferredSize(comp); + int minTotalColumnWidth = 0; + for (int i = 0; i < table.getColumnCount(); i++) + minTotalColumnWidth += table.getColumnModel().getColumn(i).getMinWidth(); + if (minTotalColumnWidth == 0 || table.getRowCount() == 0) + return null; + return new Dimension(minTotalColumnWidth, table.getRowCount()*table.getRowHeight()); } public Dimension getPreferredSize(JComponent comp) @@ -233,8 +267,657 @@ public class BasicTableUI highlightCellBorder = defaults.getBorder("Table.focusCellHighlightBorder"); cellBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1); } + + private int convertModifiers(int mod) + { + if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0) + { + mod |= KeyEvent.SHIFT_MASK; + mod &= ~KeyEvent.SHIFT_DOWN_MASK; + } + if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0) + { + mod |= KeyEvent.CTRL_MASK; + mod &= ~KeyEvent.CTRL_DOWN_MASK; + } + if ((mod & KeyEvent.META_DOWN_MASK) != 0) + { + mod |= KeyEvent.META_MASK; + mod &= ~KeyEvent.META_DOWN_MASK; + } + if ((mod & KeyEvent.ALT_DOWN_MASK) != 0) + { + mod |= KeyEvent.ALT_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; + } + return mod; + } + protected void installKeyboardActions() { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + InputMap ancestorMap = (InputMap)defaults.get("Table.ancestorInputMap"); + InputMapUIResource parentInputMap = new InputMapUIResource(); + // FIXME: The JDK uses a LazyActionMap for parentActionMap + ActionMap parentActionMap = new ActionMap(); + action = new TableAction(); + Object keys[] = ancestorMap.allKeys(); + // Register key bindings in the UI InputMap-ActionMap pair + // Note that we register key bindings with both the old and new modifier + // masks: InputEvent.SHIFT_MASK and InputEvent.SHIFT_DOWN_MASK and so on. + for (int i = 0; i < keys.length; i++) + { + parentInputMap.put(KeyStroke.getKeyStroke + (((KeyStroke)keys[i]).getKeyCode(), convertModifiers + (((KeyStroke)keys[i]).getModifiers())), + (String)ancestorMap.get((KeyStroke)keys[i])); + + parentInputMap.put(KeyStroke.getKeyStroke + (((KeyStroke)keys[i]).getKeyCode(), + ((KeyStroke)keys[i]).getModifiers()), + (String)ancestorMap.get((KeyStroke)keys[i])); + + parentActionMap.put + ((String)ancestorMap.get((KeyStroke)keys[i]), new ActionListenerProxy + (action, (String)ancestorMap.get((KeyStroke)keys[i]))); + + } + // Set the UI InputMap-ActionMap pair to be the parents of the + // JTable's InputMap-ActionMap pair + parentInputMap.setParent + (table.getInputMap + (JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent()); + parentActionMap.setParent(table.getActionMap().getParent()); + table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT). + setParent(parentInputMap); + table.getActionMap().setParent(parentActionMap); + } + + /** + * This class is used to mimmic the behaviour of the JDK when registering + * keyboard actions. It is the same as the private class used in JComponent + * for the same reason. This class receives an action event and dispatches + * it to the true receiver after altering the actionCommand property of the + * event. + */ + private static class ActionListenerProxy + extends AbstractAction + { + ActionListener target; + String bindingCommandName; + + public ActionListenerProxy(ActionListener li, + String cmd) + { + target = li; + bindingCommandName = cmd; + } + + public void actionPerformed(ActionEvent e) + { + ActionEvent derivedEvent = new ActionEvent(e.getSource(), + e.getID(), + bindingCommandName, + e.getModifiers()); + target.actionPerformed(derivedEvent); + } + } + + /** + * This class implements the actions that we want to happen + * when specific keys are pressed for the JTable. The actionPerformed + * method is called when a key that has been registered for the JTable + * is received. + */ + class TableAction extends AbstractAction + { + /** + * What to do when this action is called. + * + * @param e the ActionEvent that caused this action. + */ + public void actionPerformed (ActionEvent e) + { + ListSelectionModel rowModel = table.getSelectionModel(); + ListSelectionModel colModel = table.getColumnModel().getSelectionModel(); + + int rowLead = rowModel.getLeadSelectionIndex(); + int rowMax = table.getModel().getRowCount() - 1; + + int colLead = colModel.getLeadSelectionIndex(); + int colMax = table.getModel().getColumnCount() - 1; + + if (e.getActionCommand().equals("selectPreviousRowExtendSelection")) + { + rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0)); + colModel.setLeadSelectionIndex(colLead); + } + else if (e.getActionCommand().equals("selectLastColumn")) + { + table.clearSelection(); + rowModel.setSelectionInterval(rowLead, rowLead); + colModel.setSelectionInterval(colMax, colMax); + } + else if (e.getActionCommand().equals("startEditing")) + { + if (table.isCellEditable(rowLead, colLead)) + table.editCellAt(rowLead,colLead); + } + else if (e.getActionCommand().equals("selectFirstRowExtendSelection")) + { + rowModel.setLeadSelectionIndex(0); + colModel.setLeadSelectionIndex(colLead); + } + else if (e.getActionCommand().equals("selectFirstColumn")) + { + rowModel.setSelectionInterval(rowLead, rowLead); + colModel.setSelectionInterval(0, 0); + } + else if (e.getActionCommand().equals("selectFirstColumnExtendSelection")) + { + colModel.setLeadSelectionIndex(0); + rowModel.setLeadSelectionIndex(rowLead); + } + else if (e.getActionCommand().equals("selectLastRow")) + { + rowModel.setSelectionInterval(rowMax,rowMax); + colModel.setSelectionInterval(colLead, colLead); + } + else if (e.getActionCommand().equals("selectNextRowExtendSelection")) + { + rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax)); + colModel.setLeadSelectionIndex(colLead); + } + else if (e.getActionCommand().equals("selectFirstRow")) + { + rowModel.setSelectionInterval(0,0); + colModel.setSelectionInterval(colLead, colLead); + } + else if (e.getActionCommand().equals("selectNextColumnExtendSelection")) + { + colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax)); + rowModel.setLeadSelectionIndex(rowLead); + } + else if (e.getActionCommand().equals("selectLastColumnExtendSelection")) + { + colModel.setLeadSelectionIndex(colMax); + rowModel.setLeadSelectionIndex(rowLead); + } + else if (e.getActionCommand().equals("selectPreviousColumnExtendSelection")) + { + colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0)); + rowModel.setLeadSelectionIndex(rowLead); + } + else if (e.getActionCommand().equals("selectNextRow")) + { + rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax), + Math.min(rowLead + 1, rowMax)); + colModel.setSelectionInterval(colLead,colLead); + } + else if (e.getActionCommand().equals("scrollUpExtendSelection")) + { + int target; + if (rowLead == getFirstVisibleRowIndex()) + target = Math.max + (0, rowLead - (getLastVisibleRowIndex() - + getFirstVisibleRowIndex() + 1)); + else + target = getFirstVisibleRowIndex(); + + rowModel.setLeadSelectionIndex(target); + colModel.setLeadSelectionIndex(colLead); + } + else if (e.getActionCommand().equals("selectPreviousRow")) + { + rowModel.setSelectionInterval(Math.max(rowLead - 1, 0), + Math.max(rowLead - 1, 0)); + colModel.setSelectionInterval(colLead,colLead); + } + else if (e.getActionCommand().equals("scrollRightChangeSelection")) + { + int target; + if (colLead == getLastVisibleColumnIndex()) + target = Math.min + (colMax, colLead + (getLastVisibleColumnIndex() - + getFirstVisibleColumnIndex() + 1)); + else + target = getLastVisibleColumnIndex(); + + colModel.setSelectionInterval(target, target); + rowModel.setSelectionInterval(rowLead, rowLead); + } + else if (e.getActionCommand().equals("selectPreviousColumn")) + { + rowModel.setSelectionInterval(rowLead,rowLead); + colModel.setSelectionInterval(Math.max(colLead - 1, 0), + Math.max(colLead - 1, 0)); + } + else if (e.getActionCommand().equals("scrollLeftChangeSelection")) + { + int target; + if (colLead == getFirstVisibleColumnIndex()) + target = Math.max + (0, colLead - (getLastVisibleColumnIndex() - + getFirstVisibleColumnIndex() + 1)); + else + target = getFirstVisibleColumnIndex(); + + colModel.setSelectionInterval(target, target); + rowModel.setSelectionInterval(rowLead, rowLead); + } + else if (e.getActionCommand().equals("clearSelection")) + { + table.clearSelection(); + } + else if (e.getActionCommand().equals("cancel")) + { + // FIXME: implement other parts of "cancel" like undo-ing last + // selection. Right now it just calls editingCancelled if + // we're currently editing. + if (table.isEditing()) + table.editingCanceled(new ChangeEvent("cancel")); + } + else if (e.getActionCommand().equals("selectNextRowCell") + || e.getActionCommand().equals("selectPreviousRowCell") + || e.getActionCommand().equals("selectNextColumnCell") + || e.getActionCommand().equals("selectPreviousColumnCell")) + { + // If nothing is selected, select the first cell in the table + if (table.getSelectedRowCount() == 0 && + table.getSelectedColumnCount() == 0) + { + rowModel.setSelectionInterval(0, 0); + colModel.setSelectionInterval(0, 0); + return; + } + + // If the lead selection index isn't selected (ie a remove operation + // happened, then set the lead to the first selected cell in the + // table + if (!table.isCellSelected(rowLead, colLead)) + { + rowModel.addSelectionInterval(rowModel.getMinSelectionIndex(), + rowModel.getMinSelectionIndex()); + colModel.addSelectionInterval(colModel.getMinSelectionIndex(), + colModel.getMinSelectionIndex()); + return; + } + + // multRowsSelected and multColsSelected tell us if multiple rows or + // columns are selected, respectively + boolean multRowsSelected, multColsSelected; + multRowsSelected = table.getSelectedRowCount() > 1 && + table.getRowSelectionAllowed(); + + multColsSelected = table.getSelectedColumnCount() > 1 && + table.getColumnSelectionAllowed(); + + // If there is just one selection, select the next cell, and wrap + // when you get to the edges of the table. + if (!multColsSelected && !multRowsSelected) + { + if (e.getActionCommand().indexOf("Column") != -1) + advanceSingleSelection(colModel, colMax, rowModel, rowMax, + (e.getActionCommand().equals + ("selectPreviousColumnCell"))); + else + advanceSingleSelection(rowModel, rowMax, colModel, colMax, + (e.getActionCommand().equals + ("selectPreviousRowCell"))); + return; + } + + + // rowMinSelected and rowMaxSelected are the minimum and maximum + // values respectively of selected cells in the row selection model + // Similarly for colMinSelected and colMaxSelected. + int rowMaxSelected = table.getRowSelectionAllowed() ? + rowModel.getMaxSelectionIndex() : table.getModel().getRowCount() - 1; + int rowMinSelected = table.getRowSelectionAllowed() ? + rowModel.getMinSelectionIndex() : 0; + int colMaxSelected = table.getColumnSelectionAllowed() ? + colModel.getMaxSelectionIndex() : + table.getModel().getColumnCount() - 1; + int colMinSelected = table.getColumnSelectionAllowed() ? + colModel.getMinSelectionIndex() : 0; + + // If there are multiple rows and columns selected, select the next + // cell and wrap at the edges of the selection. + if (e.getActionCommand().indexOf("Column") != -1) + advanceMultipleSelection(colModel, colMinSelected, colMaxSelected, + rowModel, rowMinSelected, rowMaxSelected, + (e.getActionCommand().equals + ("selectPreviousColumnCell")), true); + + else + advanceMultipleSelection(rowModel, rowMinSelected, rowMaxSelected, + colModel, colMinSelected, colMaxSelected, + (e.getActionCommand().equals + ("selectPreviousRowCell")), false); + } + else if (e.getActionCommand().equals("selectNextColumn")) + { + rowModel.setSelectionInterval(rowLead,rowLead); + colModel.setSelectionInterval(Math.min(colLead + 1, colMax), + Math.min(colLead + 1, colMax)); + } + else if (e.getActionCommand().equals("scrollLeftExtendSelection")) + { + int target; + if (colLead == getFirstVisibleColumnIndex()) + target = Math.max + (0, colLead - (getLastVisibleColumnIndex() - + getFirstVisibleColumnIndex() + 1)); + else + target = getFirstVisibleColumnIndex(); + + colModel.setLeadSelectionIndex(target); + rowModel.setLeadSelectionIndex(rowLead); + } + else if (e.getActionCommand().equals("scrollDownChangeSelection")) + { + int target; + if (rowLead == getLastVisibleRowIndex()) + target = Math.min + (rowMax, rowLead + (getLastVisibleRowIndex() - + getFirstVisibleRowIndex() + 1)); + else + target = getLastVisibleRowIndex(); + + rowModel.setSelectionInterval(target, target); + colModel.setSelectionInterval(colLead, colLead); + } + else if (e.getActionCommand().equals("scrollRightExtendSelection")) + { + int target; + if (colLead == getLastVisibleColumnIndex()) + target = Math.min + (colMax, colLead + (getLastVisibleColumnIndex() - + getFirstVisibleColumnIndex() + 1)); + else + target = getLastVisibleColumnIndex(); + + colModel.setLeadSelectionIndex(target); + rowModel.setLeadSelectionIndex(rowLead); + } + else if (e.getActionCommand().equals("selectAll")) + { + table.selectAll(); + } + else if (e.getActionCommand().equals("selectLastRowExtendSelection")) + { + rowModel.setLeadSelectionIndex(rowMax); + colModel.setLeadSelectionIndex(colLead); + } + else if (e.getActionCommand().equals("scrollDownExtendSelection")) + { + int target; + if (rowLead == getLastVisibleRowIndex()) + target = Math.min + (rowMax, rowLead + (getLastVisibleRowIndex() - + getFirstVisibleRowIndex() + 1)); + else + target = getLastVisibleRowIndex(); + + rowModel.setLeadSelectionIndex(target); + colModel.setLeadSelectionIndex(colLead); + } + else if (e.getActionCommand().equals("scrollUpChangeSelection")) + { + int target; + if (rowLead == getFirstVisibleRowIndex()) + target = Math.max + (0, rowLead - (getLastVisibleRowIndex() - + getFirstVisibleRowIndex() + 1)); + else + target = getFirstVisibleRowIndex(); + + rowModel.setSelectionInterval(target, target); + colModel.setSelectionInterval(colLead, colLead); + } + else + { + // If we're here that means we bound this TableAction class + // to a keyboard input but we either want to ignore that input + // or we just haven't implemented its action yet. + } + + if (table.isEditing() && e.getActionCommand() != "startEditing") + table.editingCanceled(new ChangeEvent("update")); + table.repaint(); + + table.scrollRectToVisible + (table.getCellRect(rowModel.getLeadSelectionIndex(), + colModel.getLeadSelectionIndex(), false)); + } + + int getFirstVisibleColumnIndex() + { + ComponentOrientation or = table.getComponentOrientation(); + Rectangle r = table.getVisibleRect(); + if (!or.isLeftToRight()) + r.translate((int) r.getWidth() - 1, 0); + return table.columnAtPoint(r.getLocation()); + } + + /** + * Returns the column index of the last visible column. + * + */ + int getLastVisibleColumnIndex() + { + ComponentOrientation or = table.getComponentOrientation(); + Rectangle r = table.getVisibleRect(); + if (or.isLeftToRight()) + r.translate((int) r.getWidth() - 1, 0); + return table.columnAtPoint(r.getLocation()); + } + + /** + * Returns the row index of the first visible row. + * + */ + int getFirstVisibleRowIndex() + { + ComponentOrientation or = table.getComponentOrientation(); + Rectangle r = table.getVisibleRect(); + if (!or.isLeftToRight()) + r.translate((int) r.getWidth() - 1, 0); + return table.rowAtPoint(r.getLocation()); + } + + /** + * Returns the row index of the last visible row. + * + */ + int getLastVisibleRowIndex() + { + ComponentOrientation or = table.getComponentOrientation(); + Rectangle r = table.getVisibleRect(); + r.translate(0, (int) r.getHeight() - 1); + if (or.isLeftToRight()) + r.translate((int) r.getWidth() - 1, 0); + // The next if makes sure that we don't return -1 simply because + // there is white space at the bottom of the table (ie, the display + // area is larger than the table) + if (table.rowAtPoint(r.getLocation()) == -1) + { + if (getFirstVisibleRowIndex() == -1) + return -1; + else + return table.getModel().getRowCount() - 1; + } + return table.rowAtPoint(r.getLocation()); + } + + /** + * A helper method for the key bindings. Used because the actions + * for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar. + * + * Selects the next (previous if SHIFT pressed) column for TAB, or row for + * ENTER from within the currently selected cells. + * + * @param firstModel the ListSelectionModel for columns (TAB) or + * rows (ENTER) + * @param firstMin the first selected index in firstModel + * @param firstMax the last selected index in firstModel + * @param secondModel the ListSelectionModel for rows (TAB) or + * columns (ENTER) + * @param secondMin the first selected index in secondModel + * @param secondMax the last selected index in secondModel + * @param reverse true if shift was held for the event + * @param eventIsTab true if TAB was pressed, false if ENTER pressed + */ + void advanceMultipleSelection (ListSelectionModel firstModel, int firstMin, + int firstMax, ListSelectionModel secondModel, + int secondMin, int secondMax, boolean reverse, + boolean eventIsTab) + { + // If eventIsTab, all the "firsts" correspond to columns, otherwise, to rows + // "seconds" correspond to the opposite + int firstLead = firstModel.getLeadSelectionIndex(); + int secondLead = secondModel.getLeadSelectionIndex(); + int numFirsts = eventIsTab ? + table.getModel().getColumnCount() : table.getModel().getRowCount(); + int numSeconds = eventIsTab ? + table.getModel().getRowCount() : table.getModel().getColumnCount(); + + // check if we have to wrap the "firsts" around, going to the other side + if ((firstLead == firstMax && !reverse) || + (reverse && firstLead == firstMin)) + { + firstModel.addSelectionInterval(reverse ? firstMax : firstMin, + reverse ? firstMax : firstMin); + + // check if we have to wrap the "seconds" + if ((secondLead == secondMax && !reverse) || + (reverse && secondLead == secondMin)) + secondModel.addSelectionInterval(reverse ? secondMax : secondMin, + reverse ? secondMax : secondMin); + + // if we're not wrapping the seconds, we have to find out where we + // are within the secondModel and advance to the next cell (or + // go back to the previous cell if reverse == true) + else + { + int[] secondsSelected; + if (eventIsTab && table.getRowSelectionAllowed() || + !eventIsTab && table.getColumnSelectionAllowed()) + secondsSelected = eventIsTab ? + table.getSelectedRows() : table.getSelectedColumns(); + else + { + // if row selection is not allowed, then the entire column gets + // selected when you click on it, so consider ALL rows selected + secondsSelected = new int[numSeconds]; + for (int i = 0; i < numSeconds; i++) + secondsSelected[i] = i; + } + + // and now find the "next" index within the model + int secondIndex = reverse ? secondsSelected.length - 1 : 0; + if (!reverse) + while (secondsSelected[secondIndex] <= secondLead) + secondIndex++; + else + while (secondsSelected[secondIndex] >= secondLead) + secondIndex--; + + // and select it - updating the lead selection index + secondModel.addSelectionInterval(secondsSelected[secondIndex], + secondsSelected[secondIndex]); + } + } + // We didn't have to wrap the firsts, so just find the "next" first + // and select it, we don't have to change "seconds" + else + { + int[] firstsSelected; + if (eventIsTab && table.getColumnSelectionAllowed() || + !eventIsTab && table.getRowSelectionAllowed()) + firstsSelected = eventIsTab ? + table.getSelectedColumns() : table.getSelectedRows(); + else + { + // if selection not allowed, consider ALL firsts to be selected + firstsSelected = new int[numFirsts]; + for (int i = 0; i < numFirsts; i++) + firstsSelected[i] = i; + } + int firstIndex = reverse ? firstsSelected.length - 1 : 0; + if (!reverse) + while (firstsSelected[firstIndex] <= firstLead) + firstIndex++; + else + while (firstsSelected[firstIndex] >= firstLead) + firstIndex--; + firstModel.addSelectionInterval(firstsSelected[firstIndex], + firstsSelected[firstIndex]); + secondModel.addSelectionInterval(secondLead, secondLead); + } + } + + /** + * A helper method for the key bindings. Used because the actions + * for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar. + * + * Selects the next (previous if SHIFT pressed) column (TAB) or row (ENTER) + * in the table, changing the current selection. All cells in the table + * are eligible, not just the ones that are currently selected. + * @param firstModel the ListSelectionModel for columns (TAB) or rows + * (ENTER) + * @param firstMax the last index in firstModel + * @param secondModel the ListSelectionModel for rows (TAB) or columns + * (ENTER) + * @param secondMax the last index in secondModel + * @param reverse true if SHIFT was pressed for the event + */ + + void advanceSingleSelection (ListSelectionModel firstModel, int firstMax, + ListSelectionModel secondModel, int secondMax, + boolean reverse) + { + // for TABs, "first" corresponds to columns and "seconds" to rows. + // the opposite is true for ENTERs + int firstLead = firstModel.getLeadSelectionIndex(); + int secondLead = secondModel.getLeadSelectionIndex(); + + // if we are going backwards subtract 2 because we later add 1 + // for a net change of -1 + if (reverse && (firstLead == 0)) + { + // check if we have to wrap around + if (secondLead == 0) + secondLead += secondMax + 1; + secondLead -= 2; + } + + // do we have to wrap the "seconds"? + if (reverse && (firstLead == 0) || !reverse && (firstLead == firstMax)) + secondModel.setSelectionInterval((secondLead + 1)%(secondMax + 1), + (secondLead + 1)%(secondMax + 1)); + // if not, just reselect the current lead + else + secondModel.setSelectionInterval(secondLead, secondLead); + + // if we are going backwards, subtract 2 because we add 1 later + // for net change of -1 + if (reverse) + { + // check for wraparound + if (firstLead == 0) + firstLead += firstMax + 1; + firstLead -= 2; + } + // select the next "first" + firstModel.setSelectionInterval ((firstLead + 1)%(firstMax + 1), + (firstLead + 1)%(firstMax + 1)); + } } protected void installListeners() @@ -281,7 +964,6 @@ public class BasicTableUI { table = (JTable)comp; focusListener = createFocusListener(); - keyListener = createKeyListener(); mouseInputListener = createMouseInputListener(); installDefaults(); installKeyboardActions(); @@ -332,14 +1014,19 @@ public class BasicTableUI gfx.translate(x, y); comp.setBounds(new Rectangle(0, 0, width, height)); // Set correct border on cell renderer. + // Only the lead selection cell gets a border if (comp instanceof JComponent) { - if (table.isCellSelected(r, c)) + if (table.getSelectionModel().getLeadSelectionIndex() == r + && table.getColumnModel().getSelectionModel(). + getLeadSelectionIndex() == c) ((JComponent) comp).setBorder(highlightCellBorder); else ((JComponent) comp).setBorder(cellBorder); } comp.paint(gfx); + if (comp instanceof JTextField) + ((JTextField)comp).getCaret().paint(gfx); gfx.translate(-x, -y); } y += height; @@ -392,7 +1079,5 @@ public class BasicTableUI } gfx.setColor(save); } - } - } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java index dd0828e466a..91ccb0056bb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java @@ -78,10 +78,20 @@ import javax.swing.text.Position; import javax.swing.text.View; import javax.swing.text.ViewFactory; - +/** + * The abstract base class from which the UI classes for Swings text + * components are derived. This provides most of the functionality for + * the UI classes. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public abstract class BasicTextUI extends TextUI implements ViewFactory { + /** + * A {@link DefaultCaret} that implements {@link UIResource}. + */ public static class BasicCaret extends DefaultCaret implements UIResource { @@ -90,6 +100,9 @@ public abstract class BasicTextUI extends TextUI } } + /** + * A {@link DefaultHighlighter} that implements {@link UIResource}. + */ public static class BasicHighlighter extends DefaultHighlighter implements UIResource { @@ -97,40 +110,120 @@ public abstract class BasicTextUI extends TextUI { } } - + + /** + * This view forms the root of the View hierarchy. However, it delegates + * most calls to another View which is the real root of the hierarchy. + * The purpose is to make sure that all Views in the hierarchy, including + * the (real) root have a well-defined parent to which they can delegate + * calls like {@link #preferenceChanged}, {@link #getViewFactory} and + * {@link #getContainer}. + */ private class RootView extends View { + /** The real root view. */ private View view; - + + /** + * Creates a new RootView. + */ public RootView() { super(null); } - // View methods. - + /** + * Returns the ViewFactory for this RootView. If the current EditorKit + * provides a ViewFactory, this is used. Otherwise the TextUI itself + * is returned as a ViewFactory. + * + * @return the ViewFactory for this RootView + */ public ViewFactory getViewFactory() { - // FIXME: Handle EditorKit somehow. - return BasicTextUI.this; + ViewFactory factory = null; + EditorKit editorKit = BasicTextUI.this.getEditorKit(getComponent()); + factory = editorKit.getViewFactory(); + if (factory == null) + factory = BasicTextUI.this; + return factory; + } + + /** + * Indicates that the preferences of one of the child view has changed. + * This calls revalidate on the text component. + * + * @param view the child view which's preference has changed + * @param width <code>true</code> if the width preference has changed + * @param height <code>true</code> if the height preference has changed + */ + public void preferenceChanged(View view, boolean width, boolean height) + { + textComponent.revalidate(); } + /** + * Sets the real root view. + * + * @param v the root view to set + */ public void setView(View v) { if (view != null) - view.setParent(null); + view.setParent(null); if (v != null) - v.setParent(null); + v.setParent(null); view = v; } + /** + * Returns the real root view, regardless of the index. + * + * @param index not used here + * + * @return the real root view, regardless of the index. + */ + public View getView(int index) + { + return view; + } + + /** + * Returns <code>1</code> since the RootView always contains one + * child, that is the real root of the View hierarchy. + * + * @return <code>1</code> since the RootView always contains one + * child, that is the real root of the View hierarchy + */ + public int getViewCount() + { + if (view != null) + return 1; + else + return 0; + } + + /** + * Returns the <code>Container</code> that contains this view. This + * normally will be the text component that is managed by this TextUI. + * + * @return the <code>Container</code> that contains this view + */ public Container getContainer() { return textComponent; } - + + /** + * Returns the preferred span along the specified <code>axis</code>. + * This is delegated to the real root view. + * + * @param axis the axis for which the preferred span is queried + * + * @return the preferred span along the axis + */ public float getPreferredSpan(int axis) { if (view != null) @@ -139,19 +232,61 @@ public abstract class BasicTextUI extends TextUI return Integer.MAX_VALUE; } + /** + * Paints the view. This is delegated to the real root view. + * + * @param g the <code>Graphics</code> context to paint to + * @param s the allocation for the View + */ public void paint(Graphics g, Shape s) { if (view != null) view.paint(g, s); } + + /** + * Maps a position in the document into the coordinate space of the View. + * The output rectangle usually reflects the font height but has a width + * of zero. + * + * This is delegated to the real root view. + * + * @param pos the position of the character in the model + * @param a the area that is occupied by the view + * @param bias either {@link Position.Bias.Forward} or + * {@link Position.Bias.Backward} depending on the preferred + * direction bias. If <code>null</code> this defaults to + * <code>Position.Bias.Forward</code> + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if <code>pos</code> is invalid + * @throws IllegalArgumentException if b is not one of the above listed + * valid values + */ public Shape modelToView(int position, Shape a, Position.Bias bias) throws BadLocationException { - if (view == null) - return null; - - return ((PlainView) view).modelToView(position, a, bias).getBounds(); + return ((View) view).modelToView(position, a, bias); + } + + /** + * Maps coordinates from the <code>View</code>'s space into a position + * in the document model. + * + * @param x the x coordinate in the view space + * @param y the y coordinate in the view space + * @param a the allocation of this <code>View</code> + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates <code>x, y</code> + */ + public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + { + return view.viewToModel(x, y, a, b); } /** @@ -194,8 +329,16 @@ public abstract class BasicTextUI extends TextUI } } + /** + * Receives notifications when properties of the text component change. + */ class UpdateHandler implements PropertyChangeListener { + /** + * Notifies when a property of the text component changes. + * + * @param event the PropertyChangeEvent describing the change + */ public void propertyChange(PropertyChangeEvent event) { if (event.getPropertyName().equals("document")) @@ -223,7 +366,7 @@ public abstract class BasicTextUI extends TextUI { Dimension size = textComponent.getSize(); rootView.changedUpdate(ev, new Rectangle(0, 0, size.width, size.height), - BasicTextUI.this); + rootView.getViewFactory()); } /** @@ -235,7 +378,7 @@ public abstract class BasicTextUI extends TextUI { Dimension size = textComponent.getSize(); rootView.insertUpdate(ev, new Rectangle(0, 0, size.width, size.height), - BasicTextUI.this); + rootView.getViewFactory()); int caretPos = textComponent.getCaretPosition(); if (caretPos >= ev.getOffset()) textComponent.setCaretPosition(caretPos + ev.getLength()); @@ -250,41 +393,80 @@ public abstract class BasicTextUI extends TextUI { Dimension size = textComponent.getSize(); rootView.removeUpdate(ev, new Rectangle(0, 0, size.width, size.height), - BasicTextUI.this); + rootView.getViewFactory()); int caretPos = textComponent.getCaretPosition(); if (caretPos >= ev.getOffset()) textComponent.setCaretPosition(ev.getOffset()); } } + /** + * The EditorKit used by this TextUI. + */ + // FIXME: should probably be non-static. static EditorKit kit = new DefaultEditorKit(); + /** + * The root view. + */ RootView rootView = new RootView(); + + /** + * The text component that we handle. + */ JTextComponent textComponent; + + /** + * Receives notification when the model changes. + */ UpdateHandler updateHandler = new UpdateHandler(); /** The DocumentEvent handler. */ DocumentHandler documentHandler = new DocumentHandler(); + /** + * Creates a new <code>BasicTextUI</code> instance. + */ public BasicTextUI() { } + /** + * Creates a {@link Caret} that should be installed into the text component. + * + * @return a caret that should be installed into the text component + */ protected Caret createCaret() { return new BasicCaret(); } + /** + * Creates a {@link Highlighter} that should be installed into the text + * component. + * + * @return a <code>Highlighter</code> for the text component + */ protected Highlighter createHighlighter() { return new BasicHighlighter(); } - + + /** + * The text component that is managed by this UI. + * + * @return the text component that is managed by this UI + */ protected final JTextComponent getComponent() { return textComponent; } - + + /** + * Installs this UI on the text component. + * + * @param c the text component on which to install the UI + */ public void installUI(final JComponent c) { super.installUI(c); @@ -307,6 +489,9 @@ public abstract class BasicTextUI extends TextUI installKeyboardActions(); } + /** + * Installs UI defaults on the text components. + */ protected void installDefaults() { Caret caret = textComponent.getCaret(); @@ -331,6 +516,9 @@ public abstract class BasicTextUI extends TextUI caret.setBlinkRate(defaults.getInt(prefix + ".caretBlinkRate")); } + /** + * This FocusListener triggers repaints on focus shift. + */ private FocusListener focuslistener = new FocusListener() { public void focusGained(FocusEvent e) { @@ -342,6 +530,9 @@ public abstract class BasicTextUI extends TextUI } }; + /** + * Install all listeners on the text component. + */ protected void installListeners() { textComponent.addFocusListener(focuslistener); @@ -375,6 +566,11 @@ public abstract class BasicTextUI extends TextUI return className; } + /** + * Creates the {@link Keymap} that is installed on the text component. + * + * @return the {@link Keymap} that is installed on the text component + */ protected Keymap createKeymap() { String prefix = getPropertyPrefix(); @@ -393,6 +589,9 @@ public abstract class BasicTextUI extends TextUI return km; } + /** + * Installs the keyboard actions on the text components. + */ protected void installKeyboardActions() { // load any bindings for the older Keymap interface @@ -408,6 +607,13 @@ public abstract class BasicTextUI extends TextUI SwingUtilities.replaceUIActionMap(textComponent, getActionMap()); } + /** + * Gets the input map for the specified <code>condition</code>. + * + * @param condition the condition for the InputMap + * + * @return the InputMap for the specified condition + */ InputMap getInputMap(int condition) { String prefix = getPropertyPrefix(); @@ -425,6 +631,13 @@ public abstract class BasicTextUI extends TextUI } } + /** + * Returns the ActionMap to be installed on the text component. + * + * @return the ActionMap to be installed on the text component + */ + // FIXME: The UIDefaults have no entries for .actionMap, so this should + // be handled somehow different. ActionMap getActionMap() { String prefix = getPropertyPrefix(); @@ -438,6 +651,11 @@ public abstract class BasicTextUI extends TextUI return am; } + /** + * Creates an ActionMap to be installed on the text component. + * + * @return an ActionMap to be installed on the text component + */ ActionMap createActionMap() { Action[] actions = textComponent.getActions(); @@ -450,7 +668,12 @@ public abstract class BasicTextUI extends TextUI } return am; } - + + /** + * Uninstalls this TextUI from the text component. + * + * @param component the text component to uninstall the UI from + */ public void uninstallUI(final JComponent component) { super.uninstallUI(component); @@ -465,23 +688,49 @@ public abstract class BasicTextUI extends TextUI textComponent = null; } + /** + * Uninstalls all default properties that have previously been installed by + * this UI. + */ protected void uninstallDefaults() { // Do nothing here. } + /** + * Uninstalls all listeners that have previously been installed by + * this UI. + */ protected void uninstallListeners() { textComponent.removeFocusListener(focuslistener); } + /** + * Uninstalls all keyboard actions that have previously been installed by + * this UI. + */ protected void uninstallKeyboardActions() { - // Do nothing here. + // FIXME: Uninstall keyboard actions here. } - + + /** + * Returns the property prefix by which the text component's UIDefaults + * are looked up. + * + * @return the property prefix by which the text component's UIDefaults + * are looked up + */ protected abstract String getPropertyPrefix(); + /** + * Returns the preferred size of the text component. + * + * @param c not used here + * + * @return the preferred size of the text component + */ public Dimension getPreferredSize(JComponent c) { View v = getRootView(textComponent); @@ -497,6 +746,8 @@ public abstract class BasicTextUI extends TextUI * * This returns (Integer.MAX_VALUE, Integer.MAX_VALUE). * + * @param c not used here + * * @return the maximum size for text components that use this UI */ public Dimension getMaximumSize(JComponent c) @@ -505,11 +756,22 @@ public abstract class BasicTextUI extends TextUI return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); } + /** + * Paints the text component. + * + * @param g the <code>Graphics</code> context to paint to + * @param c not used here + */ public final void paint(Graphics g, JComponent c) { paintSafely(g); } + /** + * Actually performs the painting. + * + * @param g the <code>Graphics</code> context to paint to + */ protected void paintSafely(Graphics g) { Caret caret = textComponent.getCaret(); @@ -528,74 +790,213 @@ public abstract class BasicTextUI extends TextUI caret.paint(g); } + /** + * Paints the background of the text component. + * + * @param g the <code>Graphics</code> context to paint to + */ protected void paintBackground(Graphics g) { g.setColor(textComponent.getBackground()); g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight()); } + /** + * Marks the specified range inside the text component's model as + * damaged and queues a repaint request. + * + * @param t the text component + * @param p0 the start location inside the document model of the range that + * is damaged + * @param p1 the end location inside the document model of the range that + * is damaged + */ public void damageRange(JTextComponent t, int p0, int p1) { damageRange(t, p0, p1, null, null); } + /** + * Marks the specified range inside the text component's model as + * damaged and queues a repaint request. This variant of this method + * allows a {@link Position.Bias} object to be specified for the start + * and end location of the range. + * + * @param t the text component + * @param p0 the start location inside the document model of the range that + * is damaged + * @param p1 the end location inside the document model of the range that + * is damaged + * @param firstBias the bias for the start location + * @param secondBias the bias for the end location + */ public void damageRange(JTextComponent t, int p0, int p1, Position.Bias firstBias, Position.Bias secondBias) { + // TODO: Implement me. } + /** + * Returns the {@link EditorKit} used for the text component that is managed + * by this UI. + * + * @param t the text component + * + * @return the {@link EditorKit} used for the text component that is managed + * by this UI + */ public EditorKit getEditorKit(JTextComponent t) { return kit; } + /** + * Gets the next position inside the document model that is visible on + * screen, starting from <code>pos</code>. + * + * @param t the text component + * @param pos the start positionn + * @param b the bias for pos + * @param direction the search direction + * @param biasRet filled by the method to indicate the bias of the return + * value + * + * @return the next position inside the document model that is visible on + * screen + */ public int getNextVisualPositionFrom(JTextComponent t, int pos, Position.Bias b, int direction, Position.Bias[] biasRet) throws BadLocationException { - return 0; + return 0; // TODO: Implement me. } + /** + * Returns the root {@link View} of a text component. + * + * @return the root {@link View} of a text component + */ public View getRootView(JTextComponent t) { return rootView; } + /** + * Maps a position in the document into the coordinate space of the View. + * The output rectangle usually reflects the font height but has a width + * of zero. A bias of {@link Position.Bias.Forward} is used in this method. + * + * @param pos the position of the character in the model + * @param a the area that is occupied by the view + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if <code>pos</code> is invalid + * @throws IllegalArgumentException if b is not one of the above listed + * valid values + */ public Rectangle modelToView(JTextComponent t, int pos) throws BadLocationException { return modelToView(t, pos, Position.Bias.Forward); } + /** + * Maps a position in the document into the coordinate space of the View. + * The output rectangle usually reflects the font height but has a width + * of zero. + * + * @param pos the position of the character in the model + * @param a the area that is occupied by the view + * @param bias either {@link Position.Bias.Forward} or + * {@link Position.Bias.Backward} depending on the preferred + * direction bias. If <code>null</code> this defaults to + * <code>Position.Bias.Forward</code> + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if <code>pos</code> is invalid + * @throws IllegalArgumentException if b is not one of the above listed + * valid values + */ public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias) throws BadLocationException { return rootView.modelToView(pos, getVisibleEditorRect(), bias).getBounds(); } + /** + * Maps a point in the <code>View</code> coordinate space to a position + * inside a document model. + * + * @param t the text component + * @param pt the point to be mapped + * + * @return the position inside the document model that corresponds to + * <code>pt</code> + */ public int viewToModel(JTextComponent t, Point pt) { return viewToModel(t, pt, null); } + /** + * Maps a point in the <code>View</code> coordinate space to a position + * inside a document model. + * + * @param t the text component + * @param pt the point to be mapped + * @param biasReturn filled in by the method to indicate the bias of the + * return value + * + * @return the position inside the document model that corresponds to + * <code>pt</code> + */ public int viewToModel(JTextComponent t, Point pt, Position.Bias[] biasReturn) { - return 0; + return 0; // FIXME: Implement me. } + /** + * Creates a {@link View} for the specified {@link Element}. + * + * @param elem the <code>Element</code> to create a <code>View</code> for + * + * @see ViewFactory + */ public View create(Element elem) { // Subclasses have to implement this to get this functionality. return null; } + /** + * Creates a {@link View} for the specified {@link Element}. + * + * @param elem the <code>Element</code> to create a <code>View</code> for + * @param p0 the start offset + * @param p1 the end offset + * + * @see ViewFactory + */ public View create(Element elem, int p0, int p1) { // Subclasses have to implement this to get this functionality. return null; } - + + /** + * Returns the allocation to give the root view. + * + * @return the allocation to give the root view + * + * @specnote The allocation has nothing to do with visibility. According + * to the specs the naming of this method is unfortunate and + * has historical reasons + */ protected Rectangle getVisibleEditorRect() { int width = textComponent.getWidth(); @@ -610,12 +1011,21 @@ public abstract class BasicTextUI extends TextUI height - insets.top + insets.bottom); } + /** + * Sets the root view for the text component. + * + * @param view the <code>View</code> to be set as root view + */ protected final void setView(View view) { rootView.setView(view); view.setParent(rootView); } + /** + * Indicates that the model of a text component has changed. This + * triggers a rebuild of the view hierarchy. + */ protected void modelChanged() { if (textComponent == null || rootView == null) @@ -630,6 +1040,7 @@ public abstract class BasicTextUI extends TextUI Element elem = doc.getDefaultRootElement(); if (elem == null) return; - setView(factory.create(elem)); + View view = factory.create(elem); + setView(view); } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java index 84509ad6efd..9106b0b6673 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -56,7 +56,7 @@ public class BasicToggleButtonUI extends BasicButtonUI */ protected String getPropertyPrefix() { - return "ToggleButton"; + return "ToggleButton."; } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java index bc655a2742d..8be89efcfa6 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java @@ -542,19 +542,6 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants } /** - * This method returns the preferred size of the given JComponent for this - * UI. - * - * @param c The JComponent to find a preferred size for. - * - * @return The preferred size for this UI. - */ - public Dimension getPreferredSize(JComponent c) - { - return toolBar.getLayout().preferredLayoutSize(c); - } - - /** * This method installs the needed components for the JToolBar. */ protected void installComponents() diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java index b9d3b629b66..6f714a39cb2 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java @@ -1,39 +1,39 @@ /* BasicTreeUI.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ package javax.swing.plaf.basic; @@ -60,18 +60,22 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; - import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Hashtable; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.ActionMap; import javax.swing.CellRendererPane; import javax.swing.Icon; +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.SwingUtilities; import javax.swing.Timer; import javax.swing.UIDefaults; @@ -86,21 +90,20 @@ import javax.swing.event.TreeModelListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; 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.FixedHeightLayoutCache; -import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellEditor; import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.ExpandVetoException; +import javax.swing.tree.FixedHeightLayoutCache; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreeCellRenderer; -import javax.swing.tree.TreeSelectionModel; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; - -import java.util.Enumeration; -import java.util.Hashtable; +import javax.swing.tree.TreeSelectionModel; /** * A delegate providing the user interface for <code>JTree</code> according to @@ -111,2703 +114,3482 @@ import java.util.Hashtable; * @author Lillian Angel (langel@redhat.com) */ public class BasicTreeUI - extends TreeUI + extends TreeUI { + /** Collapse Icon for the tree. */ + protected transient Icon collapsedIcon; - /** Collapse Icon for the tree. */ - protected transient Icon collapsedIcon; - - /** Expanded Icon for the tree. */ - protected transient Icon expandedIcon; - - /** Distance between left margin and where vertical dashes will be drawn. */ - protected int leftChildIndent; - - /** - * Distance between leftChildIndent and where cell contents will be drawn. - */ - protected int rightChildIndent; - - /** - * Total fistance that will be indented. The sum of leftChildIndent and - * rightChildIndent . - */ - protected int totalChildIndent; - - /** Minimum preferred size. */ - protected Dimension preferredMinsize; - - /** Index of the row that was last selected. */ - protected int lastSelectedRow; - - /** Component that we're going to be drawing onto. */ - protected JTree tree; - - /** Renderer that is being used to do the actual cell drawing. */ - protected transient TreeCellRenderer currentCellRenderer; - - /** - * Set to true if the renderer that is currently in the tree was created by - * this instance. - */ - protected boolean createdRenderer; - - /** Editor for the tree. */ - protected transient TreeCellEditor cellEditor; - - /** - * Set to true if editor that is currently in the tree was created by this - * instance. - */ - protected boolean createdCellEditor; + /** Expanded Icon for the tree. */ + protected transient Icon expandedIcon; - /** - * Set to false when editing and shouldSelectCall() returns true meaning the - * node should be selected before editing, used in completeEditing. - */ - protected boolean stopEditingInCompleteEditing; + /** Distance between left margin and where vertical dashes will be drawn. */ + protected int leftChildIndent; - /** Used to paint the TreeCellRenderer. */ - protected CellRendererPane rendererPane; + /** + * Distance between leftChildIndent and where cell contents will be drawn. + */ + protected int rightChildIndent; - /** Size needed to completely display all the nodes. */ - protected Dimension preferredSize; + /** + * Total fistance that will be indented. The sum of leftChildIndent and + * rightChildIndent . + */ + protected int totalChildIndent; - /** Is the preferredSize valid? */ - protected boolean validCachedPreferredSize; + /** Minimum preferred size. */ + protected Dimension preferredMinsize; - /** Object responsible for handling sizing and expanded issues. */ - protected AbstractLayoutCache treeState; + /** Index of the row that was last selected. */ + protected int lastSelectedRow; - /** Used for minimizing the drawing of vertical lines. */ - protected Hashtable drawingCache; + /** Component that we're going to be drawing onto. */ + protected JTree tree; - /** - * True if doing optimizations for a largeModel. Subclasses that don't - * support this may wish to override createLayoutCache to not return a - * FixedHeightLayoutCache instance. - */ - protected boolean largeModel; + /** Renderer that is being used to do the actual cell drawing. */ + protected transient TreeCellRenderer currentCellRenderer; - /** Responsible for telling the TreeState the size needed for a node. */ - protected AbstractLayoutCache.NodeDimensions nodeDimensions; + /** + * Set to true if the renderer that is currently in the tree was created by + * this instance. + */ + protected boolean createdRenderer; - /** Used to determine what to display. */ - protected TreeModel treeModel; + /** Editor for the tree. */ + protected transient TreeCellEditor cellEditor; - /** Model maintaining the selection. */ - protected TreeSelectionModel treeSelectionModel; + /** + * Set to true if editor that is currently in the tree was created by this + * instance. + */ + protected boolean createdCellEditor; - /** - * How much the depth should be offset to properly calculate x locations. - * This is based on whether or not the root is visible, and if the root - * handles are visible. - */ - protected int depthOffset; + /** + * Set to false when editing and shouldSelectCall() returns true meaning the + * node should be selected before editing, used in completeEditing. + */ + protected boolean stopEditingInCompleteEditing; - /** - * When editing, this will be the Component that is doing the actual editing. - */ - protected Component editingComponent; + /** Used to paint the TreeCellRenderer. */ + protected CellRendererPane rendererPane; - /** Path that is being edited. */ - protected TreePath editingPath; + /** Size needed to completely display all the nodes. */ + protected Dimension preferredSize; - /** - * Row that is being edited. Should only be referenced if editingComponent is - * null. - */ - protected int editingRow; + /** Is the preferredSize valid? */ + protected boolean validCachedPreferredSize; - /** Set to true if the editor has a different size than the renderer. */ - protected boolean editorHasDifferentSize; + /** Object responsible for handling sizing and expanded issues. */ + protected AbstractLayoutCache treeState; - /** Listeners */ - private PropertyChangeListener propertyChangeListener; + /** Used for minimizing the drawing of vertical lines. */ + protected Hashtable drawingCache; - private FocusListener focusListener; + /** + * True if doing optimizations for a largeModel. Subclasses that don't support + * this may wish to override createLayoutCache to not return a + * FixedHeightLayoutCache instance. + */ + protected boolean largeModel; - private TreeSelectionListener treeSelectionListener; + /** Responsible for telling the TreeState the size needed for a node. */ + protected AbstractLayoutCache.NodeDimensions nodeDimensions; - private MouseInputListener mouseInputListener; - - private KeyListener keyListener; - - private PropertyChangeListener selectionModelPropertyChangeListener; - - private ComponentListener componentListener; - - private CellEditorListener cellEditorListener; - - private TreeExpansionListener treeExpansionListener; - - private TreeModelListener treeModelListener; - - /** - * Creates a new BasicTreeUI object. - */ - public BasicTreeUI() - { - drawingCache = new Hashtable(); - cellEditor = createDefaultCellEditor(); - currentCellRenderer = createDefaultCellRenderer(); - nodeDimensions = createNodeDimensions(); - rendererPane = createCellRendererPane(); - configureLayoutCache(); - - propertyChangeListener = createPropertyChangeListener(); - focusListener = createFocusListener(); - treeSelectionListener = createTreeSelectionListener(); - mouseInputListener = new MouseInputHandler(null, null, null); - keyListener = createKeyListener(); - selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener(); - componentListener = createComponentListener(); - cellEditorListener = createCellEditorListener(); - treeExpansionListener = createTreeExpansionListener(); - treeModelListener = createTreeModelListener(); + /** Used to determine what to display. */ + protected TreeModel treeModel; + + /** Model maintaining the selection. */ + protected TreeSelectionModel treeSelectionModel; + + /** + * How much the depth should be offset to properly calculate x locations. This + * is based on whether or not the root is visible, and if the root handles are + * visible. + */ + protected int depthOffset; + + /** + * When editing, this will be the Component that is doing the actual editing. + */ + protected Component editingComponent; + + /** Path that is being edited. */ + protected TreePath editingPath; + + /** + * Row that is being edited. Should only be referenced if editingComponent is + * null. + */ + protected int editingRow; + + /** Set to true if the editor has a different size than the renderer. */ + protected boolean editorHasDifferentSize; + + /** The action listener for the editor's Timer. */ + private Timer editorTimer = new EditorUpdateTimer(); + + /** The new value of the node after editing. */ + private Object newVal; + + /** The action bound to KeyStrokes. */ + private TreeAction action; + + /** Boolean to keep track of editing. */ + private boolean isEditing; + + /** Listeners */ + private PropertyChangeListener propertyChangeListener; + + private FocusListener focusListener; + + private TreeSelectionListener treeSelectionListener; + + private MouseInputListener mouseInputListener; + + private KeyListener keyListener; + + private PropertyChangeListener selectionModelPropertyChangeListener; + + private ComponentListener componentListener; + + private CellEditorListener cellEditorListener; + + private TreeExpansionListener treeExpansionListener; + + private TreeModelListener treeModelListener; + + /** + * Creates a new BasicTreeUI object. + */ + public BasicTreeUI() + { + drawingCache = new Hashtable(); + nodeDimensions = createNodeDimensions(); + configureLayoutCache(); + + propertyChangeListener = createPropertyChangeListener(); + focusListener = createFocusListener(); + treeSelectionListener = createTreeSelectionListener(); + mouseInputListener = new MouseInputHandler(null, null, null); + keyListener = createKeyListener(); + selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener(); + componentListener = createComponentListener(); + cellEditorListener = createCellEditorListener(); + treeExpansionListener = createTreeExpansionListener(); + treeModelListener = createTreeModelListener(); + + 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. + * @return the <code>ComponentUI</code> for c. + */ + public static ComponentUI createUI(JComponent c) + { + return new BasicTreeUI(); + } + + /** + * Returns the Hash color. + * + * @return the <code>Color</code> of the Hash. + */ + protected Color getHashColor() + { + return UIManager.getLookAndFeelDefaults().getColor("Tree.hash"); + } + + /** + * Sets the Hash color. + * + * @param color + * the <code>Color</code> to set the Hash to. + */ + protected void setHashColor(Color color) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + defaults.put("Tree.hash", color); + } + + /** + * Sets the left child's indent value. + * + * @param newAmount + * is the new indent value for the left child. + */ + public void setLeftChildIndent(int newAmount) + { + leftChildIndent = newAmount; + } + + /** + * Returns the indent value for the left child. + * + * @return the indent value for the left child. + */ + public int getLeftChildIndent(int newAmount) + { + return leftChildIndent; + } + + /** + * Sets the right child's indent value. + * + * @param newAmount + * is the new indent value for the right child. + */ + public void setRightChildIndent(int newAmount) + { + rightChildIndent = newAmount; + } + + /** + * Returns the indent value for the right child. + * + * @return the indent value for the right child. + */ + public int getRightChildIndent() + { + return rightChildIndent; + } + + /** + * Sets the expanded icon. + * + * @param newG + * is the new expanded icon. + */ + public void setExpandedIcon(Icon newG) + { + expandedIcon = newG; + } + + /** + * Returns the current expanded icon. + * + * @return the current expanded icon. + */ + public Icon getExpandedIcon() + { + return expandedIcon; + } + + /** + * Sets the collapsed icon. + * + * @param newG + * is the new collapsed icon. + */ + public void setCollapsedIcon(Icon newG) + { + collapsedIcon = newG; + } + + /** + * Returns the current collapsed icon. + * + * @return the current collapsed icon. + */ + public Icon getCollapsedIcon() + { + return collapsedIcon; + } + + /** + * Updates the componentListener, if necessary. + * + * @param largeModel + * sets this.largeModel to it. + */ + protected void setLargeModel(boolean largeModel) + { + if (largeModel != this.largeModel) + { + tree.removeComponentListener(componentListener); + this.largeModel = largeModel; + tree.addComponentListener(componentListener); + } + } + + /** + * Returns true if largeModel is set + * + * @return true if largeModel is set, otherwise false. + */ + protected boolean isLargeModel() + { + return largeModel; + } + + /** + * Sets the row height. + * + * @param rowHeight + * is the height to set this.rowHeight to. + */ + protected void setRowHeight(int rowHeight) + { + treeState.setRowHeight(rowHeight); + } + + /** + * Returns the current row height. + * + * @return current row height. + */ + protected int getRowHeight() + { + return treeState.getRowHeight(); + } + + /** + * Sets the TreeCellRenderer to <code>tcr</code>. This invokes + * <code>updateRenderer</code>. + * + * @param tcr + * is the new TreeCellRenderer. + */ + protected void setCellRenderer(TreeCellRenderer tcr) + { + currentCellRenderer = tcr; + tree.setCellRenderer(tcr); + updateRenderer(); + } + + /** + * Return currentCellRenderer, which will either be the trees renderer, or + * defaultCellRenderer, which ever was not null. + * + * @return the current Cell Renderer + */ + protected TreeCellRenderer getCellRenderer() + { + if (currentCellRenderer != null) + return currentCellRenderer; + + return createDefaultCellRenderer(); + } + + /** + * Sets the tree's model. + * + * @param model + * to set the treeModel to. + */ + protected void setModel(TreeModel model) + { + tree.setModel(model); + treeModel = tree.getModel(); + } + + /** + * Returns the tree's model + * + * @return treeModel + */ + protected TreeModel getModel() + { + return treeModel; + } + + /** + * Sets the root to being visible. + * + * @param newValue + * sets the visibility of the root + */ + protected void setRootVisible(boolean newValue) + { + tree.setRootVisible(newValue); + } + + /** + * Returns true if the root is visible. + * + * @return true if the root is visible. + */ + protected boolean isRootVisible() + { + return tree.isRootVisible(); + } + + /** + * Determines whether the node handles are to be displayed. + * + * @param newValue + * sets whether or not node handles should be displayed. + */ + protected void setShowsRootHandles(boolean newValue) + { + tree.setShowsRootHandles(newValue); + } + + /** + * Returns true if the node handles are to be displayed. + * + * @return true if the node handles are to be displayed. + */ + protected boolean getShowsRootHandles() + { + return tree.getShowsRootHandles(); + } + + /** + * Sets the cell editor. + * + * @param editor + * to set the cellEditor to. + */ + protected void setCellEditor(TreeCellEditor editor) + { + cellEditor = editor; + createdCellEditor = true; + } + + /** + * Returns the <code>TreeCellEditor</code> for this tree. + * + * @return the cellEditor for this tree. + */ + protected TreeCellEditor getCellEditor() + { + return cellEditor; + } + + /** + * Configures the receiver to allow, or not allow, editing. + * + * @param newValue + * sets the receiver to allow editing if true. + */ + protected void setEditable(boolean newValue) + { + tree.setEditable(newValue); + } + + /** + * Returns true if the receiver allows editing. + * + * @return true if the receiver allows editing. + */ + protected boolean isEditable() + { + return tree.isEditable(); + } + + /** + * Resets the selection model. The appropriate listeners are installed on the + * model. + * + * @param newLSM + * resets the selection model. + */ + protected void setSelectionModel(TreeSelectionModel newLSM) + { + if (newLSM != null) + { + treeSelectionModel = newLSM; + tree.setSelectionModel(treeSelectionModel); + } + } + + /** + * Returns the current selection model. + * + * @return the current selection model. + */ + protected TreeSelectionModel getSelectionModel() + { + return treeSelectionModel; + } + + /** + * Returns the Rectangle enclosing the label portion that the last item in + * 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. + * @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) + { + if (path != null) + { + Object cell = path.getLastPathComponent(); + + TreeModel mod = tree.getModel(); + if (mod != null) + { + Object root = mod.getRoot(); + if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root))) + root = getNextNode(root); + + Point loc = getCellLocation(0, 0, tree, mod, cell, root); + return getCellBounds(loc.x, loc.y, cell); + } + } + return null; + } + + /** + * 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. + * @return the path for passed in row. If row is not visible null is returned. + */ + public TreePath getPathForRow(JTree tree, int row) + { + TreeModel mod = tree.getModel(); + if (mod != null) + { + Object node = mod.getRoot(); + if (!tree.isRootVisible() + && tree.isExpanded(new TreePath(getPathToRoot(node, 0)))) + node = getNextNode(node); + + for (int i = 0; i < row; i++) + node = getNextVisibleNode(node); + + if (node == null) + return null; + + return new TreePath(getPathToRoot(node, 0)); + } + return null; + } + + /** + * 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. + * @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 = path.getPathCount(); + if (tree.isVisible(path)) + return row; + + path = path.getParentPath(); + while (row > 0 && !tree.isVisible(path)) + { + path = path.getParentPath(); + row--; + } + return row; + } + + /** + * Returns the number of rows that are being displayed. + * + * @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) + { + TreeModel mod = tree.getModel(); + int count = 0; + if (mod != null) + { + Object node = mod.getRoot(); + if (!tree.isRootVisible() + && tree.isExpanded(new TreePath((getPathToRoot(node, 0))))) + node = getNextNode(node); + + while (node != null) + { + count++; + node = getNextVisibleNode(node); + } + } + return count; + } + + /** + * Returns the path to the node that is closest to x,y. If there is nothing + * currently visible this will return null, otherwise it'll always return a + * 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 + * @return the tree path closes to x,y. + */ + public TreePath getClosestPathForLocation(JTree tree, int x, int y) + { + // FIXME: what if root is hidden? should not depend on (0,0) + // should start counting rows from where root is. + + int row = Math.round(y / getRowHeight()); + TreePath path = getPathForRow(tree, row); + + // no row is visible at this node + while (row > 0 && path == null) + { + --row; + path = getPathForRow(tree, row); + } + + return path; + } + + /** + * 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. + * @return true if the tree is being edited. + */ + public boolean isEditing(JTree tree) + { + return isEditing; + } + + /** + * Stops the current editing session. This has no effect if the tree is not + * being edited. Returns true if the editor allows the editing session to + * stop. + * + * @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) + { + if (isEditing(tree)) + completeEditing(true, false, false); + return !isEditing(tree); + } + + /** + * Cancels the current editing session. + * + * @param tree + * is the tree to cancel the editing session on. + */ + public void cancelEditing(JTree tree) + { + if (isEditing(tree)) + completeEditing(false, true, false); + } + + /** + * 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. + */ + public void startEditingAtPath(JTree tree, TreePath path) + { + startEditing(path, null); + } + + /** + * Returns the path to the element that is being editted. + * + * @param tree + * is the tree to get the editing path from. + * @return the path that is being edited. + */ + public TreePath getEditingPath(JTree tree) + { + return editingPath; + } + + /** + * Invoked after the tree instance variable has been set, but before any + * default/listeners have been installed. + */ + protected void prepareForUIInstall() + { + // FIXME: not implemented + } + + /** + * Invoked from installUI after all the defaults/listeners have been + * installed. + */ + protected void completeUIInstall() + { + // FIXME: not implemented + } + + /** + * Invoked from uninstallUI after all the defaults/listeners have been + * uninstalled. + */ + protected void completeUIUninstall() + { + // FIXME: not implemented + } + + /** + * Installs the subcomponents of the tree, which is the renderer pane. + */ + protected void installComponents() + { + // FIXME: not implemented + } + + /** + * Creates an instance of NodeDimensions that is able to determine the size of + * a given node in the tree. + * + * @return the NodeDimensions of a given node in the tree + */ + protected AbstractLayoutCache.NodeDimensions createNodeDimensions() + { + // FIXME: not implemented + return null; + } + + /** + * Creates a listener that is reponsible for the updates the UI based on how + * the tree changes. + * + * @return the PropertyChangeListener that is reposnsible for the updates + */ + protected PropertyChangeListener createPropertyChangeListener() + { + return new PropertyChangeHandler(); + } + + /** + * Creates the listener responsible for updating the selection based on mouse + * events. + * + * @return the MouseListener responsible for updating. + */ + protected MouseListener createMouseListener() + { + return new MouseHandler(); + } + + /** + * Creates the listener that is responsible for updating the display when + * focus is lost/grained. + * + * @return the FocusListener responsible for updating. + */ + protected FocusListener createFocusListener() + { + return new FocusHandler(); + } + + /** + * Creates the listener reponsible for getting key events from the tree. + * + * @return the KeyListener responsible for getting key events. + */ + protected KeyListener createKeyListener() + { + return new KeyHandler(); + } + + /** + * Creates the listener responsible for getting property change events from + * the selection model. + * + * @returns the PropertyChangeListener reponsible for getting property change + * events from the selection model. + */ + protected PropertyChangeListener createSelectionModelPropertyChangeListener() + { + return new SelectionModelPropertyChangeHandler(); + } + + /** + * Creates the listener that updates the display based on selection change + * methods. + * + * @return the TreeSelectionListener responsible for updating. + */ + protected TreeSelectionListener createTreeSelectionListener() + { + return new TreeSelectionHandler(); + } + + /** + * Creates a listener to handle events from the current editor + * + * @return the CellEditorListener that handles events from the current editor + */ + protected CellEditorListener createCellEditorListener() + { + return new CellEditorHandler(); + } + + /** + * Creates and returns a new ComponentHandler. This is used for the large + * model to mark the validCachedPreferredSize as invalid when the component + * moves. + * + * @return a new ComponentHandler. + */ + protected ComponentListener createComponentListener() + { + return new ComponentHandler(); + } + + /** + * Creates and returns the object responsible for updating the treestate when + * a nodes expanded state changes. + * + * @return the TreeExpansionListener responsible for updating the treestate + */ + protected TreeExpansionListener createTreeExpansionListener() + { + return new TreeExpansionHandler(); + } + + /** + * Creates the object responsible for managing what is expanded, as well as + * the size of nodes. + * + * @return the object responsible for managing what is expanded. + */ + protected AbstractLayoutCache createLayoutCache() + { + return new FixedHeightLayoutCache(); + } + + /** + * Returns the renderer pane that renderer components are placed in. + * + * @return the rendererpane that render components are placed in. + */ + protected CellRendererPane createCellRendererPane() + { + return new CellRendererPane(); + } + + /** + * Creates a default cell editor. + * + * @return the default cell editor. + */ + protected TreeCellEditor createDefaultCellEditor() + { + if (currentCellRenderer != null) + return new DefaultTreeCellEditor(tree, + (DefaultTreeCellRenderer) currentCellRenderer, + cellEditor); + return new DefaultTreeCellEditor(tree, + (DefaultTreeCellRenderer) createDefaultCellRenderer(), + cellEditor); + } + + /** + * Returns the default cell renderer that is used to do the stamping of each + * node. + * + * @return the default cell renderer that is used to do the stamping of each + * node. + */ + protected TreeCellRenderer createDefaultCellRenderer() + { + return new DefaultTreeCellRenderer(); + } + + /** + * Returns a listener that can update the tree when the model changes. + * + * @return a listener that can update the tree when the model changes. + */ + protected TreeModelListener createTreeModelListener() + { + return new TreeModelHandler(); + } + + /** + * Uninstall all registered listeners + */ + protected void uninstallListeners() + { + tree.removePropertyChangeListener(propertyChangeListener); + tree.removeFocusListener(focusListener); + tree.removeTreeSelectionListener(treeSelectionListener); + tree.removeMouseListener(mouseInputListener); + tree.removeKeyListener(keyListener); + tree.removePropertyChangeListener(selectionModelPropertyChangeListener); + tree.removeComponentListener(componentListener); + tree.removeTreeExpansionListener(treeExpansionListener); + + TreeCellEditor tce = tree.getCellEditor(); + if (tce != null) + tce.removeCellEditorListener(cellEditorListener); + TreeModel tm = tree.getModel(); + if (tm != null) + tm.removeTreeModelListener(treeModelListener); + } + + /** + * Uninstall all keyboard actions. + */ + protected void uninstallKeyboardActions() + { + } + + /** + * Uninstall the rendererPane. + */ + protected void uninstallComponents() + { + // FIXME: not implemented + } + + /** + * The vertical element of legs between nodes starts at the bottom of the + * parent node by default. This method makes the leg start below that. + * + * @return the vertical leg buffer + */ + protected int getVerticalLegBuffer() + { + // FIXME: not implemented + return 0; + } + + /** + * The horizontal element of legs between nodes starts at the right of the + * left-hand side of the child node by default. This method makes the leg end + * before that. + * + * @return the horizontal leg buffer + */ + protected int getHorizontalLegBuffer() + { + // FIXME: not implemented + return 0; + } + + /** + * Make all the nodes that are expanded in JTree expanded in LayoutCache. This + * invokes update ExpandedDescendants with the root path. + */ + protected void updateLayoutCacheExpandedNodes() + { + // FIXME: not implemented + } + + /** + * Updates the expanded state of all the descendants of the <code>path</code> + * by getting the expanded descendants from the tree and forwarding to the + * tree state. + * + * @param path + * the path used to update the expanded states + */ + protected void updateExpandedDescendants(TreePath path) + { + // FIXME: not implemented + } + + /** + * Returns a path to the last child of <code>parent</code> + * + * @param parent + * is the topmost path to specified + * @return a path to the last child of parent + */ + protected TreePath getLastChildPath(TreePath parent) + { + return ((TreePath) parent.getLastPathComponent()); + } + + /** + * Updates how much each depth should be offset by. + */ + protected void updateDepthOffset() + { + // FIXME: not implemented + } + + /** + * Updates the cellEditor based on editability of the JTree that we're + * contained in. If the tree is editable but doesn't have a cellEditor, a + * basic one will be used. + */ + protected void updateCellEditor() + { + if (tree.isEditable() && cellEditor == null) + setCellEditor(createDefaultCellEditor()); + createdCellEditor = true; + } + + /** + * Messaged from the tree we're in when the renderer has changed. + */ + protected void updateRenderer() + { + // FIXME: not implemented + } + + /** + * Resets the treeState instance based on the tree we're providing the look + * and feel for. + */ + protected void configureLayoutCache() + { + treeState = createLayoutCache(); + } + + /** + * Marks the cached size as being invalid, and messages the tree with + * <code>treeDidChange</code>. + */ + protected void updateSize() + { + // FIXME: not implemented + } + + /** + * Updates the <code>preferredSize</code> instance variable, which is + * returned from <code>getPreferredSize()</code>. For left to right + * orientations, the size is determined from the current AbstractLayoutCache. + * For RTL orientations, the preferred size becomes the width minus the + * minimum x position. + */ + protected void updateCachedPreferredSize() + { + // FIXME: not implemented + } + + /** + * Messaged from the VisibleTreeNode after it has been expanded. + * + * @param path + * is the path that has been expanded. + */ + protected void pathWasExpanded(TreePath path) + { + // FIXME: not implemented + } + + /** + * Messaged from the VisibleTreeNode after it has collapsed + */ + protected void pathWasCollapsed(TreePath path) + { + // FIXME: not implemented + } + + /** + * Install all defaults for the tree. + * + * @param tree + * is the JTree to install defaults for + */ + protected void installDefaults(JTree tree) + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + + tree.setFont(defaults.getFont("Tree.font")); + tree.setForeground(defaults.getColor("Tree.foreground")); + tree.setBackground(defaults.getColor("Tree.background")); + tree.setOpaque(true); + + rightChildIndent = defaults.getInt("Tree.rightChildIndent"); + leftChildIndent = defaults.getInt("Tree.leftChildIndent"); + setRowHeight(defaults.getInt("Tree.rowHeight")); + tree.requestFocusInWindow(false); + } + + /** + * Install all keyboard actions for this + */ + protected void installKeyboardActions() + { + UIDefaults defaults = UIManager.getLookAndFeelDefaults(); + InputMap focusInputMap = (InputMap) defaults.get("Tree.focusInputMap"); + InputMapUIResource parentInputMap = new InputMapUIResource(); + ActionMap parentActionMap = new ActionMap(); + action = new TreeAction(); + Object keys[] = focusInputMap.allKeys(); + + for (int i = 0; i < keys.length; i++) + { + parentInputMap.put( + KeyStroke.getKeyStroke( + ((KeyStroke) keys[i]).getKeyCode(), + convertModifiers(((KeyStroke) keys[i]).getModifiers())), + (String) focusInputMap.get((KeyStroke) keys[i])); + + parentInputMap.put( + KeyStroke.getKeyStroke( + ((KeyStroke) keys[i]).getKeyCode(), + ((KeyStroke) keys[i]).getModifiers()), + (String) focusInputMap.get((KeyStroke) keys[i])); + + parentActionMap.put( + (String) focusInputMap.get((KeyStroke) keys[i]), + new ActionListenerProxy( + action, + (String) focusInputMap.get((KeyStroke) keys[i]))); + + } + + parentInputMap.setParent(tree.getInputMap( + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent()); + parentActionMap.setParent(tree.getActionMap().getParent()); + tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent( + parentInputMap); + tree.getActionMap().setParent(parentActionMap); + } + + /** + * Converts the modifiers. + * + * @param mod - + * modifier to convert + * @returns the new modifier + */ + private int convertModifiers(int mod) + { + if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0) + { + mod |= KeyEvent.SHIFT_MASK; + mod &= ~KeyEvent.SHIFT_DOWN_MASK; + } + if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0) + { + mod |= KeyEvent.CTRL_MASK; + mod &= ~KeyEvent.CTRL_DOWN_MASK; + } + if ((mod & KeyEvent.META_DOWN_MASK) != 0) + { + mod |= KeyEvent.META_MASK; + mod &= ~KeyEvent.META_DOWN_MASK; + } + if ((mod & KeyEvent.ALT_DOWN_MASK) != 0) + { + mod |= KeyEvent.ALT_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; + } + return mod; + } + + /** + * Install all listeners for this + */ + protected void installListeners() + { + tree.addPropertyChangeListener(propertyChangeListener); + tree.addFocusListener(focusListener); + tree.addTreeSelectionListener(treeSelectionListener); + tree.addMouseListener(mouseInputListener); + tree.addKeyListener(keyListener); + tree.addPropertyChangeListener(selectionModelPropertyChangeListener); + tree.addComponentListener(componentListener); + tree.addTreeExpansionListener(treeExpansionListener); + if (treeModel != null) + treeModel.addTreeModelListener(treeModelListener); + } + + /** + * Install the UI for the component + * + * @param c + * the component to install UI for + */ + public void installUI(JComponent c) + { + super.installUI(c); + installDefaults((JTree) c); + tree = (JTree) c; + + currentCellRenderer = createDefaultCellRenderer(); + rendererPane = createCellRendererPane(); + createdRenderer = true; + + setCellEditor(createDefaultCellEditor()); + createdCellEditor = true; + isEditing = false; + + TreeModel mod = tree.getModel(); + setModel(mod); + tree.setRootVisible(true); + if (mod != null) + tree.expandPath(new TreePath(mod.getRoot())); + treeSelectionModel = tree.getSelectionModel(); + + installKeyboardActions(); + installListeners(); + completeUIInstall(); + } + + /** + * Uninstall the defaults for the tree + * + * @param tree + * to uninstall defaults for + */ + protected void uninstallDefaults(JTree tree) + { + tree.setFont(null); + tree.setForeground(null); + tree.setBackground(null); + } + + /** + * Uninstall the UI for the component + * + * @param c + * the component to uninstall UI for + */ + public void uninstallUI(JComponent c) + { + uninstallDefaults((JTree) c); + uninstallKeyboardActions(); + uninstallListeners(); + tree = null; + completeUIUninstall(); + } + + /** + * Paints the specified component appropriate for the look and feel. This + * method is invoked from the ComponentUI.update method when the specified + * 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 + * 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; + + TreeModel mod = tree.getModel(); + + if (mod != null) + { + Object root = mod.getRoot(); + + if (!tree.isRootVisible()) + tree.expandPath(new TreePath(root)); + + paintRecursive(g, 0, 0, 0, 0, tree, mod, root); + + if (hasControlIcons()) + paintControlIcons(g, 0, 0, 0, 0, tree, mod, root); + } + } + + /** + * Ensures that the rows identified by beginRow through endRow are visible. + * + * @param beginRow + * is the first row + * @param endRow + * is the last row + */ + protected void ensureRowsAreVisible(int beginRow, int endRow) + { + // FIXME: not implemented + } + + /** + * Sets the preferred minimum size. + * + * @param newSize + * is the new preferred minimum size. + */ + public void setPreferredMinSize(Dimension newSize) + { + // FIXME: not implemented + } + + /** + * Gets the preferred minimum size. + * + * @returns the preferred minimum size. + */ + public Dimension getPreferredMinSize() + { + // FIXME: not implemented + return null; + } + + /** + * 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 + * is often ignored but might be used if the UI object is stateless + * and shared by multiple components + * @return the preferred size + */ + public Dimension getPreferredSize(JComponent c) + { + return getPreferredSize(c, false); + } + + /** + * 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 + * @return the preferred size + */ + public Dimension getPreferredSize(JComponent c, boolean checkConsistancy) + { + // FIXME: checkConsistancy not implemented, c not used + TreeModel model = tree.getModel(); + int maxWidth = 0; + int count = 0; + if (model != null) + { + Object node = model.getRoot(); + if (node != null) + { + maxWidth = (int) (getCellBounds(0, 0, node).getWidth()); + while (node != null) + { + count++; + Object nextNode = getNextVisibleNode(node); + if (nextNode != null) + maxWidth = Math.max(maxWidth, + (int) (getCellBounds(0, 0, nextNode).getWidth())); + node = nextNode; + } + } + } + return new Dimension(maxWidth, (getRowHeight() * count)); + } + + /** + * 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. + * @returns the preferred size or null + */ + public Dimension getMinimumSize(JComponent c) + { + // FIXME: not implemented + return 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 + * @return the max size or null + */ + public Dimension getMaximumSize(JComponent c) + { + // FIXME: not implemented + return getPreferredSize(c); + } + + /** + * Messages to stop the editing session. If the UI the receiver is providing + * the look and feel for returns true from + * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked + * on the current editor. Then completeEditing will be messaged with false, + * true, false to cancel any lingering editing. + */ + protected void completeEditing() + { + completeEditing(false, true, false); + } + + /** + * Stops the editing session. If messageStop is true, the editor is messaged + * with stopEditing, if messageCancel is true the editor is messaged with + * 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 + */ + protected void completeEditing(boolean messageStop, boolean messageCancel, + boolean messageTree) + { + if (messageStop) + { + getCellEditor().stopCellEditing(); + stopEditingInCompleteEditing = true; + } + + if (messageCancel) + { + getCellEditor().cancelCellEditing(); + stopEditingInCompleteEditing = true; + } + + if (messageTree) + tree.getModel().valueForPathChanged(tree.getLeadSelectionPath(), newVal); + } + + /** + * 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 + * @return true if successful + */ + protected boolean startEditing(TreePath path, MouseEvent event) + { + int x; + int y; + if (event == null) + { + Rectangle bounds = getPathBounds(tree, path); + x = bounds.x; + y = bounds.y; + } + else + { + x = event.getX(); + y = event.getY(); + } + + updateCellEditor(); + TreeCellEditor ed = getCellEditor(); + if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event)) + { + editingPath = path; + editingRow = tree.getRowForPath(editingPath); + Object val = editingPath.getLastPathComponent(); + cellEditor.addCellEditorListener(cellEditorListener); + stopEditingInCompleteEditing = false; + boolean expanded = tree.isExpanded(editingPath); + isEditing = true; + editingComponent = ed.getTreeCellEditorComponent(tree, val, true, + expanded, + isLeaf(editingRow), + editingRow); + editingComponent.getParent().setVisible(true); + editingComponent.getParent().validate(); + tree.add(editingComponent.getParent()); + editingComponent.getParent().validate(); + ((JTextField) editingComponent).requestFocusInWindow(false); + editorTimer.start(); + return true; + } + return false; + } + + /** + * 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 + */ + protected void checkForClickInExpandControl(TreePath path, int mouseX, + int mouseY) + { + // FIXME: not implemented + } + + /** + * Returns 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. + * + * @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. + */ + protected boolean isLocationInExpandControl(TreePath path, int mouseX, + int mouseY) + { + // FIXME: not implemented + return false; + } + + /** + * 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 + */ + protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY) + { + // FIXME: not implemented + } + + /** + * Expands path if it is not expanded, or collapses row if it is expanded. If + * expanding a path and JTree scroll on expand, ensureRowsAreVisible is + * 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 + */ + protected void toggleExpandState(TreePath path) + { + // FIXME: not implemented + } + + /** + * Returning true signifies a mouse event on the node should toggle the + * selection of only the row under the mouse. + * + * @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) + { + // FIXME: not implemented + return false; + } + + /** + * Returning true signifies a mouse event on the node should select from the + * anchor point. + * + * @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) + { + // FIXME: not implemented + return false; + } + + /** + * Returning true indicates the row under the mouse should be toggled based on + * 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. + * @return true indicates the row under the mouse should be toggled based on + * the event. + */ + protected boolean isToggleEvent(MouseEvent event) + { + // FIXME: not implemented + return false; + } + + /** + * Messaged to update the selection based on a MouseEvent over a particular + * 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. + * + * @param path + * is the path selected for an event + * @param event + * is the MouseEvent performed on the path. + */ + protected void selectPathForEvent(TreePath path, MouseEvent event) + { + // FIXME: not implemented + } + + /** + * Returns true if the node at <code>row</code> is a leaf. + * + * @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) + { + TreePath pathForRow = getPathForRow(tree, row); + if (pathForRow == null) + return true; + + Object node = pathForRow.getLastPathComponent(); + return tree.getModel().isLeaf(node); + } + + /** + * This class implements the actions that we want to happen when specific keys + * are pressed for the JTree. The actionPerformed method is called when a key + * that has been registered for the JTree is received. + */ + class TreeAction + extends AbstractAction + { + + /** + * What to do when this action is called. + * + * @param e + * the ActionEvent that caused this action. + */ + public void actionPerformed(ActionEvent e) + { + 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")) + (new TreeIncrementAction(0, "")).actionPerformed(e); + else if (e.getActionCommand().equals("selectParent") + || e.getActionCommand().equals("selectChild")) + (new TreeTraverseAction(0, "")).actionPerformed(e); + else if (e.getActionCommand().equals("selectAll")) + { + TreePath[] paths = new TreePath[tree.getRowCount()]; + + Object curr = getNextVisibleNode(tree.getModel().getRoot()); + int i = 0; + while (curr != null && i < paths.length) + { + paths[i] = new TreePath(getPathToRoot(curr, 0)); + i++; + } - createdRenderer = true; - createdCellEditor = true; + tree.addSelectionPaths(paths); + } + else if (e.getActionCommand().equals("startEditing")) + tree.startEditingAtPath(lead); + else if (e.getActionCommand().equals("toggle")) + { + if (tree.isEditing()) + tree.stopEditing(); + else + { + Object last = lead.getLastPathComponent(); + TreePath path = new TreePath(getPathToRoot(last, 0)); + if (!tree.getModel().isLeaf(last)) + { + if (tree.isExpanded(path)) + tree.collapsePath(path); + else + tree.expandPath(path); + } + } + } + else if (e.getActionCommand().equals("clearSelection")) + tree.clearSelection(); + + if (tree.isEditing() && !e.getActionCommand().equals("startEditing")) + tree.cancelEditing(); + + tree.scrollPathToVisible(lead); + } + } + + /** + * This class is used to mimic the behaviour of the JDK when registering + * keyboard actions. It is the same as the private class used in JComponent + * for the same reason. This class receives an action event and dispatches it + * to the true receiver after altering the actionCommand property of the + * event. + */ + private static class ActionListenerProxy + extends AbstractAction + { + ActionListener target; + + String bindingCommandName; + + public ActionListenerProxy(ActionListener li, String cmd) + { + target = li; + bindingCommandName = cmd; + } + + public void actionPerformed(ActionEvent e) + { + ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(), + bindingCommandName, + e.getModifiers()); + + target.actionPerformed(derivedEvent); + } + } + + /** + * The timer that updates the editor component. + */ + private class EditorUpdateTimer + extends Timer + implements ActionListener + { + /** + * Creates a new EditorUpdateTimer object with a default delay of 0.3 + * seconds. + */ + public EditorUpdateTimer() + { + super(300, null); + addActionListener(this); + } + + /** + * Lets the caret blink and repaints the table. + */ + public void actionPerformed(ActionEvent ev) + { + Caret c = ((JTextField) editingComponent).getCaret(); + if (c != null) + c.setVisible(!c.isVisible()); + tree.repaint(); + } + + /** + * Updates the blink delay according to the current caret. + */ + public void update() + { + stop(); + Caret c = ((JTextField) editingComponent).getCaret(); + if (c != null) + { + setDelay(c.getBlinkRate()); + if (((JTextField) editingComponent).isEditable()) + start(); + else + c.setVisible(false); + } + } + } + + /** + * Updates the preferred size when scrolling, if necessary. + */ + public class ComponentHandler + extends ComponentAdapter + implements ActionListener + { + /** + * Timer used when inside a scrollpane and the scrollbar is adjusting + */ + protected Timer timer; + + /** ScrollBar that is being adjusted */ + protected JScrollBar scrollBar; + + /** + * Constructor + */ + public ComponentHandler() + { + } + + /** + * Invoked when the component's position changes. + * + * @param e + * the event that occurs when moving the component + */ + public void componentMoved(ComponentEvent e) + { + } + + /** + * Creats, if necessary, and starts a Timer to check if needed to resize the + * bounds + */ + protected void startTimer() + { + } + + /** + * Returns the JScrollPane housing the JTree, or null if one isn't found. + * + * @return JScrollPane housing the JTree, or null if one isn't found. + */ + protected JScrollPane getScrollPane() + { + return null; + } + + /** + * 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 + */ + public void actionPerformed(ActionEvent ae) + { + } + }// ComponentHandler + + /** + * Listener responsible for getting cell editing events and updating the tree + * accordingly. + */ + public class CellEditorHandler + implements CellEditorListener + { + /** + * Constructor + */ + public CellEditorHandler() + { + } + + /** + * Messaged when editing has stopped in the tree. Tells the listeners + * editing has stopped. + * + * @param e + * is the notification event + */ + public void editingStopped(ChangeEvent e) + { + editingPath = null; 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. - * @return the <code>ComponentUI</code> for c. - */ - public static ComponentUI createUI(JComponent c) - { - return new BasicTreeUI(); - } - - /** - * Returns the Hash color. - * - * @return the <code>Color</code> of the Hash. - */ - protected Color getHashColor() - { - return UIManager.getLookAndFeelDefaults().getColor("Tree.hash"); - } - - /** - * Sets the Hash color. - * - * @param the <code>Color</code> to set the Hash to. - */ - protected void setHashColor(Color color) - { - // FIXME: not implemented - - } - - /** - * Sets the left child's indent value. - * - * @param newAmount is the new indent value for the left child. - */ - public void setLeftChildIndent(int newAmount) - { - leftChildIndent = newAmount; - } - - /** - * Returns the indent value for the left child. - * - * @return the indent value for the left child. - */ - public int getLeftChildIndent(int newAmount) - { - return leftChildIndent; - } - - /** - * Sets the right child's indent value. - * - * @param newAmount is the new indent value for the right child. - */ - public void setRightChildIndent(int newAmount) - { - rightChildIndent = newAmount; - } - - /** - * Returns the indent value for the right child. - * - * @return the indent value for the right child. - */ - public int getRightChildIndent(int newAmount) - { - return rightChildIndent; - } - - /** - * Sets the expanded icon. - * - * @param newG is the new expanded icon. - */ - public void setExpandedIcon(Icon newG) - { - expandedIcon = newG; - } - - /** - * Returns the current expanded icon. - * - * @return the current expanded icon. - */ - public Icon getExpandedIcon() - { - return expandedIcon; - } - - /** - * Sets the collapsed icon. - * - * @param newG is the new collapsed icon. - */ - public void setCollapsedIcon(Icon newG) - { - collapsedIcon = newG; - } - - /** - * Returns the current collapsed icon. - * - * @return the current collapsed icon. - */ - public Icon getCollapsedIcon() - { - return collapsedIcon; - } - - /** - * Updates the componentListener, if necessary. - * - * @param largeModel sets this.largeModel to it. - */ - protected void setLargeModel(boolean largeModel) - { - if (largeModel != this.largeModel) - { - tree.removeComponentListener(componentListener); - this.largeModel = largeModel; - tree.addComponentListener(componentListener); - } - } - - /** - * Returns true if largeModel is set - * - * @return true if largeModel is set, otherwise false. - */ - protected boolean isLargeModel() - { - return largeModel; - } - - /** - * Sets the row height. - * - * @param rowHeight is the height to set this.rowHeight to. - */ - protected void setRowHeight(int rowHeight) - { - treeState.setRowHeight(rowHeight); - } - - /** - * Returns the current row height. - * - * @return current row height. - */ - protected int getRowHeight() - { - return treeState.getRowHeight(); - } - - /** - * Sets the TreeCellRenderer to <code>tcr</code>. This invokes - * <code>updateRenderer</code>. - * - * @param tcr is the new TreeCellRenderer. - */ - protected void setCellRenderer(TreeCellRenderer tcr) - { - currentCellRenderer = tcr; - updateRenderer(); - } - - /** - * Return currentCellRenderer, which will either be the trees renderer, or - * defaultCellRenderer, which ever was not null. - * - * @return the current Cell Renderer - */ - protected TreeCellRenderer getCellRenderer() - { - if (currentCellRenderer != null) - return currentCellRenderer; - - return createDefaultCellRenderer(); - } - - /** - * Sets the tree's model. - * - * @param model to set the treeModel to. - */ - protected void setModel(TreeModel model) - { - treeState.setModel(model); - treeModel = model; - } - - /** - * Returns the tree's model - * - * @return treeModel - */ - protected TreeModel getModel() - { - return treeModel; - } - - /** - * Sets the root to being visible. - * - * @param newValue sets the visibility of the root - */ - protected void setRootVisible(boolean newValue) - { - treeState.setRootVisible(newValue); - } - - /** - * Returns true if the root is visible. - * - * @return true if the root is visible. - */ - protected boolean isRootVisible() - { - return treeState.isRootVisible(); - } - - /** - * Determines whether the node handles are to be displayed. - * - * @param newValue sets whether or not node handles should be displayed. - */ - protected void setShowsRootHandles(boolean newValue) - { - tree.setShowsRootHandles(newValue); - } - - /** - * Returns true if the node handles are to be displayed. - * - * @return true if the node handles are to be displayed. - */ - protected boolean getShowsRootHandles() - { - return tree.getShowsRootHandles(); - } - - /** - * Sets the cell editor. - * - * @param editor to set the cellEditor to. - */ - protected void setCellEditor(TreeCellEditor editor) - { - cellEditor = editor; - } - - /** - * Returns the <code>TreeCellEditor</code> for this tree. - * - * @return the cellEditor for this tree. - */ - protected TreeCellEditor getCellEditor() - { - return cellEditor; - } - - /** - * Configures the receiver to allow, or not allow, editing. - * - * @param newValue sets the receiver to allow editing if true. - */ - protected void setEditable(boolean newValue) - { - tree.setEditable(newValue); - } - - /** - * Returns true if the receiver allows editing. - * - * @return true if the receiver allows editing. - */ - protected boolean isEditable() - { - return tree.isEditable(); - } - - /** - * Resets the selection model. The appropriate listeners are installed on the - * model. - * - * @param newLSM resets the selection model. - */ - protected void setSelectionModel(TreeSelectionModel newLSM) - { - if (newLSM != null) - { - treeSelectionModel = newLSM; - tree.setSelectionModel(treeSelectionModel); - } - } - - /** - * Returns the current selection model. - * - * @return the current selection model. - */ - protected TreeSelectionModel getSelectionModel() - { - return treeSelectionModel; - } - - /** - * Returns the Rectangle enclosing the label portion that the last item in - * 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. - * @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) - { - Object cell = path.getLastPathComponent(); - TreeModel mod = tree.getModel(); - Point loc = getCellLocation(0, 0, tree, mod, cell, mod.getRoot()); - int x = (int) loc.getX(); - int y = (int) loc.getY(); - return getCellBounds(x, y, cell); - } - - /** - * 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. - * @return the path for passed in row. If row is not visible null is - * returned. - */ - public TreePath getPathForRow(JTree tree, int row) - { - DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel()) - .getRoot()); - - for (int i = 0; i < row; i++) - node = getNextVisibleNode(node); - - // in case nothing was found - if (node == null) - return null; - - // something was found - return new TreePath(node.getPath()); - } - - /** - * Get next visible node in the tree. - * Package private for use in inner classes. - * @param the current node - * @return the next visible node in the JTree. Return null if there are no - * more. - */ - DefaultMutableTreeNode getNextVisibleNode(DefaultMutableTreeNode node) - { - DefaultMutableTreeNode next = null; - TreePath current = null; - - if (node != null) - next = node.getNextNode(); - - if (next != null) - { - current = new TreePath(next.getPath()); - if (tree.isVisible(current)) - return next; - - while (next != null && !tree.isVisible(current)) - { - next = next.getNextNode(); + stopEditingInCompleteEditing = false; + if (editingComponent != null) + { + tree.remove(editingComponent.getParent()); + editingComponent = null; + } + if (cellEditor != null) + { + newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText(); + completeEditing(false, false, true); + if (cellEditor instanceof DefaultTreeCellEditor) + tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); + cellEditor.removeCellEditorListener(cellEditorListener); + setCellEditor(null); + createdCellEditor = false; + } + isEditing = false; + tree.requestFocusInWindow(false); + editorTimer.stop(); + } + + /** + * Messaged when editing has been canceled in the tree. This tells the + * listeners the editor has canceled editing. + * + * @param e + * is the notification event + */ + public void editingCanceled(ChangeEvent e) + { + editingPath = null; + editingRow = -1; + stopEditingInCompleteEditing = false; + if (editingComponent != null) + tree.remove(editingComponent.getParent()); + editingComponent = null; + if (cellEditor != null) + { + if (cellEditor instanceof DefaultTreeCellEditor) + tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); + cellEditor.removeCellEditorListener(cellEditorListener); + setCellEditor(null); + createdCellEditor = false; + } + tree.requestFocusInWindow(false); + editorTimer.stop(); + isEditing = false; + tree.repaint(); + } + }// CellEditorHandler + + /** + * Repaints the lead selection row when focus is lost/grained. + */ + public class FocusHandler + implements FocusListener + { + /** + * Constructor + */ + public FocusHandler() + { + } + + /** + * Invoked when focus is activated on the tree we're in, redraws the lead + * row. Invoked when a component gains the keyboard focus. + * + * @param e + * is the focus event that is activated + */ + public void focusGained(FocusEvent e) + { + } + + /** + * Invoked when focus is deactivated on the tree we're in, redraws the lead + * row. Invoked when a component loses the keyboard focus. + * + * @param e + * is the focus event that is deactivated + */ + public void focusLost(FocusEvent e) + { + } + }// FocusHandler + + /** + * This is used to get multiple key down events to appropriately genereate + * events. + */ + public class KeyHandler + extends KeyAdapter + { + /** Key code that is being generated for. */ + protected Action repeatKeyAction; + + /** Set to true while keyPressed is active */ + protected boolean isKeyDown; + + /** + * Constructor + */ + public KeyHandler() + { + } + + /** + * Invoked when a key has been typed. Moves the keyboard focus to the first + * element whose first letter matches the alphanumeric key pressed by the + * user. Subsequent same key presses move the keyboard focus to the next + * object that starts with the same letter. + * + * @param e + * the key typed + */ + public void keyTyped(KeyEvent e) + { + } + + /** + * Invoked when a key has been pressed. + * + * @param e + * the key pressed + */ + public void keyPressed(KeyEvent e) + { + } + + /** + * Invoked when a key has been released + * + * @param e + * the key released + */ + public void keyReleased(KeyEvent e) + { + } + }// KeyHandler + + /** + * MouseListener is responsible for updating the selection based on mouse + * events. + */ + public class MouseHandler + extends MouseAdapter + implements MouseMotionListener + { + /** + * Constructor + */ + public MouseHandler() + { + } + + /** + * Invoked when a mouse button has been pressed on a component. + * + * @param e + * is the mouse event that occured + */ + public void mousePressed(MouseEvent e) + { + } + + /** + * Invoked when a mouse button is pressed on a component and then dragged. + * MOUSE_DRAGGED events will continue to be delivered to the component where + * 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 + */ + public void mouseDragged(MouseEvent e) + { + } + + /** + * Invoked when the mouse button has been moved on a component (with no + * buttons no down). + * + * @param e + * the mouse event that occured + */ + public void mouseMoved(MouseEvent e) + { + } + + /** + * Invoked when a mouse button has been released on a component. + * + * @param e + * is the mouse event that occured + */ + public void mouseReleased(MouseEvent e) + { + } + }// MouseHandler + + /** + * MouseInputHandler handles passing all mouse events, including mouse motion + * events, until the mouse is released to the destination it is constructed + * with. + */ + public class MouseInputHandler + implements MouseInputListener + { + /** Source that events are coming from */ + protected Component source; + + /** Destination that receives all events. */ + protected Component destination; + + /** + * Constructor + * + * @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) + { + } + + /** + * Invoked when the mouse button has been clicked (pressed and released) on + * a component. + * + * @param e + * mouse event that occured + */ + public void mouseClicked(MouseEvent e) + { + } + + /** + * Invoked when a mouse button has been pressed on a component. + * + * @param e + * mouse event that occured + */ + public void mousePressed(MouseEvent e) + { + Point click = e.getPoint(); + int row = Math.round(click.y / getRowHeight()); + TreePath path = getClosestPathForLocation(tree, click.x, click.y); - if (next != null) - current = new TreePath(next.getPath()); - } - } - return next; - } - - /** - * Get previous visible node in the tree. - * Package private for use in inner classes. - * - * @param the current node - * @return the next visible node in the JTree. Return null if there are no - * more. - */ - DefaultMutableTreeNode getPreviousVisibleNode - (DefaultMutableTreeNode node) - { - DefaultMutableTreeNode prev = null; - TreePath current = null; - - if (node != null) - prev = node.getPreviousNode(); - - if (prev != null) - { - current = new TreePath(prev.getPath()); - if (tree.isVisible(current)) - return prev; + if (path != null) + { + boolean inBounds = false; + boolean cntlClick = false; + Rectangle bounds = getPathBounds(tree, path); + + bounds.x -= rightChildIndent - 4; + bounds.width += rightChildIndent + 4; + + if (bounds.contains(click.x, click.y)) + inBounds = true; + else if (hasControlIcons() + && (click.x < (bounds.x - rightChildIndent + 5) && + click.x > (bounds.x - rightChildIndent - 5))) + cntlClick = true; + + if ((inBounds || cntlClick) && tree.isVisible(path)) + { + selectPath(tree, path); - while (prev != null && !tree.isVisible(current)) - { - prev = prev.getPreviousNode(); + if ((e.getClickCount() == 2 || cntlClick) && !isLeaf(row)) + { + if (tree.isExpanded(path)) + tree.collapsePath(path); + else + tree.expandPath(path); + } - if (prev != null) - current = new TreePath(prev.getPath()); - } - } - return prev; - } - - /** - * 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. - * @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) - { - // FIXME: check visibility - // right now, just returns last element because - // expand/collapse is not implemented - return path.getPathCount() - 1; - } - - /** - * Returns the number of rows that are being displayed. - * - * @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) - { - DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel()) - .getRoot()); - int count = 0; - - while (node != null) - { - count++; - node = getNextVisibleNode(node); - } - - return count; - } - - /** - * Returns the path to the node that is closest to x,y. If there is nothing - * currently visible this will return null, otherwise it'll always return a - * 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 - * @return the tree path closes to x,y. - */ - public TreePath getClosestPathForLocation(JTree tree, int x, int y) - { - 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. - * @return true if the tree is being edited. - */ - public boolean isEditing(JTree tree) - { - // FIXME: not implemented - return false; - } - - /** - * Stops the current editing session. This has no effect if the tree is not - * being edited. Returns true if the editor allows the editing session to - * stop. - * - * @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) - { - // FIXME: not implemented - return false; - } - - /** - * Cancels the current editing session. - * - * @param tree is the tree to cancel the editing session on. - */ - public void cancelEditing(JTree tree) - { - // FIXME: not implemented - } - - /** - * 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. - */ - public void startEditingAtPath(JTree tree, TreePath path) - { - // FIXME: not implemented - } - - /** - * Returns the path to the element that is being editted. - * - * @param tree is the tree to get the editing path from. - * @return the path that is being edited. - */ - public TreePath getEditingPath(JTree tree) - { - // FIXME: not implemented - return null; - } - - /** - * Invoked after the tree instance variable has been set, but before any - * default/listeners have been installed. - */ - protected void prepareForUIInstall() - { - // FIXME: not implemented - } - - /** - * Invoked from installUI after all the defaults/listeners have been - * installed. - */ - protected void completeUIInstall() - { - // FIXME: not implemented - } - - /** - * Invoked from uninstallUI after all the defaults/listeners have been - * uninstalled. - */ - protected void completeUIUninstall() - { - // FIXME: not implemented - } - - /** - * Installs the subcomponents of the tree, which is the renderer pane. - */ - protected void installComponents() - { - // FIXME: not implemented - } - - /** - * Creates an instance of NodeDimensions that is able to determine the size - * of a given node in the tree. - * - * @return the NodeDimensions of a given node in the tree - */ - protected AbstractLayoutCache.NodeDimensions createNodeDimensions() - { - // FIXME: not implemented + if (!cntlClick && tree.isEditable()) + startEditing(path, e); + } + } + } + + /** + * Invoked when a mouse button has been released on a component. + * + * @param e + * mouse event that occured + */ + public void mouseReleased(MouseEvent e) + { + } + + /** + * Invoked when the mouse enters a component. + * + * @param e + * mouse event that occured + */ + public void mouseEntered(MouseEvent e) + { + } + + /** + * Invoked when the mouse exits a component. + * + * @param e + * mouse event that occured + */ + public void mouseExited(MouseEvent e) + { + } + + /** + * Invoked when a mouse button is pressed on a component and then dragged. + * MOUSE_DRAGGED events will continue to be delivered to the component where + * 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 + */ + public void mouseDragged(MouseEvent e) + { + } + + /** + * Invoked when the mouse cursor has been moved onto a component but no + * buttons have been pushed. + * + * @param e + * mouse event that occured + */ + public void mouseMoved(MouseEvent e) + { + } + + /** + * Removes event from the source + */ + protected void removeFromSource() + { + } + }// MouseInputHandler + + /** + * Class responsible for getting size of node, method is forwarded to + * BasicTreeUI method. X location does not include insets, that is handled in + * getPathBounds. + */ + public class NodeDimensionsHandler + extends AbstractLayoutCache.NodeDimensions + { + /** + * Constructor + */ + public NodeDimensionsHandler() + { + } + + /** + * Responsible for getting the size of a particular node. + * + * @param value + * 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 value, int row, int depth, + boolean expanded, Rectangle size) + { return null; - } - - /** - * Creates a listener that is reponsible for the updates the UI based on how - * the tree changes. - * - * @return the PropertyChangeListener that is reposnsible for the updates - */ - protected PropertyChangeListener createPropertyChangeListener() - { - return new PropertyChangeHandler(); - } - - /** - * Creates the listener responsible for updating the selection based on mouse - * events. - * - * @return the MouseListener responsible for updating. - */ - protected MouseListener createMouseListener() - { - return new MouseHandler(); - } - - /** - * Creates the listener that is responsible for updating the display when - * focus is lost/grained. - * - * @return the FocusListener responsible for updating. - */ - protected FocusListener createFocusListener() - { - return new FocusHandler(); - } - - /** - * Creates the listener reponsible for getting key events from the tree. - * - * @return the KeyListener responsible for getting key events. - */ - protected KeyListener createKeyListener() - { - return new KeyHandler(); - } - - /** - * Creates the listener responsible for getting property change events from - * the selection model. - * - * @returns the PropertyChangeListener reponsible for getting property change - * events from the selection model. - */ - protected PropertyChangeListener createSelectionModelPropertyChangeListener() - { - return new SelectionModelPropertyChangeHandler(); - } - - /** - * Creates the listener that updates the display based on selection change - * methods. - * - * @return the TreeSelectionListener responsible for updating. - */ - protected TreeSelectionListener createTreeSelectionListener() - { - return new TreeSelectionHandler(); - } - - /** - * Creates a listener to handle events from the current editor - * - * @return the CellEditorListener that handles events from the current editor - */ - protected CellEditorListener createCellEditorListener() - { - return new CellEditorHandler(); - } - - /** - * Creates and returns a new ComponentHandler. This is used for the large - * model to mark the validCachedPreferredSize as invalid when the component - * moves. - * - * @return a new ComponentHandler. - */ - protected ComponentListener createComponentListener() - { - return new ComponentHandler(); - } - - /** - * Creates and returns the object responsible for updating the treestate when - * a nodes expanded state changes. - * - * @return the TreeExpansionListener responsible for updating the treestate - */ - protected TreeExpansionListener createTreeExpansionListener() - { - return new TreeExpansionHandler(); - } - - /** - * Creates the object responsible for managing what is expanded, as well as - * the size of nodes. - * - * @return the object responsible for managing what is expanded. - */ - protected AbstractLayoutCache createLayoutCache() - { - return new FixedHeightLayoutCache(); - } - - /** - * Returns the renderer pane that renderer components are placed in. - * - * @return the rendererpane that render components are placed in. - */ - protected CellRendererPane createCellRendererPane() - { - return new CellRendererPane(); - } - - /** - * Creates a default cell editor. - * - * @return the default cell editor. - */ - protected TreeCellEditor createDefaultCellEditor() - { - return new DefaultTreeCellEditor(tree, - (DefaultTreeCellRenderer) createDefaultCellRenderer(), cellEditor); - } - - /** - * Returns the default cell renderer that is used to do the stamping of each - * node. - * - * @return the default cell renderer that is used to do the stamping of each - * node. - */ - protected TreeCellRenderer createDefaultCellRenderer() - { - return new DefaultTreeCellRenderer(); - } - - /** - * Returns a listener that can update the tree when the model changes. - * - * @return a listener that can update the tree when the model changes. - */ - protected TreeModelListener createTreeModelListener() - { - return new TreeModelHandler(); - } - - /** - * Uninstall all registered listeners - */ - protected void uninstallListeners() - { - tree.removePropertyChangeListener(propertyChangeListener); - tree.removeFocusListener(focusListener); - tree.removeTreeSelectionListener(treeSelectionListener); - tree.removeMouseListener(mouseInputListener); - tree.removeKeyListener(keyListener); - tree.removePropertyChangeListener(selectionModelPropertyChangeListener); - tree.removeComponentListener(componentListener); - tree.getCellEditor().removeCellEditorListener(cellEditorListener); - tree.removeTreeExpansionListener(treeExpansionListener); - tree.getModel().removeTreeModelListener(treeModelListener); - } - - /** - * Uninstall all keyboard actions. - */ - protected void uninstallKeyboardActions() - { - } - - /** - * Uninstall the rendererPane. - */ - protected void uninstallComponents() - { - // FIXME: not implemented - } - - /** - * The vertical element of legs between nodes starts at the bottom of the - * parent node by default. This method makes the leg start below that. - * - * @return the vertical leg buffer - */ - protected int getVerticalLegBuffer() - { - // FIXME: not implemented - return 0; - } - - /** - * The horizontal element of legs between nodes starts at the right of the - * left-hand side of the child node by default. This method makes the leg end - * before that. - * - * @return the horizontal leg buffer - */ - protected int getHorizontalLegBuffer() - { - // FIXME: not implemented + } + + /** + * Returns the amount to indent the given row + * + * @return amount to indent the given row. + */ + protected int getRowX(int row, int depth) + { return 0; - } - - /** - * Make all the nodes that are expanded in JTree expanded in LayoutCache. - * This invokes update ExpandedDescendants with the root path. - */ - protected void updateLayoutCacheExpandedNodes() - { - // FIXME: not implemented - } - - /** - * Updates the expanded state of all the descendants of the <code>path</code> - * by getting the expanded descendants from the tree and forwarding to the - * tree state. - * - * @param path the path used to update the expanded states - */ - protected void updateExpandedDescendants(TreePath path) - { - // FIXME: not implemented - } - - /** - * Returns a path to the last child of <code>parent</code> - * - * @param parent is the topmost path to specified - * @return a path to the last child of parent - */ - protected TreePath getLastChildPath(TreePath parent) - { - return ((TreePath) parent.getLastPathComponent()); - } - - /** - * Updates how much each depth should be offset by. - */ - protected void updateDepthOffset() - { - // FIXME: not implemented - } - - /** - * Updates the cellEditor based on editability of the JTree that we're - * contained in. Ig the tree is editable but doesn't have a cellEditor, a - * basic one will be used. - */ - protected void updateCellEditor() - { - // FIXME: not implemented - } - - /** - * Messaged from the tree we're in when the renderer has changed. - */ - protected void updateRenderer() - { - // FIXME: not implemented - } - - /** - * Resets the treeState instance based on the tree we're providing the look - * and feel for. - */ - protected void configureLayoutCache() - { - treeState = createLayoutCache(); - } - - /** - * Marks the cached size as being invalid, and messages the tree with - * <code>treeDidChange</code>. - */ - protected void updateSize() - { - // FIXME: not implemented - } - - /** - * Updates the <code>preferredSize</code> instance variable, which is - * returned from <code>getPreferredSize()</code>. For left to right - * orientations, the size is determined from the current AbstractLayoutCache. - * For RTL orientations, the preferred size becomes the width minus the - * minimum x position. - */ - protected void updateCachedPreferredSize() - { - // FIXME: not implemented - } - - /** - * Messaged from the VisibleTreeNode after it has been expanded. - * - * @param path is the path that has been expanded. - */ - protected void pathWasExpanded(TreePath path) - { - // FIXME: not implemented - } - - /** - * Messaged from the VisibleTreeNode after it has collapsed - */ - protected void pathWasCollapsed(TreePath path) - { - // FIXME: not implemented - } - - /** - * Install all defaults for the tree. - * - * @param tree is the JTree to install defaults for - */ - protected void installDefaults(JTree tree) - { - UIDefaults defaults = UIManager.getLookAndFeelDefaults(); - - tree.setFont(defaults.getFont("Tree.font")); - tree.setForeground(defaults.getColor("Tree.foreground")); - tree.setBackground(defaults.getColor("Tree.background")); - tree.setOpaque(true); - - rightChildIndent = defaults.getInt("Tree.rightChildIndent"); - leftChildIndent = defaults.getInt("Tree.leftChildIndent"); - setRowHeight(defaults.getInt("Tree.rowHeight")); - } - - /** - * Install all keyboard actions for this - */ - protected void installKeyboardActions() - { - } - - /** - * Install all listeners for this - */ - protected void installListeners() - { - tree.addPropertyChangeListener(propertyChangeListener); - tree.addFocusListener(focusListener); - tree.addTreeSelectionListener(treeSelectionListener); - tree.addMouseListener(mouseInputListener); - tree.addKeyListener(keyListener); - tree.addPropertyChangeListener(selectionModelPropertyChangeListener); - tree.addComponentListener(componentListener); - cellEditor.addCellEditorListener(cellEditorListener); - tree.addTreeExpansionListener(treeExpansionListener); - treeModel.addTreeModelListener(treeModelListener); - } - - /** - * Install the UI for the component - * - * @param c the component to install UI for - */ - public void installUI(JComponent c) - { - super.installUI(c); - installDefaults((JTree) c); - tree = (JTree) c; - setModel(tree.getModel()); - tree.setRootVisible(true); - tree.expandPath(new TreePath(((DefaultMutableTreeNode) - (tree.getModel()).getRoot()).getPath())); - treeSelectionModel = tree.getSelectionModel(); - installListeners(); - installKeyboardActions(); - completeUIInstall(); - } - - /** - * Uninstall the defaults for the tree - * - * @param tree to uninstall defaults for - */ - protected void uninstallDefaults(JTree tree) - { - UIDefaults defaults = UIManager.getLookAndFeelDefaults(); - tree.setFont(null); - tree.setForeground(null); - tree.setBackground(null); - tree.setCellRenderer(null); - } - - /** - * Uninstall the UI for the component - * - * @param c the component to uninstall UI for - */ - public void uninstallUI(JComponent c) - { - uninstallDefaults((JTree) c); - uninstallKeyboardActions(); - uninstallListeners(); - tree = null; - completeUIUninstall(); - } - - /** - * Paints the specified component appropriate for the look and feel. This - * method is invoked from the ComponentUI.update method when the specified - * 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 - * 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; - TreeModel mod = tree.getModel(); - g.translate(10, 10); - paintRecursive(g, 0, 0, 0, 0, tree, mod, mod.getRoot()); - paintControlIcons(g, 0, 0, 0, 0, tree, mod, mod.getRoot()); - g.translate(-10, -10); - } - - /** - * Ensures that the rows identified by beginRow through endRow are visible. - * - * @param beginRow is the first row - * @param endRow is the last row - */ - protected void ensureRowsAreVisible(int beginRow, int endRow) - { - // FIXME: not implemented - } - - /** - * Sets the preferred minimum size. - * - * @param newSize is the new preferred minimum size. - */ - public void setPreferredMinSize(Dimension newSize) - { - // FIXME: not implemented - } - - /** - * Gets the preferred minimum size. - * - * @returns the preferred minimum size. - */ - public Dimension getPreferredMinSize() - { - // FIXME: not implemented - return null; - } - - /** - * 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 is often ignored but might be used if the UI object is - * stateless and shared by multiple components - * @return the preferred size - */ - public Dimension getPreferredSize(JComponent c) - { - return getPreferredSize(c, false); - } - - /** - * 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 - * @return the preferred size - */ - public Dimension getPreferredSize(JComponent c, boolean checkConsistancy) - { - // FIXME: checkConsistancy not implemented, c not used - DefaultMutableTreeNode node = ((DefaultMutableTreeNode) (tree.getModel()) - .getRoot()); - int maxWidth = 0; - int count = 0; - if (node != null) - { - maxWidth = (int) (getCellBounds(0, 0, node).getWidth()); - while (node != null) - { - count++; - DefaultMutableTreeNode nextNode = node.getNextNode(); - if (nextNode != null) - maxWidth = Math.max(maxWidth, (int) (getCellBounds(0, 0, nextNode) - .getWidth())); - node = nextNode; - } - } - - return new Dimension(maxWidth, (getRowHeight() * count)); - } - - /** - * 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. - * @returns the preferred size or null - */ - public Dimension getMinimumSize(JComponent c) - { - // FIXME: not implemented - return 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 - * @return the max size or null - */ - public Dimension getMaximumSize(JComponent c) - { - // FIXME: not implemented - return getPreferredSize(c); - } - - /** - * Messages to stop the editing session. If the UI the receiver is providing - * the look and feel for returns true from - * <code>getInvokesStopCellEditing</code>, stopCellEditing will be invoked - * on the current editor. Then completeEditing will be messaged with false, - * true, false to cancel any lingering editing. - */ - protected void completeEditing() - { - // FIXME: not implemented - } - - /** - * Stops the editing session. If messageStop is true, the editor is messaged - * with stopEditing, if messageCancel is true the editor is messaged with - * 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 - */ - protected void completeEditing(boolean messageStop, boolean messageCancel, - boolean messageTree) - { - // FIXME: not implemented - } - - /** - * 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 - * @return true if successful - */ - protected boolean startEditing(TreePath path, MouseEvent event) - { - // FIXME: not implemented + } + }// NodeDimensionsHandler + + /** + * PropertyChangeListener for the tree. Updates the appropriate varaible, or + * TreeState, based on what changes. + */ + public class PropertyChangeHandler + implements PropertyChangeListener + { + + /** + * Constructor + */ + public PropertyChangeHandler() + { + } + + /** + * 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. + */ + public void propertyChange(PropertyChangeEvent event) + { + } + }// PropertyChangeHandler + + /** + * Listener on the TreeSelectionModel, resets the row selection if any of the + * properties of the model change. + */ + public class SelectionModelPropertyChangeHandler + implements PropertyChangeListener + { + + /** + * Constructor + */ + public SelectionModelPropertyChangeHandler() + { + } + + /** + * 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. + */ + public void propertyChange(PropertyChangeEvent event) + { + } + }// SelectionModelPropertyChangeHandler + + /** + * ActionListener that invokes cancelEditing when action performed. + */ + public class TreeCancelEditingAction + extends AbstractAction + { + + /** + * Constructor + */ + public TreeCancelEditingAction() + { + } + + /** + * Invoked when an action occurs. + * + * @param e + * event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled, false otherwise + */ + public boolean isEnabled() + { return false; - } - - /** - * 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 - */ - protected void checkForClickInExpandControl(TreePath path, int mouseX, - int mouseY) - { - // FIXME: not implemented - } - - /** - * Returns 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. - * - * @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. - */ - protected boolean isLocationInExpandControl(TreePath path, int mouseX, - int mouseY) - { - // FIXME: not implemented + } + }// TreeCancelEditingAction + + /** + * Updates the TreeState in response to nodes expanding/collapsing. + */ + public class TreeExpansionHandler + implements TreeExpansionListener + { + + /** + * Constructor + */ + public TreeExpansionHandler() + { + } + + /** + * Called whenever an item in the tree has been expanded. + * + * @param event + * is the event that occured + */ + public void treeExpanded(TreeExpansionEvent event) + { + tree.repaint(); + } + + /** + * Called whenever an item in the tree has been collapsed. + * + * @param event + * is the event that occured + */ + public void treeCollapsed(TreeExpansionEvent event) + { + tree.repaint(); + } + }// TreeExpansionHandler + + /** + * 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 + { + + /** direction is either home or end */ + protected int direction; + + /** + * Constructor + * + * @param direction - + * it is home or end + * @param name + * is the name of the direction + */ + public TreeHomeAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e + * is the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled. + */ + public boolean isEnabled() + { return false; - } - - /** - * 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 - */ - protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY) - { - // FIXME: not implemented - } - - /** - * Expands path if it is not expanded, or collapses row if it is expanded. If - * expanding a path and JTree scroll on expand, ensureRowsAreVisible is - * 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 - */ - protected void toggleExpandState(TreePath path) - { - // FIXME: not implemented - } - - /** - * Returning true signifies a mouse event on the node should toggle the - * selection of only the row under the mouse. - * - * @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) - { - // FIXME: not implemented - return false; - } - - /** - * Returning true signifies a mouse event on the node should select from the - * anchor point. - * - * @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) - { - // FIXME: not implemented - return false; - } - - /** - * Returning true indicates the row under the mouse should be toggled based - * on 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. - * @return true indicates the row under the mouse should be toggled based on - * the event. - */ - protected boolean isToggleEvent(MouseEvent event) - { - // FIXME: not implemented - return false; - } - - /** - * Messaged to update the selection based on a MouseEvent over a particular - * 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. - * - * @param path is the path selected for an event - * @param event is the MouseEvent performed on the path. - */ - protected void selectPathForEvent(TreePath path, MouseEvent event) - { - // FIXME: not implemented - } - - /** - * Returns true if the node at <code>row</code> is a leaf. - * - * @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) - { - TreePath pathForRow = getPathForRow(tree, row); - if (pathForRow == null) - return true; - - Object node = pathForRow.getLastPathComponent(); - - if (node instanceof TreeNode) - return ((TreeNode) node).isLeaf(); - else - return true; - } - - /** - * 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 - */ - void selectPath(JTree tree, TreePath path) - { - if (path != null) - { - if (tree.isPathSelected(path)) - tree.removeSelectionPath(path); - else 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.getSelectionModel().setSelectionMode( - TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); - tree.addSelectionPath(path); - tree.setLeadSelectionPath(path); - } - } - } - - /* * INTERNAL CLASSES * */ - - /** - * Updates the preferred size when scrolling, if necessary. - */ - public class ComponentHandler - extends ComponentAdapter - implements ActionListener - { - /** - * Timer used when inside a scrollpane and the scrollbar is adjusting - */ - protected Timer timer; - - /** ScrollBar that is being adjusted */ - protected JScrollBar scrollBar; - - /** - * Constructor - */ - public ComponentHandler() - { - } - - /** - * Invoked when the component's position changes. - * - * @param e the event that occurs when moving the component - */ - public void componentMoved(ComponentEvent e) - { - } - - /** - * Creats, if necessary, and starts a Timer to check if needed to resize - * the bounds - */ - protected void startTimer() - { - } - - /** - * Returns the JScrollPane housing the JTree, or null if one isn't found. - * - * @return JScrollPane housing the JTree, or null if one isn't found. - */ - protected JScrollPane getScrollPane() - { - return null; - } - - /** - * 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 - */ - public void actionPerformed(ActionEvent ae) - { - } - }// ComponentHandler - - /** - * Listener responsible for getting cell editing events and updating the tree - * accordingly. - */ - public class CellEditorHandler - implements CellEditorListener - { - /** - * Constructor - */ - public CellEditorHandler() - { - } - - /** - * Messaged when editing has stopped in the tree. Tells the listeners - * editing has stopped. - * - * @param e is the notification event - */ - public void editingStopped(ChangeEvent e) - { - } - - /** - * Messaged when editing has been canceled in the tree. This tells the - * listeners the editor has canceled editing. - * - * @param e is the notification event - */ - public void editingCanceled(ChangeEvent e) - { - } - }// CellEditorHandler - - /** - * Repaints the lead selection row when focus is lost/grained. - */ - public class FocusHandler - implements FocusListener - { - /** - * Constructor - */ - public FocusHandler() - { - } - - /** - * Invoked when focus is activated on the tree we're in, redraws the lead - * row. Invoked when a component gains the keyboard focus. - * - * @param e is the focus event that is activated - */ - public void focusGained(FocusEvent e) - { - } - - /** - * Invoked when focus is deactivated on the tree we're in, redraws the - * lead row. Invoked when a component loses the keyboard focus. - * - * @param e is the focus event that is deactivated - */ - public void focusLost(FocusEvent e) - { - } - }// FocusHandler - - /** - * This is used to get multiple key down events to appropriately genereate - * events. - */ - public class KeyHandler - extends KeyAdapter - { - /** Key code that is being generated for. */ - protected Action repeatKeyAction; - - /** Set to true while keyPressed is active */ - protected boolean isKeyDown; - - /** - * Constructor - */ - public KeyHandler() - { - } - - /** - * Invoked when a key has been typed. Moves the keyboard focus to the - * first element whose first letter matches the alphanumeric key pressed - * by the user. Subsequent same key presses move the keyboard focus to the - * next object that starts with the same letter. - * - * @param e the key typed - */ - public void keyTyped(KeyEvent e) - { - } - - /** - * Invoked when a key has been pressed. - * - * @param e the key pressed - */ - public void keyPressed(KeyEvent e) - { - TreePath start = BasicTreeUI.this.tree.getLeadSelectionPath(); - DefaultMutableTreeNode last = null; - - if (start != null) - last = (DefaultMutableTreeNode) start.getLastPathComponent(); - if (last != null) - { - if (e.getKeyCode() == KeyEvent.VK_DOWN) + } + }// TreeHomeAction + + /** + * TreeIncrementAction is used to handle up/down actions. Selection is moved + * up or down based on direction. + */ + public class TreeIncrementAction + extends AbstractAction + { + + /** Specifies the direction to adjust the selection by. */ + protected int direction; + + /** + * Constructor + * + * @param direction + * up or down + * @param name + * is the name of the direction + */ + public TreeIncrementAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e + * is the event that occured + */ + public void actionPerformed(ActionEvent e) + { + Object last = tree.getLeadSelectionPath().getLastPathComponent(); + + if (e.getActionCommand().equals("selectPreviousChangeLead")) + { + Object prev = getPreviousVisibleNode(last); + + if (prev != null) { - DefaultMutableTreeNode next = (DefaultMutableTreeNode) - BasicTreeUI.this.getNextVisibleNode(last); - - if (next != null) - BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, - new TreePath(next.getPath())); + TreePath newPath = new TreePath(getPathToRoot(prev, 0)); + selectPath(tree, new TreePath(getPathToRoot(prev, 0))); + tree.setLeadSelectionPath(newPath); } - else if (e.getKeyCode() == KeyEvent.VK_UP) + } + else if (e.getActionCommand().equals("selectPreviousExtendSelection")) + { + Object prev = getPreviousVisibleNode(last); + if (prev != null) { - DefaultMutableTreeNode prev = (DefaultMutableTreeNode) - BasicTreeUI.this.getPreviousVisibleNode(last); - - if (prev != null) - BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, - new TreePath(prev.getPath())); + TreePath newPath = new TreePath(getPathToRoot(prev, 0)); + tree.addSelectionPath(newPath); + tree.setLeadSelectionPath(newPath); } - else if (e.getKeyCode() == KeyEvent.VK_LEFT) + } + else if (e.getActionCommand().equals("selectPrevious")) + { + Object prev = getPreviousVisibleNode(last); + if (prev != null) { - TreePath path = new TreePath(last.getPath()); - - if (!last.isLeaf() && BasicTreeUI.this.tree.isExpanded(path)) - { - BasicTreeUI.this.tree.collapsePath(path); - BasicTreeUI.this.tree.fireTreeCollapsed(path); - } + TreePath newPath = new TreePath(getPathToRoot(prev, 0)); + selectPath(tree, new TreePath(getPathToRoot(prev, 0))); } - else if (e.getKeyCode() == KeyEvent.VK_RIGHT) + } + else if (e.getActionCommand().equals("selectNext")) + { + Object next = getNextVisibleNode(last); + if (next != null) { - TreePath path = new TreePath(last.getPath()); - - if (!last.isLeaf() && BasicTreeUI.this.tree.isCollapsed(path)) - { - BasicTreeUI.this.tree.expandPath(path); - BasicTreeUI.this.tree.fireTreeExpanded(path); - } + TreePath newPath = new TreePath(getPathToRoot(next, 0)); + selectPath(tree, newPath); } - } - } - - /** - * Invoked when a key has been released - * - * @param e the key released - */ - public void keyReleased(KeyEvent e) - { - } - }// KeyHandler - - /** - * MouseListener is responsible for updating the selevtion based on mouse - * events. - */ - public class MouseHandler - extends MouseAdapter - implements MouseMotionListener - { - /** - * Constructor - */ - public MouseHandler() - { - } - - /** - * Invoked when a mouse button has been pressed on a component. - * - * @param e is the mouse event that occured - */ - public void mousePressed(MouseEvent e) - { - } - - /** - * Invoked when a mouse button is pressed on a component and then dragged. - * MOUSE_DRAGGED events will continue to be delivered to the component - * where 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 - */ - public void mouseDragged(MouseEvent e) - { - } - - /** - * Invoked when the mouse button has been moved on a component (with no - * buttons no down). - * - * @param e the mouse event that occured - */ - public void mouseMoved(MouseEvent e) - { - } - - /** - * Invoked when a mouse button has been released on a component. - * - * @param e is the mouse event that occured - */ - public void mouseReleased(MouseEvent e) - { - } - }// MouseHandler - - /** - * MouseInputHandler handles passing all mouse events, including mouse motion - * events, until the mouse is released to the destination it is constructed - * with. - */ - public class MouseInputHandler - implements MouseInputListener - { - /** Source that events are coming from */ - protected Component source; - - /** Destination that receives all events. */ - protected Component destination; - - /** Number of mouse clicks on a non-leaf */ - private int clickCount = 0; - - /** - * Constructor - * - * @param source that events are coming from - * @param destination that receives all events - * @param event is the event received - */ - public MouseInputHandler(Component source, Component destination, - MouseEvent e) - { - } - - /** - * Invoked when the mouse button has been clicked (pressed and released) - * on a component. - * - * @param e mouse event that occured - */ - public void mouseClicked(MouseEvent e) - { - Point click = e.getPoint(); - int clickX = (int) click.getX(); - int clickY = (int) click.getY(); - int row = (clickY / getRowHeight()) - 1; - TreePath path = BasicTreeUI.this.tree.getPathForRow(row); - - boolean inBounds = false; - boolean cntlClick = false; - Rectangle bounds = BasicTreeUI.this.getPathBounds( - BasicTreeUI.this.tree, path); - int x = (int) bounds.getX(); - int y = (int) bounds.getY(); - - if (clickY > y && clickY < (y + bounds.height + 10)) - { - if (clickX > x && clickX < (x + bounds.width + 20)) - inBounds = true; - else if (clickX < (x - rightChildIndent + 5) && - clickX > (x - rightChildIndent - 5)) - cntlClick = true; - } - - if ((inBounds || cntlClick) && path != null && - BasicTreeUI.this.tree.isVisible(path)) - { - if (!cntlClick && !BasicTreeUI.this.isLeaf(row)) - clickCount++; - - if (clickCount == 2 || cntlClick == true) + } + else if (e.getActionCommand().equals("selectNextExtendSelection")) + { + Object next = getNextVisibleNode(last); + if (next != null) { - clickCount = 0; - BasicTreeUI.this.tree.getSelectionModel().clearSelection(); - if (BasicTreeUI.this.tree.isExpanded(path)) - { - BasicTreeUI.this.tree.collapsePath(path); - BasicTreeUI.this.tree.fireTreeCollapsed(path); - } - else - { - BasicTreeUI.this.tree.expandPath(path); - BasicTreeUI.this.tree.fireTreeExpanded(path); - } + TreePath newPath = new TreePath(getPathToRoot(next, 0)); + tree.addSelectionPath(newPath); + tree.setLeadSelectionPath(newPath); } - - BasicTreeUI.this.selectPath(BasicTreeUI.this.tree, path); - } - } - - /** - * Invoked when a mouse button has been pressed on a component. - * - * @param e mouse event that occured - */ - public void mousePressed(MouseEvent e) - { - } - - /** - * Invoked when a mouse button has been released on a component. - * - * @param e mouse event that occured - */ - public void mouseReleased(MouseEvent e) - { - } - - /** - * Invoked when the mouse enters a component. - * - * @param e mouse event that occured - */ - public void mouseEntered(MouseEvent e) - { - } - - /** - * Invoked when the mouse exits a component. - * - * @param e mouse event that occured - */ - public void mouseExited(MouseEvent e) - { - } - - /** - * Invoked when a mouse button is pressed on a component and then dragged. - * MOUSE_DRAGGED events will continue to be delivered to the component - * where 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 - */ - public void mouseDragged(MouseEvent e) - { - } - - /** - * Invoked when the mouse cursor has been moved onto a component but no - * buttons have been pushed. - * - * @param e mouse event that occured - */ - public void mouseMoved(MouseEvent e) - { - } - - /** - * Removes event from the source - */ - protected void removeFromSource() - { - } - }// MouseInputHandler - - /** - * Class responsible for getting size of node, method is forwarded to - * BasicTreeUI method. X location does not include insets, that is handled in - * getPathBounds. - */ - public class NodeDimensionsHandler - extends AbstractLayoutCache.NodeDimensions - { - /** - * Constructor - */ - public NodeDimensionsHandler() - { - } - - /** - * Responsible for getting the size of a particular node. - * - * @param value 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 value, int row, int depth, - boolean expanded, Rectangle size) - { - return null; - } - - /** - * Returns the amount to indent the given row - * - * @return amount to indent the given row. - */ - protected int getRowX(int row, int depth) - { - return 0; - } - }// NodeDimensionsHandler - - /** - * PropertyChangeListener for the tree. Updates the appropriate varaible, or - * TreeState, based on what changes. - */ - public class PropertyChangeHandler - implements PropertyChangeListener - { - - /** - * Constructor - */ - public PropertyChangeHandler() - { - } - - /** - * 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. - */ - public void propertyChange(PropertyChangeEvent event) - { - } - }// PropertyChangeHandler - - /** - * Listener on the TreeSelectionModel, resets the row selection if any of the - * properties of the model change. - */ - public class SelectionModelPropertyChangeHandler - implements PropertyChangeListener - { - - /** - * Constructor - */ - public SelectionModelPropertyChangeHandler() - { - } - - /** - * 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. - */ - public void propertyChange(PropertyChangeEvent event) - { - } - }// SelectionModelPropertyChangeHandler - - /** - * ActionListener that invokes cancelEditing when action performed. - */ - public class TreeCancelEditingAction - extends AbstractAction - { - - /** - * Constructor - */ - public TreeCancelEditingAction() - { - } - - /** - * Invoked when an action occurs. - * - * @param e event that occured - */ - public void actionPerformed(ActionEvent e) - { - } - - /** - * Returns true if the action is enabled. - * - * @return true if the action is enabled, false otherwise - */ - public boolean isEnabled() - { - return false; - } - }// TreeCancelEditingAction - - /** - * Updates the TreeState in response to nodes expanding/collapsing. - */ - public class TreeExpansionHandler - implements TreeExpansionListener - { - - /** - * Constructor - */ - public TreeExpansionHandler() - { - } - - /** - * Called whenever an item in the tree has been expanded. - * - * @param event is the event that occured - */ - public void treeExpanded(TreeExpansionEvent event) - { - BasicTreeUI.this.tree.repaint(); - } - - /** - * Called whenever an item in the tree has been collapsed. - * - * @param event is the event that occured - */ - public void treeCollapsed(TreeExpansionEvent event) - { - BasicTreeUI.this.tree.repaint(); - } - }// TreeExpansionHandler - - /** - * 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 - { - - /** direction is either home or end */ - protected int direction; - - /** - * Constructor - * - * @param direction - it is home or end - * @param name is the name of the direction - */ - public TreeHomeAction(int direction, String name) - { - } - - /** - * Invoked when an action occurs. - * - * @param e is the event that occured - */ - public void actionPerformed(ActionEvent e) - { - } + } + else if (e.getActionCommand().equals("selectNextChangeLead")) + { + Object next = getNextVisibleNode(last); + if (next != null) + { + TreePath newPath = new TreePath(getPathToRoot(next, 0)); + selectPath(tree, newPath); + tree.setLeadSelectionPath(newPath); + } + } + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled. + */ + public boolean isEnabled() + { + return false; + } + }// TreeIncrementAction + + /** + * Forwards all TreeModel events to the TreeState. + */ + public class TreeModelHandler + implements TreeModelListener + { + /** + * Constructor + */ + public TreeModelHandler() + { + } + + /** + * Invoked after a node (or a set of siblings) has changed in some way. The + * node(s) have not changed locations in the tree or altered their children + * arrays, but other attributes have changed and may affect presentation. + * Example: the name of a file has changed, but it is in the same location + * in the file system. To indicate the root has changed, childIndices and + * children will be null. Use e.getPath() to get the parent of the changed + * node(s). e.getChildIndices() returns the index(es) of the changed + * node(s). + * + * @param e + * is the event that occured + */ + public void treeNodesChanged(TreeModelEvent e) + { + tree.repaint(); + } + + /** + * Invoked after nodes have been inserted into the tree. Use e.getPath() to + * 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 + */ + public void treeNodesInserted(TreeModelEvent e) + { + tree.repaint(); + } + + /** + * Invoked after nodes have been removed from the tree. Note that if a + * subtree is removed from the tree, this method may only be invoked once + * for the root of the removed subtree, not once for each individual set of + * siblings removed. Use e.getPath() to get the former parent of the deleted + * 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 + */ + public void treeNodesRemoved(TreeModelEvent e) + { + tree.repaint(); + } + + /** + * Invoked after the tree has drastically changed structure from a given + * node down. If the path returned by e.getPath() is of length one and the + * first element does not identify the current root node the first element + * 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 + */ + public void treeStructureChanged(TreeModelEvent e) + { + tree.repaint(); + } + }// TreeModelHandler + + /** + * TreePageAction handles page up and page down events. + */ + public class TreePageAction + extends AbstractAction + { + /** Specifies the direction to adjust the selection by. */ + protected int direction; + + /** + * Constructor + * + * @param direction + * up or down + * @param name + * is the name of the direction + */ + public TreePageAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e + * is the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled. + */ + public boolean isEnabled() + { + return false; + } + }// TreePageAction + + /** + * Listens for changes in the selection model and updates the display + * accordingly. + */ + public class TreeSelectionHandler + implements TreeSelectionListener + { + /** + * Constructor + */ + public TreeSelectionHandler() + { + } + + /** + * 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. + */ + public void valueChanged(TreeSelectionEvent event) + { + if (tree.isEditing()) + tree.cancelEditing(); + } + }// TreeSelectionHandler + + /** + * For the first selected row expandedness will be toggled. + */ + public class TreeToggleAction + extends AbstractAction + { + /** + * Constructor + * + * @param name + * is the name of <code>Action</code> field + */ + public TreeToggleAction(String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e + * the event that occured + */ + public void actionPerformed(ActionEvent e) + { + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled, false otherwise + */ + public boolean isEnabled() + { + return false; + } + } // TreeToggleAction + + /** + * 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 + { + /** + * Determines direction to traverse, 1 means expand, -1 means collapse. + */ + protected int direction; + + /** + * Constructor + * + * @param direction + * to traverse + * @param name + * is the name of the direction + */ + public TreeTraverseAction(int direction, String name) + { + } + + /** + * Invoked when an action occurs. + * + * @param e + * the event that occured + */ + public void actionPerformed(ActionEvent e) + { + TreeModel mod = tree.getModel(); + Object last = tree.getLeadSelectionPath().getLastPathComponent(); + + if (e.getActionCommand().equals("selectParent")) + { + TreePath path = new TreePath(getPathToRoot(last, 0)); + Object p = getParent(mod.getRoot(), last); + + if (!mod.isLeaf(last) && tree.isExpanded(path)) + tree.collapsePath(path); + else if (p != null) + selectPath(tree, new TreePath(getPathToRoot(p, 0))); + } + else if (e.getActionCommand().equals("selectChild")) + { + TreePath path = new TreePath(getPathToRoot(last, 0)); + + if (!mod.isLeaf(last) && tree.isCollapsed(path)) + tree.expandPath(path); + else + { + Object next = getNextVisibleNode(last); - /** - * Returns true if the action is enabled. - * - * @return true if the action is enabled. - */ - public boolean isEnabled() - { - return false; - } - }// TreeHomeAction - - /** - * TreeIncrementAction is used to handle up/down actions. Selection is moved - * up or down based on direction. - */ - public class TreeIncrementAction - extends AbstractAction - { - - /** Specifies the direction to adjust the selection by. */ - protected int direction; - - /** - * Constructor - * - * @param direction up or down - * @param name is the name of the direction - */ - public TreeIncrementAction(int direction, String name) - { - } + if (next != null) + selectPath(tree, new TreePath(getPathToRoot(next, 0))); + } + } + } + + /** + * Returns true if the action is enabled. + * + * @return true if the action is enabled, false otherwise + */ + public boolean isEnabled() + { + return false; + } + } // TreeTraverseAction + + /** + * Returns the cell bounds for painting selected cells Package private for use + * in inner classes. + * + * @param x + * is the x location of the cell + * @param y + * is the y location of the cell + * @param cell + * is the Object to get the bounds for + * @returns Rectangle that represents the cell bounds + */ + Rectangle getCellBounds(int x, int y, Object cell) + { + if (cell != null) + { + String s = cell.toString(); + Font f = tree.getFont(); + FontMetrics fm = tree.getToolkit().getFontMetrics(f); + + if (s != null) + return new Rectangle(x, y, + SwingUtilities.computeStringWidth(fm, s) + 4, + fm.getHeight()); + } + return new Rectangle(x, y, 0, 0); + } + + /** + * Retrieves the location of some node, recursively starting at from some + * node. Package private for use in inner classes. + * + * @param x + * is the starting x position, offset + * @param y + * is the starting y position, offset + * @param tree + * is the tree to traverse + * @param mod + * is the TreeModel to use + * @param node + * is the node to get the location for + * @param startNode + * is the node to start searching from + * @return Point - the location of node + */ + Point getCellLocation(int x, int y, JTree tree, TreeModel mod, Object node, + Object startNode) + { + int rowHeight = getRowHeight(); + if (startNode == null || startNode.equals(node)) + { + if (!tree.isRootVisible() + && tree.isExpanded(new TreePath(mod.getRoot()))) + return new Point(x + ((getLevel(node)) * rightChildIndent), y); + + return new Point(x + ((getLevel(node) + 1) * rightChildIndent), y); + } + + if (!mod.isLeaf(startNode) + && tree.isExpanded(new TreePath(getPathToRoot(startNode, 0))) + && !mod.isLeaf(startNode) && mod.getChildCount(startNode) > 0) + { + Object child = mod.getChild(startNode, 0); + if (child != null) + return getCellLocation(x, y + rowHeight, tree, mod, node, child); + } + + return getCellLocation(x, y + rowHeight, tree, mod, node, + getNextVisibleNode(startNode)); + } + + /** + * Paints a node in the tree Package private for use in inner classes. + * + * @param g + * the Graphics context in which to paint + * @param x + * the x location of the node + * @param y + * the y location of the node + * @param tree + * the tree to draw on + * @param node + * the object to draw + */ + void paintNode(Graphics g, int x, int y, JTree tree, Object node, + boolean isLeaf) + { + TreePath curr = new TreePath(getPathToRoot(node, 0)); + boolean selected = tree.isPathSelected(curr); + boolean expanded = false; + boolean hasIcons = false; + + if (tree.isVisible(curr)) + { + if (!isLeaf) + expanded = tree.isExpanded(curr); + + if (editingComponent != null && editingPath != null && isEditing(tree) + && node.equals(editingPath.getLastPathComponent())) + { + Rectangle bounds = getPathBounds(tree, editingPath); + rendererPane.paintComponent(g, editingComponent.getParent(), null, + new Rectangle(0, 0, bounds.width, + bounds.height)); + } + else + { + TreeCellRenderer dtcr = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + int row = getRowForPath(tree, curr); + + Component c = dtcr.getTreeCellRendererComponent(tree, node, + selected, expanded, + isLeaf, row, false); + + rendererPane.paintComponent(g, c, c.getParent(), + getCellBounds(x, y, node)); + } + } + } + + /** + * Recursively paints all elements of the tree Package private for use in + * inner classes. + * + * @param g + * the Graphics context in which to paint + * @param indentation + * of the current object + * @param descent + * is the number of elements drawn + * @param childNumber + * is the index of the current child in the tree + * @param depth + * is the depth of the current object in the tree + * @param tree + * is the tree to draw to + * @param mod + * is the TreeModel we are using to draw + * @param curr + * is the current object to draw + * @return int - current descent of the tree + */ + int paintRecursive(Graphics g, int indentation, int descent, int childNumber, + int depth, JTree tree, TreeModel mod, Object curr) + { + Rectangle clip = g.getClipBounds(); + if (indentation > clip.x + clip.width + rightChildIndent + || descent > clip.y + clip.height + getRowHeight()) + return descent; - /** - * Invoked when an action occurs. - * - * @param e is the event that occured - */ - public void actionPerformed(ActionEvent e) - { - } + int halfHeight = getRowHeight() / 2; + int halfWidth = rightChildIndent / 2; + int y0 = descent + halfHeight; + int heightOfLine = descent + halfHeight; + boolean isRootVisible = tree.isRootVisible(); - /** - * Returns true if the action is enabled. - * - * @return true if the action is enabled. - */ - public boolean isEnabled() - { - return false; - } - }// TreeIncrementAction - - /** - * Forwards all TreeModel events to the TreeState. - */ - public class TreeModelHandler - implements TreeModelListener - { - /** - * Constructor - */ - public TreeModelHandler() + if (mod.isLeaf(curr)) { + paintNode(g, indentation + 4, descent, tree, curr, true); + descent += getRowHeight(); } - - /** - * Invoked after a node (or a set of siblings) has changed in some way. - * The node(s) have not changed locations in the tree or altered their - * children arrays, but other attributes have changed and may affect - * presentation. Example: the name of a file has changed, but it is in the - * same location in the file system. To indicate the root has changed, - * childIndices and children will be null. Use e.getPath() to get the - * parent of the changed node(s). e.getChildIndices() returns the - * index(es) of the changed node(s). - * - * @param e is the event that occured - */ - public void treeNodesChanged(TreeModelEvent e) + else { - } + if (depth > 0 || isRootVisible) + { + paintNode(g, indentation + 4, descent, tree, curr, false); + descent += getRowHeight(); + y0 += halfHeight; + } + + int max = 0; + if (!mod.isLeaf(curr)) + max = mod.getChildCount(curr); + if (tree.isExpanded(new TreePath(getPathToRoot(curr, 0)))) + { + for (int i = 0; i < max; i++) + { + int indent = indentation + rightChildIndent; + if (!isRootVisible && depth == 0) + indent = 0; + else if ((!isRootVisible && !curr.equals(mod.getRoot())) + || isRootVisible) + { + g.setColor(getHashColor()); + heightOfLine = descent + halfHeight; + g.drawLine(indentation + halfWidth, heightOfLine, + indentation + rightChildIndent, heightOfLine); + } - /** - * Invoked after nodes have been inserted into the tree. Use e.getPath() - * to 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 - */ - public void treeNodesInserted(TreeModelEvent e) - { - } + descent = paintRecursive(g, indent, descent, i, depth + 1, + tree, mod, mod.getChild(curr, i)); + } + } + } + + if (tree.isExpanded(new TreePath(getPathToRoot(curr, 0)))) + if (y0 != heightOfLine && !mod.isLeaf(curr) + && mod.getChildCount(curr) > 0) + { + g.setColor(getHashColor()); + g.drawLine(indentation + halfWidth, y0, indentation + halfWidth, + heightOfLine); + } + + return descent; + } + + /** + * Recursively paints all the control icons on the tree. Package private for + * use in inner classes. + * + * @param g + * the Graphics context in which to paint + * @param indentation + * of the current object + * @param descent + * is the number of elements drawn + * @param childNumber + * is the index of the current child in the tree + * @param depth + * is the depth of the current object in the tree + * @param tree + * is the tree to draw to + * @param mod + * is the TreeModel we are using to draw + * @param curr + * is the current object to draw + * @return int - current descent of the tree + */ + int paintControlIcons(Graphics g, int indentation, int descent, + int childNumber, int depth, JTree tree, TreeModel mod, + Object node) + { + int h = descent; + int rowHeight = getRowHeight(); + Icon ei = UIManager.getLookAndFeelDefaults().getIcon("Tree.expandedIcon"); + Icon ci = UIManager.getLookAndFeelDefaults().getIcon("Tree.collapsedIcon"); + Rectangle clip = g.getClipBounds(); + if (indentation > clip.x + clip.width + rightChildIndent + || descent > clip.y + clip.height + getRowHeight()) + return descent; - /** - * Invoked after nodes have been removed from the tree. Note that if a - * subtree is removed from the tree, this method may only be invoked once - * for the root of the removed subtree, not once for each individual set - * of siblings removed. Use e.getPath() to get the former parent of the - * deleted 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 - */ - public void treeNodesRemoved(TreeModelEvent e) + if (mod.isLeaf(node)) + descent += rowHeight; + else { - } + if (depth > 0 || tree.isRootVisible()) + descent += rowHeight; - /** - * Invoked after the tree has drastically changed structure from a given - * node down. If the path returned by e.getPath() is of length one and the - * first element does not identify the current root node the first element - * 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 - */ - public void treeStructureChanged(TreeModelEvent e) - { - } - }// TreeModelHandler - - /** - * TreePageAction handles page up and page down events. - */ - public class TreePageAction - extends AbstractAction - { - /** Specifies the direction to adjust the selection by. */ - protected int direction; - - /** - * Constructor - * - * @param direction up or down - * @param name is the name of the direction - */ - public TreePageAction(int direction, String name) - { - } + int max = 0; + if (!mod.isLeaf(node)) + max = mod.getChildCount(node); + if (tree.isExpanded(new TreePath(getPathToRoot(node, 0)))) + { + if (!node.equals(mod.getRoot())) + ei.paintIcon(tree, g, indentation - rightChildIndent - 3, h); + + for (int i = 0; i < max; i++) + { + int indent = indentation + rightChildIndent; + if (depth == 0 && !tree.isRootVisible()) + indent = -1; + + descent = paintControlIcons(g, indent, descent, i, depth + 1, + tree, mod, mod.getChild(node, i)); + } + } + else if (!node.equals(mod.getRoot())) + ci.paintIcon(tree, g, indentation - rightChildIndent - 3, + descent - getRowHeight()); + } + + return descent; + } + + /** + * Returns true if the LookAndFeel implements the control icons Package + * private for use in inner classes. + * + * @return true if control icons are visible + */ + boolean hasControlIcons() + { + if (UIManager.getLookAndFeelDefaults().getIcon("Tree.expandedIcon") == null + || UIManager.getLookAndFeelDefaults().getIcon("Tree.collapsedIcon") == null) + return false; + return true; + } + + /** + * Returns the parent of 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) + { + if (root == null || node == null) + return null; + if (node instanceof TreeNode) + return ((TreeNode) node).getParent(); + return findNode(root, node); + } + + /** + * 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 + * @return the parent node of node + */ + private Object findNode(Object root, Object node) + { + TreeModel mod = tree.getModel(); + int size = 0; + if (!mod.isLeaf(root)) + size = mod.getChildCount(root); + for (int i = 0; i < size; i++) + { + if (mod.getIndexOfChild(root, node) != -1) + return root; + + Object n = findNode(mod.getChild(root, i), node); + if (n != null) + return n; + } + return null; + } + + /** + * Get next visible node in the tree. Package private for use in inner + * classes. + * + * @param the + * current node + * @return the next visible node in the JTree. Return null if there are no + * more. + */ + Object getNextVisibleNode(Object node) + { + Object next = null; + TreePath current = null; + + if (node != null) + next = getNextNode(node); + + if (next != null) + { + current = new TreePath(getPathToRoot(next, 0)); + if (tree.isVisible(current)) + return next; + + while (next != null && !tree.isVisible(current)) + { + next = getNextNode(next); - /** - * Invoked when an action occurs. - * - * @param e is the event that occured - */ - public void actionPerformed(ActionEvent e) - { - } + if (next != null) + current = new TreePath(getPathToRoot(next, 0)); + } + } + return next; + } + + /** + * Get previous visible node in the tree. Package private for use in inner + * classes. + * + * @param the + * current node + * @return the next visible node in the JTree. Return null if there are no + * more. + */ + Object getPreviousVisibleNode(Object node) + { + Object prev = null; + TreePath current = null; + + if (node != null) + prev = getPreviousNode(node); + + if (prev != null) + { + current = new TreePath(getPathToRoot(prev, 0)); + if (tree.isVisible(current)) + return prev; + + while (prev != null && !tree.isVisible(current)) + { + prev = getPreviousNode(prev); - /** - * Returns true if the action is enabled. - * - * @return true if the action is enabled. - */ - public boolean isEnabled() - { - return false; - } - }// TreePageAction - - /** - * Listens for changes in the selection model and updates the display - * accordingly. - */ - public class TreeSelectionHandler - implements TreeSelectionListener - { - /** - * Constructor - */ - public TreeSelectionHandler() - { - } + if (prev != null) + current = new TreePath(getPathToRoot(prev, 0)); + } + } + return prev; + } + + /** + * Returns the next node in the tree Package private for use in inner classes. + * + * @param the + * current node + * @return the next node in the tree + */ + Object getNextNode(Object curr) + { + TreeModel mod = tree.getModel(); + if (!mod.isLeaf(curr) && mod.getChildCount(curr) > 0) + return mod.getChild(curr, 0); + + Object node = curr; + Object sibling = null; + + do + { + sibling = getNextSibling(node); + node = getParent(mod.getRoot(), node); + } + while (sibling == null && node != null); + + return sibling; + } + + /** + * Returns the previous node in the tree Package private for use in inner + * classes. + * + * @param the + * current node + * @return the previous node in the tree + */ + Object getPreviousNode(Object node) + { + TreeModel mod = tree.getModel(); + Object parent = getParent(mod.getRoot(), node); + if (parent == null) + return null; - /** - * 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. - */ - public void valueChanged(TreeSelectionEvent event) - { - } - }// TreeSelectionHandler - - /** - * For the first selected row expandedness will be toggled. - */ - public class TreeToggleAction - extends AbstractAction - { - /** - * Constructor - * - * @param name is the name of <code>Action</code> field - */ - public TreeToggleAction(String name) - { - } + Object sibling = getPreviousSibling(node); + + if (sibling == null) + return parent; + + int size = 0; + if (!mod.isLeaf(sibling)) + size = mod.getChildCount(sibling); + while (size > 0) + { + sibling = mod.getChild(sibling, size - 1); + if (!mod.isLeaf(sibling)) + size = mod.getChildCount(sibling); + else + size = 0; + } + + return sibling; + } + + /** + * Returns the next sibling in the tree Package private for use in inner + * classes. + * + * @param the + * current node + * @return the next sibling in the tree + */ + Object getNextSibling(Object node) + { + TreeModel mod = tree.getModel(); + Object parent = getParent(mod.getRoot(), node); + if (parent == null) + return null; - /** - * Invoked when an action occurs. - * - * @param e the event that occured - */ - public void actionPerformed(ActionEvent e) - { - } + int index = mod.getIndexOfChild(parent, node) + 1; - /** - * Returns true if the action is enabled. - * - * @return true if the action is enabled, false otherwise - */ - public boolean isEnabled() - { - return false; - } - } // TreeToggleAction - - /** - * 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 - { - /** - * Determines direction to traverse, 1 means expand, -1 means collapse. - */ - protected int direction; - - /** - * Constructor - * - * @param direction to traverse - * @param name is the name of the direction - */ - public TreeTraverseAction(int direction, String name) - { - } + int size = 0; + if (!mod.isLeaf(parent)) + size = mod.getChildCount(parent); + if (index == 0 || index >= size) + return null; - /** - * Invoked when an action occurs. - * - * @param e the event that occured - */ - public void actionPerformed(ActionEvent e) - { - } + return mod.getChild(parent, index); + } + + /** + * Returns the previous sibling in the tree Package private for use in inner + * classes. + * + * @param the + * current node + * @return the previous sibling in the tree + */ + Object getPreviousSibling(Object node) + { + TreeModel mod = tree.getModel(); + Object parent = getParent(mod.getRoot(), node); + if (parent == null) + return null; - /** - * Returns true if the action is enabled. - * - * @return true if the action is enabled, false otherwise - */ - public boolean isEnabled() - { - return false; - } - } // TreeTraverseAction - - /** - * Returns the cell bounds for painting selected cells - * - * @param x is the x location of the cell - * @param y is the y location of the cell - * @param cell is the Object to get the bounds for - * - * @returns Rectangle that represents the cell bounds - */ - private Rectangle getCellBounds(int x, int y, Object cell) - { - if (cell != null) - { - String s = cell.toString(); - Font f = tree.getFont(); - FontMetrics fm = tree.getToolkit().getFontMetrics(tree.getFont()); + int index = mod.getIndexOfChild(parent, node) - 1; - return new Rectangle(x, y, SwingUtilities.computeStringWidth(fm, s), - fm.getHeight()); - } + int size = 0; + if (!mod.isLeaf(parent)) + size = mod.getChildCount(parent); + if (index < 0 || index >= size) return null; - } - - /** - * Retrieves the location of some node, recursively starting at from - * some node. - * - * @param x is the starting x position, offset - * @param y is the starting y position, offset - * @param tree is the tree to traverse - * @param mod is the TreeModel to use - * @param node is the node to get the location for - * @param startNode is the node to start searching from - * - * @return Point - the location of node - */ - private Point getCellLocation(int x, int y, JTree tree, TreeModel mod, - Object node, Object startNode) - { - int rowHeight = getRowHeight(); - if (startNode == null || startNode.equals(node)) - return new Point(x + ((((DefaultMutableTreeNode) node). - getLevel() + 1) * rightChildIndent), y); - - if (!mod.isLeaf(startNode) - && tree.isExpanded(new TreePath( - ((DefaultMutableTreeNode) startNode).getPath()))) - { - Object child = mod.getChild(startNode, 0); - if (child != null) - return getCellLocation(x, y + rowHeight, tree, mod, - node, child); - } - - return getCellLocation(x, y + rowHeight, tree, mod, node, - getNextVisibleNode((DefaultMutableTreeNode) startNode)); - } - - /** - * Paints a leaf in the tree - * - * @param g the Graphics context in which to paint - * @param x the x location of the leaf - * @param y the y location of the leaf - * @param tree the tree to draw on - * @param leaf the object to draw - */ - private void paintLeaf(Graphics g, int x, int y, JTree tree, Object leaf) - { - TreePath curr = new TreePath(((DefaultMutableTreeNode) leaf).getPath()); - boolean selected = tree.isPathSelected(curr); - - if (tree.isVisible(curr)) - { - DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) - tree.getCellRenderer(); - boolean hasIcons = false; - Icon li = dtcr.getLeafIcon(); - if (li != null) - hasIcons = true; - - if (selected) - { - Component c = dtcr.getTreeCellRendererComponent(tree, leaf, - true, false, true, 0, false); - - if (hasIcons) - { - li.paintIcon(c, g, x, y + 2); - x += li.getIconWidth() + 4; - } - rendererPane.paintComponent(g, c, tree, - getCellBounds(x, y, leaf)); - } - else - { - Component c = dtcr.getTreeCellRendererComponent( - tree, leaf, false, false, true, 0, false); - - g.translate(x, y); - - if (hasIcons) - { - Component icon = dtcr.getTreeCellRendererComponent(tree, - li, false, false, true, 0, false); - icon.paint(g); - } - - c.paint(g); - g.translate(-x, -y); - } - } - } - - /** - * Paints a non-leaf in the tree - * - * @param g the Graphics context in which to paint - * @param x the x location of the non-leaf - * @param y the y location of the non-leaf - * @param tree the tree to draw on - * @param nonLeaf the object to draw - */ - private void paintNonLeaf(Graphics g, int x, int y, JTree tree, - Object nonLeaf) - { - TreePath curr = new TreePath(((DefaultMutableTreeNode) nonLeaf).getPath()); - boolean selected = tree.isPathSelected(curr); - boolean expanded = tree.isExpanded(curr); - - if (tree.isVisible(curr)) - { - DefaultTreeCellRenderer dtcr = (DefaultTreeCellRenderer) - tree.getCellRenderer(); - boolean hasIcons = false; - boolean hasOtherIcons = false; - Icon oi = dtcr.getOpenIcon(); - Icon ci = dtcr.getClosedIcon(); - - if (oi != null || ci != null) - hasIcons = true; - - if (selected) - { - Component c = dtcr.getTreeCellRendererComponent(tree, nonLeaf, - true, expanded, false, 0, false); - - if (hasIcons) - { - if (expanded) - { - oi.paintIcon(c, g, x, y + 2); - x += (oi.getIconWidth() + 4); - } - else - { - ci.paintIcon(c, g, x, y + 2); - x += (ci.getIconWidth() + 4); - } - - } - rendererPane.paintComponent(g, c, tree, - getCellBounds(x, y, nonLeaf)); - } - else - { - Component c = dtcr.getTreeCellRendererComponent(tree, nonLeaf, - false, expanded, false, 0, false); - g.translate(x, y); - - if (hasIcons) - { - Component icon; - if (expanded) - icon = dtcr.getTreeCellRendererComponent(tree, - oi, false, false, false, 0, false); - else - icon = dtcr.getTreeCellRendererComponent(tree, - ci, false, false, false, 0, false); - - icon.paint(g); - } - c.paint(g); - g.translate(-x, -y); - } - } - } - - /** - * Recursively paints all elements of the tree - * - * @param g the Graphics context in which to paint - * @param indentation of the current object - * @param descent is the number of elements drawn - * @param childNumber is the index of the current child in the tree - * @param depth is the depth of the current object in the tree - * @param tree is the tree to draw to - * @param mod is the TreeModel we are using to draw - * @param curr is the current object to draw - * - * @return int - current descent of the tree - */ - private int paintRecursive(Graphics g, int indentation, int descent, - int childNumber, int depth, JTree tree, TreeModel mod, Object curr) - { - Rectangle clip = g.getClipBounds(); - if (indentation > clip.x + clip.width + rightChildIndent - || descent > clip.y + clip.height + getRowHeight()) - return descent; - - int halfHeight = getRowHeight() / 2; - int halfWidth = rightChildIndent / 2; - int y0 = descent + halfHeight; - int heightOfLine = descent + halfHeight; - - if (mod.isLeaf(curr)) - { - paintLeaf(g, indentation + 4, descent, tree, curr); - descent += getRowHeight(); - } - else - { - if (depth > 0 || tree.isRootVisible()) - { - paintNonLeaf(g, indentation + 4, descent, tree, curr); - descent += getRowHeight(); - y0 += halfHeight; - } - - int max = mod.getChildCount(curr); - if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) curr) - .getPath()))) - { - for (int i = 0; i < max; ++i) - { - g.setColor(getHashColor()); - heightOfLine = descent + halfHeight; - g.drawLine(indentation + halfWidth, heightOfLine, - indentation + rightChildIndent, heightOfLine); - - descent = paintRecursive(g, indentation + rightChildIndent, - descent, i, depth + 1, tree, mod, mod.getChild(curr, i)); - } - } - } - if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) curr) - .getPath()))) - if (y0 != heightOfLine) - { - g.setColor(getHashColor()); - g.drawLine(indentation + halfWidth, y0, indentation + halfWidth, - heightOfLine); - } - - return descent; - } - - /** - * Recursively paints all the control icons on the tree. - * - * @param g the Graphics context in which to paint - * @param indentation of the current object - * @param descent is the number of elements drawn - * @param childNumber is the index of the current child in the tree - * @param depth is the depth of the current object in the tree - * @param tree is the tree to draw to - * @param mod is the TreeModel we are using to draw - * @param curr is the current object to draw - * - * @return int - current descent of the tree - */ - private int paintControlIcons(Graphics g, int indentation, int descent, - int childNumber, int depth, JTree tree, TreeModel mod, Object node) - { - int h = descent; - int rowHeight = getRowHeight(); - Icon ei = UIManager.getLookAndFeelDefaults(). - getIcon("Tree.expandedIcon"); - Icon ci = UIManager.getLookAndFeelDefaults(). - getIcon("Tree.collapsedIcon"); - Rectangle clip = g.getClipBounds(); - if (ci == null || ei == null || indentation > clip.x + clip.width + - rightChildIndent || descent > clip.y + clip.height + - getRowHeight()) - return descent; - - if (mod.isLeaf(node)) - descent += rowHeight; - else - { - if (depth > 0 || tree.isRootVisible()) - descent += rowHeight; - - int max = mod.getChildCount(node); - if (tree.isExpanded(new TreePath(((DefaultMutableTreeNode) node) - .getPath()))) - { - if (!node.equals(mod.getRoot())) - ei.paintIcon(tree, g, indentation - rightChildIndent - 3, h); - - for (int i = 0; i < max; ++i) - { - descent = paintControlIcons(g, indentation + rightChildIndent, - descent, i, depth + 1, tree, mod, mod.getChild(node, i)); - } - } - else if (!node.equals(mod.getRoot())) - ci.paintIcon(tree, g, indentation - rightChildIndent - 3, - descent - getRowHeight()); - } - - return descent; - } -} // BasicTreeUI
\ No newline at end of file + return mod.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 + */ + void selectPath(JTree tree, TreePath path) + { + if (path != null) + { + if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) + { + tree.addSelectionPath(path); + tree.setLeadSelectionPath(path); + } + else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) + { + // TODO + } + else + { + tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + + tree.getSelectionModel().clearSelection(); + tree.addSelectionPath(path); + tree.setLeadSelectionPath(path); + } + } + } + + /** + * 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 + * @return an array of tree nodes that represent the path to node. + */ + Object[] getPathToRoot(Object node, int depth) + { + TreeModel mod = tree.getModel(); + if (node == null) + { + if (depth == 0) + return null; + + return new Object[depth]; + } + + Object[] path = getPathToRoot(getParent(mod.getRoot(), node), depth + 1); + path[path.length - depth - 1] = node; + return path; + } + + /** + * Returns the level of the node in the tree. + * + * @param the + * current node + * @return the number of the level + */ + int getLevel(Object node) + { + int count = -1; + Object current = node; + + do + { + current = getParent(tree.getModel().getRoot(), 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 + */ + protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, + int bottom) + { + g.drawLine(x, top, x, bottom); + } + + /** + * 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 + */ + protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, + int right) + { + g.drawLine(left, y, right, y); + } + + /** + * 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 FIXME what to do if x < + * (icon.width / 2). Same with y + */ + protected void drawCentered(JComponent c, Graphics g, Icon icon, int x, int y) + { + int beginPositionX = x - icon.getIconWidth() / 2; + int beginPositionY = y - icon.getIconHeight() / 2; + icon.paintIcon(c, g, beginPositionX, beginPositionY); + } +} // BasicTreeUI diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java index 8ce772bedf9..0d461332a70 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicViewportUI.java @@ -160,18 +160,18 @@ public class BasicViewportUI extends ViewportUI Rectangle viewBounds, Rectangle portBounds) { - Rectangle oldClip = g.getClipBounds (); - g.setClip (oldClip.intersection (viewBounds)); + Rectangle oldClip = g.getClipBounds(); + g.setClip(new Rectangle(0, 0, portBounds.width, portBounds.height)); g.translate (-pos.x, -pos.y); try - { + { view.paint(g); } finally { g.translate (pos.x, pos.y); g.setClip (oldClip); - } + } } private void paintBackingStore(Graphics g, |

