summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing
diff options
context:
space:
mode:
authorMark Wielaard <mark@gcc.gnu.org>2006-08-14 23:12:35 +0000
committerMark Wielaard <mark@gcc.gnu.org>2006-08-14 23:12:35 +0000
commitac1ed908de999523efc36f38e69bca1aadfe0808 (patch)
tree97037d2c09c8384d80531f67ec36a01205df6bdb /libjava/classpath/javax/swing
parentabab460491408e05ea93fb85e1975296a87df504 (diff)
downloadgcc-ac1ed908de999523efc36f38e69bca1aadfe0808.tar.gz
Imported GNU Classpath 0.92
2006-08-14 Mark Wielaard <mark@klomp.org> Imported GNU Classpath 0.92 * HACKING: Add more importing hints. Update automake version requirement. * configure.ac (gconf-peer): New enable AC argument. Add --disable-gconf-peer and --enable-default-preferences-peer to classpath configure when gconf is disabled. * scripts/makemake.tcl: Set gnu/java/util/prefs/gconf and gnu/java/awt/dnd/peer/gtk to bc. Classify gnu/java/security/Configuration.java as generated source file. * gnu/java/lang/management/VMGarbageCollectorMXBeanImpl.java, gnu/java/lang/management/VMMemoryPoolMXBeanImpl.java, gnu/java/lang/management/VMClassLoadingMXBeanImpl.java, gnu/java/lang/management/VMRuntimeMXBeanImpl.java, gnu/java/lang/management/VMMemoryManagerMXBeanImpl.java, gnu/java/lang/management/VMThreadMXBeanImpl.java, gnu/java/lang/management/VMMemoryMXBeanImpl.java, gnu/java/lang/management/VMCompilationMXBeanImpl.java: New VM stub classes. * java/lang/management/VMManagementFactory.java: Likewise. * java/net/VMURLConnection.java: Likewise. * gnu/java/nio/VMChannel.java: Likewise. * java/lang/Thread.java (getState): Add stub implementation. * java/lang/Class.java (isEnum): Likewise. * java/lang/Class.h (isEnum): Likewise. * gnu/awt/xlib/XToolkit.java (getClasspathTextLayoutPeer): Removed. * javax/naming/spi/NamingManager.java: New override for StackWalker functionality. * configure, sources.am, Makefile.in, gcj/Makefile.in, include/Makefile.in, testsuite/Makefile.in: Regenerated. From-SVN: r116139
Diffstat (limited to 'libjava/classpath/javax/swing')
-rw-r--r--libjava/classpath/javax/swing/AbstractButton.java57
-rw-r--r--libjava/classpath/javax/swing/AbstractCellEditor.java12
-rw-r--r--libjava/classpath/javax/swing/AbstractSpinnerModel.java2
-rw-r--r--libjava/classpath/javax/swing/Box.java10
-rw-r--r--libjava/classpath/javax/swing/BoxLayout.java2
-rw-r--r--libjava/classpath/javax/swing/ButtonGroup.java53
-rw-r--r--libjava/classpath/javax/swing/DefaultBoundedRangeModel.java34
-rw-r--r--libjava/classpath/javax/swing/DefaultButtonModel.java4
-rw-r--r--libjava/classpath/javax/swing/DefaultComboBoxModel.java4
-rw-r--r--libjava/classpath/javax/swing/DefaultListModel.java4
-rw-r--r--libjava/classpath/javax/swing/DefaultListSelectionModel.java117
-rw-r--r--libjava/classpath/javax/swing/GrayFilter.java5
-rw-r--r--libjava/classpath/javax/swing/InputMap.java131
-rw-r--r--libjava/classpath/javax/swing/JCheckBoxMenuItem.java187
-rw-r--r--libjava/classpath/javax/swing/JComboBox.java47
-rw-r--r--libjava/classpath/javax/swing/JComponent.java753
-rw-r--r--libjava/classpath/javax/swing/JFileChooser.java12
-rw-r--r--libjava/classpath/javax/swing/JInternalFrame.java195
-rw-r--r--libjava/classpath/javax/swing/JLabel.java351
-rw-r--r--libjava/classpath/javax/swing/JLayeredPane.java145
-rw-r--r--libjava/classpath/javax/swing/JList.java124
-rw-r--r--libjava/classpath/javax/swing/JMenu.java60
-rw-r--r--libjava/classpath/javax/swing/JMenuItem.java2
-rw-r--r--libjava/classpath/javax/swing/JOptionPane.java42
-rw-r--r--libjava/classpath/javax/swing/JPopupMenu.java2
-rw-r--r--libjava/classpath/javax/swing/JRadioButtonMenuItem.java1
-rw-r--r--libjava/classpath/javax/swing/JSplitPane.java3
-rw-r--r--libjava/classpath/javax/swing/JTabbedPane.java30
-rw-r--r--libjava/classpath/javax/swing/JTable.java236
-rw-r--r--libjava/classpath/javax/swing/JTree.java7
-rw-r--r--libjava/classpath/javax/swing/LookAndFeel.java18
-rw-r--r--libjava/classpath/javax/swing/ProgressMonitor.java26
-rw-r--r--libjava/classpath/javax/swing/ProgressMonitorInputStream.java2
-rw-r--r--libjava/classpath/javax/swing/RepaintManager.java208
-rw-r--r--libjava/classpath/javax/swing/ScrollPaneLayout.java9
-rw-r--r--libjava/classpath/javax/swing/SizeSequence.java6
-rw-r--r--libjava/classpath/javax/swing/SpringLayout.java2
-rw-r--r--libjava/classpath/javax/swing/SwingUtilities.java26
-rw-r--r--libjava/classpath/javax/swing/Timer.java10
-rw-r--r--libjava/classpath/javax/swing/ToolTipManager.java18
-rw-r--r--libjava/classpath/javax/swing/UIManager.java139
-rw-r--r--libjava/classpath/javax/swing/border/TitledBorder.java8
-rw-r--r--libjava/classpath/javax/swing/event/EventListenerList.java2
-rw-r--r--libjava/classpath/javax/swing/event/ListDataEvent.java60
-rw-r--r--libjava/classpath/javax/swing/event/MenuEvent.java28
-rw-r--r--libjava/classpath/javax/swing/event/TreeExpansionListener.java26
-rw-r--r--libjava/classpath/javax/swing/filechooser/FileSystemView.java21
-rw-r--r--libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java27
-rw-r--r--libjava/classpath/javax/swing/plaf/IconUIResource.java9
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java50
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java29
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java8
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java99
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java464
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java57
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java174
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java280
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java72
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicListUI.java124
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java26
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java98
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java30
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java28
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java220
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java675
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java78
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java50
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java17
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java1218
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java329
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java19
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java264
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java196
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java309
-rw-r--r--libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java13
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java4
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java134
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java162
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java26
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java5
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java1
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java148
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalUtils.java90
-rw-r--r--libjava/classpath/javax/swing/table/DefaultTableColumnModel.java10
-rw-r--r--libjava/classpath/javax/swing/text/AbstractDocument.java208
-rw-r--r--libjava/classpath/javax/swing/text/BoxView.java264
-rw-r--r--libjava/classpath/javax/swing/text/CompositeView.java82
-rw-r--r--libjava/classpath/javax/swing/text/DefaultCaret.java86
-rw-r--r--libjava/classpath/javax/swing/text/EmptyAttributeSet.java153
-rw-r--r--libjava/classpath/javax/swing/text/FlowView.java75
-rw-r--r--libjava/classpath/javax/swing/text/GapContent.java371
-rw-r--r--libjava/classpath/javax/swing/text/IconView.java18
-rw-r--r--libjava/classpath/javax/swing/text/JTextComponent.java302
-rw-r--r--libjava/classpath/javax/swing/text/ParagraphView.java37
-rw-r--r--libjava/classpath/javax/swing/text/PlainDocument.java201
-rw-r--r--libjava/classpath/javax/swing/text/Segment.java10
-rw-r--r--libjava/classpath/javax/swing/text/SimpleAttributeSet.java6
-rw-r--r--libjava/classpath/javax/swing/text/StringContent.java6
-rw-r--r--libjava/classpath/javax/swing/text/TabSet.java121
-rw-r--r--libjava/classpath/javax/swing/text/TabStop.java68
-rw-r--r--libjava/classpath/javax/swing/text/View.java113
-rw-r--r--libjava/classpath/javax/swing/text/html/BRView.java (renamed from libjava/classpath/javax/swing/text/html/HTMLTableView.java)47
-rw-r--r--libjava/classpath/javax/swing/text/html/HRuleView.java189
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLDocument.java370
-rw-r--r--libjava/classpath/javax/swing/text/html/HTMLEditorKit.java20
-rw-r--r--libjava/classpath/javax/swing/text/html/StyleSheet.java52
-rw-r--r--libjava/classpath/javax/swing/text/html/TableView.java137
-rw-r--r--libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java3
-rw-r--r--libjava/classpath/javax/swing/text/rtf/RTFParser.java14
-rw-r--r--libjava/classpath/javax/swing/text/rtf/RTFScanner.java28
-rw-r--r--libjava/classpath/javax/swing/tree/TreePath.java2
111 files changed, 8154 insertions, 3613 deletions
diff --git a/libjava/classpath/javax/swing/AbstractButton.java b/libjava/classpath/javax/swing/AbstractButton.java
index 9b2b526f30b..63f827a1ae0 100644
--- a/libjava/classpath/javax/swing/AbstractButton.java
+++ b/libjava/classpath/javax/swing/AbstractButton.java
@@ -199,7 +199,7 @@ public abstract class AbstractButton extends JComponent
Icon pressed_icon;
/** The icon displayed when the button is disabled. */
- Icon disabeldIcon;
+ Icon disabledIcon;
/** The icon displayed when the button is selected. */
Icon selectedIcon;
@@ -923,7 +923,7 @@ public abstract class AbstractButton extends JComponent
// constructor).
// This way the behavior of the JDK is matched.
if(text != null)
- this.text = text;
+ setText(text);
if (icon != null)
default_icon = icon;
@@ -1297,9 +1297,11 @@ public abstract class AbstractButton extends JComponent
* alignment is a numeric constant from {@link SwingConstants}. It must
* be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
* <code>LEADING</code> or <code>TRAILING</code>. The default is
- * <code>RIGHT</code>.
+ * <code>CENTER</code>.
*
* @return The current horizontal alignment
+ *
+ * @see #setHorizontalAlignment(int)
*/
public int getHorizontalAlignment()
{
@@ -1311,17 +1313,21 @@ public abstract class AbstractButton extends JComponent
* alignment is a numeric constant from {@link SwingConstants}. It must
* be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
* <code>LEADING</code> or <code>TRAILING</code>. The default is
- * <code>RIGHT</code>.
+ * <code>CENTER</code>.
*
* @param a The new horizontal alignment
* @throws IllegalArgumentException If alignment is not one of the legal
* constants.
+ *
+ * @see #getHorizontalAlignment()
*/
public void setHorizontalAlignment(int a)
{
if (horizontalAlignment == a)
return;
-
+ if (a != LEFT && a != CENTER && a != RIGHT && a != LEADING
+ && a != TRAILING)
+ throw new IllegalArgumentException("Invalid alignment.");
int old = horizontalAlignment;
horizontalAlignment = a;
firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
@@ -1358,6 +1364,9 @@ public abstract class AbstractButton extends JComponent
{
if (horizontalTextPosition == t)
return;
+ if (t != LEFT && t != CENTER && t != RIGHT && t != LEADING
+ && t != TRAILING)
+ throw new IllegalArgumentException("Invalid alignment.");
int old = horizontalTextPosition;
horizontalTextPosition = t;
@@ -1373,6 +1382,8 @@ public abstract class AbstractButton extends JComponent
* <code>BOTTOM</code>. The default is <code>CENTER</code>.
*
* @return The current vertical alignment
+ *
+ * @see #setVerticalAlignment(int)
*/
public int getVerticalAlignment()
{
@@ -1388,12 +1399,16 @@ public abstract class AbstractButton extends JComponent
* @param a The new vertical alignment
* @throws IllegalArgumentException If alignment is not one of the legal
* constants.
+ *
+ * @see #getVerticalAlignment()
*/
public void setVerticalAlignment(int a)
{
if (verticalAlignment == a)
return;
-
+ if (a != TOP && a != CENTER && a != BOTTOM)
+ throw new IllegalArgumentException("Invalid alignment.");
+
int old = verticalAlignment;
verticalAlignment = a;
firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
@@ -1430,6 +1445,8 @@ public abstract class AbstractButton extends JComponent
{
if (verticalTextPosition == t)
return;
+ if (t != TOP && t != CENTER && t != BOTTOM)
+ throw new IllegalArgumentException("Invalid alignment.");
int old = verticalTextPosition;
verticalTextPosition = t;
@@ -1708,14 +1725,14 @@ public abstract class AbstractButton extends JComponent
*/
public Icon getDisabledIcon()
{
- if (disabeldIcon == null && default_icon instanceof ImageIcon)
+ if (disabledIcon == null && default_icon instanceof ImageIcon)
{
Image iconImage = ((ImageIcon) default_icon).getImage();
Image grayImage = GrayFilter.createDisabledImage(iconImage);
- disabeldIcon = new ImageIcon(grayImage);
+ disabledIcon = new ImageIcon(grayImage);
}
- return disabeldIcon;
+ return disabledIcon;
}
/**
@@ -1729,7 +1746,11 @@ public abstract class AbstractButton extends JComponent
*/
public void setDisabledIcon(Icon d)
{
- disabeldIcon = d;
+ if (disabledIcon == d)
+ return;
+ Icon old = disabledIcon;
+ disabledIcon = d;
+ firePropertyChange(DISABLED_ICON_CHANGED_PROPERTY, old, d);
revalidate();
repaint();
}
@@ -2092,7 +2113,8 @@ public abstract class AbstractButton extends JComponent
}
/**
- * Set the button's rollover icon. The look and feel class should
+ * Set the button's rollover icon and sets the <code>rolloverEnabled</code>
+ * property to <code>true</code>. The look and feel class should
* paint this icon when the "rolloverEnabled" property of the button is
* <code>true</code> and the mouse rolls over the button.
*
@@ -2106,6 +2128,7 @@ public abstract class AbstractButton extends JComponent
Icon old = rolloverIcon;
rolloverIcon = r;
firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, rolloverIcon);
+ setRolloverEnabled(true);
revalidate();
repaint();
}
@@ -2124,12 +2147,13 @@ public abstract class AbstractButton extends JComponent
}
/**
- * Set the button's rollover selected icon. The look and feel class
- * should paint this icon when the "rolloverEnabled" property of the button
- * is <code>true</code>, the "selected" property of the button's model is
- * <code>true</code>, and the mouse rolls over the button.
+ * Set the button's rollover selected icon and sets the
+ * <code>rolloverEnabled</code> property to <code>true</code>. The look and
+ * feel class should paint this icon when the "rolloverEnabled" property of
+ * the button is <code>true</code>, the "selected" property of the button's
+ * model is <code>true</code>, and the mouse rolls over the button.
*
- * @param r The new rollover selected icon
+ * @param r The new rollover selected icon.
*/
public void setRolloverSelectedIcon(Icon r)
{
@@ -2139,6 +2163,7 @@ public abstract class AbstractButton extends JComponent
Icon old = rolloverSelectedIcon;
rolloverSelectedIcon = r;
firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, r);
+ setRolloverEnabled(true);
revalidate();
repaint();
}
diff --git a/libjava/classpath/javax/swing/AbstractCellEditor.java b/libjava/classpath/javax/swing/AbstractCellEditor.java
index df0d3db12b5..e993df5cfc7 100644
--- a/libjava/classpath/javax/swing/AbstractCellEditor.java
+++ b/libjava/classpath/javax/swing/AbstractCellEditor.java
@@ -134,9 +134,9 @@ public abstract class AbstractCellEditor
*
* @param listener the CellEditorListener to add
*/
- public void addCellEditorListener (CellEditorListener listener)
+ public void addCellEditorListener(CellEditorListener listener)
{
- listenerList.add (CellEditorListener.class, listener);
+ listenerList.add(CellEditorListener.class, listener);
}
/**
@@ -145,9 +145,9 @@ public abstract class AbstractCellEditor
*
* @param listener the CellEditorListener to remove
*/
- public void removeCellEditorListener (CellEditorListener listener)
+ public void removeCellEditorListener(CellEditorListener listener)
{
- listenerList.remove (CellEditorListener.class, listener);
+ listenerList.remove(CellEditorListener.class, listener);
}
/**
@@ -161,8 +161,8 @@ public abstract class AbstractCellEditor
*/
public CellEditorListener[] getCellEditorListeners()
{
- return (CellEditorListener[]) listenerList.getListeners
- (CellEditorListener.class);
+ return (CellEditorListener[]) listenerList.getListeners(
+ CellEditorListener.class);
}
/**
diff --git a/libjava/classpath/javax/swing/AbstractSpinnerModel.java b/libjava/classpath/javax/swing/AbstractSpinnerModel.java
index 1a82f0a359d..089e2048da2 100644
--- a/libjava/classpath/javax/swing/AbstractSpinnerModel.java
+++ b/libjava/classpath/javax/swing/AbstractSpinnerModel.java
@@ -113,7 +113,7 @@ public abstract class AbstractSpinnerModel implements SpinnerModel
{
ChangeListener[] listeners = getChangeListeners();
- for(int i = 0; i < listeners.length; ++i)
+ for (int i = 0; i < listeners.length; ++i)
listeners[i].stateChanged(changeEvent);
}
}
diff --git a/libjava/classpath/javax/swing/Box.java b/libjava/classpath/javax/swing/Box.java
index 57519f6fcbd..0f984a98465 100644
--- a/libjava/classpath/javax/swing/Box.java
+++ b/libjava/classpath/javax/swing/Box.java
@@ -196,9 +196,8 @@ public class Box extends JComponent implements Accessible
*/
public static Component createGlue()
{
- Filler glue = new Filler(new Dimension(0,0), new Dimension(0,0),
- new Dimension(Short.MAX_VALUE,Short.MAX_VALUE)
- );
+ Filler glue = new Filler(new Dimension(0, 0), new Dimension(0, 0),
+ new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
return glue;
}
@@ -216,9 +215,8 @@ public class Box extends JComponent implements Accessible
*/
public static Component createHorizontalGlue()
{
- Filler glue = new Filler(new Dimension(0,0), new Dimension(0,0),
- new Dimension(Short.MAX_VALUE, 0)
- );
+ Filler glue = new Filler(new Dimension(0, 0), new Dimension(0, 0),
+ new Dimension(Short.MAX_VALUE, 0));
return glue;
}
diff --git a/libjava/classpath/javax/swing/BoxLayout.java b/libjava/classpath/javax/swing/BoxLayout.java
index 408dea934f8..a7f9dd61a6e 100644
--- a/libjava/classpath/javax/swing/BoxLayout.java
+++ b/libjava/classpath/javax/swing/BoxLayout.java
@@ -426,7 +426,7 @@ public class BoxLayout implements LayoutManager2, Serializable
Insets in = container.getInsets();
int width = container.getWidth() - in.left - in.right;
- int height = container.getHeight() - in.top -in.bottom;
+ int height = container.getHeight() - in.top - in.bottom;
if (isHorizontalIn(container))
{
diff --git a/libjava/classpath/javax/swing/ButtonGroup.java b/libjava/classpath/javax/swing/ButtonGroup.java
index 2f8d19831cb..efa36b5f641 100644
--- a/libjava/classpath/javax/swing/ButtonGroup.java
+++ b/libjava/classpath/javax/swing/ButtonGroup.java
@@ -1,5 +1,5 @@
/* ButtonGroup.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -65,10 +65,9 @@ import java.util.Vector;
*/
public class ButtonGroup implements Serializable
{
- /** DOCUMENT ME! */
private static final long serialVersionUID = 4259076101881721375L;
- /** The buttons added to this button group. */
+ /** Stores references to the buttons added to this button group. */
protected Vector buttons = new Vector();
/** The currently selected button model. */
@@ -83,12 +82,20 @@ public class ButtonGroup implements Serializable
}
/**
- * Adds a button to this group.
+ * Adds a button to this group. If the button is in the selected state, then:
+ * <ul>
+ * <li>if the group has no current selection, the new button becomes the
+ * selected button for the group;</li>
+ * <li>if the group already has a selected button, the new button is set to
+ * "not selected".</li>
+ * </ul>
*
- * @param b the button to add
+ * @param b the button to add (<code>null</code> is ignored).
*/
public void add(AbstractButton b)
{
+ if (b == null)
+ return;
b.getModel().setGroup(this);
if (b.isSelected())
{
@@ -96,17 +103,24 @@ public class ButtonGroup implements Serializable
sel = b.getModel();
else
b.setSelected(false);
- } buttons.addElement(b);
+ }
+ buttons.addElement(b);
}
/**
- * Removed a given button from this group.
+ * Removes the specified button from this group. If the button is the
+ * selected button, the current selection is set to <code>null</code>.
+ * The group for the removed button's model is set to <code>null</code>.
*
- * @param b the button to remove
+ * @param b the button to remove (<code>null</code> is ignored).
*/
public void remove(AbstractButton b)
{
+ if (b == null)
+ return;
b.getModel().setGroup(null);
+ if (b.getModel() == sel)
+ sel = null;
buttons.removeElement(b);
}
@@ -132,19 +146,20 @@ public class ButtonGroup implements Serializable
}
/**
- * DOCUMENT ME!
+ * Returns the button that has the specified model, or <code>null</code> if
+ * there is no such button in the group.
*
- * @param m DOCUMENT ME!
+ * @param m the button model.
*
- * @return DOCUMENT ME!
+ * @return The button that has the specified model, or <code>null</code>.
*/
- AbstractButton FindButton(ButtonModel m)
+ AbstractButton findButton(ButtonModel m)
{
for (int i = 0; i < buttons.size(); i++)
{
- AbstractButton a = (AbstractButton) buttons.get(i);
- if (a.getModel() == m)
- return a;
+ AbstractButton a = (AbstractButton) buttons.get(i);
+ if (a.getModel() == m)
+ return a;
}
return null;
}
@@ -168,7 +183,7 @@ public class ButtonGroup implements Serializable
if (old != null)
old.setSelected(false);
- AbstractButton button = FindButton(old);
+ AbstractButton button = findButton(old);
if (button != null)
button.repaint();
}
@@ -180,10 +195,10 @@ public class ButtonGroup implements Serializable
* Checks if the given <code>ButtonModel</code> is selected in this button
* group.
*
- * @param m DOCUMENT ME!
+ * @param m the button model (<code>null</code> permitted).
*
- * @return true of given <code>ButtonModel</code> is selected, false
- * otherwise
+ * @return <code>true</code> if <code>m</code> is the selected button model
+ * in this group, and <code>false</code> otherwise.
*/
public boolean isSelected(ButtonModel m)
{
diff --git a/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java b/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java
index 10de4b94837..efca148f449 100644
--- a/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java
+++ b/libjava/classpath/javax/swing/DefaultBoundedRangeModel.java
@@ -1,6 +1,6 @@
/* DefaultBoundedRangeModel.java -- Default implementation
of BoundedRangeModel.
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,6 +39,9 @@ exception statement from your version. */
package javax.swing;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.EventListener;
@@ -440,4 +443,33 @@ public class DefaultBoundedRangeModel
{
return (ChangeListener[]) getListeners(ChangeListener.class);
}
+
+ /**
+ * Provides serialization support.
+ *
+ * @param stream the output stream (<code>null</code> not permitted).
+ *
+ * @throws IOException if there is an I/O error.
+ */
+ private void writeObject(ObjectOutputStream stream)
+ throws IOException
+ {
+ stream.defaultWriteObject();
+ }
+
+ /**
+ * Provides serialization support.
+ *
+ * @param stream the input stream (<code>null</code> not permitted).
+ *
+ * @throws IOException if there is an I/O error.
+ * @throws ClassNotFoundException if there is a classpath problem.
+ */
+ private void readObject(ObjectInputStream stream)
+ throws ClassNotFoundException, IOException
+ {
+ stream.defaultReadObject();
+ listenerList = new EventListenerList();
+ }
+
}
diff --git a/libjava/classpath/javax/swing/DefaultButtonModel.java b/libjava/classpath/javax/swing/DefaultButtonModel.java
index 2be18cc8aac..020c904a4e9 100644
--- a/libjava/classpath/javax/swing/DefaultButtonModel.java
+++ b/libjava/classpath/javax/swing/DefaultButtonModel.java
@@ -466,14 +466,14 @@ public class DefaultButtonModel implements ButtonModel, Serializable
if (s)
{
fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
- null, ItemEvent.SELECTED));
+ this, ItemEvent.SELECTED));
if (group != null)
group.setSelected(this, true);
}
else
{
fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED,
- null, ItemEvent.DESELECTED));
+ this, ItemEvent.DESELECTED));
if (group != null)
group.setSelected(this, false);
}
diff --git a/libjava/classpath/javax/swing/DefaultComboBoxModel.java b/libjava/classpath/javax/swing/DefaultComboBoxModel.java
index ab80b61f1f9..ef785f34dec 100644
--- a/libjava/classpath/javax/swing/DefaultComboBoxModel.java
+++ b/libjava/classpath/javax/swing/DefaultComboBoxModel.java
@@ -146,9 +146,9 @@ public class DefaultComboBoxModel extends AbstractListModel
if (selected == index) // choose a new selected item
{
if (selected > 0)
- selectedItem = getElementAt(selected - 1);
+ setSelectedItem(getElementAt(selected - 1));
else
- selectedItem = getElementAt(selected + 1);
+ setSelectedItem(getElementAt(selected + 1));
}
list.removeElementAt(index);
fireIntervalRemoved(this, index, index);
diff --git a/libjava/classpath/javax/swing/DefaultListModel.java b/libjava/classpath/javax/swing/DefaultListModel.java
index fdbbb562c90..2d02874a7e4 100644
--- a/libjava/classpath/javax/swing/DefaultListModel.java
+++ b/libjava/classpath/javax/swing/DefaultListModel.java
@@ -184,7 +184,7 @@ public class DefaultListModel extends AbstractListModel
/**
* Inserts an element at a particular index in the list. Each element at
- * index <code>i >= index</code> is shifted to position <code>i+1</code>.
+ * index <code>i >= index</code> is shifted to position <code>i + 1</code>.
* If <code>index</code> is equal to <code>size()</code>, this is
* equivalent to appending an element to the array. Any
* <code>index</code> greater than <code>size()</code> is illegal.
@@ -420,7 +420,7 @@ public class DefaultListModel extends AbstractListModel
/**
* Inserts an element at a particular index in the list. Each element at
- * index <code>i >= index</code> is shifted to position <code>i+1</code>.
+ * index <code>i >= index</code> is shifted to position <code>i + 1</code>.
* If <code>index</code> is equal to <code>size()</code>, this is
* equivalent to appending an element to the array. Any
* <code>index</code> greater than <code>size()</code> is illegal.
diff --git a/libjava/classpath/javax/swing/DefaultListSelectionModel.java b/libjava/classpath/javax/swing/DefaultListSelectionModel.java
index 998aee45279..482ce2cc224 100644
--- a/libjava/classpath/javax/swing/DefaultListSelectionModel.java
+++ b/libjava/classpath/javax/swing/DefaultListSelectionModel.java
@@ -150,9 +150,14 @@ public class DefaultListSelectionModel implements Cloneable,
boolean setLeadCalledFromAdd = false;
/**
- * Gets the value of the {@link #selectionMode} property.
- *
- * @return The current value of the property
+ * Returns the selection mode, which is one of {@link #SINGLE_SELECTION},
+ * {@link #SINGLE_INTERVAL_SELECTION} and
+ * {@link #MULTIPLE_INTERVAL_SELECTION}. The default value is
+ * {@link #MULTIPLE_INTERVAL_SELECTION}.
+ *
+ * @return The selection mode.
+ *
+ * @see #setSelectionMode(int)
*/
public int getSelectionMode()
{
@@ -187,13 +192,19 @@ public class DefaultListSelectionModel implements Cloneable,
/**
* Sets the value of the {@link #anchorSelectionIndex} property.
*
- * @param anchorIndex The new property value
+ * @param index The new property value
*
* @see #getAnchorSelectionIndex
*/
- public void setAnchorSelectionIndex(int anchorIndex)
+ public void setAnchorSelectionIndex(int index)
{
- anchorSelectionIndex = anchorIndex;
+ if (anchorSelectionIndex != index)
+ {
+ int old = anchorSelectionIndex;
+ anchorSelectionIndex = index;
+ if (leadAnchorNotificationEnabled)
+ fireValueChanged(index, old);
+ }
}
/**
@@ -459,12 +470,14 @@ public class DefaultListSelectionModel implements Cloneable,
if (index0 == -1 || index1 == -1)
return;
+ if (selectionMode == SINGLE_SELECTION)
+ setSelectionInterval(index0, index1);
+ else
+ {
int lo = Math.min(index0, index1);
int hi = Math.max(index0, index1);
oldSel = sel.clone();
- if (selectionMode == SINGLE_SELECTION)
- setSelectionInterval(index0, index1);
// COMPAT: Like Sun (but not like IBM), we allow calls to
// addSelectionInterval when selectionMode is
@@ -503,6 +516,7 @@ public class DefaultListSelectionModel implements Cloneable,
sel.set(lo, hi+1);
fireDifference(sel, (BitSet) oldSel);
}
+ }
}
@@ -588,27 +602,82 @@ public class DefaultListSelectionModel implements Cloneable,
* the current selection mode is <code>SINGLE_SELECTION</code> only the
* index <code>index2</code> is selected.
*
- * @param index0 The low end of the new selection
- * @param index1 The high end of the new selection
+ * @param anchor the anchor selection index.
+ * @param lead the lead selection index.
*/
- public void setSelectionInterval(int index0, int index1)
+ public void setSelectionInterval(int anchor, int lead)
{
- if (index0 == -1 || index1 == -1)
+ if (anchor == -1 || lead == -1)
return;
-
- BitSet oldSel = (BitSet) sel.clone();
- sel.clear();
if (selectionMode == SINGLE_SELECTION)
- index0 = index1;
-
- int lo = Math.min(index0, index1);
- int hi = Math.max(index0, index1);
- sel.set(lo, hi+1);
- // update the anchorSelectionIndex and leadSelectionIndex variables
- setAnchorSelectionIndex(index0);
- leadSelectionIndex=index1;
+ {
+ int lo = lead;
+ int hi = lead;
+ int selected = sel.nextSetBit(0);
+ if (selected == lead)
+ return; // the selection is not changing
+ if (selected >= 0)
+ {
+ lo = Math.min(lo, selected);
+ hi = Math.max(hi, selected);
+ }
+ if (anchorSelectionIndex >= 0)
+ {
+ lo = Math.min(lo, anchorSelectionIndex);
+ hi = Math.max(hi, anchorSelectionIndex);
+ }
+ sel.clear();
+ sel.set(lead);
+ leadSelectionIndex = lead;
+ anchorSelectionIndex = lead;
+ fireValueChanged(lo, hi);
+ }
+ else if (selectionMode == SINGLE_INTERVAL_SELECTION)
+ {
+ // determine the current interval
+ int first = sel.nextSetBit(0);
+ int last = first;
+ if (first >= 0)
+ last += (sel.cardinality() - 1);
+
+ // update the selection
+ int lo = Math.min(anchor, lead);
+ int hi = Math.max(anchor, lead);
+ if (lo == first && hi == last)
+ return; // selected interval is not being changed
+ sel.clear();
+ sel.set(lo, hi + 1);
+
+ // include the old selection in the event range
+ if (first >= 0)
+ lo = Math.min(lo, first);
+ if (last >= 0)
+ hi = Math.max(hi, last);
+ if (anchorSelectionIndex >= 0)
+ {
+ lo = Math.min(lo, anchorSelectionIndex);
+ hi = Math.max(hi, anchorSelectionIndex);
+ }
+ anchorSelectionIndex = anchor;
+ leadSelectionIndex = lead;
+ fireValueChanged(lo, hi);
+ }
+ else
+ {
+ BitSet oldSel = (BitSet) sel.clone();
+ sel.clear();
+ if (selectionMode == SINGLE_SELECTION)
+ anchor = lead;
+
+ int lo = Math.min(anchor, lead);
+ int hi = Math.max(anchor, lead);
+ sel.set(lo, hi+1);
+ // update the anchorSelectionIndex and leadSelectionIndex variables
+ setAnchorSelectionIndex(anchor);
+ leadSelectionIndex = lead;
- fireDifference(sel, oldSel);
+ fireDifference(sel, oldSel);
+ }
}
/**
diff --git a/libjava/classpath/javax/swing/GrayFilter.java b/libjava/classpath/javax/swing/GrayFilter.java
index b920b088a17..ef0d14718d6 100644
--- a/libjava/classpath/javax/swing/GrayFilter.java
+++ b/libjava/classpath/javax/swing/GrayFilter.java
@@ -76,9 +76,8 @@ public class GrayFilter extends RGBImageFilter
*/
public static Image createDisabledImage(Image src)
{
- return (Toolkit.getDefaultToolkit().
- createImage(new FilteredImageSource(src.getSource(),
- new GrayFilter(true, 0))));
+ return (Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(
+ src.getSource(), new GrayFilter(true, 0))));
}
/**
diff --git a/libjava/classpath/javax/swing/InputMap.java b/libjava/classpath/javax/swing/InputMap.java
index 28fccd9b9cd..19a75f4e985 100644
--- a/libjava/classpath/javax/swing/InputMap.java
+++ b/libjava/classpath/javax/swing/InputMap.java
@@ -1,5 +1,5 @@
/* InputMap.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,9 +37,6 @@ exception statement from your version. */
package javax.swing;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.HashMap;
@@ -47,14 +44,13 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-
/**
* Maps {@link KeyStroke}s to arbitrary objects, usually Strings. This
* is used in combination with {@link ActionMap}s.
*
* If a component receives an input event, this is looked up in
* the component's <code>InputMap</code>. The result is an object which
- * serves as a key to the components <code>ActionMap</code>. Finally
+ * serves as a key to the component's <code>ActionMap</code>. Finally
* the <code>Action</code> that is stored is executed.
*
* @author Andrew Selkirk
@@ -68,33 +64,37 @@ public class InputMap
private static final long serialVersionUID = -5429059542008604257L;
/**
- * inputMap
+ * Storage for the KeyStroke --> Object mappings.
*/
- private Map inputMap = new HashMap();
+ private Map inputMap;
/**
- * parent
+ * An optional parent map.
*/
private InputMap parent;
/**
- * Creates a new <code>InputMap</code> instance.
+ * Creates a new <code>InputMap</code> instance. This default instance
+ * contains no mappings and has no parent.
*/
public InputMap()
{
- // TODO
+ // nothing to do
}
/**
- * Returns the binding for keystroke.
+ * Returns the binding for the specified keystroke, if there is one.
*
- * @param keystroke the key of the enty
+ * @param keystroke the key of the entry (<code>null</code> is ignored).
*
- * @return the binding associated with keystroke may be null
+ * @return The binding associated with the specified keystroke (or
+ * <code>null</code>).
*/
public Object get(KeyStroke keystroke)
{
- Object result = inputMap.get(keystroke);
+ Object result = null;
+ if (inputMap != null)
+ result = inputMap.get(keystroke);
if (result == null && parent != null)
result = parent.get(keystroke);
@@ -102,14 +102,20 @@ public class InputMap
}
/**
- * Puts a new entry into the <code>InputMap</code>.
- * If actionMapKey is null an existing entry will be removed.
+ * Puts a new entry into the <code>InputMap</code>. If
+ * <code>actionMapKey</code> is <code>null</code> any existing entry will be
+ * removed.
*
- * @param keystroke the keystroke for the entry
- * @param actionMapKey the action.
+ * @param keystroke the keystroke for the entry (<code>null</code> is
+ * ignored).
+ * @param actionMapKey the action (<code>null</code> permitted).
*/
public void put(KeyStroke keystroke, Object actionMapKey)
{
+ if (keystroke == null)
+ return;
+ if (inputMap == null)
+ inputMap = new HashMap();
if (actionMapKey == null)
inputMap.remove(keystroke);
else
@@ -117,19 +123,25 @@ public class InputMap
}
/**
- * Remove an entry from the <code>InputMap</code>.
+ * Removes an entry from this <code>InputMap</code>. Note that this will
+ * not remove any entry from the parent map, if there is one.
*
- * @param keystroke the key of the entry to remove
+ * @param keystroke the key of the entry to remove (<code>null</code> is
+ * ignored).
*/
public void remove(KeyStroke keystroke)
{
- inputMap.remove(keystroke);
+ if (inputMap != null)
+ inputMap.remove(keystroke);
}
/**
- * Returns the parent of this <code>InputMap</code>.
+ * Returns the parent of this <code>InputMap</code>. The default value
+ * is <code>null</code>.
*
- * @return the parent, may be null.
+ * @return The parent map (possibly <code>null</code>).
+ *
+ * @see #setParent(InputMap)
*/
public InputMap getParent()
{
@@ -137,9 +149,13 @@ public class InputMap
}
/**
- * Sets a parent for this <code>InputMap</code>.
+ * Sets a parent for this <code>InputMap</code>. If a parent is specified,
+ * the {@link #get(KeyStroke)} method will look in the parent if it cannot
+ * find an entry in this map.
*
- * @param parentMap the new parent
+ * @param parentMap the new parent (<code>null</code> permitted).
+ *
+ * @see #getParent()
*/
public void setParent(InputMap parentMap)
{
@@ -147,31 +163,44 @@ public class InputMap
}
/**
- * Returns the number of entries in this <code>InputMap</code>.
+ * Returns the number of entries in this <code>InputMap</code>. This count
+ * does not include any entries from the parent map, if there is one.
*
- * @return the number of entries
+ * @return The number of entries.
*/
public int size()
{
- return inputMap.size();
+ int result = 0;
+ if (inputMap != null)
+ result = inputMap.size();
+ return result;
}
/**
- * Clears the <code>InputMap</code>.
+ * Clears the entries from this <code>InputMap</code>. The parent map, if
+ * there is one, is not cleared.
*/
public void clear()
{
- inputMap.clear();
+ if (inputMap != null)
+ inputMap.clear();
}
/**
- * Returns all keys of entries in this <code>InputMap</code>.
+ * Returns all keys of entries in this <code>InputMap</code>. This does not
+ * include keys defined in the parent, if there is one (use the
+ * {@link #allKeys()} method for that case).
+ * <br><br>
+ * Following the behaviour of the reference implementation, this method will
+ * return <code>null</code> when no entries have been added to the map,
+ * and a zero length array if entries have been added but subsequently
+ * removed (or cleared) from the map.
*
- * @return an array of keys
+ * @return An array of keys (may be <code>null</code> or have zero length).
*/
public KeyStroke[] keys()
{
- if (size() != 0)
+ if (inputMap != null)
{
KeyStroke[] array = new KeyStroke[size()];
return (KeyStroke[]) inputMap.keySet().toArray(array);
@@ -180,10 +209,10 @@ public class InputMap
}
/**
- * Returns all keys of entries in this <code>InputMap</code>
- * and all its parents.
+ * Returns all keys of entries in this <code>InputMap</code> and all its
+ * parents.
*
- * @return an array of keys
+ * @return An array of keys (may be <code>null</code> or have zero length).
*/
public KeyStroke[] allKeys()
{
@@ -195,36 +224,12 @@ public class InputMap
if (parentKeys != null)
set.addAll(Arrays.asList(parentKeys));
}
- set.addAll(inputMap.keySet());
+ if (inputMap != null)
+ set.addAll(inputMap.keySet());
if (set.size() == 0)
return null;
KeyStroke[] array = new KeyStroke[set.size()];
return (KeyStroke[]) set.toArray(array);
}
- /**
- * writeObject
- *
- * @param stream the stream to write to
- *
- * @exception IOException If an error occurs
- */
- private void writeObject(ObjectOutputStream stream) throws IOException
- {
- // TODO
- }
-
- /**
- * readObject
- *
- * @param stream the stream to read from
- *
- * @exception ClassNotFoundException If the serialized class cannot be found
- * @exception IOException If an error occurs
- */
- private void readObject(ObjectInputStream stream)
- throws ClassNotFoundException, IOException
- {
- // TODO
- }
}
diff --git a/libjava/classpath/javax/swing/JCheckBoxMenuItem.java b/libjava/classpath/javax/swing/JCheckBoxMenuItem.java
index 3222d189f37..51634c93f0b 100644
--- a/libjava/classpath/javax/swing/JCheckBoxMenuItem.java
+++ b/libjava/classpath/javax/swing/JCheckBoxMenuItem.java
@@ -1,39 +1,39 @@
/* JCheckBoxMenuItem.java --
- Copyright (C) 2002, 2004, 2006, 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, 2006, 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;
@@ -43,20 +43,20 @@ import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
/**
- * A menu item that displays a checkbox. Its behaviour is very similar
- * to {@link JCheckBox}. Just like the <code>JCheckBox</code>, user can check
+ * A menu item that displays a checkbox. Its behaviour is very similar to
+ * {@link JCheckBox}. Just like the <code>JCheckBox</code>, user can check
* and uncheck this menu item by clicking on it. Also
- * {@link AbstractButton#setSelected} and {@link #setState} can be use used
- * for the same purpose.
- * <code>JCheckBoxMenuItem</code> uses
+ * {@link AbstractButton#setSelected} and {@link #setState} can be use used for
+ * the same purpose. <code>JCheckBoxMenuItem</code> uses
* <code>ToggleButtonModel</code> to keep track of its selection.
- *
+ *
* @author original author unknown
*/
-public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
- Accessible
+public class JCheckBoxMenuItem
+ extends JMenuItem
+ implements SwingConstants, Accessible
{
- private static final long serialVersionUID = -6676402307973384715L;
+ private static final long serialVersionUID = - 6676402307973384715L;
/** name for the UI delegate for this menuItem. */
private static final String uiClassID = "CheckBoxMenuItemUI";
@@ -65,8 +65,8 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
private boolean state;
/**
- * This array contains text of this menu item if this menu item is in
- * checked state and null it is not.
+ * This array contains text of this menu item if this menu item is in checked
+ * state and null it is not.
*/
private Object[] selectedObjects = new Object[1];
@@ -80,7 +80,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
/**
* Creates a new JCheckBoxMenuItem with given icon
- *
+ *
* @param icon Icon for this menu item
*/
public JCheckBoxMenuItem(Icon icon)
@@ -90,7 +90,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
/**
* Creates a new JCheckBoxMenuItem with given label
- *
+ *
* @param text Label for this menu item
*/
public JCheckBoxMenuItem(String text)
@@ -100,7 +100,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
/**
* Creates a new JCheckBoxMenuItem using given action
- *
+ *
* @param action Action for this menu item.
*/
public JCheckBoxMenuItem(Action action)
@@ -111,7 +111,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
/**
* Creates a new JCheckBoxMenuItem object with given label and icon
- *
+ *
* @param text Label for this menu item
* @param icon Icon for this menu item
*/
@@ -121,12 +121,12 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * Creates a new JCheckBoxMenuItem object using specified label and
- * marked as checked if given 'state' is true.
- *
+ * Creates a new JCheckBoxMenuItem object using specified label and marked as
+ * checked if given 'state' is true.
+ *
* @param text Label for this menu item
- * @param state <code>true</code> if this item should be in checked state and
- * <code>false</code> otherwise
+ * @param state <code>true</code> if this item should be in checked state
+ * and <code>false</code> otherwise
*/
public JCheckBoxMenuItem(String text, boolean state)
{
@@ -134,26 +134,28 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * Creates a new JCheckBoxMenuItem object with given label, icon,
- * and marked as checked if given 'state' is true.
- *
+ * Creates a new JCheckBoxMenuItem object with given label, icon, and marked
+ * as checked if given 'state' is true.
+ *
* @param text Label for this menu item
* @param icon icon for this menu item
- * @param state <code>true</code> if this item should be in checked state and
- * false otherwise
+ * @param state <code>true</code> if this item should be in checked state
+ * and false otherwise
*/
public JCheckBoxMenuItem(String text, Icon icon, boolean state)
{
super(text, icon);
setModel(new JToggleButton.ToggleButtonModel());
this.state = state;
- this.setVisible(true);
+ if (state == true)
+ this.setSelected(true);
+ setFocusable(false);
}
/**
* This method returns a name to identify which look and feel class will be
* the UI delegate for the menuItem.
- *
+ *
* @return The Look and Feel classID. "JCheckBoxMenuItemUI"
*/
public String getUIClassID()
@@ -163,9 +165,9 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
/**
* Returns checked state for this check box menu item.
- *
- * @return Returns true if this menu item is in checked state
- * and false otherwise.
+ *
+ * @return Returns true if this menu item is in checked state and false
+ * otherwise.
*/
public boolean getState()
{
@@ -173,10 +175,9 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * Sets state for this check box menu item. If
- * given 'state' is true, then mark menu item as checked,
- * and uncheck this menu item otherwise.
- *
+ * Sets state for this check box menu item. If given 'state' is true, then
+ * mark menu item as checked, and uncheck this menu item otherwise.
+ *
* @param state new state for this menu item
*/
public synchronized void setState(boolean state)
@@ -185,11 +186,11 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * This method returns array containing label of this
- * menu item if it is selected and null otherwise.
- *
- * @return Array containing label of this
- * menu item if this menu item is selected or null otherwise.
+ * This method returns array containing label of this menu item if it is
+ * selected and null otherwise.
+ *
+ * @return Array containing label of this menu item if this menu item is
+ * selected or null otherwise.
*/
public Object[] getSelectedObjects()
{
@@ -202,27 +203,26 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * This method overrides JComponent.requestFocus with an empty
- * implementation, since JCheckBoxMenuItems should not
- * receive focus in general.
- */
+ * This method overrides JComponent.requestFocus with an empty implementation,
+ * since JCheckBoxMenuItems should not receive focus in general.
+ */
public void requestFocus()
{
- // Should do nothing here
+ // Should do nothing here
}
/**
- * Returns a string describing the attributes for the
- * <code>JCheckBoxMenuItem</code> component, for use in debugging. The
- * return value is guaranteed to be non-<code>null</code>, but the format
+ * Returns a string describing the attributes for the
+ * <code>JCheckBoxMenuItem</code> component, for use in debugging. The
+ * return value is guaranteed to be non-<code>null</code>, but the format
* of the string may vary between implementations.
- *
- * @return A string describing the attributes of the
- * <code>JCheckBoxMenuItem</code>.
+ *
+ * @return A string describing the attributes of the
+ * <code>JCheckBoxMenuItem</code>.
*/
protected String paramString()
{
- // calling super seems to be sufficient to match the reference
+ // calling super seems to be sufficient to match the reference
// implementation here...
return super.paramString();
}
@@ -230,9 +230,9 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
/**
* Returns the object that provides accessibility features for this
* <code>JCheckBoxMenuItem</code> component.
- *
- * @return The accessible context (an instance of
- * {@link AccessibleJCheckBoxMenuItem}).
+ *
+ * @return The accessible context (an instance of
+ * {@link AccessibleJCheckBoxMenuItem}).
*/
public AccessibleContext getAccessibleContext()
{
@@ -243,12 +243,13 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * Provides the accessibility features for the <code>JCheckBoxMenuItem</code>
+ * Provides the accessibility features for the <code>JCheckBoxMenuItem</code>
* component.
*
* @see JCheckBoxMenuItem#getAccessibleContext()
*/
- protected class AccessibleJCheckBoxMenuItem extends AccessibleJMenuItem
+ protected class AccessibleJCheckBoxMenuItem
+ extends AccessibleJMenuItem
{
private static final long serialVersionUID = 1079958073579370777L;
@@ -261,9 +262,9 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants,
}
/**
- * Returns the accessible role for the <code>JCheckBoxMenuItem</code>
+ * Returns the accessible role for the <code>JCheckBoxMenuItem</code>
* component.
- *
+ *
* @return {@link AccessibleRole#CHECK_BOX}.
*/
public AccessibleRole getAccessibleRole()
diff --git a/libjava/classpath/javax/swing/JComboBox.java b/libjava/classpath/javax/swing/JComboBox.java
index efb04592b50..c75a94bdc36 100644
--- a/libjava/classpath/javax/swing/JComboBox.java
+++ b/libjava/classpath/javax/swing/JComboBox.java
@@ -471,6 +471,7 @@ public class JComboBox extends JComponent implements ItemSelectable,
public void setSelectedItem(Object item)
{
dataModel.setSelectedItem(item);
+ fireActionEvent();
}
/**
@@ -1028,7 +1029,8 @@ public class JComboBox extends JComponent implements ItemSelectable,
}
/**
- * This method hides combo box's popup whenever TAB key is pressed.
+ * This method is fired whenever a key is pressed with the combo box
+ * in focus
*
* @param e The KeyEvent indicating which key was pressed.
*/
@@ -1036,15 +1038,6 @@ public class JComboBox extends JComponent implements ItemSelectable,
{
if (e.getKeyCode() == KeyEvent.VK_TAB)
setPopupVisible(false);
- else if (keySelectionManager != null)
- {
- int i = keySelectionManager.selectionForKey(e.getKeyChar(),
- getModel());
- if (i >= 0)
- setSelectedIndex(i);
- else
- super.processKeyEvent(e);
- }
else
super.processKeyEvent(e);
}
@@ -1066,7 +1059,7 @@ public class JComboBox extends JComponent implements ItemSelectable,
*/
public KeySelectionManager getKeySelectionManager()
{
- return null;
+ return keySelectionManager;
}
/**
@@ -1098,7 +1091,7 @@ public class JComboBox extends JComponent implements ItemSelectable,
*/
protected KeySelectionManager createDefaultKeySelectionManager()
{
- return null;
+ return new DefaultKeySelectionManager();
}
/**
@@ -1471,4 +1464,34 @@ public class JComboBox extends JComponent implements ItemSelectable,
// Nothing to do here.
}
}
+
+ private class DefaultKeySelectionManager
+ implements KeySelectionManager
+ {
+
+ public int selectionForKey(char aKey, ComboBoxModel aModel)
+ {
+ int selectedIndex = getSelectedIndex();
+
+ // Start at currently selected item and iterate to end of list
+ for (int i = selectedIndex + 1; i < aModel.getSize(); i++)
+ {
+ String nextItem = aModel.getElementAt(i).toString();
+
+ if (nextItem.charAt(0) == aKey)
+ return i;
+ }
+
+ // Wrap to start of list if no match yet
+ for (int i = 0; i <= selectedIndex; i++)
+ {
+ String nextItem = aModel.getElementAt(i).toString();
+
+ if (nextItem.charAt(0) == aKey)
+ return i;
+ }
+
+ return - 1;
+ }
+ }
}
diff --git a/libjava/classpath/javax/swing/JComponent.java b/libjava/classpath/javax/swing/JComponent.java
index 66c562d110b..fa83502946d 100644
--- a/libjava/classpath/javax/swing/JComponent.java
+++ b/libjava/classpath/javax/swing/JComponent.java
@@ -48,12 +48,10 @@ import java.awt.EventQueue;
import java.awt.FocusTraversalPolicy;
import java.awt.Font;
import java.awt.Graphics;
-import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
-import java.awt.Shape;
import java.awt.Window;
import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent;
@@ -69,8 +67,8 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
+import java.beans.VetoableChangeSupport;
import java.io.Serializable;
-import java.util.ArrayList;
import java.util.EventListener;
import java.util.Hashtable;
import java.util.Locale;
@@ -571,6 +569,21 @@ public abstract class JComponent extends Container implements Serializable
*/
String toolTipText;
+ /**
+ * The popup menu for the component.
+ *
+ * @see #getComponentPopupMenu()
+ * @see #setComponentPopupMenu(JPopupMenu)
+ */
+ JPopupMenu componentPopupMenu;
+
+ /**
+ * A flag that controls whether the {@link #getComponentPopupMenu()} method
+ * looks to the component's parent when the <code>componentPopupMenu</code>
+ * field is <code>null</code>.
+ */
+ boolean inheritsPopupMenu;
+
/**
* <p>Whether to double buffer this component when painting. This flag
* should generally be <code>true</code>, to ensure good painting
@@ -668,7 +681,13 @@ public abstract class JComponent extends Container implements Serializable
* Indicates whether the current paint call is already double buffered or
* not.
*/
- static boolean isPaintingDoubleBuffered = false;
+ static boolean paintingDoubleBuffered = false;
+
+ /**
+ * Indicates whether we are calling paintDoubleBuffered() from
+ * paintImmadiately (RepaintManager) or from paint() (AWT refresh).
+ */
+ static private boolean isRepainting = false;
/**
* Listeners for events other than {@link PropertyChangeEvent} are
@@ -677,6 +696,11 @@ public abstract class JComponent extends Container implements Serializable
*/
protected EventListenerList listenerList = new EventListenerList();
+ /**
+ * Handles VetoableChangeEvents.
+ */
+ private VetoableChangeSupport vetoableChangeSupport;
+
/**
* Storage for "client properties", which are key/value pairs associated
* with this component by a "client", such as a user application or a
@@ -690,7 +714,7 @@ public abstract class JComponent extends Container implements Serializable
private ComponentInputMap inputMap_whenInFocusedWindow;
private ActionMap actionMap;
/** @since 1.3 */
- private boolean verifyInputWhenFocusTarget;
+ private boolean verifyInputWhenFocusTarget = true;
private InputVerifier inputVerifier;
private TransferHandler transferHandler;
@@ -784,7 +808,7 @@ public abstract class JComponent extends Container implements Serializable
{
super();
setDropTarget(new DropTarget());
- defaultLocale = Locale.getDefault();
+ setLocale(getDefaultLocale());
debugGraphicsOptions = DebugGraphics.NONE_OPTION;
setRequestFocusEnabled(true);
}
@@ -868,7 +892,8 @@ public abstract class JComponent extends Container implements Serializable
*/
public void removeVetoableChangeListener(VetoableChangeListener listener)
{
- listenerList.remove(VetoableChangeListener.class, listener);
+ if (vetoableChangeSupport != null)
+ vetoableChangeSupport.removeVetoableChangeListener(listener);
}
/**
@@ -884,23 +909,6 @@ public abstract class JComponent extends Container implements Serializable
}
/**
- * Register a <code>PropertyChangeListener</code> for a specific, named
- * property. To listen to all property changes, regardless of name, use
- * {@link #addPropertyChangeListener(PropertyChangeListener)} instead.
- *
- * @param propertyName The property name to listen to
- * @param listener The listener to register
- *
- * @see #removePropertyChangeListener(String, PropertyChangeListener)
- * @see #changeSupport
- */
- public void addPropertyChangeListener(String propertyName,
- PropertyChangeListener listener)
- {
- listenerList.add(PropertyChangeListener.class, listener);
- }
-
- /**
* Register a <code>VetoableChangeListener</code>.
*
* @param listener The listener to register
@@ -910,7 +918,10 @@ public abstract class JComponent extends Container implements Serializable
*/
public void addVetoableChangeListener(VetoableChangeListener listener)
{
- listenerList.add(VetoableChangeListener.class, listener);
+ // Lazily instantiate this, it's rarely needed.
+ if (vetoableChangeSupport == null)
+ vetoableChangeSupport = new VetoableChangeSupport(this);
+ vetoableChangeSupport.addVetoableChangeListener(listener);
}
/**
@@ -936,6 +947,8 @@ public abstract class JComponent extends Container implements Serializable
{
if (listenerType == PropertyChangeListener.class)
return getPropertyChangeListeners();
+ else if (listenerType == VetoableChangeListener.class)
+ return getVetoableChangeListeners();
else
return listenerList.getListeners(listenerType);
}
@@ -954,84 +967,89 @@ public abstract class JComponent extends Container implements Serializable
/**
* Return all registered <code>VetoableChangeListener</code> objects.
*
- * @return The set of <code>VetoableChangeListener</code> objects in {@link
- * #listenerList}
+ * @return An array of the <code>VetoableChangeListener</code> objects
+ * registered with this component (possibly empty but never
+ * <code>null</code>).
+ *
+ * @since 1.4
*/
public VetoableChangeListener[] getVetoableChangeListeners()
- {
- return (VetoableChangeListener[]) getListeners(VetoableChangeListener.class);
+ {
+ return vetoableChangeSupport == null ? new VetoableChangeListener[0]
+ : vetoableChangeSupport.getVetoableChangeListeners();
}
/**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>boolean</code> values.
+ * Call {@link VetoableChangeListener#vetoableChange} on all listeners
+ * registered to listen to a given property. Any method which changes
+ * the specified property of this component should call this method.
+ *
+ * @param propertyName The property which changed
+ * @param oldValue The old value of the property
+ * @param newValue The new value of the property
+ *
+ * @throws PropertyVetoException if the change was vetoed by a listener
*
- * @specnote It seems that in JDK1.5 all property related methods have been
- * moved to java.awt.Component, except this and 2 others. We call
- * super here. I guess this will also be removed in one of the next
- * releases.
+ * @see #addVetoableChangeListener
+ * @see #removeVetoableChangeListener
*/
- public void firePropertyChange(String propertyName, boolean oldValue,
- boolean newValue)
+ protected void fireVetoableChange(String propertyName, Object oldValue,
+ Object newValue)
+ throws PropertyVetoException
{
- super.firePropertyChange(propertyName, oldValue, newValue);
+ if (vetoableChangeSupport != null)
+ vetoableChangeSupport.fireVetoableChange(propertyName, oldValue, newValue);
}
+
/**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>char</code> values.
+ * Fires a property change for a primitive integer property.
+ *
+ * @param property the name of the property
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
*
- * @specnote It seems that in JDK1.5 all property related methods have been
- * moved to java.awt.Component, except this and 2 others. We call
- * super here. I guess this will also be removed in one of the next
- * releases.
+ * @specnote This method is implemented in
+ * {@link Component#firePropertyChange(String, int, int)}. It is
+ * only here because it is specified to be public, whereas the
+ * Component method is protected.
*/
- public void firePropertyChange(String propertyName, char oldValue,
- char newValue)
+ public void firePropertyChange(String property, int oldValue, int newValue)
{
- super.firePropertyChange(propertyName, oldValue, newValue);
+ super.firePropertyChange(property, oldValue, newValue);
}
-
+
/**
- * A variant of {@link #firePropertyChange(String,Object,Object)}
- * for properties with <code>int</code> values.
+ * Fires a property change for a primitive boolean property.
+ *
+ * @param property the name of the property
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
*
- * @specnote It seems that in JDK1.5 all property related methods have been
- * moved to java.awt.Component, except this and 2 others. We call
- * super here. I guess this will also be removed in one of the next
- * releases.
+ * @specnote This method is implemented in
+ * {@link Component#firePropertyChange(String, boolean, boolean)}.
+ * It is only here because it is specified to be public, whereas
+ * the Component method is protected.
*/
- public void firePropertyChange(String propertyName, int oldValue,
- int newValue)
+ public void firePropertyChange(String property, boolean oldValue,
+ boolean newValue)
{
- super.firePropertyChange(propertyName, oldValue, newValue);
+ super.firePropertyChange(property, oldValue, newValue);
}
/**
- * Call {@link VetoableChangeListener#vetoableChange} on all listeners
- * registered to listen to a given property. Any method which changes
- * the specified property of this component should call this method.
- *
- * @param propertyName The property which changed
- * @param oldValue The old value of the property
- * @param newValue The new value of the property
- *
- * @throws PropertyVetoException if the change was vetoed by a listener
+ * Fires a property change for a primitive character property.
*
- * @see #addVetoableChangeListener
- * @see #removeVetoableChangeListener
+ * @param property the name of the property
+ * @param oldValue the old value of the property
+ * @param newValue the new value of the property
*/
- protected void fireVetoableChange(String propertyName, Object oldValue,
- Object newValue)
- throws PropertyVetoException
+ public void firePropertyChange(String property, char oldValue,
+ char newValue)
{
- VetoableChangeListener[] listeners = getVetoableChangeListeners();
-
- PropertyChangeEvent evt =
- new PropertyChangeEvent(this, propertyName, oldValue, newValue);
-
- for (int i = 0; i < listeners.length; i++)
- listeners[i].vetoableChange(evt);
+ // FIXME - This method is already public in awt Component, but
+ // is included here to work around a compilation bug in gcj 4.1.
+ super.firePropertyChange(property, oldValue, newValue);
}
/**
@@ -1402,11 +1420,32 @@ public abstract class JComponent extends Container implements Serializable
* Return the set of {@link KeyStroke} objects which are registered
* to initiate actions on this component.
*
- * @return An array of the registered keystrokes
+ * @return An array of the registered keystrokes (possibly empty but never
+ * <code>null</code>).
*/
public KeyStroke[] getRegisteredKeyStrokes()
{
- return null;
+ KeyStroke[] ks0;
+ KeyStroke[] ks1;
+ KeyStroke[] ks2;
+ if (inputMap_whenFocused != null)
+ ks0 = inputMap_whenFocused.keys();
+ else
+ ks0 = new KeyStroke[0];
+ if (inputMap_whenAncestorOfFocused != null)
+ ks1 = inputMap_whenAncestorOfFocused.keys();
+ else
+ ks1 = new KeyStroke[0];
+ if (inputMap_whenInFocusedWindow != null)
+ ks2 = inputMap_whenInFocusedWindow.keys();
+ else
+ ks2 = new KeyStroke[0];
+ int count = ks0.length + ks1.length + ks2.length;
+ KeyStroke[] result = new KeyStroke[count];
+ System.arraycopy(ks0, 0, result, 0, ks0.length);
+ System.arraycopy(ks1, 0, result, ks0.length, ks1.length);
+ System.arraycopy(ks2, 0, result, ks0.length + ks1.length, ks2.length);
+ return result;
}
/**
@@ -1524,8 +1563,90 @@ public abstract class JComponent extends Container implements Serializable
{
return getToolTipText();
}
+
+ /**
+ * Returns the flag that controls whether or not the component inherits its
+ * parent's popup menu when no popup menu is specified for this component.
+ *
+ * @return A boolean.
+ *
+ * @since 1.5
+ *
+ * @see #setInheritsPopupMenu(boolean)
+ */
+ public boolean getInheritsPopupMenu()
+ {
+ return inheritsPopupMenu;
+ }
+
+ /**
+ * Sets the flag that controls whether or not the component inherits its
+ * parent's popup menu when no popup menu is specified for this component.
+ * This is a bound property with the property name 'inheritsPopupMenu'.
+ *
+ * @param inherit the new flag value.
+ *
+ * @since 1.5
+ *
+ * @see #getInheritsPopupMenu()
+ */
+ public void setInheritsPopupMenu(boolean inherit)
+ {
+ if (inheritsPopupMenu != inherit)
+ {
+ inheritsPopupMenu = inherit;
+ this.firePropertyChange("inheritsPopupMenu", ! inherit, inherit);
+ }
+ }
+
+ /**
+ * Returns the popup menu for this component. If the popup menu is
+ * <code>null</code> AND the {@link #getInheritsPopupMenu()} method returns
+ * <code>true</code>, this method will return the parent's popup menu (if it
+ * has one).
+ *
+ * @return The popup menu (possibly <code>null</code>.
+ *
+ * @since 1.5
+ *
+ * @see #setComponentPopupMenu(JPopupMenu)
+ * @see #getInheritsPopupMenu()
+ */
+ public JPopupMenu getComponentPopupMenu()
+ {
+ if (componentPopupMenu == null && getInheritsPopupMenu())
+ {
+ Container parent = getParent();
+ if (parent instanceof JComponent)
+ return ((JComponent) parent).getComponentPopupMenu();
+ else
+ return null;
+ }
+ else
+ return componentPopupMenu;
+ }
/**
+ * Sets the popup menu for this component (this is a bound property with
+ * the property name 'componentPopupMenu').
+ *
+ * @param popup the popup menu (<code>null</code> permitted).
+ *
+ * @since 1.5
+ *
+ * @see #getComponentPopupMenu()
+ */
+ public void setComponentPopupMenu(JPopupMenu popup)
+ {
+ if (componentPopupMenu != popup)
+ {
+ JPopupMenu old = componentPopupMenu;
+ componentPopupMenu = popup;
+ firePropertyChange("componentPopupMenu", old, popup);
+ }
+ }
+
+ /**
* Return the top level ancestral container (usually a {@link
* java.awt.Window} or {@link java.applet.Applet}) which this component is
* contained within, or <code>null</code> if no ancestors exist.
@@ -1725,7 +1846,7 @@ public abstract class JComponent extends Container implements Serializable
// buffer. When this method completes, the call stack unwinds back to
// paintDoubleBuffered, where the buffer contents is finally drawn to the
// screen.
- if (!isPaintingDoubleBuffered && isDoubleBuffered()
+ if (!paintingDoubleBuffered && isDoubleBuffered()
&& rm.isDoubleBufferingEnabled())
{
Rectangle clip = g.getClipBounds();
@@ -1816,235 +1937,77 @@ public abstract class JComponent extends Container implements Serializable
{
if (getComponentCount() > 0)
{
- if (isOptimizedDrawingEnabled())
- paintChildrenOptimized(g);
- else
- paintChildrenWithOverlap(g);
- }
- }
-
- /**
- * Paints the children of this JComponent in the case when the component
- * is not marked as optimizedDrawingEnabled, that means the container cannot
- * guarantee that it's children are tiled. For this case we must
- * perform a more complex optimization to determine the minimal rectangle
- * to be painted for each child component.
- *
- * @param g the graphics context to use
- */
- private void paintChildrenWithOverlap(Graphics g)
- {
- Shape originalClip = g.getClip();
- Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache);
- g.clipRect(inner.x, inner.y, inner.width, inner.height);
- Component[] children = getComponents();
-
- // Find the rectangles that need to be painted for each child component.
- // We push on this list arrays that have the Rectangles to be painted as
- // the first elements and the component to be painted as the last one.
- // Later we go through that list in reverse order and paint the rectangles.
- ArrayList paintRegions = new ArrayList(children.length);
- ArrayList paintRectangles = new ArrayList();
- ArrayList newPaintRects = new ArrayList();
- paintRectangles.add(g.getClipBounds());
- ArrayList componentRectangles = new ArrayList();
-
- // Go through children from top to bottom and find out their paint
- // rectangles.
- for (int index = 0; paintRectangles.size() > 0 &&
- index < children.length; index++)
- {
- Component comp = children[index];
- if (! comp.isVisible())
- continue;
-
- Rectangle compBounds = comp.getBounds();
- boolean isOpaque = comp instanceof JComponent
- && ((JComponent) comp).isOpaque();
-
- // Add all the current paint rectangles that intersect with the
- // component to the component's paint rectangle array.
- for (int i = paintRectangles.size() - 1; i >= 0; i--)
+ // Need to lock the tree to avoid problems with AWT and concurrency.
+ synchronized (getTreeLock())
{
- Rectangle r = (Rectangle) paintRectangles.get(i);
- if (r.intersects(compBounds))
+ for (int i = getComponentCount() - 1; i >= 0; i--)
{
- Rectangle compRect = r.intersection(compBounds);
- componentRectangles.add(compRect);
- // If the component is opaque, split up each paint rect and
- // add paintRect - compBounds to the newPaintRects array.
- if (isOpaque)
+ Component child = getComponent(i);
+ if (child != null && child.isLightweight()
+ && child.isVisible())
{
- int x, y, w, h;
- Rectangle rect = new Rectangle();
-
- // The north retangle.
- x = Math.max(compBounds.x, r.x);
- y = r.y;
- w = Math.min(compBounds.width, r.width + r.x - x);
- h = compBounds.y - r.y;
- rect.setBounds(x, y, w, h);
- if (! rect.isEmpty())
- {
- newPaintRects.add(rect);
- rect = new Rectangle();
- }
-
- // The south rectangle.
- x = Math.max(compBounds.x, r.x);
- y = compBounds.y + compBounds.height;
- w = Math.min(compBounds.width, r.width + r.x - x);
- h = r.height - (compBounds.y - r.y) - compBounds.height;
- rect.setBounds(x, y, w, h);
- if (! rect.isEmpty())
- {
- newPaintRects.add(rect);
- rect = new Rectangle();
- }
-
- // The west rectangle.
- x = r.x;
- y = r.y;
- w = compBounds.x - r.x;
- h = r.height;
- rect.setBounds(x, y, w, h);
- if (! rect.isEmpty())
+ int cx = child.getX();
+ int cy = child.getY();
+ int cw = child.getWidth();
+ int ch = child.getHeight();
+ if (g.hitClip(cx, cy, cw, ch))
{
- newPaintRects.add(rect);
- rect = new Rectangle();
- }
-
- // The east rectangle.
- x = compBounds.x + compBounds.width;
- y = r.y;
- w = r.width - (compBounds.x - r.x) - compBounds.width;
- h = r.height;
- rect.setBounds(x, y, w, h);
- if (! rect.isEmpty())
- {
- newPaintRects.add(rect);
+ if ((! isOptimizedDrawingEnabled()) && i > 0)
+ {
+ // Check if the child is completely obscured.
+ Rectangle clip = g.getClipBounds(); // A copy.
+ SwingUtilities.computeIntersection(cx, cy, cw, ch,
+ clip);
+ if (isCompletelyObscured(i, clip))
+ continue; // Continues the for-loop.
+ }
+ Graphics cg = g.create(cx, cy, cw, ch);
+ cg.setColor(child.getForeground());
+ cg.setFont(child.getFont());
+ try
+ {
+ child.paint(cg);
+ }
+ finally
+ {
+ cg.dispose();
+ }
}
}
- else
- {
- // Not opaque, need to reuse the current paint rectangles
- // for the next component.
- newPaintRects.add(r);
- }
-
- }
- else
- {
- newPaintRects.add(r);
}
}
-
- // Replace the paintRectangles with the new split up
- // paintRectangles.
- paintRectangles.clear();
- paintRectangles.addAll(newPaintRects);
- newPaintRects.clear();
-
- // Store paint rectangles if there are any for the current component.
- int compRectsSize = componentRectangles.size();
- if (compRectsSize > 0)
- {
- componentRectangles.add(comp);
- paintRegions.add(componentRectangles);
- componentRectangles = new ArrayList();
- }
}
-
- // paintingTile becomes true just before we start painting the component's
- // children.
- paintingTile = true;
-
- // We must go through the painting regions backwards, because the
- // topmost components have been added first, followed by the components
- // below.
- int prEndIndex = paintRegions.size() - 1;
- for (int i = prEndIndex; i >= 0; i--)
- {
- // paintingTile must be set to false before we begin to start painting
- // the last tile.
- if (i == 0)
- paintingTile = false;
-
- ArrayList paintingRects = (ArrayList) paintRegions.get(i);
- // The last element is always the component.
- Component c = (Component) paintingRects.get(paintingRects.size() - 1);
- int endIndex = paintingRects.size() - 2;
- for (int j = 0; j <= endIndex; j++)
- {
- Rectangle cBounds = c.getBounds();
- Rectangle bounds = (Rectangle) paintingRects.get(j);
- Rectangle oldClip = g.getClipBounds();
- if (oldClip == null)
- oldClip = bounds;
-
- boolean translated = false;
- try
- {
- g.setClip(bounds);
- g.translate(cBounds.x, cBounds.y);
- translated = true;
- c.paint(g);
- }
- finally
- {
- if (translated)
- g.translate(-cBounds.x, -cBounds.y);
- g.setClip(oldClip);
- }
- }
- }
- g.setClip(originalClip);
}
/**
- * Paints the children of this container when it is marked as
- * optimizedDrawingEnabled. In this case the container can guarantee that
- * it's children are tiled, which allows for a much more efficient
- * algorithm to determine the minimum rectangles to be painted for
- * each child.
+ * Determines if a region of a child component is completely obscured by one
+ * of its siblings.
+ *
+ * @param index the index of the child component
+ * @param rect the region to check
*
- * @param g the graphics context to use
+ * @return <code>true</code> if the region is completely obscured by a
+ * sibling, <code>false</code> otherwise
*/
- private void paintChildrenOptimized(Graphics g)
+ private boolean isCompletelyObscured(int index, Rectangle rect)
{
- Shape originalClip = g.getClip();
- Rectangle inner = SwingUtilities.calculateInnerArea(this, rectCache);
- g.clipRect(inner.x, inner.y, inner.width, inner.height);
- Component[] children = getComponents();
-
- // paintingTile becomes true just before we start painting the component's
- // children.
- paintingTile = true;
- for (int i = children.length - 1; i >= 0; i--) //children.length; i++)
+ boolean obscured = false;
+ for (int i = index - 1; i >= 0 && obscured == false; i--)
{
- // paintingTile must be set to false before we begin to start painting
- // the last tile.
- if (i == children.length - 1)
- paintingTile = false;
-
- if (!children[i].isVisible())
- continue;
-
- Rectangle bounds = children[i].getBounds(rectCache);
- Rectangle oldClip = g.getClipBounds();
- if (oldClip == null)
- oldClip = bounds;
-
- if (!g.hitClip(bounds.x, bounds.y, bounds.width, bounds.height))
- continue;
-
- boolean translated = false;
- Graphics g2 = g.create(bounds.x, bounds.y, bounds.width,
- bounds.height);
- children[i].paint(g2);
- g2.dispose();
+ Component sib = getComponent(i);
+ if (sib.isVisible())
+ {
+ Rectangle sibRect = sib.getBounds(rectCache);
+ if (sib.isOpaque() && rect.x >= sibRect.x
+ && (rect.x + rect.width) <= (sibRect.x + sibRect.width)
+ && rect.y >= sibRect.y
+ && (rect.y + rect.height) <= (sibRect.y + sibRect.height))
+ {
+ obscured = true;
+ }
+ }
}
- g.setClip(originalClip);
+ return obscured;
}
/**
@@ -2064,12 +2027,15 @@ public abstract class JComponent extends Container implements Serializable
{
if (ui != null)
{
- Graphics g2 = g;
- if (!(g instanceof Graphics2D))
- g2 = g.create();
- ui.update(g2, this);
- if (!(g instanceof Graphics2D))
- g2.dispose();
+ Graphics g2 = g.create();
+ try
+ {
+ ui.update(g2, this);
+ }
+ finally
+ {
+ g2.dispose();
+ }
}
}
@@ -2112,16 +2078,13 @@ public abstract class JComponent extends Container implements Serializable
Component root = findPaintRoot(r);
// If no paint root is found, then this component is completely overlapped
// by another component and we don't need repainting.
- if (root == null)
+ if (root == null|| !root.isShowing())
return;
- if (root == null || !root.isShowing())
- return;
-
- Rectangle rootClip = SwingUtilities.convertRectangle(this, r, root);
+ SwingUtilities.convertRectangleToAncestor(this, r, root);
if (root instanceof JComponent)
- ((JComponent) root).paintImmediately2(rootClip);
+ ((JComponent) root).paintImmediately2(r);
else
- root.repaint(rootClip.x, rootClip.y, rootClip.width, rootClip.height);
+ root.repaint(r.x, r.y, r.width, r.height);
}
/**
@@ -2131,40 +2094,35 @@ public abstract class JComponent extends Container implements Serializable
*/
void paintImmediately2(Rectangle r)
{
+ isRepainting = true;
RepaintManager rm = RepaintManager.currentManager(this);
- if (rm.isDoubleBufferingEnabled() && isDoubleBuffered())
+ if (rm.isDoubleBufferingEnabled() && isPaintingDoubleBuffered())
paintDoubleBuffered(r);
else
paintSimple(r);
+ isRepainting = false;
}
/**
- * Gets the root of the component given. If a parent of the
- * component is an instance of Applet, then the applet is
- * returned. The applet is considered the root for painting
- * and adding/removing components. Otherwise, the root Window
- * is returned if it exists.
- *
- * @param comp - The component to get the root for.
- * @return the parent root. An applet if it is a parent,
- * or the root window. If neither exist, null is returned.
+ * Returns true if we must paint double buffered, that is, when this
+ * component or any of it's ancestors are double buffered.
+ *
+ * @return true if we must paint double buffered, that is, when this
+ * component or any of it's ancestors are double buffered
*/
- private Component getRoot(Component comp)
+ private boolean isPaintingDoubleBuffered()
{
- Applet app = null;
-
- while (comp != null)
- {
- if (app == null && comp instanceof Window)
- return comp;
- else if (comp instanceof Applet)
- app = (Applet) comp;
- comp = comp.getParent();
- }
-
- return app;
+ boolean doubleBuffered = isDoubleBuffered();
+ Component parent = getParent();
+ while (! doubleBuffered && parent != null)
+ {
+ doubleBuffered = parent instanceof JComponent
+ && ((JComponent) parent).isDoubleBuffered();
+ parent = parent.getParent();
+ }
+ return doubleBuffered;
}
-
+
/**
* Performs double buffered repainting.
*/
@@ -2173,7 +2131,7 @@ public abstract class JComponent extends Container implements Serializable
RepaintManager rm = RepaintManager.currentManager(this);
// Paint on the offscreen buffer.
- Component root = getRoot(this);
+ Component root = SwingUtilities.getRoot(this);
Image buffer = rm.getVolatileOffscreenBuffer(this, root.getWidth(),
root.getHeight());
@@ -2183,26 +2141,30 @@ public abstract class JComponent extends Container implements Serializable
buffer = rm.getOffscreenBuffer(this, root.getWidth(), root.getHeight());
//Rectangle targetClip = SwingUtilities.convertRectangle(this, r, root);
- Point translation = SwingUtilities.convertPoint(this, 0, 0, root);
Graphics g2 = buffer.getGraphics();
clipAndTranslateGraphics(root, this, g2);
g2.clipRect(r.x, r.y, r.width, r.height);
g2 = getComponentGraphics(g2);
- isPaintingDoubleBuffered = true;
+ paintingDoubleBuffered = true;
try
{
- paint(g2);
+ if (isRepainting) // Called from paintImmediately, go through paint().
+ paint(g2);
+ else // Called from paint() (AWT refresh), don't call it again.
+ {
+ paintComponent(g2);
+ paintBorder(g2);
+ paintChildren(g2);
+ }
}
finally
{
- isPaintingDoubleBuffered = false;
+ paintingDoubleBuffered = false;
g2.dispose();
}
// Paint the buffer contents on screen.
- rm.commitBuffer(root, new Rectangle(translation.x + r.x,
- translation.y + r.y, r.width,
- r.height));
+ rm.commitBuffer(this, r);
}
/**
@@ -2217,11 +2179,16 @@ public abstract class JComponent extends Container implements Serializable
private void clipAndTranslateGraphics(Component root, Component target,
Graphics g)
{
- Component parent = target.getParent();
- if (parent != root)
- clipAndTranslateGraphics(root, parent, g);
-
- g.translate(target.getX(), target.getY());
+ Component parent = target;
+ int deltaX = 0;
+ int deltaY = 0;
+ while (parent != root)
+ {
+ deltaX += parent.getX();
+ deltaY += parent.getY();
+ parent = parent.getParent();
+ }
+ g.translate(deltaX, deltaY);
g.clipRect(0, 0, target.getWidth(), target.getHeight());
}
@@ -2271,7 +2238,13 @@ public abstract class JComponent extends Container implements Serializable
/**
* A variant of {@link
* #registerKeyboardAction(ActionListener,String,KeyStroke,int)} which
- * provides <code>null</code> for the command name.
+ * provides <code>null</code> for the command name.
+ *
+ * @param act the action listener to notify when the keystroke occurs.
+ * @param stroke the key stroke.
+ * @param cond the condition (one of {@link #WHEN_FOCUSED},
+ * {@link #WHEN_IN_FOCUSED_WINDOW} and
+ * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}).
*/
public void registerKeyboardAction(ActionListener act,
KeyStroke stroke,
@@ -2348,9 +2321,22 @@ public abstract class JComponent extends Container implements Serializable
KeyStroke stroke,
int cond)
{
- getInputMap(cond).put(stroke, new ActionListenerProxy(act, cmd));
+ ActionListenerProxy proxy = new ActionListenerProxy(act, cmd);
+ getInputMap(cond).put(stroke, proxy);
+ getActionMap().put(proxy, proxy);
}
+ /**
+ * Sets the input map for the given condition.
+ *
+ * @param condition the condition (one of {@link #WHEN_FOCUSED},
+ * {@link #WHEN_IN_FOCUSED_WINDOW} and
+ * {@link #WHEN_ANCESTOR_OF_FOCUSED_COMPONENT}).
+ * @param map the map.
+ *
+ * @throws IllegalArgumentException if <code>condition</code> is not one of
+ * the specified values.
+ */
public final void setInputMap(int condition, InputMap map)
{
enableEvents(AWTEvent.KEY_EVENT_MASK);
@@ -2486,13 +2472,17 @@ public abstract class JComponent extends Container implements Serializable
*/
public ActionListener getActionForKeyStroke(KeyStroke ks)
{
- Object cmd = getInputMap().get(ks);
- if (cmd != null)
+ Object key = getInputMap(JComponent.WHEN_FOCUSED).get(ks);
+ if (key == null)
+ key = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).get(ks);
+ if (key == null)
+ key = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).get(ks);
+ if (key != null)
{
- if (cmd instanceof ActionListenerProxy)
- return (ActionListenerProxy) cmd;
- else if (cmd instanceof String)
- return getActionMap().get(cmd);
+ if (key instanceof ActionListenerProxy)
+ return ((ActionListenerProxy) key).target;
+ else
+ return getActionMap().get(key);
}
return null;
}
@@ -2591,10 +2581,11 @@ public abstract class JComponent extends Container implements Serializable
if (isEnabled())
{
Action act = null;
+ Object cmd = null;
InputMap map = getInputMap(condition);
if (map != null)
{
- Object cmd = map.get(ks);
+ cmd = map.get(ks);
if (cmd != null)
{
if (cmd instanceof ActionListenerProxy)
@@ -2604,7 +2595,23 @@ public abstract class JComponent extends Container implements Serializable
}
}
if (act != null && act.isEnabled())
- return SwingUtilities.notifyAction(act, ks, e, this, e.getModifiers());
+ {
+ // Need to synchronize here so we don't get in trouble with
+ // our __command__ hack.
+ synchronized (act)
+ {
+ // We add the command as value to the action, so that
+ // the action can later determine the command with which it
+ // was called. This is undocumented, but shouldn't affect
+ // compatibility. It allows us to use only one Action instance
+ // to do the work for all components of one type, instead of
+ // having loads of small Actions. This effectivly saves startup
+ // time of Swing.
+ act.putValue("__command__", cmd);
+ return SwingUtilities.notifyAction(act, ks, e, this,
+ e.getModifiers());
+ }
+ }
}
return false;
}
@@ -2706,6 +2713,11 @@ public abstract class JComponent extends Container implements Serializable
*/
public void revalidate()
{
+ // As long as we don't have a parent we don't need to do any layout, since
+ // this is done anyway as soon as we get connected to a parent.
+ if (getParent() == null)
+ return;
+
if (! EventQueue.isDispatchThread())
SwingUtilities.invokeLater(new Runnable()
{
@@ -3089,11 +3101,29 @@ public abstract class JComponent extends Container implements Serializable
// Nothing to do here.
}
+ /**
+ * Returns the locale used as the default for all new components. The
+ * default value is {@link Locale#getDefault()} (that is, the platform
+ * default locale).
+ *
+ * @return The locale (never <code>null</code>).
+ *
+ * @see #setDefaultLocale(Locale)
+ */
public static Locale getDefaultLocale()
{
+ if (defaultLocale == null)
+ defaultLocale = Locale.getDefault();
return defaultLocale;
}
+ /**
+ * Sets the locale to be used as the default for all new components. If this
+ * is set to <code>null</code>, the {@link #getDefaultLocale()} method will
+ * return the platform default locale.
+ *
+ * @param l the locale (<code>null</code> permitted).
+ */
public static void setDefaultLocale(Locale l)
{
defaultLocale = l;
@@ -3531,12 +3561,13 @@ public abstract class JComponent extends Container implements Serializable
}
}
// Dispatch event to all children.
- Component[] children = getComponents();
- for (int i = 0; i < children.length; i++)
+ int numChildren = getComponentCount();
+ for (int i = 0; i < numChildren; i++)
{
- if (!(children[i] instanceof JComponent))
+ Component child = getComponent(i);
+ if (! (child instanceof JComponent))
continue;
- JComponent jc = (JComponent) children[i];
+ JComponent jc = (JComponent) child;
jc.fireAncestorEvent(ancestor, id);
}
}
@@ -3619,10 +3650,10 @@ public abstract class JComponent extends Container implements Serializable
! SwingUtilities.isRectangleContainingRectangle(parentRect, target);
if (! haveOverlap)
{
- Component[] children = newParent.getComponents();
- for (int i = 0; children[i] != parent && !haveOverlap; i++)
+ Component child;
+ for (int i = 0; (child = newParent.getComponent(i)) != parent && !haveOverlap; i++)
{
- Rectangle childRect = children[i].getBounds();
+ Rectangle childRect = child.getBounds();
haveOverlap = target.intersects(childRect);
}
}
@@ -3654,7 +3685,7 @@ public abstract class JComponent extends Container implements Serializable
{
if ((found instanceof JComponent) && ((JComponent) found).isOpaque())
break;
- else if (!(found instanceof JComponent))
+ else if (!(found instanceof JComponent) && !found.isLightweight())
break;
Container p = found.getParent();
if (p == null)
diff --git a/libjava/classpath/javax/swing/JFileChooser.java b/libjava/classpath/javax/swing/JFileChooser.java
index 64f9bd0f4e6..a508b8fcb20 100644
--- a/libjava/classpath/javax/swing/JFileChooser.java
+++ b/libjava/classpath/javax/swing/JFileChooser.java
@@ -43,6 +43,8 @@ import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowAdapter;
import java.beans.PropertyChangeEvent;
import java.io.File;
import java.util.ArrayList;
@@ -351,7 +353,7 @@ public class JFileChooser extends JComponent implements Accessible
* The file selection mode.
* @see #setFileSelectionMode(int)
*/
- private int fileSelectionMode = FILES_AND_DIRECTORIES;
+ private int fileSelectionMode = FILES_ONLY;
/**
* The file view.
@@ -744,10 +746,16 @@ public class JFileChooser extends JComponent implements Accessible
JDialog dialog = new JDialog(toUse);
setSelectedFile(null);
dialog.getContentPane().add(this);
+ dialog.addWindowListener( new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent e)
+ {
+ cancelSelection();
+ }
+ });
dialog.setModal(true);
dialog.invalidate();
dialog.repaint();
-
return dialog;
}
diff --git a/libjava/classpath/javax/swing/JInternalFrame.java b/libjava/classpath/javax/swing/JInternalFrame.java
index 79dcc7326be..ff3ae1faa66 100644
--- a/libjava/classpath/javax/swing/JInternalFrame.java
+++ b/libjava/classpath/javax/swing/JInternalFrame.java
@@ -38,9 +38,11 @@ exception statement from your version. */
package javax.swing;
+import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
+import java.awt.IllegalComponentStateException;
import java.awt.KeyboardFocusManager;
import java.awt.LayoutManager;
import java.awt.Rectangle;
@@ -490,12 +492,6 @@ public class JInternalFrame extends JComponent implements Accessible,
/** Whether the JInternalFrame has become visible for the very first time. */
private transient boolean isFirstTimeVisible = true;
- /**
- * Whether the JInternalFrame is in the transition from being a maximized
- * frame back to a regular sized frame.
- */
- private transient boolean maxTransition = false;
-
/** DOCUMENT ME! */
private transient boolean wasIcon = false;
@@ -581,11 +577,12 @@ public class JInternalFrame extends JComponent implements Accessible,
this.closable = closable;
this.maximizable = maximizable;
this.iconable = iconifiable;
- storedBounds = new Rectangle();
+ isMaximum = false;
setRootPane(createRootPane());
// JInternalFrames are invisible and opaque by default.
setVisible(false);
setOpaque(true);
+ desktopIcon = new JDesktopIcon(this);
updateUI();
setRootPaneCheckingEnabled(true); // Done the init stage, now adds go to content pane.
}
@@ -643,24 +640,25 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void dispose()
{
- setVisible(false);
- JDesktopPane pane = getDesktopPane();
- if (pane != null)
- pane.setSelectedFrame(null);
- else
+ if (isVisible())
+ setVisible(false);
+ if (isSelected())
{
- try
- {
- setSelected(false);
- }
- catch (PropertyVetoException e)
- {
- // Do nothing if they don't want to be unselected.
- }
+ try
+ {
+ setSelected(false);
+ }
+ catch (PropertyVetoException e)
+ {
+ // Do nothing if they don't want to be unselected.
+ }
+ }
+ if (! isClosed)
+ {
+ firePropertyChange(IS_CLOSED_PROPERTY, Boolean.FALSE, Boolean.TRUE);
+ isClosed = true;
}
- isClosed = true;
fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED);
- removeNotify();
}
/**
@@ -799,8 +797,6 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public JDesktopIcon getDesktopIcon()
{
- if (desktopIcon == null)
- desktopIcon = new JDesktopIcon(this);
return desktopIcon;
}
@@ -904,18 +900,7 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public int getLayer()
{
- JDesktopPane pane = getDesktopPane();
- if (pane != null)
- // The cast here forces the call to the instance method getLayer()
- // instead of the static method (this would lead to infinite
- // recursion).
- return pane.getLayer((Component) this);
-
- Integer layer = (Integer) getClientProperty(JLayeredPane.LAYER_PROPERTY);
- if (layer != null)
- return layer.intValue();
-
- return JLayeredPane.DEFAULT_LAYER.intValue();
+ return JLayeredPane.getLayer(this);
}
/**
@@ -970,7 +955,7 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public Rectangle getNormalBounds()
{
- if (! isMaximum() && ! maxTransition)
+ if (storedBounds == null)
return getBounds();
else
return storedBounds;
@@ -1035,20 +1020,8 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void hide()
{
- JDesktopPane pane = getDesktopPane();
- if (pane != null)
- pane.setSelectedFrame(null);
- else
- {
- try
- {
- setSelected(false);
- }
- catch (PropertyVetoException e)
- {
- // Do nothing.
- }
- }
+ if (isIcon())
+ getDesktopIcon().hide();
super.hide();
}
@@ -1162,8 +1135,9 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void moveToBack()
{
- if (getParent() instanceof JLayeredPane)
- ((JLayeredPane) getParent()).moveToBack(this);
+ Container p = getParent();
+ if (p instanceof JLayeredPane)
+ ((JLayeredPane) p).moveToBack(this);
}
/**
@@ -1172,8 +1146,9 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void moveToFront()
{
- if (getParent() instanceof JLayeredPane)
- ((JLayeredPane) getParent()).moveToFront(this);
+ Container p = getParent();
+ if (p != null && p instanceof JLayeredPane)
+ ((JLayeredPane) p).moveToFront(this);
}
/**
@@ -1196,6 +1171,7 @@ public class JInternalFrame extends JComponent implements Accessible,
// Do nothing if they don't want to be restored first.
}
setSize(getPreferredSize());
+ validate();
}
/**
@@ -1311,7 +1287,6 @@ public class JInternalFrame extends JComponent implements Accessible,
dispose();
firePropertyChange(IS_CLOSED_PROPERTY, false, true);
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED);
}
}
@@ -1468,7 +1443,9 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setJMenuBar(JMenuBar b)
{
+ JMenuBar old = getJMenuBar();
getRootPane().setJMenuBar(b);
+ firePropertyChange(MENU_BAR_PROPERTY, old, b);
}
/**
@@ -1493,11 +1470,17 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setLayer(Integer layer)
{
- JDesktopPane p = getDesktopPane();
- if (p != null)
+ Container p = getParent();
+ if (p instanceof JLayeredPane)
{
- int pos = p.getPosition(this);
- p.setLayer(this, layer.intValue(), pos);
+ JLayeredPane lp = (JLayeredPane) p;
+ lp.setLayer(this, layer.intValue(), lp.getPosition(this));
+ }
+ else
+ {
+ JLayeredPane.putLayer(this, layer.intValue());
+ if (p != null)
+ p.repaint(getX(), getY(), getWidth(), getHeight());
}
}
@@ -1508,6 +1491,9 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setLayeredPane(JLayeredPane layered)
{
+ if (layered == null)
+ throw new IllegalComponentStateException("LayeredPane must not be null");
+
if (layered != getLayeredPane())
{
JLayeredPane old = getLayeredPane();
@@ -1561,15 +1547,11 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setMaximum(boolean b) throws PropertyVetoException
{
- if (b != isMaximum())
+ if (b != isMaximum)
{
- fireVetoableChange(IS_MAXIMUM_PROPERTY, b, isMaximum);
+ fireVetoableChange(IS_MAXIMUM_PROPERTY, isMaximum, b);
isMaximum = b;
- if (b)
- setNormalBounds(getBounds());
- maxTransition = ! b;
firePropertyChange(IS_MAXIMUM_PROPERTY, ! isMaximum, isMaximum);
- maxTransition = false;
}
}
@@ -1593,7 +1575,7 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setNormalBounds(Rectangle r)
{
- storedBounds.setBounds(r.x, r.y, r.width, r.height);
+ storedBounds = r;
}
/**
@@ -1621,8 +1603,23 @@ public class JInternalFrame extends JComponent implements Accessible,
if (rootPane != null)
remove(rootPane);
+ JRootPane old = rootPane;
rootPane = root;
- add(root);
+
+ if (rootPane != null)
+ {
+ boolean checkingEnabled = isRootPaneCheckingEnabled();
+ try
+ {
+ setRootPaneCheckingEnabled(false);
+ add(rootPane, BorderLayout.CENTER);
+ }
+ finally
+ {
+ setRootPaneCheckingEnabled(checkingEnabled);
+ }
+ }
+ firePropertyChange(ROOT_PANE_PROPERTY, old, rootPane);
}
/**
@@ -1652,27 +1649,26 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setSelected(boolean selected) throws PropertyVetoException
{
- if (selected != isSelected())
+ if (selected != isSelected
+ && (! selected || (isIcon ? desktopIcon.isShowing() : isShowing())))
{
- fireVetoableChange(IS_SELECTED_PROPERTY, selected, isSelected);
-
- if (! selected)
- defaultFocus = getMostRecentFocusOwner();
+ fireVetoableChange(IS_SELECTED_PROPERTY, isSelected, selected);
- isSelected = selected;
+ if (! selected)
+ defaultFocus = getMostRecentFocusOwner();
- if (selected)
- restoreSubcomponentFocus();
+ isSelected = selected;
+ firePropertyChange(IS_SELECTED_PROPERTY, ! isSelected, isSelected);
- if (isShowing())
- repaint();
+ if (isSelected)
+ fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ACTIVATED);
+ else
+ fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED);
- firePropertyChange(IS_SELECTED_PROPERTY, ! isSelected, isSelected);
+ if (selected)
+ restoreSubcomponentFocus();
- if (isSelected)
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ACTIVATED);
- else
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED);
+ repaint();
}
}
@@ -1687,14 +1683,9 @@ public class JInternalFrame extends JComponent implements Accessible,
*/
public void setTitle(String title)
{
- if (title == null && this.title == null)
- return;
- if (title == null || this.title == null || ! this.title.equals(title))
- {
- String old = this.title;
- this.title = title;
- firePropertyChange(TITLE_PROPERTY, old, this.title);
- }
+ String old = this.title;
+ this.title = title;
+ firePropertyChange(TITLE_PROPERTY, old, this.title);
}
/**
@@ -1707,12 +1698,21 @@ public class JInternalFrame extends JComponent implements Accessible,
{
if (! isVisible())
{
+ if (isFirstTimeVisible)
+ {
+ isFirstTimeVisible = false;
+ fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED);
+ }
+
+ getDesktopIcon().setVisible(true);
+
+ toFront();
super.show();
- JDesktopPane pane = getDesktopPane();
- if (pane != null)
- pane.setSelectedFrame(this);
- else
+ if (isIcon())
+ return;
+
+ if (! isSelected())
{
try
{
@@ -1723,11 +1723,6 @@ public class JInternalFrame extends JComponent implements Accessible,
// Do nothing. if they don't want to be selected.
}
}
- if (isFirstTimeVisible)
- {
- isFirstTimeVisible = false;
- fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED);
- }
}
}
diff --git a/libjava/classpath/javax/swing/JLabel.java b/libjava/classpath/javax/swing/JLabel.java
index a5fe3ba1af0..fcf0fd7cb13 100644
--- a/libjava/classpath/javax/swing/JLabel.java
+++ b/libjava/classpath/javax/swing/JLabel.java
@@ -46,6 +46,7 @@ import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
+import java.beans.PropertyChangeEvent;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
@@ -57,7 +58,7 @@ import javax.swing.text.AttributeSet;
import javax.swing.text.SimpleAttributeSet;
/**
- * A swing widget that displays a text message and/or an icon.
+ * A component that displays a static text message and/or an icon.
*/
public class JLabel extends JComponent implements Accessible, SwingConstants
{
@@ -359,7 +360,7 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
/** The label's mnemnonic key. */
private transient int displayedMnemonic = KeyEvent.VK_UNDEFINED;
- /** The index of the menemonic character in the text. */
+ /** The index of the mnemonic character in the text. */
private transient int displayedMnemonicIndex = -1;
/** The gap between the icon and the text. */
@@ -435,11 +436,12 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
this.icon = icon;
this.horizontalAlignment = horizontalAlignment;
setAlignmentX(0.0F);
+ setInheritsPopupMenu(true);
updateUI();
}
/**
- * This method returns the label's UI delegate.
+ * Returns the label's UI delegate.
*
* @return The label's UI delegate.
*/
@@ -449,9 +451,9 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method sets the label's UI delegate.
+ * Sets the label's UI delegate.
*
- * @param ui The label's UI delegate.
+ * @param ui The label's UI delegate (<code>null</code> not permitted).
*/
public void setUI(LabelUI ui)
{
@@ -459,8 +461,8 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method resets the label's UI delegate to the default UI for the
- * current look and feel.
+ * Resets the label's UI delegate to the default UI for the current look and
+ * feel.
*/
public void updateUI()
{
@@ -468,10 +470,10 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns a name to identify which look and feel class will be
+ * Returns a name to identify which look and feel class will be
* the UI delegate for this label.
*
- * @return The UIClass identifier. "LabelUI"
+ * @return <code>"LabelUI"</code>
*/
public String getUIClassID()
{
@@ -518,9 +520,11 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the label text.
+ * Returns the text displayed by the label.
*
- * @return The label text.
+ * @return The label text (possibly <code>null</code>).
+ *
+ * @see #setText(String)
*/
public String getText()
{
@@ -528,31 +532,42 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "text" property. The given text will be painted
- * in the label.
+ * Sets the text for the label and sends a {@link PropertyChangeEvent} (with
+ * the name 'text') to all registered listeners. This method will also
+ * update the <code>displayedMnemonicIndex</code>, if necessary.
*
- * @param newText The label's text.
+ * @param newText The text (<code>null</code> permitted).
+ *
+ * @see #getText()
+ * @see #getDisplayedMnemonicIndex()
*/
public void setText(String newText)
{
- if (text != newText)
- {
- String oldText = text;
- text = newText;
- firePropertyChange("text", oldText, newText);
+ if (text == null && newText == null)
+ return;
+ if (text != null && text.equals(newText))
+ return;
- if (text != null && text.length() <= displayedMnemonicIndex)
- setDisplayedMnemonicIndex(text.length() - 1);
- revalidate();
- repaint();
- }
+ String oldText = text;
+ text = newText;
+ firePropertyChange("text", oldText, newText);
+
+ if (text != null)
+ setDisplayedMnemonicIndex(text.toUpperCase().indexOf(displayedMnemonic));
+ else
+ setDisplayedMnemonicIndex(-1);
+ revalidate();
+ repaint();
}
/**
- * This method returns the active icon. The active icon is painted when the
- * label is enabled.
+ * Returns the active icon. The active icon is painted when the label is
+ * enabled.
*
* @return The active icon.
+ *
+ * @see #setIcon(Icon)
+ * @see #getDisabledIcon()
*/
public Icon getIcon()
{
@@ -560,81 +575,93 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "icon" property. This icon (the active icon) will
- * be the one displayed when the label is enabled.
+ * Sets the icon for the label (this is a bound property with the name
+ * 'icon'). This icon will be displayed when the label is enabled.
*
- * @param newIcon The active icon.
+ * @param newIcon The icon (<code>null</code> permitted).
+ *
+ * @see #getIcon()
+ * @see #setDisabledIcon(Icon)
*/
public void setIcon(Icon newIcon)
{
if (icon != newIcon)
{
- Icon oldIcon = icon;
- icon = newIcon;
- firePropertyChange("icon", oldIcon, newIcon);
- repaint();
+ Icon oldIcon = icon;
+ icon = newIcon;
+ firePropertyChange("icon", oldIcon, newIcon);
+ repaint();
}
}
/**
- * This method returns the disabled icon. The disabled icon is painted when
- * the label is disabled. If the disabled icon is null and the active icon
- * is an ImageIcon, this method returns a grayed version of the icon. The
- * grayed version of the icon becomes the disabledIcon.
+ * Returns the disabled icon. The disabled icon is painted when the label is
+ * disabled. If the disabled icon is <code>null</code> and the active icon
+ * is an {@link ImageIcon}, this method returns a grayed version of the icon.
+ * The grayed version of the icon becomes the <code>disabledIcon</code>.
*
* @return The disabled icon.
+ *
+ * @see #setDisabledIcon(Icon)
*/
public Icon getDisabledIcon()
{
if (disabledIcon == null && icon instanceof ImageIcon)
- disabledIcon = new ImageIcon(GrayFilter.createDisabledImage(((ImageIcon) icon)
- .getImage()));
+ disabledIcon = new ImageIcon(
+ GrayFilter.createDisabledImage(((ImageIcon) icon).getImage()));
return disabledIcon;
}
/**
- * This method changes the "disabledIcon" property. This icon (the disabled
- * icon) will be the one displayed when the label is disabled.
+ * Sets the icon displayed when the label is disabled (this is a bound
+ * property with the name 'disabledIcon').
*
- * @param newIcon The disabled icon.
+ * @param newIcon The disabled icon (<code>null</code> permitted).
+ *
+ * @see #getDisabledIcon()
*/
public void setDisabledIcon(Icon newIcon)
{
if (disabledIcon != newIcon)
{
- Icon oldIcon = disabledIcon;
- disabledIcon = newIcon;
- firePropertyChange("disabledIcon", oldIcon, newIcon);
+ Icon oldIcon = disabledIcon;
+ disabledIcon = newIcon;
+ firePropertyChange("disabledIcon", oldIcon, newIcon);
}
}
/**
- * This method sets the keycode that will be the label's mnemonic. If the
- * label is used as a label for another component, the label will give
- * focus to that component when the mnemonic is activated.
+ * Sets the keycode that will be the label's mnemonic (this is a bound
+ * property with the name 'displayedMnemonic'). If the label is used as a
+ * label for another component, the label will give focus to that component
+ * when the mnemonic is activated.
*
* @param mnemonic The keycode to use for the mnemonic.
+ *
+ * @see #getDisplayedMnemonic()
*/
public void setDisplayedMnemonic(int mnemonic)
{
if (displayedMnemonic != mnemonic)
{
- firePropertyChange("displayedMnemonic",
- displayedMnemonic, mnemonic);
- displayedMnemonic = mnemonic;
-
- if (text != null)
- setDisplayedMnemonicIndex(text.toUpperCase().indexOf(mnemonic));
+ int old = displayedMnemonic;
+ displayedMnemonic = mnemonic;
+ firePropertyChange("displayedMnemonic", old, displayedMnemonic);
+ if (text != null)
+ setDisplayedMnemonicIndex(text.toUpperCase().indexOf(mnemonic));
}
}
/**
- * This method sets the character that will be the mnemonic used. If the
+ * Sets the character that will be the label's mnemonic. If the
* label is used as a label for another component, the label will give
- * focus to that component when the mnemonic is activated.
+ * focus to that component when the mnemonic is activated via the keyboard.
*
- * @param mnemonic The character to use for the mnemonic.
+ * @param mnemonic The character to use for the mnemonic (this will be
+ * converted to the equivalent upper case character).
+ *
+ * @see #getDisplayedMnemonic()
*/
public void setDisplayedMnemonic(char mnemonic)
{
@@ -642,51 +669,63 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the keycode that is used for the label's mnemonic.
+ * Returns the keycode that is used for the label's mnemonic.
*
* @return The keycode that is used for the label's mnemonic.
+ *
+ * @see #setDisplayedMnemonic(int)
*/
public int getDisplayedMnemonic()
{
- return (int) displayedMnemonic;
+ return displayedMnemonic;
}
/**
- * This method sets which character in the text will be the underlined
- * character. If the given index is -1, then this indicates that there is
- * no mnemonic. If the index is less than -1 or if the index is equal to
- * the length, this method will throw an IllegalArgumentException.
+ * Sets the index of the character in the text that will be underlined to
+ * indicate that it is the mnemonic character for the label. You only need
+ * to call this method if you wish to override the automatically calculated
+ * character index. For instance, for a label "Find Next" with the mnemonic
+ * character 'n', you might wish to underline the second occurrence of 'n'
+ * rather than the first (which is the default).
+ * <br><br>
+ * Note that this method does not validate the character at the specified
+ * index to ensure that it matches the key code returned by
+ * {@link #getDisplayedMnemonic()}.
*
* @param newIndex The index of the character to underline.
*
- * @throws IllegalArgumentException If index less than -1 or index equals
- * length.
+ * @throws IllegalArgumentException If index less than -1 or index is greater
+ * than or equal to the label length.
+ *
+ * @see #getDisplayedMnemonicIndex()
+ * @since 1.4
*/
public void setDisplayedMnemonicIndex(int newIndex)
throws IllegalArgumentException
{
- if (newIndex < -1 || (text != null && newIndex >= text.length()))
+ int maxValid = -1;
+ if (text != null)
+ maxValid = text.length() - 1;
+ if (newIndex < -1 || newIndex > maxValid)
throw new IllegalArgumentException();
- if (newIndex == -1
- || text == null
- || text.charAt(newIndex) != displayedMnemonic)
- newIndex = -1;
-
if (newIndex != displayedMnemonicIndex)
{
- int oldIndex = displayedMnemonicIndex;
- displayedMnemonicIndex = newIndex;
- firePropertyChange("displayedMnemonicIndex",
- oldIndex, newIndex);
+ int oldIndex = displayedMnemonicIndex;
+ displayedMnemonicIndex = newIndex;
+ firePropertyChange("displayedMnemonicIndex", oldIndex, newIndex);
}
}
/**
- * This method returns which character in the text will be the underlined
- * character.
+ * Returns the index of the character in the label's text that will be
+ * underlined (to indicate that it is the mnemonic character), or -1 if no
+ * character is to be underlined.
*
* @return The index of the character that will be underlined.
+ *
+ * @see #setDisplayedMnemonicIndex(int)
+ * @since 1.4
*/
public int getDisplayedMnemonicIndex()
{
@@ -694,14 +733,16 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method ensures that the key is valid as a horizontal alignment.
- * Valid keys are: LEFT, CENTER, RIGHT, LEADING, TRAILING
+ * Checks the specified key to ensure that it is valid as a horizontal
+ * alignment, throwing an {@link IllegalArgumentException} if the key is
+ * invalid. Valid keys are {@link #LEFT}, {@link #CENTER}, {@link #RIGHT},
+ * {@link #LEADING} and {@link #TRAILING}.
*
* @param key The key to check.
* @param message The message of the exception to be thrown if the key is
* invalid.
*
- * @return The key if it's valid.
+ * @return The key if it is valid.
*
* @throws IllegalArgumentException If the key is invalid.
*/
@@ -715,14 +756,15 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method ensures that the key is valid as a vertical alignment. Valid
- * keys are: TOP, CENTER, and BOTTOM.
+ * Checks the specified key to ensure that it is valid as a vertical
+ * alignment, throwing an {@link IllegalArgumentException} if the key is
+ * invalid. Valid keys are {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}.
*
* @param key The key to check.
* @param message The message of the exception to be thrown if the key is
* invalid.
*
- * @return The key if it's valid.
+ * @return The key if it is valid.
*
* @throws IllegalArgumentException If the key is invalid.
*/
@@ -735,9 +777,11 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the gap between the icon and the text.
+ * Returns the gap between the icon and the text.
*
* @return The gap between the icon and the text.
+ *
+ * @see #setIconTextGap(int)
*/
public int getIconTextGap()
{
@@ -745,10 +789,12 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "iconTextGap" property. The iconTextGap
- * determines how much space there is between the icon and the text.
+ * Sets the gap between the icon and the text, in the case that both are
+ * visible (this is a bound property with the name 'iconTextGap').
*
- * @param newGap The gap between the icon and the text.
+ * @param newGap The gap (in pixels).
+ *
+ * @see #getIconTextGap()
*/
public void setIconTextGap(int newGap)
{
@@ -760,9 +806,13 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the vertical alignment of the label.
+ * Returns the vertical alignment of the label (one of
+ * {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}). The default value
+ * depends on the installed look and feel, but is usually {@link #CENTER}.
*
- * @return The vertical alignment of the label.
+ * @return The vertical alignment.
+ *
+ * @see #setVerticalAlignment(int)
*/
public int getVerticalAlignment()
{
@@ -770,12 +820,18 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "verticalAlignment" property of the label. The
- * vertical alignment determines how where the label will be placed
- * vertically. If the alignment is not valid, it will default to the
- * center.
+ * Sets the vertical alignment for the label (this is a bound property with
+ * the name 'verticalAlignment'). The vertical alignment determines where
+ * the label (icon and text) will be placed vertically within the component
+ * bounds. Valid alignment codes are {@link #TOP}, {@link #CENTER} and
+ * {@link #BOTTOM}.
*
* @param alignment The vertical alignment of the label.
+ *
+ * @throws IllegalArgumentException if <code>alignment</code> is not one of
+ * the specified values.
+ *
+ * @see #getVerticalAlignment()
*/
public void setVerticalAlignment(int alignment)
{
@@ -788,9 +844,14 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the horziontal alignment of the label.
+ * Returns the horizontal alignment of the label (one of {@link #LEFT},
+ * {@link #CENTER}, {@link #RIGHT}, {@link #LEADING} and {@link #TRAILING}).
+ * The default value depends on the installed look and feel, but is usually
+ * {@link #LEFT}.
*
- * @return The horizontal alignment of the label.
+ * @return The horizontal alignment.
+ *
+ * @see #setHorizontalAlignment(int)
*/
public int getHorizontalAlignment()
{
@@ -798,10 +859,18 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "horizontalAlignment" property. The horizontal
- * alignment determines where the label will be placed horizontally.
+ * Sets the horizontal alignment for the label (this is a bound property with
+ * the name 'horizontalAlignment'). The horizontal alignment determines where
+ * the label (icon and text) will be placed horizontally within the
+ * component bounds. Valid alignment codes are {@link #LEFT},
+ * {@link #CENTER}, {@link #RIGHT}, {@link #LEADING} and {@link #TRAILING}.
*
* @param alignment The horizontal alignment of the label.
+ *
+ * @throws IllegalArgumentException if <code>alignment</code> is not one of
+ * the specified values.
+ *
+ * @see #getHorizontalAlignment()
*/
public void setHorizontalAlignment(int alignment)
{
@@ -815,9 +884,12 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the vertical text position of the label.
- *
- * @return The vertical text position of the label.
+ * Returns the vertical position of the label's text relative to the icon.
+ * This will be one of {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}.
+ *
+ * @return The vertical position of the label's text relative to the icon.
+ *
+ * @see #setVerticalTextPosition(int)
*/
public int getVerticalTextPosition()
{
@@ -825,28 +897,35 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "verticalTextPosition" property of the label. The
- * vertical text position determines where the text will be placed
- * vertically relative to the icon.
+ * Sets the vertical position of the label's text relative to the icon (this
+ * is a bound property with the name 'verticalTextPosition'). Valid
+ * positions are {@link #TOP}, {@link #CENTER} and {@link #BOTTOM}.
*
* @param textPosition The vertical text position.
+ *
+ * @throws IllegalArgumentException if <code>textPosition</code> is not one
+ * of the specified values.
*/
public void setVerticalTextPosition(int textPosition)
{
if (textPosition != verticalTextPosition)
{
- int oldPos = verticalTextPosition;
- verticalTextPosition = checkVerticalKey(textPosition,
- "verticalTextPosition");
- firePropertyChange("verticalTextPosition", oldPos,
- verticalTextPosition);
+ int oldPos = verticalTextPosition;
+ verticalTextPosition = checkVerticalKey(textPosition,
+ "verticalTextPosition");
+ firePropertyChange("verticalTextPosition", oldPos,
+ verticalTextPosition);
}
}
/**
- * This method returns the horizontal text position of the label.
- *
- * @return The horizontal text position.
+ * Returns the horizontal position of the label's text relative to the icon.
+ * This will be one of {@link #LEFT}, {@link #CENTER}, {@link #RIGHT},
+ * {@link #LEADING} and {@link #TRAILING}.
+ *
+ * @return The horizontal position of the label's text relative to the icon.
+ *
+ * @see #setHorizontalTextPosition(int)
*/
public int getHorizontalTextPosition()
{
@@ -854,28 +933,31 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "horizontalTextPosition" property of the label.
- * The horizontal text position determines where the text will be placed
- * horizontally relative to the icon.
+ * Sets the horizontal position of the label's text relative to the icon (this
+ * is a bound property with the name 'horizontalTextPosition'). Valid
+ * positions are {@link #LEFT}, {@link #CENTER}, {@link #RIGHT},
+ * {@link #LEADING} and {@link #TRAILING}.
*
* @param textPosition The horizontal text position.
+ *
+ * @throws IllegalArgumentException if <code>textPosition</code> is not one
+ * of the specified values.
*/
public void setHorizontalTextPosition(int textPosition)
{
if (textPosition != horizontalTextPosition)
{
- int oldPos = horizontalTextPosition;
- horizontalTextPosition = checkHorizontalKey(textPosition,
- "horizontalTextPosition");
- firePropertyChange("horizontalTextPosition", oldPos,
- horizontalTextPosition);
+ int oldPos = horizontalTextPosition;
+ horizontalTextPosition = checkHorizontalKey(textPosition,
+ "horizontalTextPosition");
+ firePropertyChange("horizontalTextPosition", oldPos,
+ horizontalTextPosition);
}
}
/**
- * This method simply returns false if the current icon image (current icon
- * will depend on whether the label is enabled) is not equal to the passed
- * in image.
+ * Returns false if the current icon image (current icon will depend on
+ * whether the label is enabled) is not equal to the passed in image.
*
* @param img The image to check.
* @param infoflags The bitwise inclusive OR of ABORT, ALLBITS, ERROR,
@@ -900,11 +982,11 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method returns the component that the label gives focus to when the
- * mnemonic is activated.
+ * Returns the component that this <code>JLabel</code> is providing the label
+ * for. This component will typically receive the focus when the label's
+ * mnemonic key is activated via the keyboard.
*
- * @return The component that gets focus when the label's mnemonic is
- * activated.
+ * @return The component (possibly <code>null</code>).
*/
public Component getLabelFor()
{
@@ -912,12 +994,14 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method changes the "labelFor" property. The component that the label
- * is acting as a label for will request focus when the label's mnemonic
- * is activated.
+ * Sets the component that this <code>JLabel</code> is providing the label
+ * for (this is a bound property with the name 'labelFor'). This component
+ * will typically receive the focus when the label's mnemonic key is
+ * activated via the keyboard.
*
- * @param c The component that gets focus when the label's mnemonic is
- * activated.
+ * @param c the component (<code>null</code> permitted).
+ *
+ * @see #getLabelFor()
*/
public void setLabelFor(Component c)
{
@@ -946,10 +1030,9 @@ public class JLabel extends JComponent implements Accessible, SwingConstants
}
/**
- * This method overrides setFont so that we can call for a repaint after the
- * font is changed.
+ * Sets the font for the label (this a bound property with the name 'font').
*
- * @param f The font for this label.
+ * @param f The font (<code>null</code> permitted).
*/
public void setFont(Font f)
{
diff --git a/libjava/classpath/javax/swing/JLayeredPane.java b/libjava/classpath/javax/swing/JLayeredPane.java
index 11650e721d0..ca913e97fed 100644
--- a/libjava/classpath/javax/swing/JLayeredPane.java
+++ b/libjava/classpath/javax/swing/JLayeredPane.java
@@ -43,6 +43,7 @@ import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Rectangle;
+import java.util.ArrayList;
import java.util.Hashtable;
import javax.accessibility.Accessible;
@@ -326,13 +327,13 @@ public class JLayeredPane extends JComponent implements Accessible
{
int pos = -1;
int index = getIndexOf(c);
- Component[] components = getComponents();
- int layer = getLayer(c);
if (index >= 0)
{
- for (int i = index; i >= 0; --i)
+ pos = 0;
+ int layer = getLayer(c);
+ for (int i = index - 1; i >= 0; --i)
{
- if (layer == getLayer(components[i]))
+ if (layer == getLayer(getComponent(i)))
pos++;
else
break;
@@ -353,9 +354,7 @@ public class JLayeredPane extends JComponent implements Accessible
*/
public void setPosition(Component c, int position)
{
- int layer = getLayer(c);
- int index = insertIndexForLayer(layer, position);
- setComponentZOrder(c, index);
+ setLayer(c, getLayer(c), position);
}
/**
@@ -478,34 +477,85 @@ public class JLayeredPane extends JComponent implements Accessible
*/
protected int insertIndexForLayer(int layer, int position)
{
- // position < 0 means insert at greatest position within layer.
- if (position < 0)
- position = Integer.MAX_VALUE;
+ return insertIndexForLayer(null, layer, position);
+ }
- Component[] components = getComponents();
- int index = 0;
+ /**
+ * Similar to {@link #insertIndexForLayer(int, int)}, only that it takes a
+ * component parameter, which should be ignored in the search. This is
+ * necessary to support {@link #setLayer(Component, int, int)} which uses
+ * Container.setComponentZOrder(), which doesn't remove the component.
+ *
+ * @param comp the component to ignore
+ * @param layer the layer
+ * @param position the position
+ *
+ * @return the insertion index
+ */
+ private int insertIndexForLayer(Component comp, int layer, int position)
+ {
+ // Create the component list to search through.
+ ArrayList l = new ArrayList();
+ int count = getComponentCount();
+ for (int i = 0; i < count; i++)
+ {
+ Component c = getComponent(i);
+ if (c != comp)
+ l.add(c);
+ }
- // Try to find the start index of the specified layer.
- int p = -1;
- for (int i = 0; i < components.length; i++)
+ count = l.size();
+ int layerStart = -1;
+ int layerEnd = -1;
+ for (int i = 0; i < count; i++)
{
- int l = getLayer(components[i]);
- if (l > layer)
- index++;
- // If we are in the layer we look for, try to find the position.
- else if (l == layer)
+ int layerOfComponent = getLayer((Component) l.get(i));
+ if (layerStart == -1 && layerOfComponent == layer)
+ layerStart = i;
+ if (layerOfComponent < layer)
{
- p++;
- if (p < position)
- index++;
+ // We are beyond the layer that we are looking for. Update the
+ // layerStart and layerEnd and exit the loop.
+ if (i == 0)
+ {
+ layerStart = 0;
+ layerEnd = 0;
+ }
else
- break;
+ layerEnd = i;
+ break;
}
- // No need to look further if the layer at i is smaller than layer.
+ }
+
+ // No layer found. The requested layer is lower than any existing layer,
+ // put the component at the end.
+ int insertIndex;
+ if (layerStart == -1 && layerEnd == -1)
+ {
+ insertIndex = count;
+ }
+ else
+ {
+ // Corner cases.
+ if (layerStart != -1 && layerEnd == -1)
+ layerEnd = count;
+ if (layerStart == -1 && layerEnd != -1)
+ layerStart = layerEnd;
+
+ // Adding to the bottom of a layer returns the end index
+ // in the layer.
+ if (position == -1)
+ insertIndex = layerEnd;
else
- break;
+ {
+ // Insert into a layer.
+ if (position > -1 && layerStart + position <= layerEnd)
+ insertIndex = layerStart + position;
+ else
+ insertIndex = layerEnd;
+ }
}
- return index;
+ return insertIndex;
}
/**
@@ -559,17 +609,29 @@ public class JLayeredPane extends JComponent implements Accessible
public void setLayer(Component c, int layer, int position)
{
Integer layerObj = getObjectForLayer(layer);
- if (c instanceof JComponent)
+
+ // Nothing to do if neither the layer nor the position is
+ // changed.
+ if (layer != getLayer(c) || position != getPosition(c))
{
- JComponent jc = (JComponent) c;
- jc.putClientProperty(LAYER_PROPERTY, layerObj);
- }
- else
- componentToLayer.put (c, layerObj);
+ // Store the layer either in the JComponent or in the hashtable
+ if (c instanceof JComponent)
+ {
+ JComponent jc = (JComponent) c;
+ jc.putClientProperty(LAYER_PROPERTY, layerObj);
+ }
+ else
+ componentToLayer.put (c, layerObj);
- // Set position only of component is already added to this layered pane.
- if (getIndexOf(c) != -1)
- setPosition(c, position);
+ // Update the component in the Z order of the Container.
+ Container parent = c.getParent();
+ if (parent == this)
+ {
+ int index = insertIndexForLayer(c, layer, position);
+ setComponentZOrder(c, index);
+ }
+ }
+ repaint(c.getX(), c.getY(), c.getWidth(), c.getHeight());
}
/**
@@ -592,14 +654,17 @@ public class JLayeredPane extends JComponent implements Accessible
{
int layer;
if (layerConstraint != null && layerConstraint instanceof Integer)
- layer = ((Integer) layerConstraint).intValue();
+ {
+ layer = ((Integer) layerConstraint).intValue();
+ setLayer(comp, layer);
+ }
else
- layer = getLayer(comp);
+ layer = getLayer(comp);
int newIdx = insertIndexForLayer(layer, index);
- setLayer(comp, layer);
super.addImpl(comp, layerConstraint, newIdx);
- repaint(comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight());
+ comp.validate();
+ comp.repaint();
}
/**
diff --git a/libjava/classpath/javax/swing/JList.java b/libjava/classpath/javax/swing/JList.java
index eab6be3c30c..6a98770eeda 100644
--- a/libjava/classpath/javax/swing/JList.java
+++ b/libjava/classpath/javax/swing/JList.java
@@ -944,17 +944,6 @@ public class JList extends JComponent implements Accessible, Scrollable
*/
ListSelectionModel selectionModel;
-
- /**
- * This property indicates that the list's selection is currently
- * "adjusting" -- perhaps due to a user actively dragging the mouse over
- * multiple list elements -- and is therefore likely to change again in
- * the near future. A {@link ListSelectionListener} might choose to delay
- * updating its view of the list's selection until this property is
- * false, meaning that the adjustment has completed.
- */
- boolean valueIsAdjusting;
-
/**
* This property indicates a <em>preference</em> for the number of rows
* displayed in the list, and will scale the
@@ -1085,8 +1074,7 @@ public class JList extends JComponent implements Accessible, Scrollable
fixedCellWidth = -1;
layoutOrientation = VERTICAL;
opaque = true;
- valueIsAdjusting = false;
- visibleRowCount = 7;
+ visibleRowCount = 8;
cellRenderer = new DefaultListCellRenderer();
listListener = new ListListener();
@@ -1196,11 +1184,13 @@ public class JList extends JComponent implements Accessible, Scrollable
}
/**
- * Gets the value of the {@link #visibleRowCount} property.
+ * Gets the value of the {@link #visibleRowCount} property. The default
+ * value is 8.
*
* @return the current value of the property.
+ *
+ * @see #setVisibleRowCount(int)
*/
-
public int getVisibleRowCount()
{
return visibleRowCount;
@@ -1210,12 +1200,19 @@ public class JList extends JComponent implements Accessible, Scrollable
* Sets the value of the {@link #visibleRowCount} property.
*
* @param vc The new property value
+ *
+ * @see #getVisibleRowCount()
*/
public void setVisibleRowCount(int vc)
{
- visibleRowCount = vc;
- revalidate();
- repaint();
+ if (visibleRowCount != vc)
+ {
+ int oldValue = visibleRowCount;
+ visibleRowCount = Math.max(vc, 0);
+ firePropertyChange("visibleRowCount", oldValue, vc);
+ revalidate();
+ repaint();
+ }
}
/**
@@ -2184,23 +2181,25 @@ public class JList extends JComponent implements Accessible, Scrollable
}
/**
- * Returns the value of the <code>valueIsAdjusting</code> property.
+ * Returns the <code>valueIsAdjusting</code> flag from the list's selection
+ * model.
*
* @return the value
*/
public boolean getValueIsAdjusting()
{
- return valueIsAdjusting;
+ return selectionModel.getValueIsAdjusting();
}
/**
- * Sets the <code>valueIsAdjusting</code> property.
+ * Sets the <code>valueIsAdjusting</code> flag in the list's selection
+ * model.
*
* @param isAdjusting the new value
*/
public void setValueIsAdjusting(boolean isAdjusting)
{
- valueIsAdjusting = isAdjusting;
+ selectionModel.setValueIsAdjusting(isAdjusting);
}
/**
@@ -2228,11 +2227,13 @@ public class JList extends JComponent implements Accessible, Scrollable
}
/**
- * Returns the layout orientation.
+ * Returns the layout orientation, which will be one of {@link #VERTICAL},
+ * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}. The default value
+ * is {@link #VERTICAL}.
*
- * @return the orientation, one of <code>JList.VERTICAL</code>,
- * <code>JList.VERTICAL_WRAP</code> and <code>JList.HORIZONTAL_WRAP</code>
+ * @return the orientation.
*
+ * @see #setLayoutOrientation(int)
* @since 1.4
*/
public int getLayoutOrientation()
@@ -2241,15 +2242,21 @@ public class JList extends JComponent implements Accessible, Scrollable
}
/**
- * Sets the layout orientation.
+ * Sets the layout orientation (this is a bound property with the name
+ * 'layoutOrientation'). Valid orientations are {@link #VERTICAL},
+ * {@link #VERTICAL_WRAP} and {@link #HORIZONTAL_WRAP}.
*
- * @param orientation the orientation to set, one of <code>JList.VERTICAL</code>,
- * <code>JList.VERTICAL_WRAP</code> and <code>JList.HORIZONTAL_WRAP</code>
+ * @param orientation the orientation.
*
+ * @throws IllegalArgumentException if <code>orientation</code> is not one
+ * of the specified values.
* @since 1.4
+ * @see #getLayoutOrientation()
*/
public void setLayoutOrientation(int orientation)
{
+ if (orientation < JList.VERTICAL || orientation > JList.HORIZONTAL_WRAP)
+ throw new IllegalArgumentException();
if (layoutOrientation == orientation)
return;
@@ -2282,14 +2289,16 @@ public class JList extends JComponent implements Accessible, Scrollable
}
/**
- * Returns the next list element (beginning from <code>startIndex</code>
- * that starts with <code>prefix</code>. Searching is done in the direction
- * specified by <code>bias</code>.
+ * Returns the index of the next list element (beginning at
+ * <code>startIndex</code> and moving in the specified direction through the
+ * list, looping around if necessary) that starts with <code>prefix</code>
+ * (ignoring case).
*
* @param prefix the prefix to search for in the cell values
* @param startIndex the index where to start searching from
- * @param bias the search direction, either {@link Position.Bias#Forward}
- * or {@link Position.Bias#Backward}
+ * @param direction the search direction, either {@link Position.Bias#Forward}
+ * or {@link Position.Bias#Backward} (<code>null</code> is interpreted
+ * as {@link Position.Bias#Backward}.
*
* @return the index of the found element or -1 if no such element has
* been found
@@ -2299,7 +2308,8 @@ public class JList extends JComponent implements Accessible, Scrollable
*
* @since 1.4
*/
- public int getNextMatch(String prefix, int startIndex, Position.Bias bias)
+ public int getNextMatch(String prefix, int startIndex,
+ Position.Bias direction)
{
if (prefix == null)
throw new IllegalArgumentException("The argument 'prefix' must not be"
@@ -2309,37 +2319,33 @@ public class JList extends JComponent implements Accessible, Scrollable
+ " be less than zero.");
int size = model.getSize();
- if (startIndex > model.getSize())
+ if (startIndex >= model.getSize())
throw new IllegalArgumentException("The argument 'startIndex' must not"
+ " be greater than the number of"
+ " elements in the ListModel.");
- int index = -1;
- if (bias == Position.Bias.Forward)
- {
- for (int i = startIndex; i < size; i++)
- {
- String item = model.getElementAt(i).toString();
- if (item.startsWith(prefix))
- {
- index = i;
- break;
- }
- }
- }
- else
+ int result = -1;
+ int current = startIndex;
+ int delta = -1;
+ int itemCount = model.getSize();
+ boolean finished = false;
+ prefix = prefix.toUpperCase();
+
+ if (direction == Position.Bias.Forward)
+ delta = 1;
+ while (!finished)
{
- for (int i = startIndex; i >= 0; i--)
- {
- String item = model.getElementAt(i).toString();
- if (item.startsWith(prefix))
- {
- index = i;
- break;
- }
- }
+ String itemStr = model.getElementAt(current).toString().toUpperCase();
+ if (itemStr.startsWith(prefix))
+ return current;
+ current = (current + delta);
+ if (current == -1)
+ current += itemCount;
+ else
+ current = current % itemCount;
+ finished = current == startIndex;
}
- return index;
+ return result;
}
/**
diff --git a/libjava/classpath/javax/swing/JMenu.java b/libjava/classpath/javax/swing/JMenu.java
index 02cb20eab57..0840509f906 100644
--- a/libjava/classpath/javax/swing/JMenu.java
+++ b/libjava/classpath/javax/swing/JMenu.java
@@ -40,6 +40,7 @@ package javax.swing;
import java.awt.Component;
import java.awt.Point;
+import java.awt.PopupMenu;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
@@ -74,7 +75,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
private static final long serialVersionUID = 4227225638931828014L;
/** A Popup menu associated with this menu, which pops up when menu is selected */
- private JPopupMenu popupMenu = new JPopupMenu();
+ private JPopupMenu popupMenu = null;
/** Whenever menu is selected or deselected the MenuEvent is fired to
menu's registered listeners. */
@@ -98,6 +99,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
{
super();
setOpaque(false);
+ setDelay(200);
}
/**
@@ -108,8 +110,10 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
public JMenu(String text)
{
super(text);
+ popupMenu = new JPopupMenu();
popupMenu.setInvoker(this);
setOpaque(false);
+ setDelay(200);
}
/**
@@ -122,8 +126,10 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
{
super(action);
createActionChangeListener(this);
+ popupMenu = new JPopupMenu();
popupMenu.setInvoker(this);
setOpaque(false);
+ setDelay(200);
}
/**
@@ -137,6 +143,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
{
// FIXME: tearoff not implemented
this(text);
+ setDelay(200);
}
/**
@@ -148,7 +155,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public JMenuItem add(JMenuItem item)
{
- return popupMenu.add(item);
+ return getPopupMenu().add(item);
}
/**
@@ -160,7 +167,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public Component add(Component component)
{
- popupMenu.insert(component, -1);
+ getPopupMenu().insert(component, -1);
return component;
}
@@ -174,7 +181,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public Component add(Component component, int index)
{
- return popupMenu.add(component, index);
+ return getPopupMenu().add(component, index);
}
/**
@@ -186,7 +193,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public JMenuItem add(String text)
{
- return popupMenu.add(text);
+ return getPopupMenu().add(text);
}
/**
@@ -198,7 +205,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public JMenuItem add(Action action)
{
- return popupMenu.add(action);
+ return getPopupMenu().add(action);
}
/**
@@ -209,7 +216,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public void remove(JMenuItem item)
{
- popupMenu.remove(item);
+ getPopupMenu().remove(item);
}
/**
@@ -219,7 +226,11 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public void remove(int index)
{
- popupMenu.remove(index);
+ if (index < 0 || (index > 0 && getMenuComponentCount() == 0))
+ throw new IllegalArgumentException();
+
+ if (getMenuComponentCount() > 0)
+ popupMenu.remove(index);
}
/**
@@ -229,8 +240,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public void remove(Component component)
{
- int index = popupMenu.getComponentIndex(component);
- popupMenu.remove(index);
+ int index = getPopupMenu().getComponentIndex(component);
+ if (index >= 0)
+ getPopupMenu().remove(index);
}
/**
@@ -238,7 +250,8 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public void removeAll()
{
- popupMenu.removeAll();
+ if (popupMenu != null)
+ popupMenu.removeAll();
}
/**
@@ -267,7 +280,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
if (index < 0)
throw new IllegalArgumentException("index less than zero");
- popupMenu.insert(item, index);
+ getPopupMenu().insert(item, index);
return item;
}
@@ -381,7 +394,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
super.setSelected(false);
super.setArmed(false);
fireMenuDeselected();
- popupMenu.setVisible(false);
+ getPopupMenu().setVisible(false);
}
}
@@ -404,7 +417,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public boolean isPopupMenuVisible()
{
- return popupMenu.isVisible();
+ return getPopupMenu().isVisible();
}
/**
@@ -415,7 +428,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
public void setPopupMenuVisible(boolean popup)
{
if (getModel().isEnabled())
- popupMenu.setVisible(popup);
+ getPopupMenu().setVisible(popup);
}
/**
@@ -530,6 +543,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
if (index < 0)
throw new IllegalArgumentException("index less than 0");
+ if (getItemCount() == 0)
+ return null;
+
Component c = popupMenu.getComponentAtIndex(index);
if (c instanceof JMenuItem)
@@ -558,7 +574,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
public boolean isTearOff()
{
// NOT YET IMPLEMENTED
- return false;
+ throw new Error("The method isTearOff() has not yet been implemented.");
}
/**
@@ -568,7 +584,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public int getMenuComponentCount()
{
- return popupMenu.getComponentCount();
+ return getPopupMenu().getComponentCount();
}
/**
@@ -581,6 +597,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public Component getMenuComponent(int index)
{
+ if (getPopupMenu() == null || getMenuComponentCount() == 0)
+ return null;
+
return (Component) popupMenu.getComponentAtIndex(index);
}
@@ -591,7 +610,7 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public Component[] getMenuComponents()
{
- return popupMenu.getComponents();
+ return getPopupMenu().getComponents();
}
/**
@@ -626,6 +645,11 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement
*/
public JPopupMenu getPopupMenu()
{
+ if (popupMenu == null)
+ {
+ popupMenu = new JPopupMenu();
+ popupMenu.setInvoker(this);
+ }
return popupMenu;
}
diff --git a/libjava/classpath/javax/swing/JMenuItem.java b/libjava/classpath/javax/swing/JMenuItem.java
index 90d54b1d30a..f7f93bf00d7 100644
--- a/libjava/classpath/javax/swing/JMenuItem.java
+++ b/libjava/classpath/javax/swing/JMenuItem.java
@@ -184,7 +184,7 @@ public class JMenuItem extends AbstractButton implements Accessible,
out statement below for now. */
//borderPainted = false;
focusPainted = false;
- horizontalAlignment = JButton.LEFT;
+ horizontalAlignment = JButton.LEADING;
horizontalTextPosition = JButton.TRAILING;
}
diff --git a/libjava/classpath/javax/swing/JOptionPane.java b/libjava/classpath/javax/swing/JOptionPane.java
index f9490553834..43caecd1a48 100644
--- a/libjava/classpath/javax/swing/JOptionPane.java
+++ b/libjava/classpath/javax/swing/JOptionPane.java
@@ -48,6 +48,8 @@ import java.awt.MenuComponent;
import java.awt.Toolkit;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseMotionAdapter;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
@@ -378,11 +380,49 @@ public class JOptionPane extends JComponent implements Accessible
dialog.setResizable(false);
dialog.pack();
dialog.setLocationRelativeTo(parentComponent);
-
+
+ addPropertyChangeListener(new ValuePropertyHandler(dialog));
return dialog;
}
/**
+ * Handles changes of the value property. Whenever this property changes,
+ * the JOptionPane dialog should be closed.
+ */
+ private static class ValuePropertyHandler
+ implements PropertyChangeListener
+ {
+ /**
+ * The dialog to close.
+ */
+ JDialog dialog;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param d the dialog to be closed
+ */
+ ValuePropertyHandler(JDialog d)
+ {
+ dialog = d;
+ }
+
+ /**
+ * Receives notification when any of the properties change.
+ */
+ public void propertyChange(PropertyChangeEvent p)
+ {
+ String prop = p.getPropertyName();
+ Object val = p.getNewValue();
+ if (prop.equals(VALUE_PROPERTY) && val != null
+ && val != UNINITIALIZED_VALUE)
+ {
+ dialog.setVisible(false);
+ }
+ }
+ }
+
+ /**
* This method creates a new JInternalFrame that is in the JLayeredPane
* which contains the parentComponent given. If no suitable JLayeredPane
* can be found from the parentComponent given, a RuntimeException will be
diff --git a/libjava/classpath/javax/swing/JPopupMenu.java b/libjava/classpath/javax/swing/JPopupMenu.java
index c7890ea0e1e..d46015afdf3 100644
--- a/libjava/classpath/javax/swing/JPopupMenu.java
+++ b/libjava/classpath/javax/swing/JPopupMenu.java
@@ -120,7 +120,7 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement
private boolean lightWeightPopupEnabled;
/** SelectionModel that keeps track of menu selection. */
- private SingleSelectionModel selectionModel;
+ protected SingleSelectionModel selectionModel;
/* Popup that is used to display JPopupMenu */
private transient Popup popup;
diff --git a/libjava/classpath/javax/swing/JRadioButtonMenuItem.java b/libjava/classpath/javax/swing/JRadioButtonMenuItem.java
index 0d7c1d10533..13ef189a514 100644
--- a/libjava/classpath/javax/swing/JRadioButtonMenuItem.java
+++ b/libjava/classpath/javax/swing/JRadioButtonMenuItem.java
@@ -144,6 +144,7 @@ public class JRadioButtonMenuItem extends JMenuItem implements Accessible
super(text, icon);
setModel(new JToggleButton.ToggleButtonModel());
model.setSelected(selected);
+ setFocusable(false);
}
/**
diff --git a/libjava/classpath/javax/swing/JSplitPane.java b/libjava/classpath/javax/swing/JSplitPane.java
index 2747686a31a..5b77f5176ae 100644
--- a/libjava/classpath/javax/swing/JSplitPane.java
+++ b/libjava/classpath/javax/swing/JSplitPane.java
@@ -708,7 +708,8 @@ public class JSplitPane extends JComponent implements Accessible
throw new IllegalArgumentException
("proportion has to be between 0 and 1.");
- int max = (orientation == HORIZONTAL_SPLIT) ? getWidth() : getHeight();
+ int max = ((orientation == HORIZONTAL_SPLIT) ? getWidth() : getHeight())
+ - getDividerSize();
setDividerLocation((int) (proportionalLocation * max));
}
diff --git a/libjava/classpath/javax/swing/JTabbedPane.java b/libjava/classpath/javax/swing/JTabbedPane.java
index ee6af857ee3..5c8d0474852 100644
--- a/libjava/classpath/javax/swing/JTabbedPane.java
+++ b/libjava/classpath/javax/swing/JTabbedPane.java
@@ -990,6 +990,8 @@ public class JTabbedPane extends JComponent implements Serializable,
checkIndex(index, -1, tabs.size());
if (index != getSelectedIndex())
{
+ // Hiding and showing the involved components
+ // is done by the JTabbedPane's UI.
model.setSelectedIndex(index);
}
}
@@ -1247,7 +1249,32 @@ public class JTabbedPane extends JComponent implements Serializable,
*/
public void remove(Component component)
{
- super.remove(component);
+ // Since components implementing UIResource
+ // are not added as regular tabs by the add()
+ // methods we have to take special care when
+ // removing these object. Especially
+ // Container.remove(Component) cannot be used
+ // because it will call JTabbedPane.remove(int)
+ // later which is overridden and can only
+ // handle tab components.
+ // This implementation can even cope with a
+ // situation that someone called insertTab()
+ // with a component that implements UIResource.
+ int index = indexOfComponent(component);
+
+ // If the component is not a tab component
+ // find out its Container-given index
+ // and call that class' implementation
+ // directly.
+ if (index == -1)
+ {
+ Component[] cs = getComponents();
+ for (int i = 0; i< cs.length; i++)
+ if (cs[i] == component)
+ super.remove(i);
+ }
+ else
+ removeTabAt(index);
}
/**
@@ -1257,7 +1284,6 @@ public class JTabbedPane extends JComponent implements Serializable,
*/
public void remove(int index)
{
- super.remove(index);
removeTabAt(index);
}
diff --git a/libjava/classpath/javax/swing/JTable.java b/libjava/classpath/javax/swing/JTable.java
index 855530881f5..5c7bff5d019 100644
--- a/libjava/classpath/javax/swing/JTable.java
+++ b/libjava/classpath/javax/swing/JTable.java
@@ -2922,56 +2922,189 @@ public class JTable
{
// update the column model from the table model if the structure has
// changed and the flag autoCreateColumnsFromModel is set
- if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
- && autoCreateColumnsFromModel)
+ if (event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
+ handleCompleteChange(event);
+ else if (event.getType() == TableModelEvent.INSERT)
+ handleInsert(event);
+ else if (event.getType() == TableModelEvent.DELETE)
+ handleDelete(event);
+ else
+ handleUpdate(event);
+ }
+
+ /**
+ * Handles a request for complete relayout. This is the case when
+ * event.getFirstRow() == TableModelEvent.HEADER_ROW.
+ *
+ * @param ev the table model event
+ */
+ private void handleCompleteChange(TableModelEvent ev)
+ {
+ clearSelection();
+ checkSelection();
+ rowHeights = null;
+ if (getAutoCreateColumnsFromModel())
+ createDefaultColumnsFromModel();
+ else
+ resizeAndRepaint();
+ }
+
+ /**
+ * Handles table model insertions.
+ *
+ * @param ev the table model event
+ */
+ private void handleInsert(TableModelEvent ev)
+ {
+ // Sync selection model with data model.
+ int first = ev.getFirstRow();
+ if (first < 0)
+ first = 0;
+ int last = ev.getLastRow();
+ if (last < 0)
+ last = getRowCount() - 1;
+ selectionModel.insertIndexInterval(first, last - first + 1, true);
+ checkSelection();
+
+ // For variable height rows we must update the SizeSequence thing.
+ if (rowHeights != null)
{
- rowHeights = null;
- if (getAutoCreateColumnsFromModel())
- createDefaultColumnsFromModel();
- resizeAndRepaint();
- return;
+ rowHeights.insertEntries(first, last - first + 1, rowHeight);
+ // TODO: We repaint the whole thing when the rows have variable
+ // heights. We might want to handle this better though.
+ repaint();
+ }
+ else
+ {
+ // Repaint the dirty region and revalidate.
+ int rowHeight = getRowHeight();
+ Rectangle dirty = new Rectangle(0, first * rowHeight,
+ getColumnModel().getTotalColumnWidth(),
+ (getRowCount() - first) * rowHeight);
+ repaint(dirty);
+ }
+ revalidate();
+ }
+
+ /**
+ * Handles table model deletions.
+ *
+ * @param ev the table model event
+ */
+ private void handleDelete(TableModelEvent ev)
+ {
+ // Sync selection model with data model.
+ int first = ev.getFirstRow();
+ if (first < 0)
+ first = 0;
+ int last = ev.getLastRow();
+ if (last < 0)
+ last = getRowCount() - 1;
+
+ selectionModel.removeIndexInterval(first, last);
+
+ checkSelection();
+
+ if (dataModel.getRowCount() == 0)
+ clearSelection();
+
+ // For variable height rows we must update the SizeSequence thing.
+ if (rowHeights != null)
+ {
+ rowHeights.removeEntries(first, last - first + 1);
+ // TODO: We repaint the whole thing when the rows have variable
+ // heights. We might want to handle this better though.
+ repaint();
+ }
+ else
+ {
+ // Repaint the dirty region and revalidate.
+ int rowHeight = getRowHeight();
+ int oldRowCount = getRowCount() + last - first + 1;
+ Rectangle dirty = new Rectangle(0, first * rowHeight,
+ getColumnModel().getTotalColumnWidth(),
+ (oldRowCount - first) * rowHeight);
+ repaint(dirty);
}
+ revalidate();
+ }
- // If the structure changes, we need to revalidate, since that might
- // affect the size parameters of the JTable. Otherwise we only need
- // to perform a repaint to update the view.
- if (event == null || event.getType() == TableModelEvent.INSERT)
+ /**
+ * Handles table model updates without structural changes.
+ *
+ * @param ev the table model event
+ */
+ private void handleUpdate(TableModelEvent ev)
+ {
+ if (rowHeights == null)
{
- // Sync selection model with data model.
- if (event != null)
+ // Some cells have been changed without changing the structure.
+ // Figure out the dirty rectangle and repaint.
+ int firstRow = ev.getFirstRow();
+ int lastRow = ev.getLastRow();
+ int col = ev.getColumn();
+ Rectangle dirty;
+ if (col == TableModelEvent.ALL_COLUMNS)
{
- int first = event.getFirstRow();
- if (first < 0)
- first = 0;
- int last = event.getLastRow();
- if (last < 0)
- last = getRowCount() - 1;
- selectionModel.insertIndexInterval(first, last - first + 1, true);
- if (rowHeights != null)
- rowHeights.insertEntries(first, last - first + 1, rowHeight);
+ // All columns changed.
+ dirty = new Rectangle(0, firstRow * getRowHeight(),
+ getColumnModel().getTotalColumnWidth(), 0);
}
- revalidate();
+ else
+ {
+ // Only one cell or column of cells changed.
+ // We need to convert to view column first.
+ int column = convertColumnIndexToModel(col);
+ dirty = getCellRect(firstRow, column, false);
+ }
+
+ // Now adjust the height of the dirty region.
+ dirty.height = (lastRow + 1) * getRowHeight();
+ // .. and repaint.
+ repaint(dirty);
}
- if (event == null || event.getType() == TableModelEvent.DELETE)
+ else
{
- // Sync selection model with data model.
- if (event != null)
+ // TODO: We repaint the whole thing when the rows have variable
+ // heights. We might want to handle this better though.
+ repaint();
+ }
+ }
+
+ /**
+ * Helper method for adjusting the lead and anchor indices when the
+ * table structure changed. This sets the lead and anchor to -1 if there's
+ * no more rows, or set them to 0 when they were at -1 and there are actually
+ * some rows now.
+ */
+ private void checkSelection()
+ {
+ TableModel m = getModel();
+ ListSelectionModel sm = selectionModel;
+ if (m != null)
+ {
+ int lead = sm.getLeadSelectionIndex();
+ int c = m.getRowCount();
+ if (c == 0 && lead != -1)
+ {
+ // No rows in the model, reset lead and anchor to -1.
+ sm.setValueIsAdjusting(true);
+ sm.setAnchorSelectionIndex(-1);
+ sm.setLeadSelectionIndex(-1);
+ sm.setValueIsAdjusting(false);
+ }
+ else if (c != 0 && lead == -1)
{
- int first = event.getFirstRow();
- if (first < 0)
- first = 0;
- int last = event.getLastRow();
- if (last < 0)
- last = getRowCount() - 1;
- selectionModel.removeIndexInterval(first, last);
- if (rowHeights != null)
- rowHeights.removeEntries(first, last - first + 1);
+ // We have rows, but no lead/anchor. Set them to 0. We
+ // do a little trick here so that the actual selection is not
+ // touched.
+ if (sm.isSelectedIndex(0))
+ sm.addSelectionInterval(0, 0);
+ else
+ sm.removeSelectionInterval(0, 0);
}
- if (dataModel.getRowCount() == 0)
- clearSelection();
- revalidate();
+ // Nothing to do in the other cases.
}
- repaint();
}
/**
@@ -3468,6 +3601,8 @@ public class JTable
* Get the value of the {@link #rowSelectionAllowed} property.
*
* @return The current value of the property
+ *
+ * @see #setRowSelectionAllowed(boolean)
*/
public boolean getRowSelectionAllowed()
{
@@ -3621,6 +3756,8 @@ public class JTable
* Get the value of the <code>columnSelectionAllowed</code> property.
*
* @return The current value of the columnSelectionAllowed property
+ *
+ * @see #setColumnSelectionAllowed(boolean)
*/
public boolean getColumnSelectionAllowed()
{
@@ -3874,11 +4011,17 @@ public class JTable
* Set the value of the {@link #rowSelectionAllowed} property.
*
* @param r The new value of the rowSelectionAllowed property
+ *
+ * @see #getRowSelectionAllowed()
*/
public void setRowSelectionAllowed(boolean r)
{
- rowSelectionAllowed = r;
- repaint();
+ if (rowSelectionAllowed != r)
+ {
+ rowSelectionAllowed = r;
+ firePropertyChange("rowSelectionAllowed", !r, r);
+ repaint();
+ }
}
/**
@@ -3988,11 +4131,17 @@ public class JTable
* Set the value of the <code>columnSelectionAllowed</code> property.
*
* @param c The new value of the property
+ *
+ * @see #getColumnSelectionAllowed()
*/
public void setColumnSelectionAllowed(boolean c)
{
- getColumnModel().setColumnSelectionAllowed(c);
- repaint();
+ if (columnModel.getColumnSelectionAllowed() != c)
+ {
+ columnModel.setColumnSelectionAllowed(c);
+ firePropertyChange("columnSelectionAllowed", !c, c);
+ repaint();
+ }
}
/**
@@ -4014,6 +4163,7 @@ public class JTable
if (s != null)
s.addListSelectionListener(this);
selectionModel = s;
+ checkSelection();
}
/**
diff --git a/libjava/classpath/javax/swing/JTree.java b/libjava/classpath/javax/swing/JTree.java
index f7583ad69e2..fa898c5a940 100644
--- a/libjava/classpath/javax/swing/JTree.java
+++ b/libjava/classpath/javax/swing/JTree.java
@@ -1392,9 +1392,9 @@ public class JTree extends JComponent implements Scrollable, Accessible
public static final String EXPANDS_SELECTED_PATHS_PROPERTY =
"expandsSelectedPaths";
- private static final Object EXPANDED = new Object();
+ private static final Object EXPANDED = Boolean.TRUE;
- private static final Object COLLAPSED = new Object();
+ private static final Object COLLAPSED = Boolean.FALSE;
private boolean dragEnabled;
@@ -1515,6 +1515,9 @@ public class JTree extends JComponent implements Scrollable, Accessible
// The root node appears expanded by default.
nodeStates = new Hashtable();
+ // The cell renderer gets set by the UI.
+ cellRenderer = null;
+
// Install the UI before installing the model. This way we avoid double
// initialization of lots of UI and model stuff inside the UI and related
// classes. The necessary UI updates are performed via property change
diff --git a/libjava/classpath/javax/swing/LookAndFeel.java b/libjava/classpath/javax/swing/LookAndFeel.java
index 7f59f1b5f93..be543439636 100644
--- a/libjava/classpath/javax/swing/LookAndFeel.java
+++ b/libjava/classpath/javax/swing/LookAndFeel.java
@@ -242,15 +242,15 @@ public abstract class LookAndFeel
{
if (keys == null)
return;
- for (int i = 0; i < keys.length - 1; i+= 2)
+ for (int i = 0; i < keys.length - 1; i += 2)
{
Object key = keys[i];
KeyStroke keyStroke;
if (key instanceof KeyStroke)
- keyStroke = (KeyStroke)key;
+ keyStroke = (KeyStroke) key;
else
- keyStroke = KeyStroke.getKeyStroke((String)key);
- retMap.put(keyStroke, keys[i+1]);
+ keyStroke = KeyStroke.getKeyStroke((String) key);
+ retMap.put(keyStroke, keys[i + 1]);
}
}
@@ -328,15 +328,15 @@ public abstract class LookAndFeel
{
JTextComponent.KeyBinding[] retBindings =
new JTextComponent.KeyBinding[keyBindingList.length / 2];
- for (int i = 0; i < keyBindingList.length - 1; i+= 2)
+ for (int i = 0; i < keyBindingList.length - 1; i += 2)
{
KeyStroke stroke;
if (keyBindingList[i] instanceof KeyStroke)
- stroke = (KeyStroke)keyBindingList[i];
+ stroke = (KeyStroke) keyBindingList[i];
else
- stroke = KeyStroke.getKeyStroke((String)keyBindingList[i]);
- retBindings[i/2] = new JTextComponent.KeyBinding(stroke,
- (String) keyBindingList[i+1]);
+ stroke = KeyStroke.getKeyStroke((String) keyBindingList[i]);
+ retBindings[i / 2] = new JTextComponent.KeyBinding(stroke,
+ (String) keyBindingList[i + 1]);
}
return retBindings;
}
diff --git a/libjava/classpath/javax/swing/ProgressMonitor.java b/libjava/classpath/javax/swing/ProgressMonitor.java
index 28d22e8a63e..b4c3d222349 100644
--- a/libjava/classpath/javax/swing/ProgressMonitor.java
+++ b/libjava/classpath/javax/swing/ProgressMonitor.java
@@ -142,12 +142,12 @@ public class ProgressMonitor
*/
public void close()
{
- if ( progressDialog != null )
+ if (progressDialog != null)
{
progressDialog.setVisible(false);
}
- if ( timer != null )
+ if (timer != null)
{
timer.stop();
timer = null;
@@ -173,7 +173,7 @@ public class ProgressMonitor
// Initializes and starts a timer with a task
// which measures the duration and displays
// a progress dialog if neccessary.
- if ( timer == null && progressDialog == null )
+ if (timer == null && progressDialog == null)
{
timer = new Timer(25, null);
timer.addActionListener(new TimerListener());
@@ -182,7 +182,7 @@ public class ProgressMonitor
// Cancels timer and hides progress dialog if the
// maximum value is reached.
- if ( progressBar != null && this.progress >= progressBar.getMaximum() )
+ if (progressBar != null && this.progress >= progressBar.getMaximum())
{
// The reason for using progressBar.getMaximum() instead of max is that
// we want to prevent that changes to the value have any effect after the
@@ -326,7 +326,7 @@ public class ProgressMonitor
*/
public void setNote(String note)
{
- if ( noteLabel != null )
+ if (noteLabel != null)
{
noteLabel.setText(note);
}
@@ -401,18 +401,18 @@ public class ProgressMonitor
{
long now = System.currentTimeMillis();
- if ( first )
+ if (first)
{
- if (( now - timestamp ) > millisToDecideToPopup )
+ if ((now - timestamp) > millisToDecideToPopup)
{
first = false;
- long expected = ( progress - min == 0 ) ?
- ( now - timestamp ) * ( max - min ) :
- ( now - timestamp ) * ( max - min ) / ( progress - min );
+ long expected = (progress - min == 0) ?
+ (now - timestamp) * (max - min) :
+ (now - timestamp) * (max - min) / (progress - min);
- if ( expected > millisToPopup )
+ if (expected > millisToPopup)
{
createDialog();
}
@@ -424,14 +424,14 @@ public class ProgressMonitor
return;
}
}
- else if ( progressDialog != null )
+ else if (progressDialog != null)
{
// The progress dialog is being displayed. We now calculate
// whether setting the progress bar to the current progress
// value would result in a visual difference.
int delta = progress - progressBar.getValue();
- if ( ( delta * progressBar.getWidth() / (max - min) ) > 0 )
+ if ((delta * progressBar.getWidth() / (max - min)) > 0)
{
// At least one pixel would change.
progressBar.setValue(progress);
diff --git a/libjava/classpath/javax/swing/ProgressMonitorInputStream.java b/libjava/classpath/javax/swing/ProgressMonitorInputStream.java
index fec5c2ee03b..90e721247b1 100644
--- a/libjava/classpath/javax/swing/ProgressMonitorInputStream.java
+++ b/libjava/classpath/javax/swing/ProgressMonitorInputStream.java
@@ -240,7 +240,7 @@ public class ProgressMonitorInputStream extends FilterInputStream
private void checkMonitorCanceled() throws InterruptedIOException
{
- if ( monitor.isCanceled() )
+ if (monitor.isCanceled())
{
throw new InterruptedIOException("ProgressMonitor was canceled");
}
diff --git a/libjava/classpath/javax/swing/RepaintManager.java b/libjava/classpath/javax/swing/RepaintManager.java
index f95934123ea..80f0a3481cd 100644
--- a/libjava/classpath/javax/swing/RepaintManager.java
+++ b/libjava/classpath/javax/swing/RepaintManager.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package javax.swing;
-import java.applet.Applet;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -314,26 +313,45 @@ public class RepaintManager
*/
public void addInvalidComponent(JComponent component)
{
- Component ancestor = component;
-
- while (ancestor != null
- && (! (ancestor instanceof JComponent)
- || ! ((JComponent) ancestor).isValidateRoot() ))
- ancestor = ancestor.getParent();
+ Component validateRoot = null;
+ Component c = component;
+ while (c != null)
+ {
+ // Special cases we don't bother validating are when the invalidated
+ // component (or any of it's ancestors) is inside a CellRendererPane
+ // or if it doesn't have a peer yet (== not displayable).
+ if (c instanceof CellRendererPane || ! c.isDisplayable())
+ return;
+ if (c instanceof JComponent && ((JComponent) c).isValidateRoot())
+ {
+ validateRoot = c;
+ break;
+ }
- if (ancestor != null
- && ancestor instanceof JComponent
- && ((JComponent) ancestor).isValidateRoot())
- component = (JComponent) ancestor;
+ c = c.getParent();
+ }
- if (invalidComponents.contains(component))
+ // If we didn't find a validate root, then we don't validate.
+ if (validateRoot == null)
return;
- synchronized (invalidComponents)
+ // Make sure the validate root and all of it's ancestors are visible.
+ c = validateRoot;
+ while (c != null)
{
- invalidComponents.add(component);
+ if (! c.isVisible() || ! c.isDisplayable())
+ return;
+ c = c.getParent();
}
+ if (invalidComponents.contains(validateRoot))
+ return;
+
+ //synchronized (invalidComponents)
+ // {
+ invalidComponents.add(validateRoot);
+ // }
+
if (! repaintWorker.isLive())
{
repaintWorker.setLive(true);
@@ -379,7 +397,7 @@ public class RepaintManager
{
if (w <= 0 || h <= 0 || !component.isShowing())
return;
-
+
Component parent = component.getParent();
component.computeVisibleRect(rectCache);
@@ -444,8 +462,7 @@ public class RepaintManager
*/
public void markCompletelyDirty(JComponent component)
{
- Rectangle r = component.getBounds();
- addDirtyRegion(component, 0, 0, r.width, r.height);
+ addDirtyRegion(component, 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
@@ -483,13 +500,11 @@ public class RepaintManager
*/
public boolean isCompletelyDirty(JComponent component)
{
- boolean retVal = false;
- if (dirtyComponents.containsKey(component))
- {
- Rectangle dirtyRegion = (Rectangle) dirtyComponents.get(component);
- retVal = dirtyRegion.equals(SwingUtilities.getLocalBounds(component));
- }
- return retVal;
+ boolean dirty = false;
+ Rectangle r = getDirtyRegion(component);
+ if(r.width == Integer.MAX_VALUE && r.height == Integer.MAX_VALUE)
+ dirty = true;
+ return dirty;
}
/**
@@ -618,7 +633,7 @@ public class RepaintManager
public Image getOffscreenBuffer(Component component, int proposedWidth,
int proposedHeight)
{
- Component root = getRoot(component);
+ Component root = SwingUtilities.getWindowAncestor(component);
Image buffer = (Image) offscreenBuffers.get(root);
if (buffer == null
|| buffer.getWidth(null) < proposedWidth
@@ -628,38 +643,12 @@ public class RepaintManager
width = Math.min(doubleBufferMaximumSize.width, width);
int height = Math.max(proposedHeight, root.getHeight());
height = Math.min(doubleBufferMaximumSize.height, height);
- buffer = component.createImage(width, height);
+ buffer = root.createImage(width, height);
offscreenBuffers.put(root, buffer);
}
return buffer;
}
-
- /**
- * Gets the root of the component given. If a parent of the
- * component is an instance of Applet, then the applet is
- * returned. The applet is considered the root for painting.
- * Otherwise, the root Window is returned if it exists.
- *
- * @param comp - The component to get the root for.
- * @return the parent root. An applet if it is a parent,
- * or the root window. If neither exist, null is returned.
- */
- private Component getRoot(Component comp)
- {
- Applet app = null;
-
- while (comp != null)
- {
- if (app == null && comp instanceof Window)
- return comp;
- else if (comp instanceof Applet)
- app = (Applet) comp;
- comp = comp.getParent();
- }
-
- return app;
- }
-
+
/**
* Blits the back buffer of the specified root component to the screen. If
* the RepaintManager is currently working on a paint request, the commit
@@ -667,67 +656,98 @@ public class RepaintManager
* done (by {@link #commitRemainingBuffers}). This is package private because
* it must get called by JComponent.
*
- * @param root the component, either a Window or an Applet instance
- * @param area the area to paint on screen
+ * @param comp the component to be painted
+ * @param area the area to paint on screen, in comp coordinates
*/
- void commitBuffer(Component root, Rectangle area)
+ void commitBuffer(Component comp, Rectangle area)
{
+ // Determine the component that we finally paint the buffer upon.
+ // We need to paint on the nearest heavyweight component, so that Swing
+ // hierarchies inside (non-window) heavyweights get painted correctly.
+ // Otherwise we would end up blitting the backbuffer behind the heavyweight
+ // which is wrong.
+ Component root = getHeavyweightParent(comp);
+ // FIXME: Optimize this.
+ Rectangle rootRect = SwingUtilities.convertRectangle(comp, area, root);
+
// We synchronize on dirtyComponents here because that is what
// paintDirtyRegions also synchronizes on while painting.
synchronized (dirtyComponents)
{
// If the RepaintManager is not currently painting, then directly
// blit the requested buffer on the screen.
- if (! repaintUnderway)
+ if (true || ! repaintUnderway)
{
- Graphics g = root.getGraphics();
- Image buffer = (Image) offscreenBuffers.get(root);
- Rectangle clip = g.getClipBounds();
- if (clip != null)
- area = SwingUtilities.computeIntersection(clip.x, clip.y,
- clip.width, clip.height,
- area);
- int dx1 = area.x;
- int dy1 = area.y;
- int dx2 = area.x + area.width;
- int dy2 = area.y + area.height;
- // Make sure we have a sane clip at this point.
- g.clipRect(area.x, area.y, area.width, area.height);
-
- // Make sure the coordinates are inside the buffer, everything else
- // might lead to problems.
- // TODO: This code should not really be necessary, however, in fact
- // we have two issues here:
- // 1. We shouldn't get repaint requests in areas outside the buffer
- // region in the first place. This still happens for example
- // when a component is inside a JViewport, and the component has
- // a size that would reach beyond the window size.
- // 2. Graphics.drawImage() should not behave strange when trying
- // to draw regions outside the image.
- int bufferWidth = buffer.getWidth(root);
- int bufferHeight = buffer.getHeight(root);
- dx1 = Math.min(bufferWidth, dx1);
- dy1 = Math.min(bufferHeight, dy1);
- dx2 = Math.min(bufferWidth, dx2);
- dy2 = Math.min(bufferHeight, dy2);
- g.drawImage(buffer, 0, 0, root);
- g.dispose();
+ blitBuffer(root, rootRect);
}
+
// Otherwise queue this request up, until all the RepaintManager work
// is done.
else
{
if (commitRequests.containsKey(root))
- SwingUtilities.computeUnion(area.x, area.y, area.width,
- area.height,
+ SwingUtilities.computeUnion(rootRect.x, rootRect.y,
+ rootRect.width, rootRect.height,
(Rectangle) commitRequests.get(root));
else
- commitRequests.put(root, area);
+ commitRequests.put(root, rootRect);
}
}
}
/**
+ * Copies the buffer to the screen. Note that the root component here is
+ * not necessarily the component with which the offscreen buffer is
+ * associated. The offscreen buffers are always allocated for the toplevel
+ * windows. However, painted is performed on lower-level heavyweight
+ * components too, if they contain Swing components.
+ *
+ * @param root the heavyweight component to blit upon
+ * @param rootRect the rectangle in the root component's coordinate space
+ */
+ private void blitBuffer(Component root, Rectangle rootRect)
+ {
+ if (! root.isShowing())
+ return;
+
+ // Find the Window from which we use the backbuffer.
+ Component bufferRoot = root;
+ Rectangle bufferRect = rootRect.getBounds();
+ if (!(bufferRoot instanceof Window))
+ {
+ bufferRoot = SwingUtilities.getWindowAncestor(bufferRoot);
+ SwingUtilities.convertRectangleToAncestor(root, rootRect, bufferRoot);
+ }
+
+ Graphics g = root.getGraphics();
+ Image buffer = (Image) offscreenBuffers.get(bufferRoot);
+
+ // Make sure we have a sane clip at this point.
+ g.clipRect(rootRect.x, rootRect.y, rootRect.width, rootRect.height);
+ g.drawImage(buffer, rootRect.x - bufferRect.x, rootRect.y - bufferRect.y,
+ root);
+ g.dispose();
+
+ }
+
+ /**
+ * Finds and returns the nearest heavyweight parent for the specified
+ * component. If the component isn't contained inside a heavyweight parent,
+ * this returns null.
+ *
+ * @param comp the component
+ *
+ * @return the nearest heavyweight parent for the specified component or
+ * null if the component has no heavyweight ancestor
+ */
+ private Component getHeavyweightParent(Component comp)
+ {
+ while (comp != null && comp.isLightweight())
+ comp = comp.getParent();
+ return comp;
+ }
+
+ /**
* Commits the queued up back buffers to screen all at once.
*/
private void commitRemainingBuffers()
@@ -743,7 +763,7 @@ public class RepaintManager
Map.Entry entry = (Map.Entry) i.next();
Component root = (Component) entry.getKey();
Rectangle area = (Rectangle) entry.getValue();
- commitBuffer(root, area);
+ blitBuffer(root, area);
i.remove();
}
}
@@ -767,7 +787,7 @@ public class RepaintManager
public Image getVolatileOffscreenBuffer(Component comp, int proposedWidth,
int proposedHeight)
{
- Component root = getRoot(comp);
+ Component root = SwingUtilities.getWindowAncestor(comp);
Image buffer = (Image) offscreenBuffers.get(root);
if (buffer == null
|| buffer.getWidth(null) < proposedWidth
diff --git a/libjava/classpath/javax/swing/ScrollPaneLayout.java b/libjava/classpath/javax/swing/ScrollPaneLayout.java
index 31846fa557d..8ce8fd86f7a 100644
--- a/libjava/classpath/javax/swing/ScrollPaneLayout.java
+++ b/libjava/classpath/javax/swing/ScrollPaneLayout.java
@@ -82,7 +82,8 @@ public class ScrollPaneLayout
// Nothing to do here.
}
- public void syncWithScrollPane(JScrollPane scrollPane) {
+ public void syncWithScrollPane(JScrollPane scrollPane)
+ {
viewport = scrollPane.getViewport();
rowHead = scrollPane.getRowHeader();
colHead = scrollPane.getColumnHeader();
@@ -145,7 +146,8 @@ public class ScrollPaneLayout
throw new IllegalArgumentException();
}
- public void removeLayoutComponent(Component component) {
+ public void removeLayoutComponent(Component component)
+ {
if (component == viewport)
viewport = null;
else if (component == vsb)
@@ -448,7 +450,8 @@ public class ScrollPaneLayout
* @deprecated As of Swing 1.1 replaced by
* {@link javax.swing.JScrollPane#getViewportBorderBounds}.
*/
- public Rectangle getViewportBorderBounds(JScrollPane scrollPane) {
+ public Rectangle getViewportBorderBounds(JScrollPane scrollPane)
+ {
return null;
}
diff --git a/libjava/classpath/javax/swing/SizeSequence.java b/libjava/classpath/javax/swing/SizeSequence.java
index 26099a15461..a5f34710c76 100644
--- a/libjava/classpath/javax/swing/SizeSequence.java
+++ b/libjava/classpath/javax/swing/SizeSequence.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package javax.swing;
+import java.util.Arrays;
+
/**
* A sequence of values that represent the dimensions (widths or heights) of
* some collection of items (for example, the widths of the columns in a table).
@@ -80,8 +82,8 @@ public class SizeSequence
*/
public SizeSequence(int numEntries, int value)
{
- sizes = new int[0];
- insertEntries(0, numEntries, value);
+ sizes = new int[numEntries];
+ Arrays.fill(sizes, value);
}
/**
diff --git a/libjava/classpath/javax/swing/SpringLayout.java b/libjava/classpath/javax/swing/SpringLayout.java
index d87050639fe..2595b196703 100644
--- a/libjava/classpath/javax/swing/SpringLayout.java
+++ b/libjava/classpath/javax/swing/SpringLayout.java
@@ -505,7 +505,7 @@ public class SpringLayout implements LayoutManager2
}
}
- private static abstract class DeferredDimension extends Spring
+ private abstract static class DeferredDimension extends Spring
{
private int value;
diff --git a/libjava/classpath/javax/swing/SwingUtilities.java b/libjava/classpath/javax/swing/SwingUtilities.java
index 5d02d9bb396..ccd37d03a55 100644
--- a/libjava/classpath/javax/swing/SwingUtilities.java
+++ b/libjava/classpath/javax/swing/SwingUtilities.java
@@ -1045,8 +1045,7 @@ public class SwingUtilities
*/
public static boolean isLeftMouseButton(MouseEvent event)
{
- return ((event.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK)
- == InputEvent.BUTTON1_DOWN_MASK);
+ return ((event.getModifiers() & InputEvent.BUTTON1_MASK) != 0);
}
/**
@@ -1599,4 +1598,27 @@ public class SwingUtilities
throw new IllegalArgumentException("Unrecognised code: " + code);
}
}
+
+ /**
+ * Converts a rectangle in the coordinate system of a child component into
+ * a rectangle of one of it's Ancestors. The result is stored in the input
+ * rectangle.
+ *
+ * @param comp the child component
+ * @param r the rectangle to convert
+ * @param ancestor the ancestor component
+ */
+ static void convertRectangleToAncestor(Component comp, Rectangle r,
+ Component ancestor)
+ {
+ if (comp == ancestor)
+ return;
+
+ r.x += comp.getX();
+ r.y += comp.getY();
+
+ Component parent = comp.getParent();
+ if (parent != null && parent != ancestor)
+ convertRectangleToAncestor(parent, r, ancestor);
+ }
}
diff --git a/libjava/classpath/javax/swing/Timer.java b/libjava/classpath/javax/swing/Timer.java
index 231b71d73bb..acd22624947 100644
--- a/libjava/classpath/javax/swing/Timer.java
+++ b/libjava/classpath/javax/swing/Timer.java
@@ -1,5 +1,5 @@
/* Timer.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -264,9 +264,13 @@ public class Timer
* firing the first event.
*
* @param d The time gap between the subsequent events, in milliseconds
+ *
+ * @throws IllegalArgumentException if <code>d</code> is less than zero.
*/
public void setDelay(int d)
{
+ if (d < 0)
+ throw new IllegalArgumentException("Invalid delay: " + d);
delay = d;
}
@@ -287,9 +291,13 @@ public class Timer
* subsequent events.
*
* @param i the initial delay, in milliseconds
+ *
+ * @throws IllegalArgumentException if <code>i</code> is less than zero.
*/
public void setInitialDelay(int i)
{
+ if (i < 0)
+ throw new IllegalArgumentException("Invalid initial delay: " + i);
initialDelay = i;
}
diff --git a/libjava/classpath/javax/swing/ToolTipManager.java b/libjava/classpath/javax/swing/ToolTipManager.java
index c7de4db8330..963ccf88117 100644
--- a/libjava/classpath/javax/swing/ToolTipManager.java
+++ b/libjava/classpath/javax/swing/ToolTipManager.java
@@ -1,5 +1,5 @@
/* ToolTipManager.java --
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -267,10 +267,12 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener
}
/**
- * This method sets the initial delay before the ToolTip is shown when the
+ * Sets the initial delay before the ToolTip is shown when the
* mouse enters a Component.
*
* @param delay The initial delay before the ToolTip is shown.
+ *
+ * @throws IllegalArgumentException if <code>delay</code> is less than zero.
*/
public void setInitialDelay(int delay)
{
@@ -289,9 +291,11 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener
}
/**
- * This method sets the time the ToolTip will be shown before being hidden.
+ * Sets the time the ToolTip will be shown before being hidden.
*
- * @param delay The time the ToolTip will be shown before being hidden.
+ * @param delay the delay (in milliseconds) before tool tips are hidden.
+ *
+ * @throws IllegalArgumentException if <code>delay</code> is less than zero.
*/
public void setDismissDelay(int delay)
{
@@ -310,10 +314,12 @@ public class ToolTipManager extends MouseAdapter implements MouseMotionListener
}
/**
- * This method sets the amount of delay where if the mouse re-enters a
+ * Sets the amount of delay where if the mouse re-enters a
* Component, the tooltip will be shown immediately.
*
- * @param delay The reshow delay.
+ * @param delay The reshow delay (in milliseconds).
+ *
+ * @throws IllegalArgumentException if <code>delay</code> is less than zero.
*/
public void setReshowDelay(int delay)
{
diff --git a/libjava/classpath/javax/swing/UIManager.java b/libjava/classpath/javax/swing/UIManager.java
index e6f80116321..77be44afcbb 100644
--- a/libjava/classpath/javax/swing/UIManager.java
+++ b/libjava/classpath/javax/swing/UIManager.java
@@ -45,6 +45,7 @@ import java.awt.Insets;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
+import java.util.Enumeration;
import java.util.Locale;
import javax.swing.border.Border;
@@ -117,6 +118,87 @@ public class UIManager implements Serializable
}
}
+ /**
+ * A UIDefaults subclass that multiplexes between itself and a 'fallback'
+ * UIDefaults instance. This is used to protect the L&F UIDefaults from beeing
+ * overwritten by applications.
+ */
+ private static class MultiplexUIDefaults
+ extends UIDefaults
+ {
+ private class MultiplexEnumeration
+ implements Enumeration
+ {
+ Enumeration[] enums;
+ int i;
+ MultiplexEnumeration(Enumeration e1, Enumeration e2)
+ {
+ enums = new Enumeration[]{ e1, e2 };
+ i = 0;
+ }
+
+ public boolean hasMoreElements()
+ {
+ return enums[i].hasMoreElements() || i < enums.length - 1;
+ }
+
+ public Object nextElement()
+ {
+ Object val = enums[i].nextElement();
+ if (! enums[i].hasMoreElements() && i < enums.length - 1)
+ i++;
+ return val;
+ }
+
+ }
+
+ UIDefaults fallback;
+
+ MultiplexUIDefaults(UIDefaults d)
+ {
+ fallback = d;
+ }
+
+ public Object get(Object key)
+ {
+ Object val = super.get(key);
+ if (val == null)
+ val = fallback.get(key);
+ return val;
+ }
+
+ public Object get(Object key, Locale l)
+ {
+ Object val = super.get(key, l);
+ if (val == null)
+ val = fallback.get(key, l);
+ return val;
+ }
+
+ public Object remove(Object key)
+ {
+ Object val = super.remove(key);
+ if (val == null)
+ val = fallback.remove(key);
+ return val;
+ }
+
+ public int size()
+ {
+ return super.size() + fallback.size();
+ }
+
+ public Enumeration keys()
+ {
+ return new MultiplexEnumeration(super.keys(), fallback.keys());
+ }
+
+ public Enumeration elements()
+ {
+ return new MultiplexEnumeration(super.elements(), fallback.elements());
+ }
+ }
+
private static final long serialVersionUID = -5547433830339189365L;
/** The installed look and feel(s). */
@@ -131,12 +213,9 @@ public class UIManager implements Serializable
/** The current look and feel. */
static LookAndFeel currentLookAndFeel;
- static UIDefaults currentUIDefaults;
+ static MultiplexUIDefaults currentUIDefaults;
- /**
- * UIDefaults set by the user.
- */
- static UIDefaults userUIDefaults;
+ static UIDefaults lookAndFeelDefaults;
/** Property change listener mechanism. */
static PropertyChangeSupport listeners
@@ -149,9 +228,7 @@ public class UIManager implements Serializable
{
if (defaultlaf != null)
{
- Class lafClass = Class.forName(defaultlaf);
- LookAndFeel laf = (LookAndFeel) lafClass.newInstance();
- setLookAndFeel(laf);
+ setLookAndFeel(defaultlaf);
}
else
{
@@ -162,6 +239,7 @@ public class UIManager implements Serializable
{
System.err.println("cannot initialize Look and Feel: " + defaultlaf);
System.err.println("error: " + ex.toString());
+ ex.printStackTrace();
System.err.println("falling back to Metal Look and Feel");
try
{
@@ -312,12 +390,7 @@ public class UIManager implements Serializable
*/
public static Object get(Object key)
{
- Object val = null;
- if (userUIDefaults != null)
- val = userUIDefaults.get(key);
- if (val == null)
- val = getLookAndFeelDefaults().get(key);
- return val;
+ return getDefaults().get(key);
}
/**
@@ -330,12 +403,7 @@ public class UIManager implements Serializable
*/
public static Object get(Object key, Locale locale)
{
- Object val = null;
- if (userUIDefaults != null)
- val = userUIDefaults.get(key, locale);
- if (val == null)
- val = getLookAndFeelDefaults().get(key, locale);
- return val;
+ return getDefaults().get(key, locale);
}
/**
@@ -414,6 +482,8 @@ public class UIManager implements Serializable
*/
public static UIDefaults getDefaults()
{
+ if (currentUIDefaults == null)
+ currentUIDefaults = new MultiplexUIDefaults(null);
return currentUIDefaults;
}
@@ -546,7 +616,7 @@ public class UIManager implements Serializable
*/
public static UIDefaults getLookAndFeelDefaults()
{
- return currentUIDefaults;
+ return lookAndFeelDefaults;
}
/**
@@ -587,13 +657,7 @@ public class UIManager implements Serializable
*/
public static ComponentUI getUI(JComponent target)
{
- ComponentUI ui = null;
- if (userUIDefaults != null
- && userUIDefaults.get(target.getUIClassID()) != null)
- ui = userUIDefaults.getUI(target);
- if (ui == null)
- ui = currentUIDefaults.getUI(target);
- return ui;
+ return getDefaults().getUI(target);
}
/**
@@ -625,11 +689,7 @@ public class UIManager implements Serializable
*/
public static Object put(Object key, Object value)
{
- Object old = get(key);
- if (userUIDefaults == null)
- userUIDefaults = new UIDefaults();
- userUIDefaults.put(key, value);
- return old;
+ return getDefaults().put(key, value);
}
/**
@@ -654,7 +714,8 @@ public class UIManager implements Serializable
throws UnsupportedLookAndFeelException
{
if (newLookAndFeel != null && ! newLookAndFeel.isSupportedLookAndFeel())
- throw new UnsupportedLookAndFeelException(newLookAndFeel.getName());
+ throw new UnsupportedLookAndFeelException(newLookAndFeel.getName()
+ + " not supported on this platform");
LookAndFeel oldLookAndFeel = currentLookAndFeel;
if (oldLookAndFeel != null)
oldLookAndFeel.uninitialize();
@@ -664,7 +725,12 @@ public class UIManager implements Serializable
if (newLookAndFeel != null)
{
newLookAndFeel.initialize();
- currentUIDefaults = newLookAndFeel.getDefaults();
+ lookAndFeelDefaults = newLookAndFeel.getDefaults();
+ if (currentUIDefaults == null)
+ currentUIDefaults =
+ new MultiplexUIDefaults(lookAndFeelDefaults);
+ else
+ currentUIDefaults.fallback = lookAndFeelDefaults;
}
else
{
@@ -689,7 +755,8 @@ public class UIManager implements Serializable
throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException
{
- Class c = Class.forName(className);
+ Class c = Class.forName(className, true,
+ Thread.currentThread().getContextClassLoader());
LookAndFeel a = (LookAndFeel) c.newInstance(); // throws class-cast-exception
setLookAndFeel(a);
}
diff --git a/libjava/classpath/javax/swing/border/TitledBorder.java b/libjava/classpath/javax/swing/border/TitledBorder.java
index 56146e01d1b..38ccd720f16 100644
--- a/libjava/classpath/javax/swing/border/TitledBorder.java
+++ b/libjava/classpath/javax/swing/border/TitledBorder.java
@@ -1,5 +1,5 @@
/* TitledBorder.java --
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -961,7 +961,8 @@ public class TitledBorder extends AbstractBorder
public void setTitlePosition(int titlePosition)
{
if ((titlePosition < DEFAULT_POSITION) || (titlePosition > BELOW_BOTTOM))
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(titlePosition
+ + " is not a valid title position.");
// Swing borders are not JavaBeans, thus no need to fire an event.
this.titlePosition = titlePosition;
@@ -982,7 +983,8 @@ public class TitledBorder extends AbstractBorder
{
if ((titleJustification < DEFAULT_JUSTIFICATION)
|| (titleJustification > TRAILING))
- throw new IllegalArgumentException();
+ throw new IllegalArgumentException(titleJustification
+ + " is not a valid title justification.");
// Swing borders are not JavaBeans, thus no need to fire an event.
this.titleJustification = titleJustification;
diff --git a/libjava/classpath/javax/swing/event/EventListenerList.java b/libjava/classpath/javax/swing/event/EventListenerList.java
index 6a2f34ebb3d..bde8b3c7e4f 100644
--- a/libjava/classpath/javax/swing/event/EventListenerList.java
+++ b/libjava/classpath/javax/swing/event/EventListenerList.java
@@ -108,7 +108,7 @@ public class EventListenerList
* An array with all currently registered listeners. The array has
* twice as many elements as there are listeners. For an even
* integer <code>i</code>, <code>listenerList[i]</code> indicates
- * the registered class, and <code>listenerList[i+1]</code> is the
+ * the registered class, and <code>listenerList[i + 1]</code> is the
* listener.
*/
protected transient Object[] listenerList = NO_LISTENERS;
diff --git a/libjava/classpath/javax/swing/event/ListDataEvent.java b/libjava/classpath/javax/swing/event/ListDataEvent.java
index 2a6e6dbe9f0..897fc128f20 100644
--- a/libjava/classpath/javax/swing/event/ListDataEvent.java
+++ b/libjava/classpath/javax/swing/event/ListDataEvent.java
@@ -1,5 +1,5 @@
/* ListDataEvent.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -41,6 +41,9 @@ package javax.swing.event;
import java.util.EventObject;
/**
+ * An event that contains information about a modification to the content of
+ * a list.
+ *
* @author Andrew Selkirk
* @author Ronald Veldema
*/
@@ -48,32 +51,46 @@ public class ListDataEvent extends EventObject
{
private static final long serialVersionUID = 2510353260071004774L;
+ /** An event type indicating that the list content has been modified. */
public static final int CONTENTS_CHANGED = 0;
+
+ /** An event type indicating that an interval has been added to the list. */
public static final int INTERVAL_ADDED = 1;
+
+ /**
+ * An event type indicating that an interval has been removed from the
+ * list.
+ */
public static final int INTERVAL_REMOVED = 2;
- private int type = 0;
- private int index0 = 0;
- private int index1 = 0;
+ private int type;
+ private int index0;
+ private int index1;
/**
* Creates a <code>ListDataEvent</code> object.
*
- * @param source The source of the event.
- * @param type The type of the event
- * @param index0 Bottom of range
- * @param index1 Top of range
+ * @param source the source of the event (<code>null</code> not permitted).
+ * @param type the type of the event (should be one of
+ * {@link #CONTENTS_CHANGED}, {@link #INTERVAL_ADDED} or
+ * {@link #INTERVAL_REMOVED}, although this is not enforced).
+ * @param index0 the index for one end of the modified range of list
+ * elements.
+ * @param index1 the index for the other end of the modified range of list
+ * elements.
*/
public ListDataEvent(Object source, int type, int index0, int index1)
{
super(source);
this.type = type;
- this.index0 = index0;
- this.index1 = index1;
+ this.index0 = Math.min(index0, index1);
+ this.index1 = Math.max(index0, index1);
}
/**
- * Returns the bottom index.
+ * Returns the index of the first item in the range of modified list items.
+ *
+ * @return The index of the first item in the range of modified list items.
*/
public int getIndex0()
{
@@ -81,7 +98,9 @@ public class ListDataEvent extends EventObject
}
/**
- * Returns the top index.
+ * Returns the index of the last item in the range of modified list items.
+ *
+ * @return The index of the last item in the range of modified list items.
*/
public int getIndex1()
{
@@ -89,10 +108,25 @@ public class ListDataEvent extends EventObject
}
/**
- * Returns the type of this event.
+ * Returns a code representing the type of this event, which is usually one
+ * of {@link #CONTENTS_CHANGED}, {@link #INTERVAL_ADDED} or
+ * {@link #INTERVAL_REMOVED}.
+ *
+ * @return The event type.
*/
public int getType()
{
return type;
}
+
+ /**
+ * Returns a string representing the state of this event.
+ *
+ * @return A string.
+ */
+ public String toString()
+ {
+ return getClass().getName() + "[type=" + type + ",index0=" + index0
+ + ",index1=" + index1 + "]";
+ }
}
diff --git a/libjava/classpath/javax/swing/event/MenuEvent.java b/libjava/classpath/javax/swing/event/MenuEvent.java
index 35bb5b97b43..8ba32929e2d 100644
--- a/libjava/classpath/javax/swing/event/MenuEvent.java
+++ b/libjava/classpath/javax/swing/event/MenuEvent.java
@@ -1,5 +1,5 @@
/* MenuEvent.java --
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,7 +37,6 @@ exception statement from your version. */
package javax.swing.event;
-// Imports
import java.util.EventObject;
/**
@@ -45,15 +44,16 @@ import java.util.EventObject;
* @author Andrew Selkirk
* @author Ronald Veldema
*/
-public class MenuEvent extends EventObject {
-
- /**
- * Constructor MenuEvent
- * @param source Source object
- */
- public MenuEvent(Object source) {
- super(source);
- } // MenuEvent()
-
-
-} // MenuEvent
+public class MenuEvent extends EventObject
+{
+
+ /**
+ * Constructor MenuEvent
+ * @param source Source object
+ */
+ public MenuEvent(Object source)
+ {
+ super(source);
+ }
+
+}
diff --git a/libjava/classpath/javax/swing/event/TreeExpansionListener.java b/libjava/classpath/javax/swing/event/TreeExpansionListener.java
index 08507a0ffe9..45a5ef93c6d 100644
--- a/libjava/classpath/javax/swing/event/TreeExpansionListener.java
+++ b/libjava/classpath/javax/swing/event/TreeExpansionListener.java
@@ -37,26 +37,26 @@ exception statement from your version. */
package javax.swing.event;
-// Imports
import java.util.EventListener;
/**
* TreeExpansionListener public interface
* @author Andrew Selkirk
*/
-public interface TreeExpansionListener extends EventListener {
+public interface TreeExpansionListener extends EventListener
+{
- /**
- * Tree collapsed
- * @param event Tree Expansion Event
- */
- void treeCollapsed(TreeExpansionEvent event);
+ /**
+ * Tree collapsed
+ * @param event Tree Expansion Event
+ */
+ void treeCollapsed(TreeExpansionEvent event);
- /**
- * Tree expanded
- * @param event Tree Expansion Event
- */
- void treeExpanded(TreeExpansionEvent event);
+ /**
+ * Tree expanded
+ * @param event Tree Expansion Event
+ */
+ void treeExpanded(TreeExpansionEvent event);
-} // TreeExpansionListener
+}
diff --git a/libjava/classpath/javax/swing/filechooser/FileSystemView.java b/libjava/classpath/javax/swing/filechooser/FileSystemView.java
index f51b745c892..84b80dd402c 100644
--- a/libjava/classpath/javax/swing/filechooser/FileSystemView.java
+++ b/libjava/classpath/javax/swing/filechooser/FileSystemView.java
@@ -76,7 +76,10 @@ public abstract class FileSystemView
*/
public File createFileObject(String path)
{
- return new File(path);
+ File f = new File(path);
+ if (isFileSystemRoot(f))
+ f = this.createFileSystemRoot(f);
+ return f;
}
/**
@@ -223,16 +226,24 @@ public abstract class FileSystemView
/**
* Returns the name of a file as it would be displayed by the underlying
- * system. This implementation returns <code>null</code>, subclasses must
- * override.
+ * system.
*
* @param f the file.
*
- * @return <code>null</code>.
+ * @return the name of a file as it would be displayed by the underlying
+ * system
+ *
+ * @specnote The specification suggests that the information here is
+ * fetched from a ShellFolder class. This seems to be a non public
+ * private file handling class. We simply return File.getName()
+ * here and leave special handling to subclasses.
*/
public String getSystemDisplayName(File f)
{
- return null;
+ String name = null;
+ if (f != null)
+ name = f.getName();
+ return name;
}
/**
diff --git a/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java b/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java
index 96dfd2e1b1a..f8d71e1df33 100644
--- a/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java
+++ b/libjava/classpath/javax/swing/filechooser/UnixFileSystemView.java
@@ -106,17 +106,34 @@ class UnixFileSystemView extends FileSystemView
/**
* Returns the name of a file as it would be displayed by the underlying
- * system. This method is NOT YET IMPLEMENTED.
+ * system.
*
* @param f the file.
*
- * @return <code>null</code>.
+ * @return the name of a file as it would be displayed by the underlying
+ * system
*/
public String getSystemDisplayName(File f)
- throws NotImplementedException
{
- // FIXME: Implement;
- return null;
+ String name = null;
+ if (f != null)
+ {
+ if (isRoot(f))
+ name = f.getAbsolutePath();
+ else
+ {
+ try
+ {
+ String path = f.getCanonicalPath();
+ name = path.substring(path.lastIndexOf(File.separator) + 1);
+ }
+ catch (IOException e)
+ {
+ name = f.getName();
+ }
+ }
+ }
+ return name;
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/IconUIResource.java b/libjava/classpath/javax/swing/plaf/IconUIResource.java
index 659c8e7bab7..8ac9e0875ae 100644
--- a/libjava/classpath/javax/swing/plaf/IconUIResource.java
+++ b/libjava/classpath/javax/swing/plaf/IconUIResource.java
@@ -1,5 +1,5 @@
/* IconUIResource.java --
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -63,7 +63,8 @@ public class IconUIResource implements Icon, UIResource, Serializable
/**
- * The icon that is wrapped by this <code>IconUIResource</code>.
+ * The icon that is wrapped by this <code>IconUIResource</code> (never
+ * <code>null</code>).
*/
private Icon delegate;
@@ -73,10 +74,12 @@ public class IconUIResource implements Icon, UIResource, Serializable
* icon. All messages are forwarded to the delegate icon.
*
* @param delegate the icon that is wrapped by this
- * <code>IconUIResource</code>.
+ * <code>IconUIResource</code> (<code>null</code> not permitted).
*/
public IconUIResource(Icon delegate)
{
+ if (delegate == null)
+ throw new IllegalArgumentException("Null 'delegate' argument.");
this.delegate = delegate;
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java
index f796d9a730a..781269b2adf 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicArrowButton.java
@@ -1,5 +1,5 @@
/* BasicArrowButton.java --
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -42,7 +42,6 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Polygon;
-import java.awt.Rectangle;
import javax.swing.ButtonModel;
import javax.swing.JButton;
@@ -86,7 +85,9 @@ public class BasicArrowButton extends JButton implements SwingConstants
transient Color highlight = Color.WHITE;
/**
- * Creates a new <code>BasicArrowButton</code> object.
+ * Creates a new <code>BasicArrowButton</code> object with an arrow pointing
+ * in the specified direction. If the <code>direction</code> is not one of
+ * the specified constants, no arrow is drawn.
*
* @param direction The direction the arrow points in (one of:
* {@link #NORTH}, {@link #SOUTH}, {@link #EAST} and {@link #WEST}).
@@ -95,6 +96,7 @@ public class BasicArrowButton extends JButton implements SwingConstants
{
super();
setDirection(direction);
+ setFocusable(false);
}
/**
@@ -116,8 +118,7 @@ public class BasicArrowButton extends JButton implements SwingConstants
this.shadow = shadow;
this.darkShadow = darkShadow;
this.highlight = highlight;
- // Mark the button as not closing the popup, we handle this ourselves.
- putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP, Boolean.TRUE);
+ setFocusable(false);
}
/**
@@ -162,28 +163,22 @@ public class BasicArrowButton extends JButton implements SwingConstants
public void paint(Graphics g)
{
super.paint(g);
- Rectangle bounds = getBounds();
- int size = bounds.height / 4;
- int x = bounds.x + (bounds.width - size) / 2;
- int y = (bounds.height - size) / 4;
+
+ int height = getHeight();
+ int size = height / 4;
+
+ int x = (getWidth() - size) / 2;
+ int y = (height - size) / 2;
+
ButtonModel m = getModel();
if (m.isArmed())
{
x++;
y++;
}
+
paintTriangle(g, x, y, size, direction, isEnabled());
}
-
- /** The preferred size for the button. */
- private static final Dimension PREFERRED_SIZE = new Dimension(16, 16);
-
- /** The minimum size for the button. */
- private static final Dimension MINIMUM_SIZE = new Dimension(5, 5);
-
- /** The maximum size for the button. */
- private static final Dimension MAXIMUM_SIZE
- = new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
/**
* Returns the preferred size of the arrow button.
@@ -192,7 +187,10 @@ public class BasicArrowButton extends JButton implements SwingConstants
*/
public Dimension getPreferredSize()
{
- return PREFERRED_SIZE;
+ // since Dimension is NOT immutable, we must return a new instance
+ // every time (if we return a cached value, the caller might modify it)
+ // - tests show that the reference implementation does the same.
+ return new Dimension(16, 16);
}
/**
@@ -202,17 +200,23 @@ public class BasicArrowButton extends JButton implements SwingConstants
*/
public Dimension getMinimumSize()
{
- return MINIMUM_SIZE;
+ // since Dimension is NOT immutable, we must return a new instance
+ // every time (if we return a cached value, the caller might modify it)
+ // - tests show that the reference implementation does the same.
+ return new Dimension(5, 5);
}
/**
* Returns the maximum size of the arrow button.
*
- * @return The maximum size.
+ * @return The maximum size (always Integer.MAX_VALUE x Integer.MAX_VALUE).
*/
public Dimension getMaximumSize()
{
- return MAXIMUM_SIZE;
+ // since Dimension is NOT immutable, we must return a new instance
+ // every time (if we return a cached value, the caller might modify it)
+ // - tests show that the reference implementation does the same.
+ return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java
index 89e99a29a31..84895821518 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonListener.java
@@ -38,13 +38,17 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
-import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
@@ -66,7 +70,23 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
public void propertyChange(PropertyChangeEvent e)
{
- // TODO: What should be done here, if anything?
+ // Store the TextLayout for this in a client property for speed-up
+ // painting of the label.
+ String property = e.getPropertyName();
+ if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
+ || property.equals("font"))
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
+ == null)
+ {
+ AbstractButton b = (AbstractButton) e.getSource();
+ String text = b.getText();
+ if (text == null)
+ text = "";
+ FontRenderContext frc = new FontRenderContext(new AffineTransform(),
+ false, false);
+ TextLayout layout = new TextLayout(text, b.getFont(), frc);
+ b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
+ }
}
protected void checkOpacity(AbstractButton b)
@@ -160,11 +180,14 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
{
AbstractButton button = (AbstractButton) e.getSource();
ButtonModel model = button.getModel();
- if (e.getButton() == MouseEvent.BUTTON1)
+ if (SwingUtilities.isLeftMouseButton(e))
{
// It is important that these transitions happen in this order.
model.setArmed(true);
model.setPressed(true);
+
+ if (! button.isFocusOwner() && button.isRequestFocusEnabled())
+ button.requestFocus();
}
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java
index 0a537c4bdd8..d531133ba26 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicButtonUI.java
@@ -442,13 +442,17 @@ public class BasicButtonUI extends ButtonUI
if (b.isEnabled())
{
g.setColor(b.getForeground());
- g.drawString(text, textRect.x, textRect.y + fm.getAscent());
+ // FIXME: Underline mnemonic.
+ BasicGraphicsUtils.drawString(b, g, text, -1, textRect.x,
+ textRect.y + fm.getAscent());
}
else
{
String prefix = getPropertyPrefix();
g.setColor(UIManager.getColor(prefix + "disabledText"));
- g.drawString(text, textRect.x, textRect.y + fm.getAscent());
+ // FIXME: Underline mnemonic.
+ BasicGraphicsUtils.drawString(b, g, text, -1, textRect.x,
+ textRect.y + fm.getAscent());
}
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java
index 2cb1623cbc2..d98fd2afe38 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -62,6 +60,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
import javax.swing.CellRendererPane;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
@@ -241,6 +240,8 @@ public class BasicComboBoxUI extends ComboBoxUI
comboBox.setLayout(createLayoutManager());
comboBox.setFocusable(true);
installKeyboardActions();
+ comboBox.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
+ Boolean.TRUE);
}
}
@@ -288,7 +289,7 @@ public class BasicComboBoxUI extends ComboBoxUI
comboBox.addPropertyChangeListener(propertyChangeListener);
focusListener = createFocusListener();
- editor.addFocusListener(focusListener);
+ comboBox.addFocusListener(focusListener);
itemListener = createItemListener();
comboBox.addItemListener(itemListener);
@@ -542,7 +543,9 @@ public class BasicComboBoxUI extends ComboBoxUI
{
editor.setFont(comboBox.getFont());
if (popupKeyListener != null)
- editor.addKeyListener(popupKeyListener);
+ editor.addKeyListener(popupKeyListener);
+ if (keyListener != null)
+ editor.addKeyListener(keyListener);
comboBox.configureEditor(comboBox.getEditor(),
comboBox.getSelectedItem());
}
@@ -554,6 +557,8 @@ public class BasicComboBoxUI extends ComboBoxUI
{
if (popupKeyListener != null)
editor.removeKeyListener(popupKeyListener);
+ if (keyListener != null)
+ editor.removeKeyListener(keyListener);
}
/**
@@ -571,6 +576,10 @@ public class BasicComboBoxUI extends ComboBoxUI
arrowButton.addMouseListener(popupMouseListener);
if (popupMouseMotionListener != null)
arrowButton.addMouseMotionListener(popupMouseMotionListener);
+
+ // Mark the button as not closing the popup, we handle this ourselves.
+ arrowButton.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
+ Boolean.TRUE);
}
}
@@ -712,18 +721,51 @@ public class BasicComboBoxUI extends ComboBoxUI
return new Dimension(32767, 32767);
}
+ /**
+ * Returns the number of accessible children of the combobox.
+ *
+ * @param c the component (combobox) to check, ignored
+ *
+ * @return the number of accessible children of the combobox
+ */
public int getAccessibleChildrenCount(JComponent c)
- throws NotImplementedException
{
- // FIXME: Need to implement
- return 0;
+ int count = 1;
+ if (comboBox.isEditable())
+ count = 2;
+ return count;
}
+ /**
+ * Returns the accessible child with the specified index.
+ *
+ * @param c the component, this is ignored
+ * @param i the index of the accessible child to return
+ */
public Accessible getAccessibleChild(JComponent c, int i)
- throws NotImplementedException
{
- // FIXME: Need to implement
- return null;
+ Accessible child = null;
+ switch (i)
+ {
+ case 0: // The popup.
+ if (popup instanceof Accessible)
+ {
+ AccessibleContext ctx = ((Accessible) popup).getAccessibleContext();
+ ctx.setAccessibleParent(comboBox);
+ child = (Accessible) popup;
+ }
+ break;
+ case 1: // The editor, if any.
+ if (comboBox.isEditable() && editor instanceof Accessible)
+ {
+ AccessibleContext ctx =
+ ((Accessible) editor).getAccessibleContext();
+ ctx.setAccessibleParent(comboBox);
+ child = (Accessible) editor;
+ }
+ break;
+ }
+ return child;
}
/**
@@ -735,10 +777,11 @@ public class BasicComboBoxUI extends ComboBoxUI
* @return true if the specified key is a navigation key and false otherwis
*/
protected boolean isNavigationKey(int keyCode)
- throws NotImplementedException
{
- // FIXME: Need to implement
- return false;
+ return keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN
+ || keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT
+ || keyCode == KeyEvent.VK_ENTER || keyCode == KeyEvent.VK_ESCAPE
+ || keyCode == KeyEvent.VK_TAB;
}
/**
@@ -759,7 +802,7 @@ public class BasicComboBoxUI extends ComboBoxUI
protected void selectPreviousPossibleValue()
{
int index = comboBox.getSelectedIndex();
- if (index != 0)
+ if (index > 0)
comboBox.setSelectedIndex(index - 1);
}
@@ -1163,10 +1206,31 @@ public class BasicComboBoxUI extends ComboBoxUI
* Invoked whenever key is pressed while JComboBox is in focus.
*/
public void keyPressed(KeyEvent e)
- throws NotImplementedException
{
- // FIXME: This method calls JComboBox.selectWithKeyChar if the key that
- // was pressed is not a navigation key.
+ if (comboBox.getModel().getSize() != 0 && comboBox.isEnabled())
+ {
+ if (! isNavigationKey(e.getKeyCode()))
+ {
+ if (! comboBox.isEditable())
+ if (comboBox.selectWithKeyChar(e.getKeyChar()))
+ e.consume();
+ }
+ else
+ {
+ if (e.getKeyCode() == KeyEvent.VK_UP && comboBox.isPopupVisible())
+ selectPreviousPossibleValue();
+ else if (e.getKeyCode() == KeyEvent.VK_DOWN)
+ {
+ if (comboBox.isPopupVisible())
+ selectNextPossibleValue();
+ else
+ comboBox.showPopup();
+ }
+ else if (e.getKeyCode() == KeyEvent.VK_ENTER
+ || e.getKeyCode() == KeyEvent.VK_ESCAPE)
+ popup.hide();
+ }
+ }
}
}
@@ -1330,5 +1394,4 @@ public class BasicComboBoxUI extends ComboBoxUI
// FIXME: Need to handle changes in other bound properties.
}
}
-
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java
index ef7a880c2ac..ed916cb5f1a 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicDirectoryModel.java
@@ -1,5 +1,5 @@
/* BasicDirectoryModel.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -40,35 +40,296 @@ package javax.swing.plaf.basic;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
import java.util.Vector;
import javax.swing.AbstractListModel;
import javax.swing.JFileChooser;
+import javax.swing.SwingUtilities;
import javax.swing.event.ListDataEvent;
import javax.swing.filechooser.FileSystemView;
/**
- * DOCUMENT ME!
+ * Implements an AbstractListModel for directories where the source
+ * of the files is a JFileChooser object.
+ *
+ * This class is used for sorting and ordering the file list in
+ * a JFileChooser L&F object.
*/
public class BasicDirectoryModel extends AbstractListModel
implements PropertyChangeListener
{
- /** DOCUMENT ME! */
+ /** The list of files itself */
private Vector contents;
- /** DOCUMENT ME! */
- private int directories;
+ /**
+ * The directories in the list.
+ */
+ private Vector directories;
+
+ /**
+ * The files in the list.
+ */
+ private Vector files;
- /** DOCUMENT ME! */
+ /** The listing mode of the associated JFileChooser,
+ either FILES_ONLY, DIRECTORIES_ONLY or FILES_AND_DIRECTORIES */
private int listingMode;
- /** DOCUMENT ME! */
+ /** The JFileCooser associated with this model */
private JFileChooser filechooser;
- /** DOCUMENT ME! */
+ /**
+ * The thread that loads the file view.
+ */
+ private DirectoryLoadThread loadThread;
+
+ /**
+ * This thread is responsible for loading file lists from the
+ * current directory and updating the model.
+ */
+ private class DirectoryLoadThread extends Thread
+ {
+
+ /**
+ * Updates the Swing list model.
+ */
+ private class UpdateSwingRequest
+ implements Runnable
+ {
+
+ private List added;
+ private int addIndex;
+ private List removed;
+ private int removeIndex;
+ private boolean cancel;
+
+ UpdateSwingRequest(List add, int ai, List rem, int ri)
+ {
+ added = add;
+ addIndex = ai;
+ removed = rem;
+ removeIndex = ri;
+ cancel = false;
+ }
+
+ public void run()
+ {
+ if (! cancel)
+ {
+ int numRemoved = removed == null ? 0 : removed.size();
+ int numAdded = added == null ? 0 : added.size();
+ synchronized (contents)
+ {
+ if (numRemoved > 0)
+ contents.removeAll(removed);
+ if (numAdded > 0)
+ contents.addAll(added);
+
+ files = null;
+ directories = null;
+ }
+ if (numRemoved > 0 && numAdded == 0)
+ fireIntervalRemoved(BasicDirectoryModel.this, removeIndex,
+ removeIndex + numRemoved - 1);
+ else if (numRemoved == 0 && numAdded > 0)
+ fireIntervalAdded(BasicDirectoryModel.this, addIndex,
+ addIndex + numAdded - 1);
+ else
+ fireContentsChanged();
+ }
+ }
+
+ void cancel()
+ {
+ cancel = true;
+ }
+ }
+
+ /**
+ * The directory beeing loaded.
+ */
+ File directory;
+
+ /**
+ * Stores all UpdateSwingRequests that are sent to the event queue.
+ */
+ private UpdateSwingRequest pending;
+
+ /**
+ * Creates a new DirectoryLoadThread that loads the specified
+ * directory.
+ *
+ * @param dir the directory to load
+ */
+ DirectoryLoadThread(File dir)
+ {
+ super("Basic L&F directory loader");
+ directory = dir;
+ }
+
+ public void run()
+ {
+ FileSystemView fsv = filechooser.getFileSystemView();
+ File[] files = fsv.getFiles(directory,
+ filechooser.isFileHidingEnabled());
+
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ // Check list for accepted files.
+ Vector accepted = new Vector();
+ for (int i = 0; i < files.length; i++)
+ {
+ if (filechooser.accept(files[i]))
+ accepted.add(files[i]);
+ }
+
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ // Sort list.
+ sort(accepted);
+
+ // Now split up directories from files so that we get the directories
+ // listed before the files.
+ Vector newFiles = new Vector();
+ Vector newDirectories = new Vector();
+ for (Iterator i = accepted.iterator(); i.hasNext();)
+ {
+ File f = (File) i.next();
+ boolean traversable = filechooser.isTraversable(f);
+ if (traversable)
+ newDirectories.add(f);
+ else if (! traversable && filechooser.isFileSelectionEnabled())
+ newFiles.add(f);
+
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ }
+
+ // Build up new file cache. Try to update only the changed elements.
+ // This will be important for actions like adding new files or
+ // directories inside a large file list.
+ Vector newCache = new Vector(newDirectories);
+ newCache.addAll(newFiles);
+
+ int newSize = newCache.size();
+ int oldSize = contents.size();
+ if (newSize < oldSize)
+ {
+ // Check for removed interval.
+ int start = -1;
+ int end = -1;
+ boolean found = false;
+ for (int i = 0; i < newSize && !found; i++)
+ {
+ if (! newCache.get(i).equals(contents.get(i)))
+ {
+ start = i;
+ end = i + oldSize - newSize;
+ found = true;
+ }
+ }
+ if (start >= 0 && end > start
+ && contents.subList(end, oldSize)
+ .equals(newCache.subList(start, newSize)))
+ {
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ Vector removed = new Vector(contents.subList(start, end));
+ UpdateSwingRequest r = new UpdateSwingRequest(null, 0,
+ removed, start);
+ invokeLater(r);
+ newCache = null;
+ }
+ }
+ else if (newSize > oldSize)
+ {
+ // Check for inserted interval.
+ int start = oldSize;
+ int end = newSize;
+ boolean found = false;
+ for (int i = 0; i < oldSize && ! found; i++)
+ {
+ if (! newCache.get(i).equals(contents.get(i)))
+ {
+ start = i;
+ boolean foundEnd = false;
+ for (int j = i; j < newSize && ! foundEnd; j++)
+ {
+ if (newCache.get(j).equals(contents.get(i)))
+ {
+ end = j;
+ foundEnd = true;
+ }
+ }
+ end = i + oldSize - newSize;
+ }
+ }
+ if (start >= 0 && end > start
+ && newCache.subList(end, newSize)
+ .equals(contents.subList(start, oldSize)))
+ {
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+
+ List added = newCache.subList(start, end);
+ UpdateSwingRequest r = new UpdateSwingRequest(added, start,
+ null, 0);
+ invokeLater(r);
+ newCache = null;
+ }
+ }
+
+ // Handle complete list changes (newCache != null).
+ if (newCache != null && ! contents.equals(newCache))
+ {
+ // Occasional check if we have been interrupted.
+ if (isInterrupted())
+ return;
+ UpdateSwingRequest r = new UpdateSwingRequest(newCache, 0,
+ contents, 0);
+ invokeLater(r);
+ }
+ }
+
+ /**
+ * Wraps SwingUtilities.invokeLater() and stores the request in
+ * a Vector so that we can still cancel it later.
+ *
+ * @param update the request to invoke
+ */
+ private void invokeLater(UpdateSwingRequest update)
+ {
+ pending = update;
+ SwingUtilities.invokeLater(update);
+ }
+
+ /**
+ * Cancels all pending update requests that might be in the AWT
+ * event queue.
+ */
+ void cancelPending()
+ {
+ if (pending != null)
+ pending.cancel();
+ }
+ }
+
+ /** A Comparator class/object for sorting the file list. */
private Comparator comparator = new Comparator()
{
public int compare(Object o1, Object o2)
@@ -91,14 +352,15 @@ public class BasicDirectoryModel extends AbstractListModel
filechooser.addPropertyChangeListener(this);
listingMode = filechooser.getFileSelectionMode();
contents = new Vector();
+ validateFileCache();
}
/**
- * DOCUMENT ME!
+ * Returns whether a given (File) object is included in the list.
*
- * @param o DOCUMENT ME!
+ * @param o - The file object to test.
*
- * @return DOCUMENT ME!
+ * @return <code>true</code> if the list contains the given object.
*/
public boolean contains(Object o)
{
@@ -106,7 +368,7 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Fires a content change event.
*/
public void fireContentsChanged()
{
@@ -114,80 +376,99 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Returns a Vector of (java.io.File) objects containing
+ * the directories in this list.
*
- * @return DOCUMENT ME!
+ * @return a Vector
*/
public Vector getDirectories()
{
- Vector tmp = new Vector();
- for (int i = 0; i < directories; i++)
- tmp.add(contents.get(i));
- return tmp;
+ // Synchronize this with the UpdateSwingRequest for the case when
+ // contents is modified.
+ synchronized (contents)
+ {
+ Vector dirs = directories;
+ if (dirs == null)
+ {
+ // Initializes this in getFiles().
+ getFiles();
+ dirs = directories;
+ }
+ return dirs;
+ }
}
/**
- * DOCUMENT ME!
+ * Returns the (java.io.File) object at
+ * an index in the list.
*
- * @param index DOCUMENT ME!
- *
- * @return DOCUMENT ME!
+ * @param index The list index
+ * @return a File object
*/
public Object getElementAt(int index)
{
if (index > getSize() - 1)
return null;
- if (listingMode == JFileChooser.FILES_ONLY)
- return contents.get(directories + index);
- else
- return contents.elementAt(index);
+ return contents.elementAt(index);
}
/**
- * DOCUMENT ME!
+ * Returns a Vector of (java.io.File) objects containing
+ * the files in this list.
*
- * @return DOCUMENT ME!
+ * @return a Vector
*/
public Vector getFiles()
{
- Vector tmp = new Vector();
- for (int i = directories; i < getSize(); i++)
- tmp.add(contents.get(i));
- return tmp;
+ synchronized (contents)
+ {
+ Vector f = files;
+ if (f == null)
+ {
+ f = new Vector();
+ Vector d = new Vector(); // Directories;
+ for (Iterator i = contents.iterator(); i.hasNext();)
+ {
+ File file = (File) i.next();
+ if (filechooser.isTraversable(file))
+ d.add(file);
+ else
+ f.add(file);
+ }
+ files = f;
+ directories = d;
+ }
+ return f;
+ }
}
/**
- * DOCUMENT ME!
+ * Returns the size of the list, which only includes directories
+ * if the JFileChooser is set to DIRECTORIES_ONLY.
+ *
+ * Otherwise, both directories and files are included in the count.
*
- * @return DOCUMENT ME!
+ * @return The size of the list.
*/
public int getSize()
{
- if (listingMode == JFileChooser.DIRECTORIES_ONLY)
- return directories;
- else if (listingMode == JFileChooser.FILES_ONLY)
- return contents.size() - directories;
return contents.size();
}
/**
- * DOCUMENT ME!
+ * Returns the index of an (java.io.File) object in the list.
*
- * @param o DOCUMENT ME!
+ * @param o The object - normally a File.
*
- * @return DOCUMENT ME!
+ * @return the index of that object, or -1 if it is not in the list.
*/
public int indexOf(Object o)
{
- if (listingMode == JFileChooser.FILES_ONLY)
- return contents.indexOf(o) - directories;
return contents.indexOf(o);
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Obsoleted method which does nothing.
*/
public void intervalAdded(ListDataEvent e)
{
@@ -195,9 +476,7 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Obsoleted method which does nothing.
*/
public void intervalRemoved(ListDataEvent e)
{
@@ -205,7 +484,7 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Obsoleted method which does nothing.
*/
public void invalidateFileCache()
{
@@ -213,12 +492,16 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Less than, determine the relative order in the list of two files
+ * for sorting purposes.
+ *
+ * The order is: directories < files, and thereafter alphabetically,
+ * using the default locale collation.
*
- * @param a DOCUMENT ME!
- * @param b DOCUMENT ME!
+ * @param a the first file
+ * @param b the second file
*
- * @return DOCUMENT ME!
+ * @return <code>true</code> if a > b, <code>false</code> if a < b.
*/
protected boolean lt(File a, File b)
{
@@ -241,73 +524,66 @@ public class BasicDirectoryModel extends AbstractListModel
}
/**
- * DOCUMENT ME!
+ * Listens for a property change; the change in file selection mode of the
+ * associated JFileChooser. Reloads the file cache on that event.
*
- * @param e DOCUMENT ME!
+ * @param e - A PropertyChangeEvent.
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getPropertyName().equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY))
- listingMode = filechooser.getFileSelectionMode();
+ String property = e.getPropertyName();
+ if (property.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)
+ || property.equals(JFileChooser.FILE_VIEW_CHANGED_PROPERTY)
+ )
+ {
+ validateFileCache();
+ }
}
/**
- * DOCUMENT ME!
+ * Renames a file - However, does <I>not</I> re-sort the list
+ * or replace the old file with the new one in the list.
*
- * @param oldFile DOCUMENT ME!
- * @param newFile DOCUMENT ME!
+ * @param oldFile The old file
+ * @param newFile The new file name
*
- * @return DOCUMENT ME!
+ * @return <code>true</code> if the rename succeeded
*/
public boolean renameFile(File oldFile, File newFile)
{
- // FIXME: implement
- return false;
+ return oldFile.renameTo( newFile );
}
/**
- * DOCUMENT ME!
+ * Sorts a Vector of File objects.
*
- * @param v DOCUMENT ME!
+ * @param v The Vector to sort.
*/
protected void sort(Vector v)
{
Collections.sort(v, comparator);
- Enumeration e = Collections.enumeration(v);
- Vector tmp = new Vector();
- for (; e.hasMoreElements();)
- tmp.add(e.nextElement());
-
- contents = tmp;
}
/**
- * DOCUMENT ME!
+ * Re-loads the list of files
*/
public void validateFileCache()
{
- contents.clear();
- directories = 0;
- FileSystemView fsv = filechooser.getFileSystemView();
- File[] list = fsv.getFiles(filechooser.getCurrentDirectory(),
- filechooser.isFileHidingEnabled());
-
- if (list == null)
- return;
-
- for (int i = 0; i < list.length; i++)
+ File dir = filechooser.getCurrentDirectory();
+ if (dir != null)
{
- if (list[i] == null)
- continue;
- if (filechooser.accept(list[i]))
- {
- contents.add(list[i]);
- if (filechooser.isTraversable(list[i]))
- directories++;
- }
+ // Cancel all pending requests.
+ if (loadThread != null)
+ {
+ loadThread.interrupt();
+ loadThread.cancelPending();
+ }
+ loadThread = new DirectoryLoadThread(dir);
+ loadThread.start();
}
- sort(contents);
- filechooser.revalidate();
- filechooser.repaint();
}
}
+
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java
index 1356db4aeec..dc1c051225c 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java
@@ -160,6 +160,8 @@ public class BasicFileChooserUI extends FileChooserUI
else
{
File f = new File(filechooser.getCurrentDirectory(), getFileName());
+ if ( selectedDir != null )
+ f = selectedDir;
if (filechooser.isTraversable(f))
{
filechooser.setCurrentDirectory(f);
@@ -266,7 +268,14 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public String getName(File f)
{
- return f.getName();
+ String name = null;
+ if (f != null)
+ {
+ JFileChooser c = getFileChooser();
+ FileSystemView v = c.getFileSystemView();
+ name = v.getSystemDisplayName(f);
+ }
+ return name;
}
/**
@@ -409,7 +418,7 @@ public class BasicFileChooserUI extends FileChooserUI
closeDialog();
}
}
- else
+ else // single click
{
String path = p.toString();
File f = fsv.createFileObject(path);
@@ -436,10 +445,11 @@ public class BasicFileChooserUI extends FileChooserUI
}
lastSelected = path;
parentPath = path.substring(0, path.lastIndexOf("/") + 1);
+
if (f.isFile())
setFileName(path.substring(path.lastIndexOf("/") + 1));
- else if (filechooser.getFileSelectionMode() ==
- JFileChooser.DIRECTORIES_ONLY)
+ else if (filechooser.getFileSelectionMode() !=
+ JFileChooser.FILES_ONLY)
setFileName(path);
}
}
@@ -538,7 +548,7 @@ public class BasicFileChooserUI extends FileChooserUI
}
/**
- * DOCUMENT ME!
+ * Sets the JFileChooser to the selected file on an update
*
* @param e DOCUMENT ME!
*/
@@ -550,9 +560,15 @@ public class BasicFileChooserUI extends FileChooserUI
return;
File file = filechooser.getFileSystemView().createFileObject(f.toString());
if (! filechooser.isTraversable(file))
- filechooser.setSelectedFile(file);
+ {
+ selectedDir = null;
+ filechooser.setSelectedFile(file);
+ }
else
- filechooser.setSelectedFile(null);
+ {
+ selectedDir = file;
+ filechooser.setSelectedFile(null);
+ }
}
}
@@ -752,6 +768,13 @@ public class BasicFileChooserUI extends FileChooserUI
* @see #getUpdateAction()
*/
private UpdateAction updateAction;
+
+ /**
+ * When in FILES_ONLY, mode a directory cannot be selected, so
+ * we save a reference to any it here. This is used to enter
+ * the directory on "Open" when in that mode.
+ */
+ private File selectedDir;
// -- end private --
@@ -874,7 +897,9 @@ public class BasicFileChooserUI extends FileChooserUI
protected void installListeners(JFileChooser fc)
{
propertyChangeListener = createPropertyChangeListener(filechooser);
- filechooser.addPropertyChangeListener(propertyChangeListener);
+ if (propertyChangeListener != null)
+ filechooser.addPropertyChangeListener(propertyChangeListener);
+ fc.addPropertyChangeListener(getModel());
}
/**
@@ -884,8 +909,12 @@ public class BasicFileChooserUI extends FileChooserUI
*/
protected void uninstallListeners(JFileChooser fc)
{
- filechooser.removePropertyChangeListener(propertyChangeListener);
- propertyChangeListener = null;
+ if (propertyChangeListener != null)
+ {
+ filechooser.removePropertyChangeListener(propertyChangeListener);
+ propertyChangeListener = null;
+ }
+ fc.removePropertyChangeListener(getModel());
}
/**
@@ -1046,12 +1075,8 @@ public class BasicFileChooserUI extends FileChooserUI
*/
public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
{
- return new PropertyChangeListener()
- {
- public void propertyChange(PropertyChangeEvent e)
- {
- }
- };
+ // The RI returns null here, so do we.
+ return null;
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
index 068de345bec..1e84be93282 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicGraphicsUtils.java
@@ -37,6 +37,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
@@ -65,6 +67,14 @@ import javax.swing.SwingUtilities;
public class BasicGraphicsUtils
{
/**
+ * Used as a key for a client property to store cached TextLayouts in. This
+ * is used for speed-up drawing of text in
+ * {@link #drawString(Graphics, String, int, int, int)}.
+ */
+ static final String CACHED_TEXT_LAYOUT =
+ "BasicGraphicsUtils.cachedTextLayout";
+
+ /**
* Constructor. It is utterly unclear why this class should
* be constructable, but this is what the API specification
* says.
@@ -536,6 +546,170 @@ public class BasicGraphicsUtils
g2.fill(underline);
}
+ /**
+ * Draws a string on the specified component.
+ *
+ * @param c the component
+ * @param g the Graphics context
+ * @param text the string
+ * @param underlinedChar the character to be underlined
+ * @param x the X location
+ * @param y the Y location
+ */
+ static void drawString(JComponent c, Graphics g, String text,
+ int underlinedChar, int x, int y)
+ {
+ int index = -1;
+
+ /* It is intentional that lower case is used. In some languages,
+ * the set of lowercase characters is larger than the set of
+ * uppercase ones. Therefore, it is good practice to use lowercase
+ * for such comparisons (which really means that the author of this
+ * code can vaguely remember having read some Unicode techreport
+ * with this recommendation, but is too lazy to look for the URL).
+ */
+ if ((underlinedChar >= 0) || (underlinedChar <= 0xffff))
+ index = text.toLowerCase().indexOf(
+ Character.toLowerCase((char) underlinedChar));
+
+ drawStringUnderlineCharAt(c, g, text, index, x, y);
+ }
+
+
+ /**
+ * Draws a String at the given location, underlining the character
+ * at the specified index. Drawing is performed in the current color
+ * and font of <code>g</code>.
+ *
+ * <p><img src="doc-files/BasicGraphicsUtils-5.png" width="500"
+ * height="100" alt="[An illustration showing how to use the
+ * method]" />
+ *
+ * This is an accelerated version of the method with the same name. It
+ * uses a pre-laid out TextLayout stored in a client property.
+ *
+ * @param c the component that is drawn
+ * @param g the graphics into which the String is drawn.
+ *
+ * @param text the String to draw.
+ *
+ * @param underlinedIndex the index of the underlined character in
+ * <code>text</code>. If <code>underlinedIndex</code> falls
+ * outside the range <code>[0, text.length() - 1]</code>, the
+ * text will be drawn without underlining anything.
+ *
+ * @param x the x coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ *
+ * @param y the y coordinate of the text, as it would be passed to
+ * {@link java.awt.Graphics#drawString(java.lang.String,
+ * int, int)}.
+ */
+ static void drawStringUnderlineCharAt(JComponent c, Graphics g, String text,
+ int underlinedIndex,
+ int x, int y)
+ {
+ Graphics2D g2;
+ Rectangle2D.Double underline;
+ FontRenderContext frc;
+ FontMetrics fmet;
+ LineMetrics lineMetrics;
+ Font font;
+ TextLayout layout;
+ double underlineX1, underlineX2;
+ boolean drawUnderline;
+ int textLength;
+
+ textLength = text.length();
+ if (textLength == 0)
+ return;
+
+ drawUnderline = (underlinedIndex >= 0) && (underlinedIndex < textLength);
+
+ // FIXME: unfortunately pango and cairo can't agree on metrics
+ // so for the time being we continue to *not* use TextLayouts.
+ if (!(g instanceof Graphics2D)
+ || SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") != null)
+ {
+ /* Fall-back. This is likely to produce garbage for any text
+ * containing right-to-left (Hebrew or Arabic) characters, even
+ * if the underlined character is left-to-right.
+ */
+ g.drawString(text, x, y);
+ if (drawUnderline)
+ {
+ fmet = g.getFontMetrics();
+ g.fillRect(
+ /* x */ x + fmet.stringWidth(text.substring(0, underlinedIndex)),
+ /* y */ y + fmet.getDescent() - 1,
+ /* width */ fmet.charWidth(text.charAt(underlinedIndex)),
+ /* height */ 1);
+ }
+
+ return;
+ }
+
+ g2 = (Graphics2D) g;
+ font = g2.getFont();
+ frc = g2.getFontRenderContext();
+ lineMetrics = font.getLineMetrics(text, frc);
+ layout = (TextLayout) c.getClientProperty(CACHED_TEXT_LAYOUT);
+ if (layout == null)
+ {
+ layout = new TextLayout(text, font, frc);
+ System.err.println("Unable to use cached TextLayout for: " + text);
+ }
+
+ /* Draw the text. */
+ layout.draw(g2, x, y);
+ if (!drawUnderline)
+ return;
+
+ underlineX1 = x + layout.getLogicalHighlightShape(
+ underlinedIndex, underlinedIndex).getBounds2D().getX();
+ underlineX2 = x + layout.getLogicalHighlightShape(
+ underlinedIndex + 1, underlinedIndex + 1).getBounds2D().getX();
+
+ underline = new Rectangle2D.Double();
+ if (underlineX1 < underlineX2)
+ {
+ underline.x = underlineX1;
+ underline.width = underlineX2 - underlineX1;
+ }
+ else
+ {
+ underline.x = underlineX2;
+ underline.width = underlineX1 - underlineX2;
+ }
+
+
+ underline.height = lineMetrics.getUnderlineThickness();
+ underline.y = lineMetrics.getUnderlineOffset();
+ if (underline.y == 0)
+ {
+ /* Some fonts do not specify an underline offset, although they
+ * actually should do so. In that case, the result of calling
+ * lineMetrics.getUnderlineOffset() will be zero. Since it would
+ * look very ugly if the underline was be positioned immediately
+ * below the baseline, we check for this and move the underline
+ * below the descent, as shown in the following ASCII picture:
+ *
+ * ##### ##### #
+ * # # # #
+ * # # # #
+ * # # # #
+ * ##### ###### ---- baseline (0)
+ * #
+ * #
+ * ------------------###----------- lineMetrics.getDescent()
+ */
+ underline.y = lineMetrics.getDescent();
+ }
+
+ underline.y += y;
+ g2.fill(underline);
+ }
/**
* Draws a rectangle, simulating a dotted stroke by painting only
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
index 23bcdc315ee..8f2181336cb 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java
@@ -38,7 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -692,17 +691,12 @@ public class BasicInternalFrameUI extends InternalFrameUI
/** The MouseEvent target. */
private transient Component mouseEventTarget;
- /** The component pressed. */
- private transient Component pressedComponent;
+ private Component dragTarget;
- /** The last component entered. */
- private transient Component lastComponentEntered;
-
- /** Used to store/reset lastComponentEntered. */
- private transient Component tempComponent;
-
- /** The number of presses. */
- private transient int pressCount;
+ /**
+ * Indicates if we are currently in a dragging operation or not.
+ */
+ private boolean isDragging;
/**
* This method is called when the mouse enters the glass pane.
@@ -767,7 +761,10 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
public void mousePressed(MouseEvent e)
{
- activateFrame(frame);
+ // Experiments show that this seems to call the
+ // borderListener.mousePressed() method to activate the frame.
+ if (borderListener != null)
+ borderListener.mousePressed(e);
handleEvent(e);
}
@@ -783,149 +780,104 @@ public class BasicInternalFrameUI extends InternalFrameUI
}
/**
- * This method acquires a candidate component to dispatch the MouseEvent to.
+ * This is a helper method that dispatches the GlassPane MouseEvents to the
+ * proper component.
*
- * @param me
- * The MouseEvent to acquire a component for.
+ * @param e the mouse event to be dispatched
*/
- private void acquireComponentForMouseEvent(MouseEvent me)
+ private void handleEvent(MouseEvent e)
{
- int x = me.getX();
- int y = me.getY();
-
- // Find the candidate which should receive this event.
- Component parent = frame.getLayeredPane();
- if (parent == null)
- return;
- Component candidate = null;
- Point p = me.getPoint();
- while (candidate == null && parent != null)
- {
- candidate = SwingUtilities.getDeepestComponentAt(parent, p.x, p.y);
- if (candidate == null)
- {
- p = SwingUtilities.convertPoint(parent, p.x, p.y,
- parent.getParent());
- parent = parent.getParent();
- }
- }
-
- // If the only candidate we found was the native container itself,
- // don't dispatch any event at all. We only care about the lightweight
- // children here.
- if (candidate == frame.getContentPane())
- candidate = null;
-
- // If our candidate is new, inform the old target we're leaving.
- if (lastComponentEntered != null && lastComponentEntered.isShowing()
- && lastComponentEntered != candidate)
+ // Find candidate component inside the JInternalFrame.
+ Component target = frame.getLayeredPane().findComponentAt(e.getX(),
+ e.getY());
+
+ // Now search upwards to find a component that actually has
+ // a MouseListener attached.
+ while (target != null
+ && target.getMouseListeners().length == 0
+ && target.getMouseMotionListeners().length == 0
+ && target.getMouseWheelListeners().length == 0)
{
- Point tp = SwingUtilities.convertPoint(frame.getContentPane(), x, y,
- lastComponentEntered);
- MouseEvent exited = new MouseEvent(lastComponentEntered,
- MouseEvent.MOUSE_EXITED,
- me.getWhen(), me.getModifiersEx(),
- tp.x, tp.y, me.getClickCount(),
- me.isPopupTrigger(),
- me.getButton());
- tempComponent = lastComponentEntered;
- lastComponentEntered = null;
- tempComponent.dispatchEvent(exited);
+ target = target.getParent();
}
- // If we have a candidate, maybe enter it.
- if (candidate != null)
+ if (target != null)
{
- mouseEventTarget = candidate;
- if (candidate.isLightweight() && candidate.isShowing()
- && candidate != frame.getContentPane()
- && candidate != lastComponentEntered)
- {
- lastComponentEntered = mouseEventTarget;
- Point cp = SwingUtilities.convertPoint(frame.getContentPane(), x,
- y, lastComponentEntered);
- MouseEvent entered = new MouseEvent(lastComponentEntered,
- MouseEvent.MOUSE_ENTERED,
- me.getWhen(),
- me.getModifiersEx(), cp.x,
- cp.y, me.getClickCount(),
- me.isPopupTrigger(),
- me.getButton());
- lastComponentEntered.dispatchEvent(entered);
- }
- }
-
- if (me.getID() == MouseEvent.MOUSE_RELEASED
- || me.getID() == MouseEvent.MOUSE_PRESSED && pressCount > 0
- || me.getID() == MouseEvent.MOUSE_DRAGGED)
- // If any of the following events occur while a button is held down,
- // they should be dispatched to the same component to which the
- // original MOUSE_PRESSED event was dispatched:
- // - MOUSE_RELEASED
- // - MOUSE_PRESSED: another button pressed while the first is held down
- // - MOUSE_DRAGGED
- mouseEventTarget = pressedComponent;
- else if (me.getID() == MouseEvent.MOUSE_CLICKED)
- {
- // Don't dispatch CLICKED events whose target is not the same as the
- // target for the original PRESSED event.
- if (candidate != pressedComponent)
- mouseEventTarget = null;
- else if (pressCount == 0)
- pressedComponent = null;
+ int id = e.getID();
+ switch (id)
+ {
+ case MouseEvent.MOUSE_ENTERED:
+ // Now redispatch the thing.
+ if (! isDragging || frame.isSelected())
+ {
+ mouseEventTarget = target;
+ redispatch(id, e, mouseEventTarget);
+ }
+ break;
+ case MouseEvent.MOUSE_EXITED:
+ if (! isDragging || frame.isSelected())
+ {
+ redispatch(id, e, mouseEventTarget);
+ }
+ break;
+ case MouseEvent.MOUSE_PRESSED:
+ mouseEventTarget = target;
+ redispatch(id, e, mouseEventTarget);
+ // Start dragging.
+ dragTarget = target;
+ break;
+ case MouseEvent.MOUSE_RELEASED:
+ if (isDragging)
+ {
+ redispatch(id, e, dragTarget);
+ isDragging = false;
+ }
+ else
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_CLICKED:
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_MOVED:
+ if (target != mouseEventTarget)
+ {
+ // Create additional MOUSE_EXITED/MOUSE_ENTERED pairs.
+ redispatch(MouseEvent.MOUSE_EXITED, e, mouseEventTarget);
+ mouseEventTarget = target;
+ redispatch(MouseEvent.MOUSE_ENTERED, e, mouseEventTarget);
+ }
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_DRAGGED:
+ if (! isDragging)
+ isDragging = true;
+ redispatch(id, e, mouseEventTarget);
+ break;
+ case MouseEvent.MOUSE_WHEEL:
+ redispatch(id, e, mouseEventTarget);
+ break;
+ default:
+ assert false : "Must not reach here";
+ }
}
}
/**
- * This is a helper method that dispatches the GlassPane MouseEvents to the
- * proper component.
- *
- * @param e
- * The AWTEvent to be dispatched. Usually an instance of
- * MouseEvent.
+ * Redispatches the event to the real target with the specified id.
+ *
+ * @param id the new event ID
+ * @param e the original event
+ * @param target the real event target
*/
- private void handleEvent(AWTEvent e)
+ private void redispatch(int id, MouseEvent e, Component target)
{
- if (e instanceof MouseEvent)
- {
- MouseEvent me = (MouseEvent) e;
- acquireComponentForMouseEvent(me);
-
- //If there is no target, return
- if (mouseEventTarget == null)
- return;
-
- //Avoid re-dispatching to ourselves and causing an infinite loop
- if (mouseEventTarget.equals(frame.getGlassPane()))
- return;
-
- // Avoid dispatching ENTERED and EXITED events twice.
- if (mouseEventTarget.isShowing()
- && e.getID() != MouseEvent.MOUSE_ENTERED
- && e.getID() != MouseEvent.MOUSE_EXITED)
- {
- MouseEvent newEvt = SwingUtilities.convertMouseEvent(
- frame.getGlassPane(),
- me,
- mouseEventTarget);
- mouseEventTarget.dispatchEvent(newEvt);
-
- switch (e.getID())
- {
- case MouseEvent.MOUSE_PRESSED:
- if (pressCount++ == 0)
- pressedComponent = mouseEventTarget;
- break;
- case MouseEvent.MOUSE_RELEASED:
- // Clear our memory of the original PRESSED event, only if
- // we're not expecting a CLICKED event after this. If
- // there is a CLICKED event after this, it will do clean up.
- if (--pressCount == 0 && mouseEventTarget != pressedComponent)
- pressedComponent = null;
- break;
- }
- }
- }
+ Point p = SwingUtilities.convertPoint(frame.getLayeredPane(), e.getX(),
+ e.getY(), target);
+ MouseEvent ev = new MouseEvent(target, id, e.getWhen(),
+ e.getModifiers() | e.getModifiersEx(),
+ p.x, p.y, e.getClickCount(),
+ e.isPopupTrigger());
+ target.dispatchEvent(ev);
}
}
@@ -945,41 +897,61 @@ public class BasicInternalFrameUI extends InternalFrameUI
*/
public void propertyChange(PropertyChangeEvent evt)
{
- if (evt.getPropertyName().equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
+ String property = evt.getPropertyName();
+ if (property.equals(JInternalFrame.IS_MAXIMUM_PROPERTY))
{
if (frame.isMaximum())
maximizeFrame(frame);
else
minimizeFrame(frame);
}
- else if (evt.getPropertyName().equals(JInternalFrame.IS_ICON_PROPERTY))
+ else if (property.equals(JInternalFrame.IS_ICON_PROPERTY))
{
if (frame.isIcon())
iconifyFrame(frame);
else
deiconifyFrame(frame);
}
- else if (evt.getPropertyName().equals(JInternalFrame.IS_SELECTED_PROPERTY))
+ else if (property.equals(JInternalFrame.IS_SELECTED_PROPERTY))
{
+ Component glassPane = frame.getGlassPane();
if (frame.isSelected())
- activateFrame(frame);
+ {
+ activateFrame(frame);
+ glassPane.setVisible(false);
+ }
else
- deactivateFrame(frame);
+ {
+ deactivateFrame(frame);
+ glassPane.setVisible(true);
+ }
}
- else if (evt.getPropertyName().equals(JInternalFrame.ROOT_PANE_PROPERTY)
- || evt.getPropertyName().equals(
- JInternalFrame.GLASS_PANE_PROPERTY))
+ else if (property.equals(JInternalFrame.ROOT_PANE_PROPERTY)
+ || property.equals(JInternalFrame.GLASS_PANE_PROPERTY))
{
Component old = (Component) evt.getOldValue();
- old.removeMouseListener(glassPaneDispatcher);
- old.removeMouseMotionListener(glassPaneDispatcher);
+ if (old != null)
+ {
+ old.removeMouseListener(glassPaneDispatcher);
+ old.removeMouseMotionListener(glassPaneDispatcher);
+ }
Component newPane = (Component) evt.getNewValue();
- newPane.addMouseListener(glassPaneDispatcher);
- newPane.addMouseMotionListener(glassPaneDispatcher);
+ if (newPane != null)
+ {
+ newPane.addMouseListener(glassPaneDispatcher);
+ newPane.addMouseMotionListener(glassPaneDispatcher);
+ }
frame.revalidate();
}
+ else if (property.equals(JInternalFrame.IS_CLOSED_PROPERTY))
+ {
+ if (evt.getNewValue() == Boolean.TRUE)
+ {
+ closeFrame(frame);
+ }
+ }
/*
* FIXME: need to add ancestor properties to JComponents. else if
* (evt.getPropertyName().equals(JComponent.ANCESTOR_PROPERTY)) { if
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
index 60e3a98684f..304e13ad735 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java
@@ -1,5 +1,5 @@
/* BasicLabelUI.java
- Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -37,20 +37,25 @@
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
+import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
import javax.swing.Icon;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JLabel;
+import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
@@ -369,14 +374,39 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
}
/**
- * This method installs the keyboard actions for the given {@link JLabel}.
+ * Installs the keyboard actions for the given {@link JLabel}.
*
* @param l The {@link JLabel} to install keyboard actions for.
*/
protected void installKeyboardActions(JLabel l)
- throws NotImplementedException
{
- //FIXME: implement.
+ Component c = l.getLabelFor();
+ if (c != null)
+ {
+ int mnemonic = l.getDisplayedMnemonic();
+ if (mnemonic > 0)
+ {
+ // add a keystroke for the given mnemonic mapping to 'press';
+ InputMap keyMap = new InputMap();
+ keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.VK_ALT),
+ "press");
+ SwingUtilities.replaceUIInputMap(l,
+ JComponent.WHEN_IN_FOCUSED_WINDOW, keyMap);
+
+ // add an action to focus the component when 'press' happens
+ ActionMap map = new ActionMap();
+ map.put("press", new AbstractAction() {
+ public void actionPerformed(ActionEvent event)
+ {
+ JLabel label = (JLabel) event.getSource();
+ Component c = label.getLabelFor();
+ if (c != null)
+ c.requestFocus();
+ }
+ });
+ SwingUtilities.replaceUIActionMap(l, map);
+ }
+ }
}
/**
@@ -385,9 +415,10 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
* @param l The {@link JLabel} to uninstall keyboard actions for.
*/
protected void uninstallKeyboardActions(JLabel l)
- throws NotImplementedException
{
- //FIXME: implement.
+ SwingUtilities.replaceUIActionMap(l, null);
+ SwingUtilities.replaceUIInputMap(l, JComponent.WHEN_IN_FOCUSED_WINDOW,
+ null);
}
/**
@@ -426,5 +457,30 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener
JLabel l = (JLabel) e.getSource();
BasicHTML.updateRenderer(l, text);
}
+ else if (e.getPropertyName().equals("displayedMnemonic"))
+ {
+ // update the key to action mapping
+ JLabel label = (JLabel) e.getSource();
+ if (label.getLabelFor() != null)
+ {
+ int oldMnemonic = ((Integer) e.getOldValue()).intValue();
+ int newMnemonic = ((Integer) e.getNewValue()).intValue();
+ InputMap keyMap = label.getInputMap(
+ JComponent.WHEN_IN_FOCUSED_WINDOW);
+ keyMap.put(KeyStroke.getKeyStroke(oldMnemonic,
+ KeyEvent.ALT_DOWN_MASK), null);
+ keyMap.put(KeyStroke.getKeyStroke(newMnemonic,
+ KeyEvent.ALT_DOWN_MASK), "press");
+ }
+ }
+ else if (e.getPropertyName().equals("labelFor"))
+ {
+ JLabel label = (JLabel) e.getSource();
+ InputMap keyMap = label.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ int mnemonic = label.getDisplayedMnemonic();
+ if (mnemonic > 0)
+ keyMap.put(KeyStroke.getKeyStroke(mnemonic, KeyEvent.ALT_DOWN_MASK),
+ "press");
+ }
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
index 44f6a408984..493fc0578e3 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -61,12 +59,12 @@ import javax.swing.DefaultListSelectionModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JList;
-import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.event.ListDataEvent;
@@ -76,8 +74,8 @@ import javax.swing.event.ListSelectionListener;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
-import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.ListUI;
+import javax.swing.plaf.UIResource;
/**
* The Basic Look and Feel UI delegate for the
@@ -215,9 +213,26 @@ public class BasicListUI extends ListUI
target.actionPerformed(derivedEvent);
}
}
-
- class ListAction extends AbstractAction
+
+ /**
+ * Implements the action for the JList's keyboard commands.
+ */
+ private class ListAction
+ extends AbstractAction
{
+ // TODO: Maybe make a couple of classes out of this bulk Action.
+ // Form logical groups of Actions when doing this.
+
+ /**
+ * Creates a new ListAction for the specified command.
+ *
+ * @param cmd the actionCommand to set
+ */
+ ListAction(String cmd)
+ {
+ putValue(ACTION_COMMAND_KEY, cmd);
+ }
+
public void actionPerformed(ActionEvent e)
{
int lead = list.getLeadSelectionIndex();
@@ -398,7 +413,7 @@ public class BasicListUI extends ListUI
list.ensureIndexIsVisible(list.getLeadSelectionIndex());
}
}
-
+
/**
* A helper class which listens for {@link MouseEvent}s
* from the {@link JList}.
@@ -464,7 +479,8 @@ public class BasicListUI extends ListUI
*/
public void mousePressed(MouseEvent event)
{
- // TODO: What should be done here, if anything?
+ // We need to explicitly request focus.
+ list.requestFocusInWindow();
}
/**
@@ -992,39 +1008,83 @@ public class BasicListUI extends ListUI
*/
protected void installKeyboardActions()
{
+ // Install UI InputMap.
InputMap focusInputMap = (InputMap) UIManager.get("List.focusInputMap");
- InputMapUIResource parentInputMap = new InputMapUIResource();
- // FIXME: The JDK uses a LazyActionMap for parentActionMap
- ActionMap parentActionMap = new ActionMapUIResource();
- action = new ListAction();
- Object keys[] = focusInputMap.allKeys();
- // Register key bindings in the UI InputMap-ActionMap pair
- for (int i = 0; i < keys.length; i++)
+ SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED,
+ focusInputMap);
+
+ // Install UI ActionMap.
+ ActionMap am = (ActionMap) UIManager.get("List.actionMap");
+ if (am == null)
{
- KeyStroke stroke = (KeyStroke) keys[i];
- String actionString = (String) focusInputMap.get(stroke);
- parentInputMap.put(KeyStroke.getKeyStroke(stroke.getKeyCode(),
- stroke.getModifiers()),
- actionString);
-
- parentActionMap.put(actionString,
- new ActionListenerProxy(action, actionString));
+ // Create the actionMap once and store it in the current UIDefaults
+ // for use in other components.
+ am = new ActionMapUIResource();
+ ListAction action;
+ action = new ListAction("selectPreviousRow");
+ am.put("selectPreviousRow", action);
+ action = new ListAction("selectNextRow");
+ am.put("selectNextRow", action);
+ action = new ListAction("selectPreviousRowExtendSelection");
+ am.put("selectPreviousRowExtendSelection", action);
+ action = new ListAction("selectNextRowExtendSelection");
+ am.put("selectNextRowExtendSelection", action);
+
+ action = new ListAction("selectPreviousColumn");
+ am.put("selectPreviousColumn", action);
+ action = new ListAction("selectNextColumn");
+ am.put("selectNextColumn", action);
+ action = new ListAction("selectPreviousColumnExtendSelection");
+ am.put("selectPreviousColumnExtendSelection", action);
+ action = new ListAction("selectNextColumnExtendSelection");
+ am.put("selectNextColumnExtendSelection", action);
+
+ action = new ListAction("selectFirstRow");
+ am.put("selectFirstRow", action);
+ action = new ListAction("selectLastRow");
+ am.put("selectLastRow", action);
+ action = new ListAction("selectFirstRowExtendSelection");
+ am.put("selectFirstRowExtendSelection", action);
+ action = new ListAction("selectLastRowExtendSelection");
+ am.put("selectLastRowExtendSelection", action);
+
+ action = new ListAction("scrollUp");
+ am.put("scrollUp", action);
+ action = new ListAction("scrollUpExtendSelection");
+ am.put("scrollUpExtendSelection", action);
+ action = new ListAction("scrollDown");
+ am.put("scrollDown", action);
+ action = new ListAction("scrollDownExtendSelection");
+ am.put("scrollDownExtendSelection", action);
+
+ action = new ListAction("selectAll");
+ am.put("selectAll", action);
+ action = new ListAction("clearSelection");
+ am.put("clearSelection", action);
+
+ am.put("copy", TransferHandler.getCopyAction());
+ am.put("cut", TransferHandler.getCutAction());
+ am.put("paste", TransferHandler.getPasteAction());
+
+ UIManager.put("List.actionMap", am);
}
- // Register the new InputMap-ActionMap as the parents of the list's
- // InputMap and ActionMap
- parentInputMap.setParent(list.getInputMap().getParent());
- parentActionMap.setParent(list.getActionMap().getParent());
- list.getInputMap().setParent(parentInputMap);
- list.getActionMap().setParent(parentActionMap);
+
+ SwingUtilities.replaceUIActionMap(list, am);
}
/**
* Uninstalls keyboard actions for this UI in the {@link JList}.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // TODO: Implement this properly.
+ // Uninstall the InputMap.
+ InputMap im = SwingUtilities.getUIInputMap(list, JComponent.WHEN_FOCUSED);
+ if (im instanceof UIResource)
+ SwingUtilities.replaceUIInputMap(list, JComponent.WHEN_FOCUSED, null);
+
+ // Uninstall the ActionMap.
+ if (SwingUtilities.getUIActionMap(list) instanceof UIResource)
+ SwingUtilities.replaceUIActionMap(list, null);
}
/**
@@ -1151,7 +1211,7 @@ public class BasicListUI extends ListUI
boolean hasFocus = (list.getLeadSelectionIndex() == row) && BasicListUI.this.list.hasFocus();
Component comp = rend.getListCellRendererComponent(list,
data.getElementAt(row),
- 0, isSel, hasFocus);
+ row, isSel, hasFocus);
rendererPane.paintComponent(g, comp, list, bounds);
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
index 0f6e0243fcf..c056a2403f9 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java
@@ -64,6 +64,7 @@ import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
+import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.LookAndFeel;
import javax.swing.MenuSelectionManager;
@@ -129,7 +130,9 @@ public abstract class BasicLookAndFeel extends LookAndFeel
if (target instanceof Container)
target = ((Container) target).findComponentAt(ev.getPoint());
if (m.getSelectedPath().length > 0
- && ! m.isComponentPartOfCurrentMenu(target))
+ && ! m.isComponentPartOfCurrentMenu(target)
+ && (((JComponent)target).getClientProperty(DONT_CANCEL_POPUP) == null
+ || !((JComponent)target).getClientProperty(DONT_CANCEL_POPUP).equals(Boolean.TRUE)))
{
m.clearSelectedPath();
}
@@ -1028,6 +1031,25 @@ public abstract class BasicLookAndFeel extends LookAndFeel
"PopupMenu.border", new BorderUIResource.BevelBorderUIResource(0),
"PopupMenu.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"PopupMenu.foreground", new ColorUIResource(darkShadow),
+ "PopupMenu.selectedWindowInputMapBindings",
+ new Object[] {"ESCAPE", "cancel",
+ "DOWN", "selectNext",
+ "KP_DOWN", "selectNext",
+ "UP", "selectPrevious",
+ "KP_UP", "selectPrevious",
+ "LEFT", "selectParent",
+ "KP_LEFT", "selectParent",
+ "RIGHT", "selectChild",
+ "KP_RIGHT", "selectChild",
+ "ENTER", "return",
+ "SPACE", "return"
+ },
+ "PopupMenu.selectedWindowInputMapBindings.RightToLeft",
+ new Object[] {"LEFT", "selectChild",
+ "KP_LEFT", "selectChild",
+ "RIGHT", "selectParent",
+ "KP_RIGHT", "selectParent",
+ },
"ProgressBar.background", new ColorUIResource(Color.LIGHT_GRAY),
"ProgressBar.border",
new BorderUIResource.LineBorderUIResource(Color.GREEN, 2),
@@ -1607,7 +1629,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel
}),
"Tree.font", new FontUIResource("Dialog", Font.PLAIN, 12),
"Tree.foreground", new ColorUIResource(Color.black),
- "Tree.hash", new ColorUIResource(new Color(128, 128, 128)),
+ "Tree.hash", new ColorUIResource(new Color(184, 207, 228)),
"Tree.leftChildIndent", new Integer(7),
"Tree.rightChildIndent", new Integer(13),
"Tree.rowHeight", new Integer(16),
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java
index f258ebe3069..cd25a3baf77 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuBarUI.java
@@ -38,24 +38,31 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Dimension;
+import java.awt.event.ActionEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BoxLayout;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
+import javax.swing.MenuSelectionManager;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.MenuBarUI;
@@ -64,6 +71,47 @@ import javax.swing.plaf.MenuBarUI;
*/
public class BasicMenuBarUI extends MenuBarUI
{
+
+ /**
+ * This action is performed for the action command 'takeFocus'.
+ */
+ private static class FocusAction
+ extends AbstractAction
+ {
+
+ /**
+ * Creates a new FocusAction.
+ */
+ FocusAction()
+ {
+ super("takeFocus");
+ }
+
+ /**
+ * Performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ // In the JDK this action seems to pop up the first menu of the
+ // menu bar.
+ JMenuBar menuBar = (JMenuBar) event.getSource();
+ MenuSelectionManager defaultManager =
+ MenuSelectionManager.defaultManager();
+ MenuElement me[];
+ MenuElement subElements[];
+ JMenu menu = menuBar.getMenu(0);
+ if (menu != null)
+ {
+ me = new MenuElement[3];
+ me[0] = (MenuElement) menuBar;
+ me[1] = (MenuElement) menu;
+ me[2] = (MenuElement) menu.getPopupMenu();
+ defaultManager.setSelectedPath(me);
+ }
+ }
+
+ }
+
protected ChangeListener changeListener;
/*ContainerListener that listens to the ContainerEvents fired from menu bar*/
@@ -178,9 +226,46 @@ public class BasicMenuBarUI extends MenuBarUI
* This method installs the keyboard actions for the JMenuBar.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement
+ // Install InputMap.
+ Object[] bindings =
+ (Object[]) SharedUIDefaults.get("MenuBar.windowBindings");
+ InputMap inputMap = LookAndFeel.makeComponentInputMap(menuBar, bindings);
+ SwingUtilities.replaceUIInputMap(menuBar,
+ JComponent.WHEN_IN_FOCUSED_WINDOW,
+ inputMap);
+
+ // Install ActionMap.
+ SwingUtilities.replaceUIActionMap(menuBar, getActionMap());
+ }
+
+ /**
+ * Creates and returns the shared action map for JTrees.
+ *
+ * @return the shared action map for JTrees
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("MenuBar.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("MenuBar.actionMap", am);
+ }
+ return am;
+ }
+
+ /**
+ * Creates the default actions when there are none specified by the L&F.
+ *
+ * @return the default actions
+ */
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new FocusAction();
+ am.put(action.getValue(Action.NAME), action);
+ return am;
}
/**
@@ -226,9 +311,10 @@ public class BasicMenuBarUI extends MenuBarUI
* This method reverses the work done in installKeyboardActions.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ SwingUtilities.replaceUIInputMap(menuBar,
+ JComponent.WHEN_IN_FOCUSED_WINDOW, null);
+ SwingUtilities.replaceUIActionMap(menuBar, null);
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
index 63a09bff6a2..bbc08535cdc 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import gnu.classpath.SystemProperties;
+
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -52,11 +54,15 @@ import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
import javax.swing.ActionMap;
import javax.swing.ButtonModel;
import javax.swing.Icon;
@@ -237,7 +243,8 @@ public class BasicMenuItemUI extends MenuItemUI
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getPropertyName() == "accelerator")
+ String property = e.getPropertyName();
+ if (property.equals("accelerator"))
{
InputMap map = SwingUtilities.getUIInputMap(menuItem,
JComponent.WHEN_IN_FOCUSED_WINDOW);
@@ -250,6 +257,22 @@ public class BasicMenuItemUI extends MenuItemUI
if (accelerator != null)
map.put(accelerator, "doClick");
}
+ // TextLayout caching for speed-up drawing of text.
+ else if ((property.equals(AbstractButton.TEXT_CHANGED_PROPERTY)
+ || property.equals("font"))
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D")
+ == null)
+
+ {
+ AbstractButton b = (AbstractButton) e.getSource();
+ String text = b.getText();
+ if (text == null)
+ text = "";
+ FontRenderContext frc = new FontRenderContext(new AffineTransform(),
+ false, false);
+ TextLayout layout = new TextLayout(text, b.getFont(), frc);
+ b.putClientProperty(BasicGraphicsUtils.CACHED_TEXT_LAYOUT, layout);
+ }
}
}
@@ -833,12 +856,13 @@ public class BasicMenuItemUI extends MenuItemUI
int mnemonicIndex = menuItem.getDisplayedMnemonicIndex();
if (mnemonicIndex != -1)
- BasicGraphicsUtils.drawStringUnderlineCharAt(g, text, mnemonicIndex,
+ BasicGraphicsUtils.drawStringUnderlineCharAt(menuItem, g, text,
+ mnemonicIndex,
textRect.x,
textRect.y
+ fm.getAscent());
else
- BasicGraphicsUtils.drawString(g, text, 0, textRect.x,
+ BasicGraphicsUtils.drawString(menuItem, g, text, 0, textRect.x,
textRect.y + fm.getAscent());
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java
index f8936be5b66..7d8784fd15a 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuUI.java
@@ -220,9 +220,8 @@ public class BasicMenuUI extends BasicMenuItemUI
*
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ super.installKeyboardActions();
}
/**
@@ -230,13 +229,12 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
protected void installListeners()
{
- ((JMenu) menuItem).addMouseListener(mouseInputListener);
- ((JMenu) menuItem).addMouseMotionListener(mouseInputListener);
+ super.installListeners();
((JMenu) menuItem).addMenuListener(menuListener);
- ((JMenu) menuItem).addMenuDragMouseListener(menuDragMouseListener);
}
protected void setupPostTimer(JMenu menu)
+ throws NotImplementedException
{
// TODO: Implement this properly.
}
@@ -265,9 +263,8 @@ public class BasicMenuUI extends BasicMenuItemUI
* Basic look and feel's defaults.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ super.installKeyboardActions();
}
/**
@@ -276,9 +273,8 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
protected void uninstallListeners()
{
- ((JMenu) menuItem).removeMouseListener(mouseInputListener);
+ super.uninstallListeners();
((JMenu) menuItem).removeMenuListener(menuListener);
- ((JMenu) menuItem).removePropertyChangeListener(propertyChangeListener);
}
/**
@@ -351,7 +347,7 @@ public class BasicMenuUI extends BasicMenuItemUI
public void mouseMoved(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
public void mousePressed(MouseEvent e)
@@ -472,7 +468,8 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public ChangeHandler(JMenu m, BasicMenuUI ui)
{
- // Not used.
+ menu = m;
+ this.ui = ui;
}
/**
@@ -520,7 +517,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuDragMouseExited(MenuDragMouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -531,7 +528,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuDragMouseReleased(MenuDragMouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
}
@@ -548,7 +545,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuKeyPressed(MenuKeyEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -558,7 +555,7 @@ public class BasicMenuUI extends BasicMenuItemUI
*/
public void menuKeyReleased(MenuKeyEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -568,6 +565,7 @@ public class BasicMenuUI extends BasicMenuItemUI
* @param e A {@link MenuKeyEvent}.
*/
public void menuKeyTyped(MenuKeyEvent e)
+ throws NotImplementedException
{
// TODO: What should be done here, if anything?
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
index 9acf8210d9e..e2380858098 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicOptionPaneUI.java
@@ -38,13 +38,12 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
+import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
@@ -58,10 +57,14 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.Icon;
+import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
@@ -76,6 +79,7 @@ import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.OptionPaneUI;
@@ -85,6 +89,21 @@ import javax.swing.plaf.OptionPaneUI;
public class BasicOptionPaneUI extends OptionPaneUI
{
/**
+ * Implements the "close" keyboard action.
+ */
+ static class OptionPaneCloseAction
+ extends AbstractAction
+ {
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JOptionPane op = (JOptionPane) event.getSource();
+ op.setValue(new Integer(JOptionPane.CLOSED_OPTION));
+ }
+
+ }
+
+ /**
* This is a helper class that listens to the buttons located at the bottom
* of the JOptionPane.
*
@@ -389,36 +408,20 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
public void propertyChange(PropertyChangeEvent e)
{
- if (e.getPropertyName().equals(JOptionPane.ICON_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.MESSAGE_TYPE_PROPERTY))
- addIcon(messageAreaContainer);
- else if (e.getPropertyName().equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY))
- resetSelectedValue();
- else if (e.getPropertyName().equals(JOptionPane.INITIAL_VALUE_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.OPTIONS_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.OPTION_TYPE_PROPERTY))
+ String property = e.getPropertyName();
+ if (property.equals(JOptionPane.ICON_PROPERTY)
+ || property.equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY)
+ || property.equals(JOptionPane.INITIAL_VALUE_PROPERTY)
+ || property.equals(JOptionPane.MESSAGE_PROPERTY)
+ || property.equals(JOptionPane.MESSAGE_TYPE_PROPERTY)
+ || property.equals(JOptionPane.OPTION_TYPE_PROPERTY)
+ || property.equals(JOptionPane.OPTIONS_PROPERTY)
+ || property.equals(JOptionPane.WANTS_INPUT_PROPERTY))
{
- Container newButtons = createButtonArea();
- optionPane.remove(buttonContainer);
- optionPane.add(newButtons);
- buttonContainer = newButtons;
+ uninstallComponents();
+ installComponents();
+ optionPane.validate();
}
-
- else if (e.getPropertyName().equals(JOptionPane.MESSAGE_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.WANTS_INPUT_PROPERTY)
- || e.getPropertyName().equals(JOptionPane.SELECTION_VALUES_PROPERTY))
- {
- optionPane.remove(messageAreaContainer);
- messageAreaContainer = createMessageArea();
- optionPane.add(messageAreaContainer);
- Container newButtons = createButtonArea();
- optionPane.remove(buttonContainer);
- optionPane.add(newButtons);
- buttonContainer = newButtons;
- optionPane.add(buttonContainer);
- }
- optionPane.invalidate();
- optionPane.repaint();
}
}
@@ -460,17 +463,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
protected JOptionPane optionPane;
/** The size of the icons. */
- // FIXME: wrong name for a constant.
- private static final int iconSize = 36;
-
- /** The foreground color for the message area. */
- private transient Color messageForeground;
-
- /** The border around the message area. */
- private transient Border messageBorder;
-
- /** The border around the button area. */
- private transient Border buttonBorder;
+ private static final int ICON_SIZE = 36;
/** The string used to describe OK buttons. */
private static final String OK_STRING = "OK";
@@ -505,7 +498,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
public int getIconWidth()
{
- return iconSize;
+ return ICON_SIZE;
}
/**
@@ -515,7 +508,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
public int getIconHeight()
{
- return iconSize;
+ return ICON_SIZE;
}
/**
@@ -566,7 +559,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
// Should be purple.
g.setColor(Color.RED);
- g.fillOval(0, 0, iconSize, iconSize);
+ g.fillOval(0, 0, ICON_SIZE, ICON_SIZE);
g.setColor(Color.BLACK);
g.drawOval(16, 6, 4, 4);
@@ -615,7 +608,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
Color saved = g.getColor();
g.setColor(Color.GREEN);
- g.fillRect(0, 0, iconSize, iconSize);
+ g.fillRect(0, 0, ICON_SIZE, ICON_SIZE);
g.setColor(Color.BLACK);
@@ -623,7 +616,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
g.drawOval(14, 5, 10, 10);
g.setColor(Color.GREEN);
- g.fillRect(0, 10, iconSize, iconSize - 10);
+ g.fillRect(0, 10, ICON_SIZE, ICON_SIZE - 10);
g.setColor(Color.BLACK);
@@ -640,10 +633,6 @@ public class BasicOptionPaneUI extends OptionPaneUI
}
};
- // FIXME: Uncomment when the ImageIcons are fixed.
-
- /* IconUIResource warningIcon, questionIcon, infoIcon, errorIcon;*/
-
/**
* Creates a new BasicOptionPaneUI object.
*/
@@ -705,6 +694,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
if (icon != null)
{
iconLabel = new JLabel(icon);
+ configureLabel(iconLabel);
top.add(iconLabel, BorderLayout.WEST);
}
}
@@ -766,7 +756,9 @@ public class BasicOptionPaneUI extends OptionPaneUI
}
else if (msg instanceof Icon)
{
- container.add(new JLabel((Icon) msg), cons);
+ JLabel label = new JLabel((Icon) msg);
+ configureLabel(label);
+ container.add(label, cons);
cons.gridy++;
}
else
@@ -783,8 +775,11 @@ public class BasicOptionPaneUI extends OptionPaneUI
addMessageComponents(container, cons, tmp, maxll, true);
}
else
- addMessageComponents(container, cons, new JLabel(msg.toString()),
- maxll, true);
+ {
+ JLabel label = new JLabel(msg.toString());
+ configureLabel(label);
+ addMessageComponents(container, cons, label, maxll, true);
+ }
}
}
@@ -815,6 +810,7 @@ public class BasicOptionPaneUI extends OptionPaneUI
remainder = d.substring(maxll);
}
JLabel label = new JLabel(line);
+ configureLabel(label);
c.add(label);
// If there is nothing left to burst, then we can stop.
@@ -825,8 +821,12 @@ public class BasicOptionPaneUI extends OptionPaneUI
if (remainder.length() > maxll || remainder.contains("\n"))
burstStringInto(c, remainder, maxll);
else
- // Add the remainder to the container and be done.
- c.add(new JLabel(remainder));
+ {
+ // Add the remainder to the container and be done.
+ JLabel l = new JLabel(remainder);
+ configureLabel(l);
+ c.add(l);
+ }
}
/**
@@ -862,6 +862,9 @@ public class BasicOptionPaneUI extends OptionPaneUI
protected Container createButtonArea()
{
JPanel buttonPanel = new JPanel();
+ Border b = UIManager.getBorder("OptionPane.buttonAreaBorder");
+ if (b != null)
+ buttonPanel.setBorder(b);
buttonPanel.setLayout(createLayoutManager());
addButtonComponents(buttonPanel, getButtons(), getInitialValueIndex());
@@ -887,6 +890,10 @@ public class BasicOptionPaneUI extends OptionPaneUI
protected Container createMessageArea()
{
JPanel messageArea = new JPanel();
+ Border messageBorder = UIManager.getBorder("OptionPane.messageAreaBorder");
+ if (messageBorder != null)
+ messageArea.setBorder(messageBorder);
+
messageArea.setLayout(new BorderLayout());
addIcon(messageArea);
@@ -941,8 +948,9 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
protected Container createSeparator()
{
- // FIXME: Figure out what this method is supposed to return and where
- // this should be added to the OptionPane.
+ // The reference implementation returns null here. When overriding
+ // to return something non-null, the component gets added between
+ // the message area and the button area. See installComponents().
return null;
}
@@ -1143,35 +1151,17 @@ public class BasicOptionPaneUI extends OptionPaneUI
*/
protected void installComponents()
{
- // reset it.
- hasCustomComponents = false;
- Container msg = createMessageArea();
- if (msg != null)
- {
- ((JComponent) msg).setBorder(messageBorder);
- msg.setForeground(messageForeground);
- messageAreaContainer = msg;
- optionPane.add(msg);
- }
+ // First thing is the message area.
+ optionPane.add(createMessageArea());
- // FIXME: Figure out if the separator should be inserted here or what
- // this thing is supposed to do. Note: The JDK does NOT insert another
- // component at this place. The JOptionPane only has two panels in it
- // and there actually are applications that depend on this beeing so.
+ // Add separator when createSeparator() is overridden to return
+ // something other than null.
Container sep = createSeparator();
if (sep != null)
optionPane.add(sep);
- Container button = createButtonArea();
- if (button != null)
- {
- ((JComponent) button).setBorder(buttonBorder);
- buttonContainer = button;
- optionPane.add(button);
- }
-
- optionPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 11, 11));
- optionPane.invalidate();
+ // Last thing is the button area.
+ optionPane.add(createButtonArea());
}
/**
@@ -1185,10 +1175,6 @@ public class BasicOptionPaneUI extends OptionPaneUI
LookAndFeel.installBorder(optionPane, "OptionPane.border");
optionPane.setOpaque(true);
- messageBorder = UIManager.getBorder("OptionPane.messageAreaBorder");
- messageForeground = UIManager.getColor("OptionPane.messageForeground");
- buttonBorder = UIManager.getBorder("OptionPane.buttonAreaBorder");
-
minimumSize = UIManager.getDimension("OptionPane.minimumSize");
// FIXME: Image icons don't seem to work properly right now.
@@ -1206,9 +1192,44 @@ public class BasicOptionPaneUI extends OptionPaneUI
* This method installs keyboard actions for the JOptionpane.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ // Install the input map.
+ Object[] bindings =
+ (Object[]) SharedUIDefaults.get("OptionPane.windowBindings");
+ InputMap inputMap = LookAndFeel.makeComponentInputMap(optionPane,
+ bindings);
+ SwingUtilities.replaceUIInputMap(optionPane,
+ JComponent.WHEN_IN_FOCUSED_WINDOW,
+ inputMap);
+
+ // FIXME: The JDK uses a LazyActionMap for parentActionMap
+ SwingUtilities.replaceUIActionMap(optionPane, getActionMap());
+ }
+
+ /**
+ * Fetches the action map from the UI defaults, or create a new one
+ * if the action map hasn't been initialized.
+ *
+ * @return the action map
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("OptionPane.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("OptionPane.actionMap", am);
+ }
+ return am;
+ }
+
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new OptionPaneCloseAction();
+
+ am.put("close", action);
+ return am;
}
/**
@@ -1321,10 +1342,6 @@ public class BasicOptionPaneUI extends OptionPaneUI
minimumSize = null;
- messageBorder = null;
- buttonBorder = null;
- messageForeground = null;
-
// FIXME: ImageIcons don't seem to work properly
/*
@@ -1339,9 +1356,10 @@ public class BasicOptionPaneUI extends OptionPaneUI
* This method uninstalls keyboard actions for the JOptionPane.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ SwingUtilities.replaceUIInputMap(optionPane, JComponent.
+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities.replaceUIActionMap(optionPane, null);
}
/**
@@ -1367,4 +1385,20 @@ public class BasicOptionPaneUI extends OptionPaneUI
optionPane = null;
}
+
+ /**
+ * Applies the proper UI configuration to labels that are added to
+ * the OptionPane.
+ *
+ * @param l the label to configure
+ */
+ private void configureLabel(JLabel l)
+ {
+ Color c = UIManager.getColor("OptionPane.messageForeground");
+ if (c != null)
+ l.setForeground(c);
+ Font f = UIManager.getFont("OptionPane.messageFont");
+ if (f != null)
+ l.setFont(f);
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
index a26a5c7c46b..8c0fe6757e3 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java
@@ -37,33 +37,574 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.KeyboardFocusManager;
+import java.awt.event.ActionEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
+import java.util.EventListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ActionMap;
import javax.swing.BoxLayout;
+import javax.swing.InputMap;
+import javax.swing.JApplet;
import javax.swing.JComponent;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
+import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PopupMenuUI;
-
/**
* UI Delegate for JPopupMenu
*/
public class BasicPopupMenuUI extends PopupMenuUI
{
+ /**
+ * Handles keyboard navigation through menus.
+ */
+ private static class NavigateAction
+ extends AbstractAction
+ {
+
+ /**
+ * Creates a new NavigateAction instance.
+ *
+ * @param name the name of the action
+ */
+ NavigateAction(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Actually performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ String name = (String) getValue(Action.NAME);
+ if (name.equals("selectNext"))
+ navigateNextPrevious(true);
+ else if (name.equals("selectPrevious"))
+ navigateNextPrevious(false);
+ else if (name.equals("selectChild"))
+ navigateParentChild(true);
+ else if (name.equals("selectParent"))
+ navigateParentChild(false);
+ else if (name.equals("cancel"))
+ cancel();
+ else if (name.equals("return"))
+ doReturn();
+ else
+ assert false : "Must not reach here";
+ }
+
+ /**
+ * Navigates to the next or previous menu item.
+ *
+ * @param dir <code>true</code>: navigate to next, <code>false</code>:
+ * navigate to previous
+ */
+ private void navigateNextPrevious(boolean dir)
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ int len = path.length;
+ if (len >= 2)
+ {
+
+ if (path[0] instanceof JMenuBar &&
+ path[1] instanceof JMenu && len == 2)
+ {
+
+ // A toplevel menu is selected, but its popup not yet shown.
+ // Show the popup and select the first item
+ JPopupMenu popup = ((JMenu)path[1]).getPopupMenu();
+ MenuElement next =
+ findEnabledChild(popup.getSubElements(), -1, true);
+ MenuElement[] newPath;
+
+ if (next != null)
+ {
+ newPath = new MenuElement[4];
+ newPath[3] = next;
+ }
+ else
+ {
+ // Menu has no enabled items, show the popup anyway.
+ newPath = new MenuElement[3];
+ }
+ System.arraycopy(path, 0, newPath, 0, 2);
+ newPath[2] = popup;
+ msm.setSelectedPath(newPath);
+ }
+ else if (path[len - 1] instanceof JPopupMenu &&
+ path[len - 2] instanceof JMenu)
+ {
+ // Select next item in already shown popup menu.
+ JMenu menu = (JMenu) path[len - 2];
+ JPopupMenu popup = menu.getPopupMenu();
+ MenuElement next =
+ findEnabledChild(popup.getSubElements(), -1, dir);
+
+ if (next != null)
+ {
+ MenuElement[] newPath = new MenuElement[len + 1];
+ System.arraycopy(path, 0, newPath, 0, len);
+ newPath[len] = next;
+ msm.setSelectedPath(newPath);
+ }
+ else
+ {
+ // All items in the popup are disabled.
+ // Find the parent popup menu and select
+ // its next item. If there's no parent popup menu , do nothing.
+ if (len > 2 && path[len - 3] instanceof JPopupMenu)
+ {
+ popup = ((JPopupMenu) path[len - 3]);
+ next = findEnabledChild(popup.getSubElements(),
+ menu, dir);
+ if (next != null && next != menu)
+ {
+ MenuElement[] newPath = new MenuElement[len - 1];
+ System.arraycopy(path, 0, newPath, 0, len - 2);
+ newPath[len - 2] = next;
+ msm.setSelectedPath(newPath);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Only select the next item.
+ MenuElement subs[] = path[len - 2].getSubElements();
+ MenuElement nextChild =
+ findEnabledChild(subs, path[len - 1], dir);
+ if (nextChild == null)
+ {
+ nextChild = findEnabledChild(subs, -1, dir);
+ }
+ if (nextChild != null)
+ {
+ path[len-1] = nextChild;
+ msm.setSelectedPath(path);
+ }
+ }
+ }
+ }
+
+ private MenuElement findEnabledChild(MenuElement[] children,
+ MenuElement start, boolean dir)
+ {
+ MenuElement found = null;
+ for (int i = 0; i < children.length && found == null; i++)
+ {
+ if (children[i] == start)
+ {
+ found = findEnabledChild(children, i, dir);
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Searches the next or previous enabled child menu element.
+ *
+ * @param children the children to search through
+ * @param start the index at which to start
+ * @param dir the direction (true == forward, false == backward)
+ *
+ * @return the found element or null
+ */
+ private MenuElement findEnabledChild(MenuElement[] children,
+ int start, boolean dir)
+ {
+ MenuElement result = null;
+ if (dir)
+ {
+ result = findNextEnabledChild(children, start + 1, children.length-1);
+ if (result == null)
+ result = findNextEnabledChild(children, 0, start - 1);
+ }
+ else
+ {
+ result = findPreviousEnabledChild(children, start - 1, 0);
+ if (result == null)
+ result = findPreviousEnabledChild(children, children.length-1,
+ start + 1);
+ }
+ return result;
+ }
+
+ /**
+ * Finds the next child element that is enabled and visible.
+ *
+ * @param children the children to search through
+ * @param start the start index
+ * @param end the end index
+ *
+ * @return the found child, or null
+ */
+ private MenuElement findNextEnabledChild(MenuElement[] children, int start,
+ int end)
+ {
+ MenuElement found = null;
+ for (int i = start; i <= end && found == null; i++)
+ {
+ if (children[i] != null)
+ {
+ Component comp = children[i].getComponent();
+ if (comp != null && comp.isEnabled() && comp.isVisible())
+ {
+ found = children[i];
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Finds the previous child element that is enabled and visible.
+ *
+ * @param children the children to search through
+ * @param start the start index
+ * @param end the end index
+ *
+ * @return the found child, or null
+ */
+ private MenuElement findPreviousEnabledChild(MenuElement[] children,
+ int start, int end)
+ {
+ MenuElement found = null;
+ for (int i = start; i >= end && found == null; i--)
+ {
+ if (children[i] != null)
+ {
+ Component comp = children[i].getComponent();
+ if (comp != null && comp.isEnabled() && comp.isVisible())
+ {
+ found = children[i];
+ }
+ }
+ }
+ return found;
+ }
+
+ /**
+ * Navigates to the parent or child menu item.
+ *
+ * @param selectChild <code>true</code>: navigate to child,
+ * <code>false</code>: navigate to parent
+ */
+ private void navigateParentChild(boolean selectChild)
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ int len = path.length;
+
+ if (selectChild)
+ {
+ if (len > 0 && path[len - 1] instanceof JMenu
+ && ! ((JMenu) path[len-1]).isTopLevelMenu())
+ {
+ // We have a submenu, open it.
+ JMenu menu = (JMenu) path[len - 1];
+ JPopupMenu popup = menu.getPopupMenu();
+ MenuElement[] subs = popup.getSubElements();
+ MenuElement item = findEnabledChild(subs, -1, true);
+ MenuElement[] newPath;
+
+ if (item == null)
+ {
+ newPath = new MenuElement[len + 1];
+ }
+ else
+ {
+ newPath = new MenuElement[len + 2];
+ newPath[len + 1] = item;
+ }
+ System.arraycopy(path, 0, newPath, 0, len);
+ newPath[len] = popup;
+ msm.setSelectedPath(newPath);
+ return;
+ }
+ }
+ else
+ {
+ int popupIndex = len-1;
+ if (len > 2
+ && (path[popupIndex] instanceof JPopupMenu
+ || path[--popupIndex] instanceof JPopupMenu)
+ && ! ((JMenu) path[popupIndex - 1]).isTopLevelMenu())
+ {
+ // We have a submenu, close it.
+ MenuElement newPath[] = new MenuElement[popupIndex];
+ System.arraycopy(path, 0, newPath, 0, popupIndex);
+ msm.setSelectedPath(newPath);
+ return;
+ }
+ }
+
+ // If we got here, we have not selected a child or parent.
+ // Check if we have a toplevel menu selected. If so, then select
+ // another one.
+ if (len > 1 && path[0] instanceof JMenuBar)
+ {
+ MenuElement currentMenu = path[1];
+ MenuElement nextMenu = findEnabledChild(path[0].getSubElements(),
+ currentMenu, selectChild);
+
+ if (nextMenu != null && nextMenu != currentMenu)
+ {
+ MenuElement newSelection[];
+ if (len == 2)
+ {
+ // Menu is selected but its popup not shown.
+ newSelection = new MenuElement[2];
+ newSelection[0] = path[0];
+ newSelection[1] = nextMenu;
+ }
+ else
+ {
+ // Menu is selected and its popup is shown.
+ newSelection = new MenuElement[3];
+ newSelection[0] = path[0];
+ newSelection[1] = nextMenu;
+ newSelection[2] = ((JMenu) nextMenu).getPopupMenu();
+ }
+ msm.setSelectedPath(newSelection);
+ }
+ }
+ }
+
+ /**
+ * Handles cancel requests (ESC key).
+ */
+ private void cancel()
+ {
+ // Fire popup menu cancelled event. Unfortunately the
+ // firePopupMenuCancelled() is protected in JPopupMenu so we work
+ // around this limitation by fetching the listeners and notifying them
+ // directly.
+ JPopupMenu lastPopup = (JPopupMenu) getLastPopup();
+ EventListener[] ll = lastPopup.getListeners(PopupMenuListener.class);
+ for (int i = 0; i < ll.length; i++)
+ {
+ PopupMenuEvent ev = new PopupMenuEvent(lastPopup);
+ ((PopupMenuListener) ll[i]).popupMenuCanceled(ev);
+ }
+
+ // Close the last popup or the whole selection if there's only one
+ // popup left.
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ if(path.length > 4)
+ {
+ MenuElement newPath[] = new MenuElement[path.length - 2];
+ System.arraycopy(path,0,newPath,0,path.length-2);
+ MenuSelectionManager.defaultManager().setSelectedPath(newPath);
+ }
+ else
+ msm.clearSelectedPath();
+ }
+
+ /**
+ * Returns the last popup menu in the current selection or null.
+ *
+ * @return the last popup menu in the current selection or null
+ */
+ private JPopupMenu getLastPopup()
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement[] p = msm.getSelectedPath();
+ JPopupMenu popup = null;
+ for(int i = p.length - 1; popup == null && i >= 0; i--)
+ {
+ if (p[i] instanceof JPopupMenu)
+ popup = (JPopupMenu) p[i];
+ }
+ return popup;
+ }
+
+ /**
+ * Handles ENTER key requests. This normally opens submenus on JMenu
+ * items, or activates the menu item as if it's been clicked on it.
+ */
+ private void doReturn()
+ {
+ KeyboardFocusManager fmgr =
+ KeyboardFocusManager.getCurrentKeyboardFocusManager();
+ Component focusOwner = fmgr.getFocusOwner();
+ if((focusOwner == null || (focusOwner instanceof JRootPane)))
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ MenuElement path[] = msm.getSelectedPath();
+ MenuElement lastElement;
+ if(path.length > 0)
+ {
+ lastElement = path[path.length - 1];
+ if(lastElement instanceof JMenu)
+ {
+ MenuElement newPath[] = new MenuElement[path.length + 1];
+ System.arraycopy(path,0,newPath,0,path.length);
+ newPath[path.length] = ((JMenu) lastElement).getPopupMenu();
+ msm.setSelectedPath(newPath);
+ }
+ else if(lastElement instanceof JMenuItem)
+ {
+ JMenuItem mi = (JMenuItem)lastElement;
+ if (mi.getUI() instanceof BasicMenuItemUI)
+ {
+ ((BasicMenuItemUI)mi.getUI()).doClick(msm);
+ }
+ else
+ {
+ msm.clearSelectedPath();
+ mi.doClick(0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Installs keyboard actions when a popup is opened, and uninstalls the
+ * keyboard actions when closed. This listens on the default
+ * MenuSelectionManager.
+ */
+ private class KeyboardHelper
+ implements ChangeListener
+ {
+ private MenuElement[] lastSelectedPath = new MenuElement[0];
+ private Component lastFocused;
+ private JRootPane invokerRootPane;
+
+ public void stateChanged(ChangeEvent event)
+ {
+ MenuSelectionManager msm = (MenuSelectionManager) event.getSource();
+ MenuElement[] p = msm.getSelectedPath();
+ JPopupMenu popup = getActivePopup(p);
+ if (popup == null || popup.isFocusable())
+ {
+ if (lastSelectedPath.length != 0 && p.length != 0 )
+ {
+ if (! invokerEquals(p[0], lastSelectedPath[0]))
+ {
+ uninstallKeyboardActionsImpl();
+ lastSelectedPath = new MenuElement[0];
+ }
+ }
+
+ if (lastSelectedPath.length == 0 && p.length > 0)
+ {
+ JComponent invoker;
+ if (popup == null)
+ {
+ if (p.length == 2 && p[0] instanceof JMenuBar
+ && p[1] instanceof JMenu)
+ {
+ // A menu has been selected but not opened.
+ invoker = (JComponent)p[1];
+ popup = ((JMenu)invoker).getPopupMenu();
+ }
+ else
+ {
+ return;
+ }
+ }
+ else
+ {
+ Component c = popup.getInvoker();
+ if(c instanceof JFrame)
+ {
+ invoker = ((JFrame) c).getRootPane();
+ }
+ else if(c instanceof JApplet)
+ {
+ invoker = ((JApplet) c).getRootPane();
+ }
+ else
+ {
+ while (!(c instanceof JComponent))
+ {
+ if (c == null)
+ {
+ return;
+ }
+ c = c.getParent();
+ }
+ invoker = (JComponent)c;
+ }
+ }
+
+ // Remember current focus owner.
+ lastFocused = KeyboardFocusManager.
+ getCurrentKeyboardFocusManager().getFocusOwner();
+
+ // Install keybindings used for menu navigation.
+ invokerRootPane = SwingUtilities.getRootPane(invoker);
+ if (invokerRootPane != null)
+ {
+ invokerRootPane.requestFocus(true);
+ installKeyboardActionsImpl();
+ }
+ }
+ else if (lastSelectedPath.length != 0 && p.length == 0)
+ {
+ // menu hidden -- return focus to where it had been before
+ // and uninstall menu keybindings
+ uninstallKeyboardActionsImpl();
+ }
+ }
+
+ // Remember the last path selected
+ lastSelectedPath = p;
+ }
+
+ private JPopupMenu getActivePopup(MenuElement[] path)
+ {
+ JPopupMenu active = null;
+ for (int i = path.length - 1; i >= 0 && active == null; i--)
+ {
+ MenuElement elem = path[i];
+ if (elem instanceof JPopupMenu)
+ {
+ active = (JPopupMenu) elem;
+ }
+ }
+ return active;
+ }
+
+ private boolean invokerEquals(MenuElement el1, MenuElement el2)
+ {
+ Component invoker1 = el1.getComponent();
+ Component invoker2 = el2.getComponent();
+ if (invoker1 instanceof JPopupMenu)
+ invoker1 = ((JPopupMenu) invoker1).getInvoker();
+ if (invoker2 instanceof JPopupMenu)
+ invoker2 = ((JPopupMenu) invoker2).getInvoker();
+ return invoker1 == invoker2;
+ }
+ }
+
/* popupMenu for which this UI delegate is for*/
protected JPopupMenu popupMenu;
@@ -75,6 +616,19 @@ public class BasicPopupMenuUI extends PopupMenuUI
TopWindowListener topWindowListener;
/**
+ * Counts how many popup menus are handled by this UI or a subclass.
+ * This is used to install a KeyboardHelper on the MenuSelectionManager
+ * for the first popup, and uninstall this same KeyboardHelper when the
+ * last popup is uninstalled.
+ */
+ private static int numPopups;
+
+ /**
+ * This is the KeyboardHelper that listens on the MenuSelectionManager.
+ */
+ private static KeyboardHelper keyboardHelper;
+
+ /**
* Creates a new BasicPopupMenuUI object.
*/
public BasicPopupMenuUI()
@@ -106,6 +660,16 @@ public class BasicPopupMenuUI extends PopupMenuUI
public void installUI(JComponent c)
{
super.installUI(c);
+
+ // Install KeyboardHelper when the first popup is initialized.
+ if (numPopups == 0)
+ {
+ keyboardHelper = new KeyboardHelper();
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ msm.addChangeListener(keyboardHelper);
+ }
+ numPopups++;
+
popupMenu = (JPopupMenu) c;
popupMenu.setLayout(new DefaultMenuLayout(popupMenu, BoxLayout.Y_AXIS));
popupMenu.setBorderPainted(true);
@@ -113,6 +677,7 @@ public class BasicPopupMenuUI extends PopupMenuUI
installDefaults();
installListeners();
+ installKeyboardActions();
}
/**
@@ -139,9 +704,77 @@ public class BasicPopupMenuUI extends PopupMenuUI
* This method installs the keyboard actions for this {@link JPopupMenu}.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ // We can't install the keyboard actions here, because then all
+ // popup menus would have their actions registered in the KeyboardManager.
+ // So we install it when the popup menu is opened, and uninstall it
+ // when it's closed. This is done in the KeyboardHelper class.
+ // Install InputMap.
+ }
+
+ /**
+ * Called by the KeyboardHandler when a popup is made visible.
+ */
+ void installKeyboardActionsImpl()
+ {
+ Object[] bindings;
+ if (popupMenu.getComponentOrientation().isLeftToRight())
+ {
+ bindings = (Object[])
+ SharedUIDefaults.get("PopupMenu.selectedWindowInputMapBindings");
+ }
+ else
+ {
+ bindings = (Object[]) SharedUIDefaults.get
+ ("PopupMenu.selectedWindowInputMapBindings.RightToLeft");
+ }
+ InputMap inputMap = LookAndFeel.makeComponentInputMap(popupMenu, bindings);
+ SwingUtilities.replaceUIInputMap(popupMenu,
+ JComponent.WHEN_IN_FOCUSED_WINDOW,
+ inputMap);
+
+ // Install ActionMap.
+ SwingUtilities.replaceUIActionMap(popupMenu, getActionMap());
+ }
+
+ /**
+ * Creates and returns the shared action map for JTrees.
+ *
+ * @return the shared action map for JTrees
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("PopupMenu.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("PopupMenu.actionMap", am);
+ }
+ return am;
+ }
+
+ /**
+ * Creates the default actions when there are none specified by the L&F.
+ *
+ * @return the default actions
+ */
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new NavigateAction("selectNext");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("selectPrevious");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("selectParent");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("selectChild");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("return");
+ am.put(action.getValue(Action.NAME), action);
+ action = new NavigateAction("cancel");
+ am.put(action.getValue(Action.NAME), action);
+
+ return am;
}
/**
@@ -155,7 +788,17 @@ public class BasicPopupMenuUI extends PopupMenuUI
{
uninstallListeners();
uninstallDefaults();
+ uninstallKeyboardActions();
popupMenu = null;
+
+ // Install KeyboardHelper when the first popup is initialized.
+ numPopups--;
+ if (numPopups == 0)
+ {
+ MenuSelectionManager msm = MenuSelectionManager.defaultManager();
+ msm.removeChangeListener(keyboardHelper);
+ }
+
}
/**
@@ -182,9 +825,22 @@ public class BasicPopupMenuUI extends PopupMenuUI
* Uninstalls any keyboard actions.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Need to implement
+ // We can't install the keyboard actions here, because then all
+ // popup menus would have their actions registered in the KeyboardManager.
+ // So we install it when the popup menu is opened, and uninstall it
+ // when it's closed. This is done in the KeyboardHelper class.
+ // Install InputMap.
+ }
+
+ /**
+ * Called by the KeyboardHandler when a popup is made invisible.
+ */
+ void uninstallKeyboardActionsImpl()
+ {
+ SwingUtilities.replaceUIInputMap(popupMenu,
+ JComponent.WHEN_IN_FOCUSED_WINDOW, null);
+ SwingUtilities.replaceUIActionMap(popupMenu, null);
}
/**
@@ -278,9 +934,10 @@ public class BasicPopupMenuUI extends PopupMenuUI
// Adds topWindowListener to top-level window to listener to
// ComponentEvents fired by it. We need to cancel this popup menu
// if topWindow to which this popup belongs was resized or moved.
- Component invoker = popupMenu.getInvoker();
+ Component invoker = popupMenu.getInvoker();
Component rootContainer = SwingUtilities.getRoot(invoker);
- rootContainer.addComponentListener(topWindowListener);
+ if (rootContainer != null)
+ rootContainer.addComponentListener(topWindowListener);
// if this popup menu is a free floating popup menu,
// then by default its first element should be always selected when
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
index a7da21c4f6e..aed4d69d6d5 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonUI.java
@@ -42,6 +42,7 @@ import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
+import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
@@ -92,14 +93,6 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
protected void installDefaults(AbstractButton b)
{
super.installDefaults(b);
- if (b.getIcon() == null)
- b.setIcon(icon);
- if (b.getSelectedIcon() == null)
- b.setSelectedIcon(icon);
- if (b.getDisabledIcon() == null)
- b.setDisabledIcon(icon);
- if (b.getDisabledSelectedIcon() == null)
- b.setDisabledSelectedIcon(icon);
}
/**
@@ -145,16 +138,17 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
g.setFont(f);
ButtonModel m = b.getModel();
- Icon currentIcon = null;
- if (m.isSelected() && m.isEnabled())
- currentIcon = b.getSelectedIcon();
- else if (! m.isSelected() && m.isEnabled())
- currentIcon = b.getIcon();
- else if (m.isSelected() && ! m.isEnabled())
- currentIcon = b.getDisabledSelectedIcon();
- else // (!m.isSelected() && ! m.isEnabled())
- currentIcon = b.getDisabledIcon();
+ // FIXME: Do a filtering on any customized icon if the following property
+ // is set.
+ boolean enabled = b.isEnabled();
+
+ Icon currentIcon = b.getIcon();
+ if (currentIcon == null)
+ {
+ currentIcon = getDefaultIcon();
+ }
+
SwingUtilities.calculateInnerArea(b, vr);
String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f),
b.getText(), currentIcon,
@@ -162,15 +156,57 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
vr, ir, tr, b.getIconTextGap() + defaultTextShiftOffset);
- if (currentIcon != null)
- {
- currentIcon.paintIcon(c, g, ir.x, ir.y);
- }
+ currentIcon.paintIcon(c, g, ir.x, ir.y);
+
if (text != null)
paintText(g, b, tr, text);
if (b.hasFocus() && b.isFocusPainted() && m.isEnabled())
paintFocus(g, tr, c.getSize());
}
+
+ public Dimension getPreferredSize(JComponent c)
+ {
+ // This is basically the same code as in
+ // BasicGraphicsUtils.getPreferredButtonSize() but takes the default icon
+ // property into account. JRadioButton and subclasses always have an icon:
+ // the check box. If the user explicitly changes it with setIcon() that
+ // one will be used for layout calculations and painting instead.
+ // The other icon properties are ignored.
+ AbstractButton b = (AbstractButton) c;
+
+ Rectangle contentRect;
+ Rectangle viewRect;
+ Rectangle iconRect = new Rectangle();
+ Rectangle textRect = new Rectangle();
+ Insets insets = b.getInsets();
+
+ Icon i = b.getIcon();
+ if (i == null)
+ i = getDefaultIcon();
+
+ viewRect = new Rectangle();
+
+ SwingUtilities.layoutCompoundLabel(
+ b, // for the component orientation
+ b.getFontMetrics(b.getFont()),
+ b.getText(),
+ i,
+ b.getVerticalAlignment(),
+ b.getHorizontalAlignment(),
+ b.getVerticalTextPosition(),
+ b.getHorizontalTextPosition(),
+ viewRect, iconRect, textRect,
+ defaultTextIconGap + defaultTextShiftOffset);
+
+ contentRect = textRect.union(iconRect);
+
+ return new Dimension(insets.left
+ + contentRect.width
+ + insets.right + b.getHorizontalAlignment(),
+ insets.top
+ + contentRect.height
+ + insets.bottom);
+ }
/**
* Paints the focus indicator for JRadioButtons.
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
index b29026342e0..78e5168fc80 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java
@@ -302,8 +302,10 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
*/
public void mouseMoved(MouseEvent e)
{
- // Not interested in where the mouse
- // is unless it is being dragged.
+ if (thumbRect.contains(e.getPoint()))
+ thumbRollover = true;
+ else
+ thumbRollover = false;
}
/**
@@ -486,6 +488,9 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
/** The scrollbar this UI is acting for. */
protected JScrollBar scrollbar;
+
+ /** True if the mouse is over the thumb. */
+ boolean thumbRollover;
/**
* This method adds a component to the layout.
@@ -1401,4 +1406,45 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager,
value = min;
return value;
}
+
+ /**
+ * Returns true if the mouse is over the thumb.
+ *
+ * @return true if the mouse is over the thumb.
+ *
+ * @since 1.5
+ */
+ public boolean isThumbRollover()
+ {
+ return thumbRollover;
+ }
+
+ /**
+ * Set thumbRollover to active. This indicates
+ * whether or not the mouse is over the thumb.
+ *
+ * @param active - true if the mouse is over the thumb.
+ *
+ * @since 1.5
+ */
+ protected void setThumbRollover(boolean active)
+ {
+ thumbRollover = active;
+ }
+
+ /**
+ * Indicates whether the user can position the thumb with
+ * a mouse click (i.e. middle button).
+ *
+ * @return true if the user can position the thumb with a mouse
+ * click.
+ *
+ * @since 1.5
+ */
+ public boolean getSupportsAbsolutePositioning()
+ {
+ // The positioning feature has not been implemented.
+ // So, false is always returned.
+ return false;
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
index 2fb16f12e63..3811eebdfd6 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicSliderUI.java
@@ -371,6 +371,7 @@ public class BasicSliderUI extends SliderUI
*/
public void mouseDragged(MouseEvent e)
{
+ dragging = true;
if (slider.isEnabled())
{
currentMouseX = e.getX();
@@ -450,6 +451,7 @@ public class BasicSliderUI extends SliderUI
*/
public void mouseReleased(MouseEvent e)
{
+ dragging = false;
if (slider.isEnabled())
{
currentMouseX = e.getX();
@@ -593,6 +595,9 @@ public class BasicSliderUI extends SliderUI
/** True if the slider has focus. */
private transient boolean hasFocus;
+
+ /** True if the user is dragging the slider. */
+ boolean dragging;
/**
* Creates a new Basic look and feel Slider UI.
@@ -605,6 +610,18 @@ public class BasicSliderUI extends SliderUI
}
/**
+ * Returns true if the user is dragging the slider.
+ *
+ * @return true if the slider is being dragged.
+ *
+ * @since 1.5
+ */
+ protected boolean isDragging()
+ {
+ return dragging;
+ }
+
+ /**
* Gets the shadow color to be used for this slider. The shadow color is the
* color used for drawing the top and left edges of the track.
*
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
index 1b2552837c6..11f25167d21 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java
@@ -1,5 +1,5 @@
/* BasicTabbedPaneUI.java --
- Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
@@ -51,6 +49,7 @@ import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
@@ -60,7 +59,10 @@ import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
import javax.swing.Icon;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
@@ -72,6 +74,7 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.PanelUI;
import javax.swing.plaf.TabbedPaneUI;
@@ -80,11 +83,127 @@ import javax.swing.text.View;
/**
* This is the Basic Look and Feel's UI delegate for JTabbedPane.
+ *
+ * @author Lillian Angel (langel@redhat.com)
+ * @author Kim Ho (kho@redhat.com)
+ * @author Roman Kennke (kennke@aicas.com)
+ * @author Robert Schuster (robertschuster@fsfe.org)
*/
public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
+
+ static class NavigateAction extends AbstractAction
+ {
+ int direction;
+
+ NavigateAction(String name, int dir)
+ {
+ super(name);
+ direction = dir;
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+ BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+ ui.navigateSelectedTab(direction);
+ }
+
+ }
+
+ static class NavigatePageDownAction extends AbstractAction
+ {
+
+ public NavigatePageDownAction()
+ {
+ super("navigatePageDown");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+ BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+ int i = tp.getSelectedIndex();
+
+ if (i < 0)
+ i = 0;
+
+ ui.selectNextTabInRun(i);
+ }
+
+ }
+
+ static class NavigatePageUpAction extends AbstractAction
+ {
+
+ public NavigatePageUpAction()
+ {
+ super("navigatePageUp");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+ BasicTabbedPaneUI ui = (BasicTabbedPaneUI) tp.getUI();
+
+ int i = tp.getSelectedIndex();
+
+ if (i < 0)
+ i = 0;
+
+ ui.selectPreviousTabInRun(i);
+
+ }
+ }
+
+ static class RequestFocusAction extends AbstractAction
+ {
+
+ public RequestFocusAction()
+ {
+ super("requestFocus");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ ((JTabbedPane) event.getSource()).requestFocus();
+ }
+
+ }
+
+ static class RequestFocusForVisibleComponentAction extends AbstractAction
+ {
+
+ public RequestFocusForVisibleComponentAction()
+ {
+ super("requestFocusForVisibleComponent");
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ JTabbedPane tp = (JTabbedPane) event.getSource();
+
+ // FIXME: This should select a suitable component within
+ // the tab content. However I dont know whether we have
+ // to search for this component or wether the called is
+ // supposed to do that.
+ tp.getSelectedComponent().requestFocus();
+ }
+
+ }
+
/**
- * A helper class that handles focus.
+ * A helper class that handles focus.
+ * <p>The purpose of this class is to implement a more flexible focus
+ * handling for the tabbed pane, which is used to determine whether the
+ * focus indicator should be painted or not. When in scrolling layout
+ * mode the area containing the tabs is a scrollpane, so simply testing
+ * whether the tabbed pane has the focus does not work.</p>
+ * <p>The <code>FocusHandler</code> is installed on the scrollpane and
+ * the tabbed pane and sets the variable <code>hasFocus</code> to
+ * <code>false</code> only when both components do not hold the focus.</p>
*
* @specnote Apparently this class was intended to be protected,
* but was made public by a compiler bug and is now
@@ -99,7 +218,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void focusGained(FocusEvent e)
{
- // FIXME: Implement.
+ Object source = e.getSource();
+ if (source == panel )
+ tabPane.requestFocus();
+ else if (source == tabPane)
+ tabPane.repaint();
}
/**
@@ -109,7 +232,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void focusLost(FocusEvent e)
{
- // FIXME: Implement.
+ if (e.getOppositeComponent() == tabPane.getSelectedComponent())
+ tabPane.requestFocus();
+ else if (e.getSource() == tabPane)
+ tabPane.repaint();
}
}
@@ -124,6 +250,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public class MouseHandler extends MouseAdapter
{
+ public void mouseReleased(MouseEvent e)
+ {
+ // Nothing to do here.
+ }
+
/**
* This method is called when the mouse is pressed. The index cannot
* change to a tab that is not enabled.
@@ -132,14 +263,84 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void mousePressed(MouseEvent e)
{
- if (tabPane.isEnabled())
+ Object s = e.getSource();
+ int placement = tabPane.getTabPlacement();
+
+ if (s == incrButton)
{
- int index = tabForCoordinate(tabPane, e.getX(), e.getY());
- if (index >= 0 && tabPane.isEnabledAt(index))
+ if(!incrButton.isEnabled())
+ return;
+
+ currentScrollLocation++;
+
+ switch (placement)
{
- tabPane.setSelectedIndex(index);
+ case JTabbedPane.TOP:
+ case JTabbedPane.BOTTOM:
+ currentScrollOffset = getTabAreaInsets(placement).left;
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].width;
+ break;
+ default:
+ currentScrollOffset = getTabAreaInsets(placement).top;
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].height;
+ break;
}
+
+ updateViewPosition();
+ updateButtons();
+
+ tabPane.repaint();
+ }
+ else if (s == decrButton)
+ {
+ if(!decrButton.isEnabled())
+ return;
+
+ // The scroll location may be zero but the offset
+ // greater than zero because of an adjustement to
+ // make a partially visible tab completely visible.
+ if (currentScrollLocation > 0)
+ currentScrollLocation--;
+
+ // Set the offset back to 0 and recompute it.
+ currentScrollOffset = 0;
+
+ switch (placement)
+ {
+ case JTabbedPane.TOP:
+ case JTabbedPane.BOTTOM:
+ // Take the tab area inset into account.
+ if (currentScrollLocation > 0)
+ currentScrollOffset = getTabAreaInsets(placement).left;
+ // Recompute scroll offset.
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].width;
+ break;
+ default:
+ // Take the tab area inset into account.
+ if (currentScrollLocation > 0)
+ currentScrollOffset = getTabAreaInsets(placement).top;
+
+ for (int i = 0; i < currentScrollLocation; i++)
+ currentScrollOffset += rects[i].height;
+ }
+
+ updateViewPosition();
+ updateButtons();
+
+ tabPane.repaint();
+ } else if (tabPane.isEnabled())
+ {
+ int index = tabForCoordinate(tabPane, e.getX(), e.getY());
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT
+ && s == panel)
+ scrollTab(index, placement);
+
+ tabPane.setSelectedIndex(index);
}
+
}
/**
@@ -197,6 +398,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
if (e.getPropertyName().equals("tabLayoutPolicy"))
{
+ currentScrollLocation = currentScrollOffset = 0;
+
layoutManager = createLayoutManager();
tabPane.setLayout(layoutManager);
@@ -265,7 +468,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// Find out the minimum/preferred size to display the largest child
// of the tabbed pane.
- for (int i = 0; i < tabPane.getTabCount(); i++)
+ int count = tabPane.getTabCount();
+ for (int i = 0; i < count; i++)
{
c = tabPane.getComponentAt(i);
if (c == null)
@@ -282,21 +486,19 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
- int min = calculateMaxTabWidth(tabPlacement);
- width = Math.max(min, width);
- int tabAreaHeight = preferredTabAreaHeight(tabPlacement,
- width - tabAreaInsets.left
- - tabAreaInsets.right);
- height += tabAreaHeight;
+ width = Math.max(calculateMaxTabWidth(tabPlacement), width);
+
+ height += preferredTabAreaHeight(tabPlacement,
+ width - tabAreaInsets.left
+ - tabAreaInsets.right);
}
else
{
- int min = calculateMaxTabHeight(tabPlacement);
- height = Math.max(min, height);
- int tabAreaWidth = preferredTabAreaWidth(tabPlacement,
- height - tabAreaInsets.top
- - tabAreaInsets.bottom);
- width += tabAreaWidth;
+ height = Math.max(calculateMaxTabHeight(tabPlacement), height);
+
+ width += preferredTabAreaWidth(tabPlacement,
+ height - tabAreaInsets.top
+ - tabAreaInsets.bottom);
}
Insets tabPaneInsets = tabPane.getInsets();
@@ -306,7 +508,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// if tab placement is LEFT OR RIGHT, they share width.
// if tab placement is TOP OR BOTTOM, they share height
- // PRE STEP: finds the default sizes for the labels as well as their locations.
+ // PRE STEP: finds the default sizes for the labels as well as their
+ // locations.
// AND where they will be placed within the run system.
// 1. calls normalizeTab Runs.
// 2. calls rotate tab runs.
@@ -345,7 +548,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
break;
case RIGHT:
maxTabWidth = calculateMaxTabWidth(tabPlacement);
- x = size.width - (insets.right + tabAreaInsets.right) - maxTabWidth;
+ x = size.width - (insets.right + tabAreaInsets.right)
+ - maxTabWidth - 1;
y = insets.top + tabAreaInsets.top;
breakAt = size.height - (insets.bottom + tabAreaInsets.bottom);
break;
@@ -353,7 +557,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
maxTabHeight = calculateMaxTabHeight(tabPlacement);
x = insets.left + tabAreaInsets.left;
y = size.height - (insets.bottom + tabAreaInsets.bottom)
- - maxTabHeight;
+ - maxTabHeight - 1;
breakAt = size.width - (insets.right + tabAreaInsets.right);
break;
case TOP:
@@ -372,6 +576,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
runCount = 0;
selectedRun = -1;
int selectedIndex = tabPane.getSelectedIndex();
+ if (selectedIndex < 0)
+ selectedIndex = 0;
Rectangle rect;
@@ -409,7 +615,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
rect.height = maxTabHeight;
if (i == selectedIndex)
selectedRun = runCount - 1;
-
}
}
else
@@ -454,9 +659,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int start;
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
- start = y;
- else
start = x;
+ else
+ start = y;
normalizeTabRuns(tabPlacement, tabCount, start, breakAt);
selectedRun = getRunForTab(tabCount, selectedIndex);
if (shouldRotateTabRuns(tabPlacement))
@@ -464,7 +669,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
rotateTabRuns(tabPlacement, selectedRun);
}
}
-
+
+ // Suppress padding if we have only one tab run.
+ if (runCount == 1)
+ return;
+
// Pad the runs.
int tabRunOverlay = getTabRunOverlay(tabPlacement);
for (int i = runCount - 1; i >= 0; --i)
@@ -604,16 +813,18 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public Dimension minimumLayoutSize(Container parent)
{
- return calculateSize(false);
+ return calculateSize(true);
}
- // If there is more free space in an adjacent run AND the tab in the run can fit in the
- // adjacent run, move it. This method is not perfect, it is merely an approximation.
+ // If there is more free space in an adjacent run AND the tab
+ // in the run can fit in the adjacent run, move it. This method
+ // is not perfect, it is merely an approximation.
// If you play around with Sun's JTabbedPane, you'll see that
// it does do some pretty strange things with regards to not moving tabs
// that should be moved.
// start = the x position where the tabs will begin
- // max = the maximum position of where the tabs can go to (tabAreaInsets.left + the width of the tab area)
+ // max = the maximum position of where the tabs can go to
+ // (tabAreaInsets.left + the width of the tab area)
/**
* This method tries to "even out" the number of tabs in each run based on
@@ -631,18 +842,20 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabPlacement == SwingUtilities.TOP
|| tabPlacement == SwingUtilities.BOTTOM)
{
- // We should only do this for runCount - 1, cause we can only shift that many times between
- // runs.
+ // We should only do this for runCount - 1, cause we can
+ // only shift that many times between runs.
for (int i = 1; i < runCount; i++)
{
Rectangle currRun = rects[lastTabInRun(tabCount, i)];
- Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
+ Rectangle nextRun = rects[lastTabInRun(tabCount,
+ getNextTabRun(i))];
int spaceInCurr = currRun.x + currRun.width;
int spaceInNext = nextRun.x + nextRun.width;
int diffNow = spaceInCurr - spaceInNext;
int diffLater = (spaceInCurr - currRun.width)
- (spaceInNext + currRun.width);
+
while (Math.abs(diffLater) < Math.abs(diffNow)
&& spaceInNext + currRun.width < max)
{
@@ -654,11 +867,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
diffLater = (spaceInCurr - currRun.width)
- (spaceInNext + currRun.width);
}
-
- // Fix the bounds.
- int first = lastTabInRun(tabCount, i) + 1;
- int last = lastTabInRun(tabCount, getNextTabRun(i));
- int currX = tabAreaInsets.left;
+
+ // Fixes the bounds of all tabs in the current
+ // run.
+ int first = tabRuns[i];
+ int last = lastTabInRun(tabCount, i);
+ int currX = start;
for (int j = first; j <= last; j++)
{
rects[j].x = currX;
@@ -671,7 +885,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
for (int i = 1; i < runCount; i++)
{
Rectangle currRun = rects[lastTabInRun(tabCount, i)];
- Rectangle nextRun = rects[lastTabInRun(tabCount, getNextTabRun(i))];
+ Rectangle nextRun = rects[lastTabInRun(tabCount,
+ getNextTabRun(i))];
int spaceInCurr = currRun.y + currRun.height;
int spaceInNext = nextRun.y + nextRun.height;
@@ -690,9 +905,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
- (spaceInNext + currRun.height);
}
- int first = lastTabInRun(tabCount, i) + 1;
- int last = lastTabInRun(tabCount, getNextTabRun(i));
- int currY = tabAreaInsets.top;
+ // Fixes the bounds of tabs in the current run.
+ int first = tabRuns[i];
+ int last = lastTabInRun(tabCount, i);
+ int currY = start;
for (int j = first; j <= last; j++)
{
rects[j].y = currY;
@@ -718,7 +934,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
rects[selectedIndex].height += insets.top + insets.bottom;
}
- // If the tabs on the run don't fill the width of the window, make it fit now.
+ // If the tabs on the run don't fill the width of the window, make it
+ // fit now.
// start = starting index of the run
// end = last index of the run
// max = tabAreaInsets.left + width (or equivalent)
@@ -742,7 +959,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int runWidth = rects[end].x + rects[end].width;
int spaceRemaining = max - runWidth;
int numTabs = end - start + 1;
-
+
// now divvy up the space.
int spaceAllocated = spaceRemaining / numTabs;
int currX = rects[start].x;
@@ -750,11 +967,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
rects[i].x = currX;
rects[i].width += spaceAllocated;
+
currX += rects[i].width;
// This is used because since the spaceAllocated
// variable is an int, it rounds down. Sometimes,
// we don't fill an entire row, so we make it do
// so now.
+
if (i == end && rects[i].x + rects[i].width != max)
rects[i].width = max - rects[i].x;
}
@@ -819,7 +1038,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// The reason why we can't use runCount:
// This method is only called to calculate the size request
- // for the tabbedPane. However, this size request is dependent on
+ // for the tabbedPane. However, this size request is dependent on
// our desired width. We need to find out what the height would
// be IF we got our desired width.
for (int i = 0; i < tabPane.getTabCount(); i++)
@@ -882,7 +1101,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
runs++;
int maxTabWidth = calculateMaxTabWidth(tabPlacement);
- int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs, maxTabWidth);
+ int tabAreaWidth = calculateTabAreaWidth(tabPlacement, runs,
+ maxTabWidth);
return tabAreaWidth;
}
@@ -896,11 +1116,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void rotateTabRuns(int tabPlacement, int selectedRun)
{
- if (runCount == 1 || selectedRun == 1 || selectedRun == -1)
+ if (runCount == 1 || selectedRun == 0 || selectedRun == -1)
return;
int[] newTabRuns = new int[tabRuns.length];
int currentRun = selectedRun;
- int i = 1;
+ int i = 0;
do
{
newTabRuns[i] = tabRuns[currentRun];
@@ -908,8 +1128,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
i++;
}
while (i < runCount);
- if (runCount > 1)
- newTabRuns[0] = tabRuns[currentRun];
tabRuns = newTabRuns;
BasicTabbedPaneUI.this.selectedRun = 1;
@@ -942,7 +1160,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public Dimension preferredLayoutSize(Container parent)
{
- return super.calculateSize(true);
+ return super.calculateSize(false);
}
/**
@@ -1016,29 +1234,27 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
SwingUtilities.calculateInnerArea(tabPane, calcRect);
Insets tabAreaInsets = getTabAreaInsets(tabPlacement);
Insets insets = tabPane.getInsets();
- int runs = 1;
- int start = 0;
- int top = 0;
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
int maxHeight = calculateMaxTabHeight(tabPlacement);
calcRect.width -= tabAreaInsets.left + tabAreaInsets.right;
- start = tabAreaInsets.left + insets.left;
int width = 0;
- int runWidth = start;
- top = insets.top + tabAreaInsets.top;
+ int runWidth = tabAreaInsets.left + insets.left;
+ int top = insets.top + tabAreaInsets.top;
for (int i = 0; i < tabCount; i++)
{
width = calculateTabWidth(tabPlacement, i, fm);
-
- rects[i] = new Rectangle(runWidth, top, width, maxHeight);
+
+ // The proper instances should exists because
+ // assureRectsCreated() was being run already.
+ rects[i].setBounds(runWidth, top, width, maxHeight);
+
runWidth += width;
}
tabAreaRect.width = tabPane.getWidth() - insets.left - insets.right;
- tabAreaRect.height = runs * maxTabHeight
- - (runs - 1) * tabRunOverlay
- + tabAreaInsets.top + tabAreaInsets.bottom;
+ tabAreaRect.height = maxTabHeight + tabAreaInsets.top
+ + tabAreaInsets.bottom;
contentRect.width = tabAreaRect.width;
contentRect.height = tabPane.getHeight() - insets.top
- insets.bottom - tabAreaRect.height;
@@ -1061,23 +1277,25 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
calcRect.height -= tabAreaInsets.top + tabAreaInsets.bottom;
int height = 0;
- start = tabAreaInsets.top + insets.top;
- int runHeight = start;
+ int runHeight = tabAreaInsets.top + insets.top;;
int fontHeight = fm.getHeight();
- top = insets.left + tabAreaInsets.left;
+ int left = insets.left + tabAreaInsets.left;
for (int i = 0; i < tabCount; i++)
{
height = calculateTabHeight(tabPlacement, i, fontHeight);
- rects[i] = new Rectangle(top, runHeight, maxWidth, height);
+
+ // The proper instances should exists because
+ // assureRectsCreated() was being run already.
+ rects[i].setBounds(left, runHeight, maxWidth, height);
runHeight += height;
}
- tabAreaRect.width = runs * maxTabWidth - (runs - 1) * tabRunOverlay
- + tabAreaInsets.left + tabAreaInsets.right;
+ tabAreaRect.width = maxTabWidth + tabAreaInsets.left
+ + tabAreaInsets.right;
tabAreaRect.height = tabPane.getHeight() - insets.top
- - insets.bottom;
+ - insets.bottom;
tabAreaRect.y = insets.top;
contentRect.width = tabPane.getWidth() - insets.left - insets.right
- - tabAreaRect.width;
+ - tabAreaRect.width;
contentRect.height = tabAreaRect.height;
contentRect.y = insets.top;
if (tabPlacement == SwingConstants.LEFT)
@@ -1091,11 +1309,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabAreaRect.x = contentRect.x + contentRect.width;
}
}
- runCount = runs;
- if (runCount > tabRuns.length)
- expandTabRunsArray();
-
- padSelectedTab(tabPlacement, tabPane.getSelectedIndex());
+
+ // Unlike the behavior in the WRAP_TAB_LAYOUT the selected
+ // tab is not padded specially.
}
/**
@@ -1113,8 +1329,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabCount == 0)
return;
int tabPlacement = tabPane.getTabPlacement();
- incrButton.setVisible(false);
- decrButton.setVisible(false);
+
if (tabPlacement == SwingConstants.TOP
|| tabPlacement == SwingConstants.BOTTOM)
{
@@ -1124,18 +1339,49 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Dimension incrDims = incrButton.getPreferredSize();
Dimension decrDims = decrButton.getPreferredSize();
- decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
- - incrDims.width - decrDims.width,
- tabAreaRect.y, decrDims.width,
- tabAreaRect.height);
- incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
- - incrDims.width, tabAreaRect.y,
- decrDims.width, tabAreaRect.height);
-
+ if (tabPlacement == SwingConstants.BOTTOM)
+ {
+ // Align scroll buttons with the bottom border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width - decrDims.width,
+ tabAreaRect.y, decrDims.width,
+ decrDims.height);
+ incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width, tabAreaRect.y,
+ incrDims.width, incrDims.height);
+ }
+ else
+ {
+ // Align scroll buttons with the top border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width - decrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - decrDims.height, decrDims.width,
+ decrDims.height);
+ incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height,
+ incrDims.width, incrDims.height);
+ }
+
tabAreaRect.width -= decrDims.width + incrDims.width;
+
+ updateButtons();
+
incrButton.setVisible(true);
decrButton.setVisible(true);
}
+ else
+ {
+ incrButton.setVisible(false);
+ decrButton.setVisible(false);
+
+ currentScrollOffset = 0;
+ currentScrollLocation = 0;
+ }
}
if (tabPlacement == SwingConstants.LEFT
@@ -1147,34 +1393,54 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Dimension incrDims = incrButton.getPreferredSize();
Dimension decrDims = decrButton.getPreferredSize();
- decrButton.setBounds(tabAreaRect.x,
- tabAreaRect.y + tabAreaRect.height
- - incrDims.height - decrDims.height,
- tabAreaRect.width, decrDims.height);
- incrButton.setBounds(tabAreaRect.x,
- tabAreaRect.y + tabAreaRect.height
- - incrDims.height, tabAreaRect.width,
- incrDims.height);
+ if (tabPlacement == SwingConstants.RIGHT)
+ {
+ // Align scroll buttons with the right border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height - decrDims.height,
+ decrDims.width, decrDims.height);
+ incrButton.setBounds(tabAreaRect.x,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height, incrDims.width,
+ incrDims.height);
+ }
+ else
+ {
+ // Align scroll buttons with the left border of the tabbed
+ // pane's content area.
+ decrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - decrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height - decrDims.height,
+ decrDims.width, decrDims.height);
+ incrButton.setBounds(tabAreaRect.x + tabAreaRect.width
+ - incrDims.width,
+ tabAreaRect.y + tabAreaRect.height
+ - incrDims.height, incrDims.width,
+ incrDims.height);
+ }
tabAreaRect.height -= decrDims.height + incrDims.height;
+
incrButton.setVisible(true);
decrButton.setVisible(true);
}
+ else
+ {
+ incrButton.setVisible(false);
+ decrButton.setVisible(false);
+
+ currentScrollOffset = 0;
+ currentScrollLocation = 0;
+ }
}
viewport.setBounds(tabAreaRect.x, tabAreaRect.y, tabAreaRect.width,
tabAreaRect.height);
- int tabC = tabPane.getTabCount() - 1;
- if (tabCount > 0)
- {
- int w = Math.max(rects[tabC].width + rects[tabC].x, tabAreaRect.width);
- int h = Math.max(rects[tabC].height, tabAreaRect.height);
- p = findPointForIndex(currentScrollLocation);
-
- // we want to cover that entire space so that borders that run under
- // the tab area don't show up when we move the viewport around.
- panel.setSize(w + p.x, h + p.y);
- }
- viewport.setViewPosition(p);
+
+ updateViewPosition();
+
viewport.repaint();
}
}
@@ -1198,7 +1464,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
selectedRun = getRunForTab(tabPane.getTabCount(),
tabPane.getSelectedIndex());
- tabPane.revalidate();
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+ tabPane.revalidate();
tabPane.repaint();
}
}
@@ -1224,7 +1492,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public void paint(Graphics g, JComponent c)
{
- paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
+ int placement = tabPane.getTabPlacement();
+ g.setColor(highlight);
+ if (placement == SwingUtilities.TOP
+ || placement == SwingUtilities.BOTTOM)
+ g.fillRect(currentScrollOffset, 0,
+ tabAreaRect.width, tabAreaRect.height);
+ else
+ g.fillRect(0, currentScrollOffset,
+ tabAreaRect.width, tabAreaRect.height);
+
+ paintTabArea(g, placement, tabPane.getSelectedIndex());
}
}
@@ -1285,6 +1563,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
/** The starting visible tab in the run in SCROLL_TAB_MODE.
* This is package-private to avoid an accessor method. */
transient int currentScrollLocation;
+
+ transient int currentScrollOffset;
/** A reusable rectangle. */
protected Rectangle calcRect;
@@ -1340,16 +1620,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
/** The gap between text and label */
protected int textIconGap;
- // Keeps track of tab runs.
- // The organization of this array is as follows (lots of experimentation to
- // figure this out)
- // index 0 = furthest away from the component area (aka outer run)
- // index 1 = closest to component area (aka selected run)
- // index > 1 = listed in order leading from selected run to outer run.
- // each int in the array is the tab index + 1 (counting starts at 1)
- // for the last tab in the run. (same as the rects array)
-
- /** This array keeps track of which tabs are in which run. See above. */
+ /** This array keeps track of which tabs are in which run.
+ * <p>The value at index i denotes the index of the first tab in run i.</p>
+ * <p>If the value for any index (i > 0) is 0 then (i - 1) is the last
+ * run.</p>
+ */
protected int[] tabRuns;
/**
@@ -1428,7 +1703,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
* The currently visible component.
*/
private Component visibleComponent;
-
+
+ private Color selectedColor;
+
+ private Rectangle tempTextRect = new Rectangle();
+
+ private Rectangle tempIconRect = new Rectangle();
+
/**
* Creates a new BasicTabbedPaneUI object.
*/
@@ -1517,8 +1798,115 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Point p = new Point(w, h);
return p;
}
+
+ /** TabbedPanes in scrolling mode should use this method to
+ * scroll properly to the tab given by the index argument.
+ *
+ * @param index The tab to scroll to.
+ * @param placement The tab's placement.
+ */
+ final void scrollTab(int index, int placement)
+ {
+ int diff;
+ if (index >= 0 && tabPane.isEnabledAt(index))
+ {
+ // If the user clicked on the last tab and that one was
+ // only partially visible shift the scroll offset to make
+ // it completely visible.
+ switch (placement)
+ {
+ case JTabbedPane.TOP:
+ case JTabbedPane.BOTTOM:
+ if ((diff = rects[index].x
+ + rects[index].width
+ - decrButton.getX() - currentScrollOffset) > 0)
+ currentScrollOffset += diff;
+ else if ((diff = rects[index].x - currentScrollOffset) < 0)
+ {
+ if (index == 0)
+ currentScrollOffset = 0;
+ else
+ currentScrollOffset += diff;
+ }
+
+ currentScrollLocation = tabForCoordinate(tabPane,
+ currentScrollOffset,
+ rects[index].y);
+ break;
+ default:
+ if ((diff = rects[index].y + rects[index].height
+ - decrButton.getY() - currentScrollOffset) > 0)
+ currentScrollOffset += diff;
+ else if ((diff = rects[index].y - currentScrollOffset) < 0)
+ {
+ if (index == 0)
+ currentScrollOffset = 0;
+ else
+ currentScrollOffset += diff;
+ }
+
+ currentScrollLocation = tabForCoordinate(tabPane,
+ rects[index].x,
+ currentScrollOffset);
+ }
+
+ updateViewPosition();
+ updateButtons();
+ }
+ }
+
+ /** Sets the enabled state of the increase and decrease button
+ * according to the current scrolling offset and tab pane width
+ * (or height in TOP/BOTTOM placement).
+ */
+ final void updateButtons()
+ {
+ int tc = tabPane.getTabCount();
+
+ // The increase button should be enabled as long as the
+ // right/bottom border of the last tab is under the left/top
+ // border of the decrease button.
+ switch (tabPane.getTabPlacement())
+ {
+ case JTabbedPane.BOTTOM:
+ case JTabbedPane.TOP:
+ incrButton.setEnabled(currentScrollLocation + 1 < tc
+ && rects[tc-1].x + rects[tc-1].width
+ - currentScrollOffset > decrButton.getX());
+ break;
+ default:
+ incrButton.setEnabled(currentScrollLocation + 1 < tc
+ && rects[tc-1].y + rects[tc-1].height
+ - currentScrollOffset > decrButton.getY());
+ }
+
+ // The decrease button is enabled when the tab pane is scrolled in any way.
+ decrButton.setEnabled(currentScrollOffset > 0);
+
+ }
/**
+ * Updates the position of the scrolling viewport's view
+ * according to the current scroll offset.
+ */
+ final void updateViewPosition()
+ {
+ Point p = viewport.getViewPosition();
+
+ switch (tabPane.getTabPlacement())
+ {
+ case JTabbedPane.LEFT:
+ case JTabbedPane.RIGHT:
+ p.y = currentScrollOffset;
+ break;
+ default:
+ p.x = currentScrollOffset;
+ }
+
+ viewport.setViewPosition(p);
+ }
+
+ /**
* This method creates a new BasicTabbedPaneUI.
*
* @param c The JComponent to create a UI for.
@@ -1583,22 +1971,30 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
return new TabbedPaneLayout();
else
{
+ runCount = 1;
+ tabRuns[0] = 0;
+
incrButton = createIncreaseButton();
+ incrButton.addMouseListener(mouseListener);
+
decrButton = createDecreaseButton();
- viewport = new ScrollingViewport();
- viewport.setLayout(null);
+ decrButton.addMouseListener(mouseListener);
+ decrButton.setEnabled(false);
+
panel = new ScrollingPanel();
+ panel.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ panel.addMouseListener(mouseListener);
+ panel.addFocusListener(focusListener);
+
+ viewport = new ScrollingViewport();
+ viewport.setBackground(Color.LIGHT_GRAY);
viewport.setView(panel);
+ viewport.setLayout(null);
+
tabPane.add(incrButton);
tabPane.add(decrButton);
tabPane.add(viewport);
- currentScrollLocation = 0;
- decrButton.setEnabled(false);
- panel.addMouseListener(mouseListener);
- incrButton.addMouseListener(mouseListener);
- decrButton.addMouseListener(mouseListener);
- viewport.setBackground(Color.LIGHT_GRAY);
-
+
return new TabbedPaneScrollLayout();
}
}
@@ -1616,7 +2012,14 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void uninstallComponents()
{
- // Nothing to be done.
+ if (incrButton != null)
+ tabPane.remove(incrButton);
+
+ if (decrButton != null)
+ tabPane.remove(decrButton);
+
+ if (viewport != null)
+ tabPane.remove(viewport);
}
/**
@@ -1629,8 +2032,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
"TabbedPane.font");
tabPane.setOpaque(false);
- highlight = UIManager.getColor("TabbedPane.highlight");
- lightHighlight = UIManager.getColor("TabbedPane.lightHighlight");
+ lightHighlight = UIManager.getColor("TabbedPane.highlight");
+ highlight = UIManager.getColor("TabbedPane.light");
shadow = UIManager.getColor("TabbedPane.shadow");
darkShadow = UIManager.getColor("TabbedPane.darkShadow");
@@ -1641,10 +2044,18 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabRunOverlay = UIManager.getInt("TabbedPane.tabRunOverlay");
tabInsets = UIManager.getInsets("TabbedPane.tabInsets");
- selectedTabPadInsets = UIManager.getInsets("TabbedPane.tabbedPaneTabPadInsets");
+ selectedTabPadInsets
+ = UIManager.getInsets("TabbedPane.selectedTabPadInsets");
tabAreaInsets = UIManager.getInsets("TabbedPane.tabAreaInsets");
- contentBorderInsets = UIManager.getInsets("TabbedPane.tabbedPaneContentBorderInsets");
+ contentBorderInsets
+ = UIManager.getInsets("TabbedPane.contentBorderInsets");
tabsOpaque = UIManager.getBoolean("TabbedPane.tabsOpaque");
+
+ // Although 'TabbedPane.contentAreaColor' is not defined in the defaults
+ // of BasicLookAndFeel it is used by this class.
+ selectedColor = UIManager.getColor("TabbedPane.contentAreaColor");
+ if (selectedColor == null)
+ selectedColor = UIManager.getColor("control");
calcRect = new Rectangle();
tabRuns = new int[10];
@@ -1661,6 +2072,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabAreaRect = null;
contentRect = null;
tabRuns = null;
+
+ tempIconRect = null;
+ tempTextRect = null;
contentBorderInsets = null;
tabAreaInsets = null;
@@ -1672,11 +2086,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
shadow = null;
lightHighlight = null;
highlight = null;
-
- // Install UI colors and fonts.
- LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
- "TabbedPane.foreground",
- "TabbedPane.font");
+
+ selectedColor = null;
}
/**
@@ -1704,6 +2115,18 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
tabPane.removePropertyChangeListener(propertyChangeListener);
tabPane.removeChangeListener(tabChangeListener);
tabPane.removeMouseListener(mouseListener);
+
+ if (incrButton != null)
+ incrButton.removeMouseListener(mouseListener);
+
+ if (decrButton != null)
+ decrButton.removeMouseListener(mouseListener);
+
+ if (panel != null)
+ {
+ panel.removeMouseListener(mouseListener);
+ panel.removeFocusListener(focusListener);
+ }
focusListener = null;
propertyChangeListener = null;
@@ -1755,18 +2178,31 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
* This method installs keyboard actions for the JTabbedPane.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Implement.
+ InputMap keyMap = (InputMap) UIManager.get("TabbedPane.focusInputMap");
+ SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, keyMap);
+
+ keyMap = (InputMap) UIManager.get("TabbedPane.ancestorInputMap");
+ SwingUtilities
+ .replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ keyMap);
+
+ ActionMap map = getActionMap();
+ SwingUtilities.replaceUIActionMap(tabPane, map);
}
/**
* This method uninstalls keyboard actions for the JTabbedPane.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: Implement.
+ SwingUtilities.replaceUIActionMap(tabPane, null);
+ SwingUtilities.replaceUIInputMap(tabPane, JComponent.WHEN_FOCUSED, null);
+ SwingUtilities
+ .replaceUIInputMap(tabPane,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ null);
}
/**
@@ -1806,9 +2242,25 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
if (tabPane.getTabCount() == 0)
return;
+
+ int index = tabPane.getSelectedIndex();
+ if (index < 0)
+ index = 0;
+
+ int tabPlacement = tabPane.getTabPlacement();
+
+ // Paint the tab area only in WRAP_TAB_LAYOUT Mode from this method
+ // because it is done through the ScrollingViewport.paint() method
+ // for the SCROLL_TAB_LAYOUT mode.
if (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
- paintTabArea(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
- paintContentBorder(g, tabPane.getTabPlacement(), tabPane.getSelectedIndex());
+ {
+ g.setColor(highlight);
+ g.fillRect(tabAreaRect.x, tabAreaRect.y,
+ tabAreaRect.width, tabAreaRect.height);
+ paintTabArea(g, tabPlacement, index);
+ }
+
+ paintContentBorder(g, tabPlacement, index);
}
/**
@@ -1821,14 +2273,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex)
{
- Rectangle ir = new Rectangle();
- Rectangle tr = new Rectangle();
-
- boolean isScroll = tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT;
-
// Please note: the ordering of the painting is important.
// we WANT to paint the outermost run first and then work our way in.
+
+ // The following drawing code works for both tab layouts.
int tabCount = tabPane.getTabCount();
+
for (int i = runCount - 1; i >= 0; --i)
{
int start = tabRuns[i];
@@ -1842,14 +2292,16 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
if (j != selectedIndex)
{
- paintTab(g, tabPlacement, rects, j, ir, tr);
+ paintTab(g, tabPlacement, rects, j,
+ tempIconRect, tempTextRect);
}
}
}
-
+
// Paint selected tab in front of every other tab.
if (selectedIndex >= 0)
- paintTab(g, tabPlacement, rects, selectedIndex, ir, tr);
+ paintTab(g, tabPlacement, rects, selectedIndex,
+ tempIconRect, tempTextRect);
}
/**
@@ -1889,8 +2341,10 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// Paint the text.
paintText(g, tabPlacement, tabPane.getFont(), fm, tabIndex, title,
textRect, isSelected);
+
// Paint icon if necessary.
paintIcon(g, tabPlacement, tabIndex, icon, iconRect, isSelected);
+
// Paint focus indicator.
paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect,
isSelected);
@@ -2030,8 +2484,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int getTabLabelShiftX(int tabPlacement, int tabIndex,
boolean isSelected)
{
- // No reason to shift.
- return 0;
+ switch (tabPlacement)
+ {
+ default:
+ case SwingUtilities.TOP:
+ case SwingUtilities.BOTTOM:
+ return 1;
+ case SwingUtilities.LEFT:
+ return (isSelected) ? -1 : 1;
+ case SwingUtilities.RIGHT:
+ return (isSelected) ? 1 : -1;
+ }
}
/**
@@ -2047,8 +2510,17 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int getTabLabelShiftY(int tabPlacement, int tabIndex,
boolean isSelected)
{
- // No reason to shift.
- return 0;
+ switch (tabPlacement)
+ {
+ default:
+ case SwingUtilities.TOP:
+ return (isSelected) ? -1 : 1;
+ case SwingUtilities.BOTTOM:
+ return (isSelected) ? 1 : -1;
+ case SwingUtilities.LEFT:
+ case SwingUtilities.RIGHT:
+ return 0;
+ }
}
/**
@@ -2078,32 +2550,33 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
g.setColor(focus);
switch (tabPlacement)
- {
- case LEFT:
- x = rect.x + 3;
- y = rect.y + 3;
- w = rect.width - 5;
- h = rect.height - 6;
- break;
- case RIGHT:
- x = rect.x + 2;
- y = rect.y + 3;
- w = rect.width - 6;
- h = rect.height - 5;
- break;
- case BOTTOM:
- x = rect.x + 3;
- y = rect.y + 2;
- w = rect.width - 6;
- h = rect.height - 5;
- break;
- case TOP:
- default:
- x = rect.x + 3;
- y = rect.y + 3;
- w = rect.width - 6;
- h = rect.height - 5;
- }
+ {
+ case LEFT:
+ x = rect.x + 3;
+ y = rect.y + 3;
+ w = rect.width - 5;
+ h = rect.height - 6;
+ break;
+ case RIGHT:
+ x = rect.x + 2;
+ y = rect.y + 3;
+ w = rect.width - 6;
+ h = rect.height - 5;
+ break;
+ case BOTTOM:
+ x = rect.x + 3;
+ y = rect.y + 2;
+ w = rect.width - 6;
+ h = rect.height - 5;
+ break;
+ case TOP:
+ default:
+ x = rect.x + 3;
+ y = rect.y + 3;
+ w = rect.width - 6;
+ h = rect.height - 5;
+ }
+
BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
}
}
@@ -2125,34 +2598,109 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
Color saved = g.getColor();
- if (! isSelected || tabPlacement != SwingConstants.TOP)
- {
+ switch (tabPlacement)
+ {
+ case SwingConstants.TOP:
g.setColor(shadow);
- g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
- g.setColor(darkShadow);
- g.drawLine(x, y + h, x + w, y + h);
- }
+ // Inner right line.
+ g.drawLine(x + w - 2, y + 2, x + w - 2, y + h);
- if (! isSelected || tabPlacement != SwingConstants.LEFT)
- {
g.setColor(darkShadow);
- g.drawLine(x + w, y, x + w, y + h);
+ // Outer right line.
+ g.drawLine(x + w - 1, y + 2, x + w - 1, y + h);
+
+ // Upper right corner.
+ g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
+
+ g.setColor(lightHighlight);
+
+ // Left line.
+ g.drawLine(x, y + 3, x, y + h);
+
+ // Upper line.
+ g.drawLine(x + 3, y, x + w - 3, y);
+
+ // Upper left corner.
+ g.drawLine(x, y + 2, x + 2, y);
+
+ break;
+ case SwingConstants.LEFT:
+ g.setColor(lightHighlight);
+ // Top line.
+ g.drawLine(x + 3, y, x + w - 1, y);
+
+ // Top left border.
+ g.drawLine(x + 2, y, x, y + 2);
+
+ // Left line.
+ g.drawLine(x, y + 3, x, y + h - 4);
+
+ // Bottom left corner.
+ g.drawLine(x, y + h - 3, x + 1, y + h - 2);
+
+ g.setColor(darkShadow);
+ // Outer bottom line.
+ g.drawLine(x + 2, y + h - 1, x + w - 1, y + h - 1);
+
g.setColor(shadow);
- g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
- }
+ // Inner bottom line.
+ g.drawLine(x + 2, y + h - 2, x + w - 1, y + h - 2);
+
+ break;
+ case SwingConstants.BOTTOM:
+ g.setColor(shadow);
+ // Inner right line.
+ g.drawLine(x + w - 2, y, x + w - 2, y + h - 2);
- if (! isSelected || tabPlacement != SwingConstants.RIGHT)
- {
- g.setColor(lightHighlight);
- g.drawLine(x, y, x, y + h);
- }
+ // Inner bottom line.
+ g.drawLine(x + 2, y + h - 1, x + w - 3, y + h - 1);
- if (! isSelected || tabPlacement != SwingConstants.BOTTOM)
- {
+ g.setColor(darkShadow);
+ // Outer right line.
+ g.drawLine(x + w - 1, y, x + w - 1, y + h - 3);
+
+ // Bottom right corner.
+ g.drawLine(x + w - 1, y + h - 2, x + w - 3, y + h);
+
+ // Bottom line.
+ g.drawLine(x + 2, y + h, x + w - 4, y + h);
+
g.setColor(lightHighlight);
- g.drawLine(x, y, x + w, y);
- }
-
+ // Left line.
+ g.drawLine(x, y, x, y + h - 3);
+
+ // Bottom left corner.
+ g.drawLine(x, y + h - 2, x + 1, y + h - 1);
+ break;
+ case SwingConstants.RIGHT:
+ g.setColor(lightHighlight);
+ // Top line.
+ g.drawLine(x, y, x + w - 3, y);
+
+ g.setColor(darkShadow);
+ // Top right corner.
+ g.drawLine(x + w - 2, y + 1, x + w - 1, y + 2);
+
+ // Outer right line.
+ g.drawLine(x + w - 1, y + 3, x + w - 1, y + h - 3);
+
+ // Bottom right corner.
+ g.drawLine(x + w - 2, y + h - 2, x + w - 3, y + h - 1);
+
+ // Bottom line.
+ g.drawLine(x, y + h - 1, x + w - 4, y + h - 1);
+
+ g.setColor(shadow);
+
+ // Inner right line.
+ g.drawLine(x + w - 2, y + 2, x + w - 2, y + h - 3);
+
+ // Inner bottom line.
+ g.drawLine(x, y + h - 2, x + w - 3, y + h - 2);
+
+ break;
+ }
+
g.setColor(saved);
}
@@ -2173,17 +2721,32 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
boolean isSelected)
{
Color saved = g.getColor();
+
if (isSelected)
- g.setColor(Color.LIGHT_GRAY);
+ g.setColor(selectedColor);
else
{
Color bg = tabPane.getBackgroundAt(tabIndex);
if (bg == null)
- bg = Color.GRAY;
+ bg = Color.LIGHT_GRAY;
g.setColor(bg);
}
- g.fillRect(x, y, w, h);
+ switch (tabPlacement)
+ {
+ case SwingConstants.TOP:
+ g.fillRect(x + 1, y + 1, w - 1, h - 1);
+ break;
+ case SwingConstants.BOTTOM:
+ g.fillRect(x, y, w - 1, h - 1);
+ break;
+ case SwingConstants.LEFT:
+ g.fillRect(x + 1, y + 1, w - 1, h - 2);
+ break;
+ case SwingConstants.RIGHT:
+ g.fillRect(x, y + 1, w - 1, h - 2);
+ break;
+ }
g.setColor(saved);
}
@@ -2260,25 +2823,27 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Color saved = g.getColor();
g.setColor(lightHighlight);
- int startgap = rects[selectedIndex].x;
- int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
-
- int diff = 0;
+ int startgap = rects[selectedIndex].x - currentScrollOffset;
+ int endgap = rects[selectedIndex].x + rects[selectedIndex].width
+ - currentScrollOffset;
- if (tabPlacement == SwingConstants.TOP)
+ // Paint the highlight line with a gap if the tabs are at the top
+ // and the selected tab is inside the visible area.
+ if (tabPlacement == SwingConstants.TOP && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.x;
- }
-
- g.drawLine(x, y, startgap - diff, y);
- g.drawLine(endgap - diff, y, x + w, y);
+ g.drawLine(x, y, startgap, y);
+ g.drawLine(endgap, y, x + w - 1, y);
+
+ g.setColor(selectedColor);
+ g.drawLine(startgap, y, endgap - 1, y);
}
else
g.drawLine(x, y, x + w, y);
-
+
+ g.setColor(selectedColor);
+ g.drawLine(x, y + 1, x + w - 1, y + 1);
+ g.drawLine(x, y + 2, x + w - 1, y + 2);
+
g.setColor(saved);
}
@@ -2300,24 +2865,25 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
Color saved = g.getColor();
g.setColor(lightHighlight);
- int startgap = rects[selectedIndex].y;
- int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
+ int startgap = rects[selectedIndex].y - currentScrollOffset;
+ int endgap = rects[selectedIndex].y + rects[selectedIndex].height
+ - currentScrollOffset;
int diff = 0;
- if (tabPlacement == SwingConstants.LEFT)
+ if (tabPlacement == SwingConstants.LEFT && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.y;
- }
-
- g.drawLine(x, y, x, startgap - diff);
- g.drawLine(x, endgap - diff, x, y + h);
+ g.drawLine(x, y, x, startgap);
+ g.drawLine(x, endgap, x, y + h - 1);
+
+ g.setColor(selectedColor);
+ g.drawLine(x, startgap, x, endgap - 1);
}
else
- g.drawLine(x, y, x, y + h);
+ g.drawLine(x, y, x, y + h - 1);
+
+ g.setColor(selectedColor);
+ g.drawLine(x + 1, y + 1, x + 1, y + h - 4);
g.setColor(saved);
}
@@ -2339,34 +2905,34 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
Color saved = g.getColor();
- int startgap = rects[selectedIndex].x;
- int endgap = rects[selectedIndex].x + rects[selectedIndex].width;
-
- int diff = 0;
+ int startgap = rects[selectedIndex].x - currentScrollOffset;
+ int endgap = rects[selectedIndex].x + rects[selectedIndex].width
+ - currentScrollOffset;
- if (tabPlacement == SwingConstants.BOTTOM)
+ if (tabPlacement == SwingConstants.BOTTOM && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.x;
- }
-
g.setColor(shadow);
- g.drawLine(x + 1, y + h - 1, startgap - diff, y + h - 1);
- g.drawLine(endgap - diff, y + h - 1, x + w - 1, y + h - 1);
+ g.drawLine(x + 1, y + h - 2, startgap, y + h - 2);
+ g.drawLine(endgap, y + h - 2, x + w - 2, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x, y + h, startgap - diff, y + h);
- g.drawLine(endgap - diff, y + h, x + w, y + h);
+ g.drawLine(x, y + h - 1, startgap , y + h - 1);
+ g.drawLine(endgap, y + h - 1, x + w - 1, y + h - 1);
+
+ g.setColor(selectedColor);
+ g.drawLine(startgap, y + h - 1, endgap - 1, y + h - 1);
+ g.drawLine(startgap, y + h - 2, endgap - 1, y + h - 2);
}
else
{
g.setColor(shadow);
- g.drawLine(x + 1, y + h - 1, x + w - 1, y + h - 1);
+ g.drawLine(x + 1, y + h - 2, x + w - 1, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x, y + h, x + w, y + h);
+ g.drawLine(x, y + h - 1, x + w - 1, y + h - 1);
}
+
+ g.setColor(selectedColor);
+ g.drawLine(x + 1, y + h - 3, x + w - 2, y + h - 3);
g.setColor(saved);
}
@@ -2387,34 +2953,36 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int w, int h)
{
Color saved = g.getColor();
- int startgap = rects[selectedIndex].y;
- int endgap = rects[selectedIndex].y + rects[selectedIndex].height;
+ int startgap = rects[selectedIndex].y - currentScrollOffset;
+ int endgap = rects[selectedIndex].y + rects[selectedIndex].height
+ - currentScrollOffset;
int diff = 0;
- if (tabPlacement == SwingConstants.RIGHT)
+ if (tabPlacement == SwingConstants.RIGHT && startgap >= 0)
{
- if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
- {
- Point p = findPointForIndex(currentScrollLocation);
- diff = p.y;
- }
-
g.setColor(shadow);
- g.drawLine(x + w - 1, y + 1, x + w - 1, startgap - diff);
- g.drawLine(x + w - 1, endgap - diff, x + w - 1, y + h - 1);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, startgap);
+ g.drawLine(x + w - 2, endgap, x + w - 2, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x + w, y, x + w, startgap - diff);
- g.drawLine(x + w, endgap - diff, x + w, y + h);
+ g.drawLine(x + w - 1, y, x + w - 1, startgap);
+ g.drawLine(x + w - 1, endgap, x + w - 1, y + h - 2);
+
+ g.setColor(selectedColor);
+ g.drawLine(x + w - 2, startgap, x + w - 2, endgap - 1);
+ g.drawLine(x + w - 1, startgap, x + w - 1, endgap - 1);
}
else
{
g.setColor(shadow);
- g.drawLine(x + w - 1, y + 1, x + w - 1, y + h - 1);
+ g.drawLine(x + w - 2, y + 1, x + w - 2, y + h - 2);
g.setColor(darkShadow);
- g.drawLine(x + w, y, x + w, y + h);
+ g.drawLine(x + w - 1, y, x + w - 1, y + h - 2);
}
+
+ g.setColor(selectedColor);
+ g.drawLine(x + w - 3, y + 1, x + w - 3, y + h - 4);
g.setColor(saved);
}
@@ -2458,11 +3026,15 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
public int tabForCoordinate(JTabbedPane pane, int x, int y)
{
+ // Note: This code is tab layout mode agnostic.
if (! tabPane.isValid())
tabPane.validate();
-
+
int tabCount = tabPane.getTabCount();
- int index = -1;
+
+ // If the user clicked outside of any tab rect the
+ // selection should not change.
+ int index = tabPane.getSelectedIndex();
for (int i = 0; i < tabCount; ++i)
{
if (rects[i].contains(x, y))
@@ -2472,8 +3044,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
}
}
- // FIXME: Handle scrollable tab layout.
-
return index;
}
@@ -2569,7 +3139,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int getRunForTab(int tabCount, int tabIndex)
{
if (runCount == 1 && tabIndex < tabCount && tabIndex >= 0)
- return 1;
+ return 0;
for (int i = 0; i < runCount; i++)
{
int first = lastTabInRun(tabCount, getPreviousTabRun(i)) + 1;
@@ -2688,6 +3258,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected View getTextViewForTab(int tabIndex)
{
+ // FIXME: When the label contains HTML this should return something
+ // non-null.
return null;
}
@@ -2704,7 +3276,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
protected int calculateTabHeight(int tabPlacement, int tabIndex,
int fontHeight)
{
- // FIXME: Handle HTML somehow.
+ // FIXME: Handle HTML by using the view (see getTextViewForTab).
int height = fontHeight;
Icon icon = getIconForTab(tabIndex);
@@ -2921,8 +3493,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
tabPane.getSelectedIndex(),
- (tabPlacement == SwingConstants.RIGHT)
- ? true : false);
+ (tabPlacement == SwingConstants.TOP)
+ ? direction == SwingConstants.NORTH
+ : direction == SwingConstants.SOUTH);
selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
offset);
}
@@ -2938,8 +3511,9 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
int offset = getTabRunOffset(tabPlacement, tabPane.getTabCount(),
tabPane.getSelectedIndex(),
- (tabPlacement == SwingConstants.RIGHT)
- ? true : false);
+ (tabPlacement == SwingConstants.LEFT)
+ ? direction == SwingConstants.WEST
+ : direction == SwingConstants.EAST);
selectAdjacentRunTab(tabPlacement, tabPane.getSelectedIndex(),
offset);
}
@@ -2953,8 +3527,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectNextTabInRun(int current)
{
- tabPane.setSelectedIndex(getNextTabIndexInRun(tabPane.getTabCount(),
- current));
+ current = getNextTabIndexInRun(tabPane.getTabCount(),
+ current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -2964,8 +3543,13 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectPreviousTabInRun(int current)
{
- tabPane.setSelectedIndex(getPreviousTabIndexInRun(tabPane.getTabCount(),
- current));
+ current = getPreviousTabIndexInRun(tabPane.getTabCount(),
+ current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -2975,7 +3559,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectNextTab(int current)
{
- tabPane.setSelectedIndex(getNextTabIndex(current));
+ current = getNextTabIndex(current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -2985,7 +3574,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
*/
protected void selectPreviousTab(int current)
{
- tabPane.setSelectedIndex(getPreviousTabIndex(current));
+ current = getPreviousTabIndex(current);
+
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(current, tabPane.getTabPlacement());
+
+ tabPane.setSelectedIndex(current);
}
/**
@@ -3019,7 +3613,11 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int index = tabForCoordinate(tabPane, x, y);
if (index != -1)
- tabPane.setSelectedIndex(index);
+ {
+ if (tabPane.getTabLayoutPolicy() == JTabbedPane.SCROLL_TAB_LAYOUT)
+ scrollTab(index, tabPlacement);
+ tabPane.setSelectedIndex(index);
+ }
}
// This method is called when you press up/down to cycle through tab runs.
@@ -3056,6 +3654,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
else
offset = rects[lastTabInRun(tabCount, nextRun)].x
- rects[lastTabInRun(tabCount, currRun)].x;
+
return offset;
}
@@ -3102,9 +3701,12 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
{
int index = getNextTabIndex(base);
int run = getRunForTab(tabCount, base);
- if (index == lastTabInRun(tabCount, run) + 1)
- index = lastTabInRun(tabCount, getPreviousTabRun(run)) + 1;
- return getNextTabIndex(base);
+ if (base == lastTabInRun(tabCount, run))
+ index = (run > 0)
+ ? lastTabInRun(tabCount, getPreviousTabRun(run)) + 1
+ : 0;
+
+ return index;
}
/**
@@ -3122,7 +3724,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
int run = getRunForTab(tabCount, base);
if (index == lastTabInRun(tabCount, getPreviousTabRun(run)))
index = lastTabInRun(tabCount, run);
- return getPreviousTabIndex(base);
+
+ return index;
}
/**
@@ -3180,6 +3783,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
// so I won't check it either.
switch (targetPlacement)
{
+ default:
case SwingConstants.TOP:
targetInsets.top = topInsets.top;
targetInsets.left = topInsets.left;
@@ -3206,6 +3810,44 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants
break;
}
}
+
+ ActionMap getActionMap()
+ {
+ ActionMap map = (ActionMap) UIManager.get("TabbedPane.actionMap");
+
+ if (map == null) // first time here
+ {
+ map = createActionMap();
+ if (map != null)
+ UIManager.put("TabbedPane.actionMap", map);
+ }
+ return map;
+ }
+
+ ActionMap createActionMap()
+ {
+ ActionMap map = new ActionMapUIResource();
+
+ map.put("navigatePageDown", new NavigatePageDownAction());
+ map.put("navigatePageUp", new NavigatePageUpAction());
+ map.put("navigateDown",
+ new NavigateAction("navigateDown", SwingConstants.SOUTH));
+
+ map.put("navigateUp",
+ new NavigateAction("navigateUp", SwingConstants.NORTH));
+
+ map.put("navigateLeft",
+ new NavigateAction("navigateLeft", SwingConstants.WEST));
+
+ map.put("navigateRight",
+ new NavigateAction("navigateRight", SwingConstants.EAST));
+
+ map.put("requestFocusForVisibleComponent",
+ new RequestFocusForVisibleComponentAction());
+ map.put("requestFocus", new RequestFocusAction());
+
+ return map;
+ }
/**
* Sets the tab which should be highlighted when in rollover mode. And
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
index cdd44a711e7..15be4d57e62 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.Color;
import java.awt.Component;
import java.awt.ComponentOrientation;
@@ -48,7 +46,6 @@ import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
@@ -58,6 +55,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractAction;
+import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.CellRendererPane;
import javax.swing.DefaultCellEditor;
@@ -65,16 +63,16 @@ import javax.swing.DefaultListSelectionModel;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JTable;
-import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
+import javax.swing.SwingUtilities;
+import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.ChangeEvent;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
-import javax.swing.plaf.InputMapUIResource;
import javax.swing.plaf.TableUI;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
@@ -164,14 +162,37 @@ public class BasicTableUI extends TableUI
public class FocusHandler implements FocusListener
{
- public void focusGained(FocusEvent e)
+ public void focusGained(FocusEvent e)
{
- // TODO: Implement this properly.
+ // The only thing that is affected by a focus change seems to be
+ // how the lead cell is painted. So we repaint this cell.
+ repaintLeadCell();
}
- public void focusLost(FocusEvent e)
+ public void focusLost(FocusEvent e)
+ {
+ // The only thing that is affected by a focus change seems to be
+ // how the lead cell is painted. So we repaint this cell.
+ repaintLeadCell();
+ }
+
+ /**
+ * Repaints the lead cell in response to a focus change, to refresh
+ * the display of the focus indicator.
+ */
+ private void repaintLeadCell()
{
- // TODO: Implement this properly.
+ int rowCount = table.getRowCount();
+ int columnCount = table.getColumnCount();
+ int rowLead = table.getSelectionModel().getLeadSelectionIndex();
+ int columnLead = table.getColumnModel().getSelectionModel().
+ getLeadSelectionIndex();
+ if (rowLead >= 0 && rowLead < rowCount && columnLead >= 0
+ && columnLead < columnCount)
+ {
+ Rectangle dirtyRect = table.getCellRect(rowLead, columnLead, false);
+ table.repaint(dirtyRect);
+ }
}
}
@@ -242,19 +263,19 @@ public class BasicTableUI extends TableUI
}
}
- public void mouseEntered(MouseEvent e)
+ public void mouseEntered(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
- public void mouseExited(MouseEvent e)
+ public void mouseExited(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
- public void mouseMoved(MouseEvent e)
+ public void mouseMoved(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
public void mousePressed(MouseEvent e)
@@ -287,6 +308,9 @@ public class BasicTableUI extends TableUI
colLead != colModel.getLeadSelectionIndex())
if (table.isEditing())
table.editingStopped(new ChangeEvent(e));
+
+ // Must request focus explicitly.
+ table.requestFocusInWindow();
}
}
@@ -456,66 +480,100 @@ public class BasicTableUI extends TableUI
table.setOpaque(true);
}
+ /**
+ * Installs keyboard actions on the table.
+ */
protected void installKeyboardActions()
{
- InputMap ancestorMap = (InputMap) UIManager.get("Table.ancestorInputMap");
- InputMapUIResource parentInputMap = new InputMapUIResource();
- // FIXME: The JDK uses a LazyActionMap for parentActionMap
- ActionMap parentActionMap = new ActionMapUIResource();
- action = new TableAction();
- Object keys[] = ancestorMap.allKeys();
- // Register key bindings in the UI InputMap-ActionMap pair
- for (int i = 0; i < keys.length; i++)
- {
- KeyStroke stroke = (KeyStroke) keys[i];
- String actionString = (String) ancestorMap.get(stroke);
+ // Install the input map.
+ InputMap inputMap =
+ (InputMap) SharedUIDefaults.get("Table.ancestorInputMap");
+ SwingUtilities.replaceUIInputMap(table,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ inputMap);
- parentInputMap.put(KeyStroke.getKeyStroke(stroke.getKeyCode(),
- stroke.getModifiers()),
- actionString);
-
- parentActionMap.put(actionString,
- new ActionListenerProxy(action, actionString));
+ // FIXME: The JDK uses a LazyActionMap for parentActionMap
+ SwingUtilities.replaceUIActionMap(table, getActionMap());
- }
- // Set the UI InputMap-ActionMap pair to be the parents of the
- // JTable's InputMap-ActionMap pair
- parentInputMap.setParent(table.getInputMap(
- JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent());
- parentActionMap.setParent(table.getActionMap().getParent());
- table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).
- setParent(parentInputMap);
- table.getActionMap().setParent(parentActionMap);
}
/**
- * This class is used to mimmic the behaviour of the JDK when registering
- * keyboard actions. It is the same as the private class used in JComponent
- * for the same reason. This class receives an action event and dispatches
- * it to the true receiver after altering the actionCommand property of the
- * event.
+ * Fetches the action map from the UI defaults, or create a new one
+ * if the action map hasn't been initialized.
+ *
+ * @return the action map
*/
- private static class ActionListenerProxy
- extends AbstractAction
+ private ActionMap getActionMap()
{
- ActionListener target;
- String bindingCommandName;
-
- public ActionListenerProxy(ActionListener li,
- String cmd)
- {
- target = li;
- bindingCommandName = cmd;
- }
+ ActionMap am = (ActionMap) UIManager.get("Table.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("Table.actionMap", am);
+ }
+ return am;
+ }
- public void actionPerformed(ActionEvent e)
- {
- ActionEvent derivedEvent = new ActionEvent(e.getSource(),
- e.getID(),
- bindingCommandName,
- e.getModifiers());
- target.actionPerformed(derivedEvent);
- }
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new TableAction();
+
+ am.put("cut", TransferHandler.getCutAction());
+ am.put("copy", TransferHandler.getCopyAction());
+ am.put("paste", TransferHandler.getPasteAction());
+
+ am.put("cancel", action);
+ am.put("selectAll", action);
+ am.put("clearSelection", action);
+ am.put("startEditing", action);
+
+ am.put("selectNextRow", action);
+ am.put("selectNextRowCell", action);
+ am.put("selectNextRowExtendSelection", action);
+ am.put("selectNextRowChangeLead", action);
+
+ am.put("selectPreviousRow", action);
+ am.put("selectPreviousRowCell", action);
+ am.put("selectPreviousRowExtendSelection", action);
+ am.put("selectPreviousRowChangeLead", action);
+
+ am.put("selectNextColumn", action);
+ am.put("selectNextColumnCell", action);
+ am.put("selectNextColumnExtendSelection", action);
+ am.put("selectNextColumnChangeLead", action);
+
+ am.put("selectPreviousColumn", action);
+ am.put("selectPreviousColumnCell", action);
+ am.put("selectPreviousColumnExtendSelection", action);
+ am.put("selectPreviousColumnChangeLead", action);
+
+ am.put("scrollLeftChangeSelection", action);
+ am.put("scrollLeftExtendSelection", action);
+ am.put("scrollRightChangeSelection", action);
+ am.put("scrollRightExtendSelection", action);
+
+ am.put("scrollUpChangeSelection", action);
+ am.put("scrollUpExtendSelection", action);
+ am.put("scrollDownChangeSelection", action);
+ am.put("scrolldownExtendSelection", action);
+
+ am.put("selectFirstColumn", action);
+ am.put("selectFirstColumnExtendSelection", action);
+ am.put("selectLastColumn", action);
+ am.put("selectLastColumnExtendSelection", action);
+
+ am.put("selectFirstRow", action);
+ am.put("selectFirstRowExtendSelection", action);
+ am.put("selectLastRow", action);
+ am.put("selectLastRowExtendSelection", action);
+
+ am.put("addToSelection", action);
+ am.put("toggleAndAnchor", action);
+ am.put("extendTo", action);
+ am.put("moveSelectionTo", action);
+
+ return am;
}
/**
@@ -524,7 +582,8 @@ public class BasicTableUI extends TableUI
* method is called when a key that has been registered for the JTable
* is received.
*/
- class TableAction extends AbstractAction
+ private static class TableAction
+ extends AbstractAction
{
/**
* What to do when this action is called.
@@ -533,6 +592,8 @@ public class BasicTableUI extends TableUI
*/
public void actionPerformed(ActionEvent e)
{
+ JTable table = (JTable) e.getSource();
+
DefaultListSelectionModel rowModel
= (DefaultListSelectionModel) table.getSelectionModel();
DefaultListSelectionModel colModel
@@ -543,9 +604,11 @@ public class BasicTableUI extends TableUI
int colLead = colModel.getLeadSelectionIndex();
int colMax = table.getModel().getColumnCount() - 1;
-
- String command = e.getActionCommand();
-
+
+ // The command with which the action has been called is stored
+ // in this undocumented action value. This allows us to have only
+ // one Action instance to serve all keyboard input for JTable.
+ String command = (String) getValue("__command__");
if (command.equals("selectPreviousRowExtendSelection"))
{
rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0));
@@ -603,11 +666,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollUpExtendSelection"))
{
int target;
- if (rowLead == getFirstVisibleRowIndex())
- target = Math.max(0, rowLead - (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getFirstVisibleRowIndex(table))
+ target = Math.max(0, rowLead - (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getFirstVisibleRowIndex();
+ target = getFirstVisibleRowIndex(table);
rowModel.setLeadSelectionIndex(target);
colModel.setLeadSelectionIndex(colLead);
@@ -620,11 +683,12 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollRightChangeSelection"))
{
int target;
- if (colLead == getLastVisibleColumnIndex())
- target = Math.min(colMax, colLead + (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getLastVisibleColumnIndex(table))
+ target = Math.min(colMax, colLead
+ + (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getLastVisibleColumnIndex();
+ target = getLastVisibleColumnIndex(table);
colModel.setSelectionInterval(target, target);
rowModel.setSelectionInterval(rowLead, rowLead);
@@ -637,11 +701,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollLeftChangeSelection"))
{
int target;
- if (colLead == getFirstVisibleColumnIndex())
- target = Math.max(0, colLead - (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getFirstVisibleColumnIndex(table))
+ target = Math.max(0, colLead - (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getFirstVisibleColumnIndex();
+ target = getFirstVisibleColumnIndex(table);
colModel.setSelectionInterval(target, target);
rowModel.setSelectionInterval(rowLead, rowLead);
@@ -723,14 +787,18 @@ public class BasicTableUI extends TableUI
// If there are multiple rows and columns selected, select the next
// cell and wrap at the edges of the selection.
if (command.indexOf("Column") != -1)
- advanceMultipleSelection(colModel, colMinSelected, colMaxSelected,
- rowModel, rowMinSelected, rowMaxSelected,
- command.equals("selectPreviousColumnCell"), true);
+ advanceMultipleSelection(table, colModel, colMinSelected,
+ colMaxSelected, rowModel, rowMinSelected,
+ rowMaxSelected,
+ command.equals("selectPreviousColumnCell"),
+ true);
else
- advanceMultipleSelection(rowModel, rowMinSelected, rowMaxSelected,
- colModel, colMinSelected, colMaxSelected,
- command.equals("selectPreviousRowCell"), false);
+ advanceMultipleSelection(table, rowModel, rowMinSelected,
+ rowMaxSelected, colModel, colMinSelected,
+ colMaxSelected,
+ command.equals("selectPreviousRowCell"),
+ false);
}
else if (command.equals("selectNextColumn"))
{
@@ -740,11 +808,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollLeftExtendSelection"))
{
int target;
- if (colLead == getFirstVisibleColumnIndex())
- target = Math.max(0, colLead - (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getFirstVisibleColumnIndex(table))
+ target = Math.max(0, colLead - (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getFirstVisibleColumnIndex();
+ target = getFirstVisibleColumnIndex(table);
colModel.setLeadSelectionIndex(target);
rowModel.setLeadSelectionIndex(rowLead);
@@ -752,11 +820,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollDownChangeSelection"))
{
int target;
- if (rowLead == getLastVisibleRowIndex())
- target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getLastVisibleRowIndex(table))
+ target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getLastVisibleRowIndex();
+ target = getLastVisibleRowIndex(table);
rowModel.setSelectionInterval(target, target);
colModel.setSelectionInterval(colLead, colLead);
@@ -764,11 +832,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollRightExtendSelection"))
{
int target;
- if (colLead == getLastVisibleColumnIndex())
- target = Math.min(colMax, colLead + (getLastVisibleColumnIndex()
- - getFirstVisibleColumnIndex() + 1));
+ if (colLead == getLastVisibleColumnIndex(table))
+ target = Math.min(colMax, colLead + (getLastVisibleColumnIndex(table)
+ - getFirstVisibleColumnIndex(table) + 1));
else
- target = getLastVisibleColumnIndex();
+ target = getLastVisibleColumnIndex(table);
colModel.setLeadSelectionIndex(target);
rowModel.setLeadSelectionIndex(rowLead);
@@ -785,11 +853,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollDownExtendSelection"))
{
int target;
- if (rowLead == getLastVisibleRowIndex())
- target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getLastVisibleRowIndex(table))
+ target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getLastVisibleRowIndex();
+ target = getLastVisibleRowIndex(table);
rowModel.setLeadSelectionIndex(target);
colModel.setLeadSelectionIndex(colLead);
@@ -797,11 +865,11 @@ public class BasicTableUI extends TableUI
else if (command.equals("scrollUpChangeSelection"))
{
int target;
- if (rowLead == getFirstVisibleRowIndex())
- target = Math.max(0, rowLead - (getLastVisibleRowIndex()
- - getFirstVisibleRowIndex() + 1));
+ if (rowLead == getFirstVisibleRowIndex(table))
+ target = Math.max(0, rowLead - (getLastVisibleRowIndex(table)
+ - getFirstVisibleRowIndex(table) + 1));
else
- target = getFirstVisibleRowIndex();
+ target = getFirstVisibleRowIndex(table);
rowModel.setSelectionInterval(target, target);
colModel.setSelectionInterval(colLead, colLead);
@@ -926,7 +994,7 @@ public class BasicTableUI extends TableUI
* Returns the column index of the first visible column.
* @return the column index of the first visible column.
*/
- int getFirstVisibleColumnIndex()
+ int getFirstVisibleColumnIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -939,7 +1007,7 @@ public class BasicTableUI extends TableUI
* Returns the column index of the last visible column.
*
*/
- int getLastVisibleColumnIndex()
+ int getLastVisibleColumnIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -952,7 +1020,7 @@ public class BasicTableUI extends TableUI
* Returns the row index of the first visible row.
*
*/
- int getFirstVisibleRowIndex()
+ int getFirstVisibleRowIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -965,7 +1033,7 @@ public class BasicTableUI extends TableUI
* Returns the row index of the last visible row.
*
*/
- int getLastVisibleRowIndex()
+ int getLastVisibleRowIndex(JTable table)
{
ComponentOrientation or = table.getComponentOrientation();
Rectangle r = table.getVisibleRect();
@@ -977,7 +1045,7 @@ public class BasicTableUI extends TableUI
// area is larger than the table)
if (table.rowAtPoint(r.getLocation()) == -1)
{
- if (getFirstVisibleRowIndex() == -1)
+ if (getFirstVisibleRowIndex(table) == -1)
return -1;
else
return table.getModel().getRowCount() - 1;
@@ -1003,7 +1071,8 @@ public class BasicTableUI extends TableUI
* @param reverse true if shift was held for the event
* @param eventIsTab true if TAB was pressed, false if ENTER pressed
*/
- void advanceMultipleSelection(ListSelectionModel firstModel, int firstMin,
+ void advanceMultipleSelection(JTable table, ListSelectionModel firstModel,
+ int firstMin,
int firstMax, ListSelectionModel secondModel,
int secondMin, int secondMax, boolean reverse,
boolean eventIsTab)
@@ -1167,30 +1236,24 @@ public class BasicTableUI extends TableUI
table.addPropertyChangeListener(propertyChangeListener);
}
- protected void uninstallDefaults()
+ /**
+ * Uninstalls UI defaults that have been installed by
+ * {@link #installDefaults()}.
+ */
+ protected void uninstallDefaults()
{
- // TODO: this method used to do the following which is not
- // quite right (at least it breaks apps that run fine with the
- // JDK):
- //
- // table.setFont(null);
- // table.setGridColor(null);
- // table.setForeground(null);
- // table.setBackground(null);
- // table.setSelectionForeground(null);
- // table.setSelectionBackground(null);
- //
- // This would leave the component in a corrupt state, which is
- // not acceptable. A possible solution would be to have component
- // level defaults installed, that get overridden by the UI defaults
- // and get restored in this method. I am not quite sure about this
- // though. / Roman Kennke
+ // Nothing to do here for now.
}
- protected void uninstallKeyboardActions()
- throws NotImplementedException
+ /**
+ * Uninstalls the keyboard actions that have been installed by
+ * {@link #installKeyboardActions()}.
+ */
+ protected void uninstallKeyboardActions()
{
- // TODO: Implement this properly.
+ SwingUtilities.replaceUIInputMap(table, JComponent.
+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities.replaceUIActionMap(table, null);
}
protected void uninstallListeners()
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
index 89c4e5a7562..6792aa065da 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextFieldUI.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.Color;
import java.beans.PropertyChangeEvent;
import javax.swing.JComponent;
@@ -94,12 +95,24 @@ public class BasicTextFieldUI extends BasicTextUI
{
if (event.getPropertyName().equals("editable"))
{
- boolean editable = ((Boolean) event.getNewValue()).booleanValue();
-
// Changing the color only if the current background is an instance of
// ColorUIResource is the behavior of the RI.
if (textComponent.getBackground() instanceof ColorUIResource)
- textComponent.setBackground(editable ? background : inactiveBackground);
+ {
+ Color c = null;
+ Color old = textComponent.getBackground();
+ String prefix = getPropertyPrefix();
+ if (! textComponent.isEnabled())
+ c = SharedUIDefaults.getColor(prefix + ".disabledBackground");
+ if (c == null && ! textComponent.isEditable())
+ c = SharedUIDefaults.getColor(prefix + ".inactiveBackground");
+ if (c == null)
+ c = SharedUIDefaults.getColor(prefix + ".background");
+ if (c != null && c != old)
+ {
+ textComponent.setBackground(c);
+ }
+ }
}
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
index 34261cfe644..8e9c8c949f3 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java
@@ -83,7 +83,6 @@ import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.Position;
-import javax.swing.text.Utilities;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
@@ -418,7 +417,19 @@ public abstract class BasicTextUI extends TextUI
if (event.getPropertyName().equals("document"))
{
// Document changed.
- modelChanged();
+ Object oldValue = event.getOldValue();
+ if (oldValue != null)
+ {
+ Document oldDoc = (Document) oldValue;
+ oldDoc.removeDocumentListener(documentHandler);
+ }
+ Object newValue = event.getNewValue();
+ if (newValue != null)
+ {
+ Document newDoc = (Document) newValue;
+ newDoc.addDocumentListener(documentHandler);
+ }
+ modelChanged();
}
BasicTextUI.this.propertyChange(event);
@@ -501,18 +512,6 @@ public abstract class BasicTextUI extends TextUI
DocumentHandler documentHandler = new DocumentHandler();
/**
- * The standard background color. This is the color which is used to paint
- * text in enabled text components.
- */
- Color background;
-
- /**
- * The inactive background color. This is the color which is used to paint
- * text in disabled text components.
- */
- Color inactiveBackground;
-
- /**
* Creates a new <code>BasicTextUI</code> instance.
*/
public BasicTextUI()
@@ -558,22 +557,23 @@ public abstract class BasicTextUI extends TextUI
*/
public void installUI(final JComponent c)
{
- super.installUI(c);
-
textComponent = (JTextComponent) c;
+ installDefaults();
+ textComponent.addPropertyChangeListener(updateHandler);
Document doc = textComponent.getDocument();
if (doc == null)
{
doc = getEditorKit(textComponent).createDefaultDocument();
textComponent.setDocument(doc);
}
- installDefaults();
+ else
+ {
+ doc.addDocumentListener(documentHandler);
+ modelChanged();
+ }
+
installListeners();
installKeyboardActions();
-
- // We need to trigger this so that the view hierarchy gets initialized.
- modelChanged();
-
}
/**
@@ -581,34 +581,60 @@ public abstract class BasicTextUI extends TextUI
*/
protected void installDefaults()
{
+ String prefix = getPropertyPrefix();
+ // Install the standard properties.
+ LookAndFeel.installColorsAndFont(textComponent, prefix + ".background",
+ prefix + ".foreground", prefix + ".font");
+ LookAndFeel.installBorder(textComponent, prefix + ".border");
+ textComponent.setMargin(UIManager.getInsets(prefix + ".margin"));
+
+ // Some additional text component only properties.
+ Color color = textComponent.getCaretColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".caretForeground");
+ textComponent.setCaretColor(color);
+ }
+
+ // Fetch the colors for enabled/disabled text components.
+ color = textComponent.getDisabledTextColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".inactiveBackground");
+ textComponent.setDisabledTextColor(color);
+ }
+ color = textComponent.getSelectedTextColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".selectionForeground");
+ textComponent.setSelectedTextColor(color);
+ }
+ color = textComponent.getSelectionColor();
+ if (color == null || color instanceof UIResource)
+ {
+ color = UIManager.getColor(prefix + ".selectionBackground");
+ textComponent.setSelectionColor(color);
+ }
+
+ Insets margin = textComponent.getMargin();
+ if (margin == null || margin instanceof UIResource)
+ {
+ margin = UIManager.getInsets(prefix + ".margin");
+ textComponent.setMargin(margin);
+ }
+
Caret caret = textComponent.getCaret();
- if (caret == null)
+ if (caret == null || caret instanceof UIResource)
{
caret = createCaret();
textComponent.setCaret(caret);
+ caret.setBlinkRate(UIManager.getInt(prefix + ".caretBlinkRate"));
}
Highlighter highlighter = textComponent.getHighlighter();
- if (highlighter == null)
+ if (highlighter == null || highlighter instanceof UIResource)
textComponent.setHighlighter(createHighlighter());
- String prefix = getPropertyPrefix();
- LookAndFeel.installColorsAndFont(textComponent, prefix + ".background",
- prefix + ".foreground", prefix + ".font");
- LookAndFeel.installBorder(textComponent, prefix + ".border");
- textComponent.setMargin(UIManager.getInsets(prefix + ".margin"));
-
- caret.setBlinkRate(UIManager.getInt(prefix + ".caretBlinkRate"));
-
- // Fetch the colors for enabled/disabled text components.
- background = UIManager.getColor(prefix + ".background");
- inactiveBackground = UIManager.getColor(prefix + ".inactiveBackground");
- textComponent.setDisabledTextColor(UIManager.getColor(prefix
- + ".inactiveForeground"));
- textComponent.setSelectedTextColor(UIManager.getColor(prefix
- + ".selectionForeground"));
- textComponent.setSelectionColor(UIManager.getColor(prefix
- + ".selectionBackground"));
}
/**
@@ -670,18 +696,6 @@ public abstract class BasicTextUI extends TextUI
protected void installListeners()
{
textComponent.addFocusListener(focuslistener);
- textComponent.addPropertyChangeListener(updateHandler);
- installDocumentListeners();
- }
-
- /**
- * Installs the document listeners on the textComponent's model.
- */
- private void installDocumentListeners()
- {
- Document doc = textComponent.getDocument();
- if (doc != null)
- doc.addDocumentListener(documentHandler);
}
/**
@@ -845,9 +859,7 @@ public abstract class BasicTextUI extends TextUI
*/
protected void uninstallListeners()
{
- textComponent.removePropertyChangeListener(updateHandler);
textComponent.removeFocusListener(focuslistener);
- textComponent.getDocument().removeDocumentListener(documentHandler);
}
/**
@@ -1029,7 +1041,7 @@ public abstract class BasicTextUI extends TextUI
*/
public void damageRange(JTextComponent t, int p0, int p1)
{
- damageRange(t, p0, p1, null, null);
+ damageRange(t, p0, p1, Position.Bias.Forward, Position.Bias.Backward);
}
/**
@@ -1049,106 +1061,36 @@ public abstract class BasicTextUI extends TextUI
public void damageRange(JTextComponent t, int p0, int p1,
Position.Bias firstBias, Position.Bias secondBias)
{
- // Do nothing if the component cannot be properly displayed.
- if (t.getWidth() == 0 || t.getHeight() == 0)
- return;
-
- try
+ Rectangle alloc = getVisibleEditorRect();
+ if (alloc != null)
{
- // Limit p0 and p1 to sane values to prevent unfriendly
- // BadLocationExceptions. This makes it possible for the highlighter
- // to send us illegal values which can happen when a large number
- // of selected characters are removed (eg. by pressing delete
- // or backspace).
- // The reference implementation does not throw an exception, too.
- p0 = Math.min(p0, t.getDocument().getLength());
- p1 = Math.min(p1, t.getDocument().getLength());
-
- Rectangle l1 = modelToView(t, p0, firstBias);
- Rectangle l2 = modelToView(t, p1, secondBias);
- if (l1 == null || l2 == null)
+ Document doc = t.getDocument();
+
+ // Acquire lock here to avoid structural changes in between.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ try
{
- // Unable to determine the start or end of the selection.
- t.repaint();
+ rootView.setSize(alloc.width, alloc.height);
+ Shape damage = rootView.modelToView(p0, firstBias, p1, secondBias,
+ alloc);
+ Rectangle r = damage instanceof Rectangle ? (Rectangle) damage
+ : damage.getBounds();
+ textComponent.repaint(r.x, r.y, r.width, r.height);
}
- else if (l1.y == l2.y)
+ catch (BadLocationException ex)
{
- SwingUtilities.computeUnion(l2.x, l2.y, l2.width, l2.height, l1);
- t.repaint(l1);
+ // Lets ignore this as it causes no serious problems.
+ // For debugging, comment this out.
+ // ex.printStackTrace();
}
- else
+ finally
{
- // The two rectangles lie on different lines and we need a
- // different algorithm to calculate the damaged area:
- // 1. The line of p0 is damaged from the position of p0
- // to the right border.
- // 2. All lines between the ones where p0 and p1 lie on
- // are completely damaged. Use the allocation area to find
- // out the bounds.
- // 3. The final line is damaged from the left bound to the
- // position of p1.
- Insets insets = t.getInsets();
-
- // Damage first line until the end.
- l1.width = insets.right + t.getWidth() - l1.x;
- t.repaint(l1);
-
- // Note: Utilities.getPositionBelow() may return the offset
- // that was put in. In that case there is no next line and
- // we should stop searching for one.
-
- int posBelow = Utilities.getPositionBelow(t, p0, l1.x);
- int p1RowStart = Utilities.getRowStart(t, p1);
-
- if (posBelow != -1
- && posBelow != p0
- && Utilities.getRowStart(t, posBelow) != p1RowStart)
- {
- // Take the rectangle of the offset we just found and grow it
- // to the maximum width. Retain y because this is our start
- // height.
- Rectangle grow = modelToView(t, posBelow);
- grow.x = insets.left;
- grow.width = t.getWidth() + insets.right;
-
- // Find further lines which have to be damaged completely.
- int nextPosBelow = posBelow;
- while (nextPosBelow != -1
- && posBelow != nextPosBelow
- && Utilities.getRowStart(t, nextPosBelow) != p1RowStart)
- {
- posBelow = nextPosBelow;
- nextPosBelow = Utilities.getPositionBelow(t, posBelow,
- l1.x);
-
- if (posBelow == nextPosBelow)
- break;
- }
- // Now posBelow is an offset on the last line which has to be
- // damaged completely. (newPosBelow is on the same line as p1)
-
- // Retrieve the rectangle of posBelow and use its y and height
- // value to calculate the final height of the multiple line
- // spanning rectangle.
- Rectangle end = modelToView(t, posBelow);
- grow.height = end.y + end.height - grow.y;
-
- // Mark that area as damage.
- t.repaint(grow);
- }
-
- // Damage last line from its beginning to the position of p1.
- l2.width += l2.x;
- l2.x = insets.left;
- t.repaint(l2);
+ // Release lock.
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
}
}
- catch (BadLocationException ex)
- {
- AssertionError err = new AssertionError("Unexpected bad location");
- err.initCause(ex);
- throw err;
- }
}
/**
@@ -1245,10 +1187,29 @@ public abstract class BasicTextUI extends TextUI
public Rectangle modelToView(JTextComponent t, int pos, Position.Bias bias)
throws BadLocationException
{
- Rectangle r = getVisibleEditorRect();
-
- return (r != null) ? rootView.modelToView(pos, r, bias).getBounds()
- : null;
+ // We need to read-lock here because we depend on the document
+ // structure not beeing changed in between.
+ Document doc = textComponent.getDocument();
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readLock();
+ Rectangle rect = null;
+ try
+ {
+ Rectangle r = getVisibleEditorRect();
+ if (r != null)
+ {
+ rootView.setSize(r.width, r.height);
+ Shape s = rootView.modelToView(pos, r, bias);
+ if (s != null)
+ rect = s.getBounds();
+ }
+ }
+ finally
+ {
+ if (doc instanceof AbstractDocument)
+ ((AbstractDocument) doc).readUnlock();
+ }
+ return rect;
}
/**
@@ -1361,7 +1322,6 @@ public abstract class BasicTextUI extends TextUI
Document doc = textComponent.getDocument();
if (doc == null)
return;
- installDocumentListeners();
Element elem = doc.getDefaultRootElement();
if (elem == null)
return;
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
index 8fce2f08a66..1c36b408d5a 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicToolBarUI.java
@@ -38,8 +38,6 @@ exception statement from your version. */
package javax.swing.plaf.basic;
-import gnu.classpath.NotImplementedException;
-
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -50,6 +48,7 @@ import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
+import java.awt.event.ActionEvent;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.FocusEvent;
@@ -62,7 +61,11 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Hashtable;
+import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
@@ -77,6 +80,7 @@ import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.event.MouseInputListener;
+import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.ToolBarUI;
import javax.swing.plaf.UIResource;
@@ -87,6 +91,35 @@ import javax.swing.plaf.basic.BasicBorders.ButtonBorder;
*/
public class BasicToolBarUI extends ToolBarUI implements SwingConstants
{
+
+ /**
+ * Implements the keyboard actions for JToolBar.
+ */
+ static class ToolBarAction
+ extends AbstractAction
+ {
+ /**
+ * Performs the action.
+ */
+ public void actionPerformed(ActionEvent event)
+ {
+ Object cmd = getValue("__command__");
+ JToolBar toolBar = (JToolBar) event.getSource();
+ BasicToolBarUI ui = (BasicToolBarUI) toolBar.getUI();
+
+ if (cmd.equals("navigateRight"))
+ ui.navigateFocusedComp(EAST);
+ else if (cmd.equals("navigateLeft"))
+ ui.navigateFocusedComp(WEST);
+ else if (cmd.equals("navigateUp"))
+ ui.navigateFocusedComp(NORTH);
+ else if (cmd.equals("navigateDown"))
+ ui.navigateFocusedComp(SOUTH);
+ else
+ assert false : "Shouldn't reach here";
+ }
+ }
+
/** Static owner of all DragWindows.
* This is package-private to avoid an accessor method. */
static JFrame owner = new JFrame();
@@ -619,9 +652,46 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* by the look and feel.
*/
protected void installKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ // Install the input map.
+ InputMap inputMap =
+ (InputMap) SharedUIDefaults.get("ToolBar.ancestorInputMap");
+ SwingUtilities.replaceUIInputMap(toolBar,
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
+ inputMap);
+
+ // FIXME: The JDK uses a LazyActionMap for parentActionMap
+ SwingUtilities.replaceUIActionMap(toolBar, getActionMap());
+ }
+
+ /**
+ * Fetches the action map from the UI defaults, or create a new one
+ * if the action map hasn't been initialized.
+ *
+ * @return the action map
+ */
+ private ActionMap getActionMap()
+ {
+ ActionMap am = (ActionMap) UIManager.get("ToolBar.actionMap");
+ if (am == null)
+ {
+ am = createDefaultActions();
+ UIManager.getLookAndFeelDefaults().put("ToolBar.actionMap", am);
+ }
+ return am;
+ }
+
+ private ActionMap createDefaultActions()
+ {
+ ActionMapUIResource am = new ActionMapUIResource();
+ Action action = new ToolBarAction();
+
+ am.put("navigateLeft", action);
+ am.put("navigateRight", action);
+ am.put("navigateUp", action);
+ am.put("navigateDown", action);
+
+ return am;
}
/**
@@ -643,7 +713,12 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
floatFrame.addWindowListener(windowListener);
toolBarFocusListener = createToolBarFocusListener();
- toolBar.addFocusListener(toolBarFocusListener);
+ if (toolBarFocusListener != null)
+ {
+ int count = toolBar.getComponentCount();
+ for (int i = 0; i < count; i++)
+ toolBar.getComponent(i).addFocusListener(toolBarFocusListener);
+ }
}
/**
@@ -758,9 +833,55 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* @param direction The direction to give focus to.
*/
protected void navigateFocusedComp(int direction)
- throws NotImplementedException
{
- // FIXME: Implement.
+ int count = toolBar.getComponentCount();
+ switch (direction)
+ {
+ case EAST:
+ case SOUTH:
+ if (focusedCompIndex >= 0 && focusedCompIndex < count)
+ {
+ int i = focusedCompIndex + 1;
+ boolean focusRequested = false;
+ // Find component to focus and request focus on it.
+ while (i != focusedCompIndex && ! focusRequested)
+ {
+ if (i >= count)
+ i = 0;
+ Component comp = toolBar.getComponentAtIndex(i++);
+ if (comp != null && comp.isFocusable()
+ && comp.isEnabled())
+ {
+ comp.requestFocus();
+ focusRequested = true;
+ }
+ }
+ }
+ break;
+ case WEST:
+ case NORTH:
+ if (focusedCompIndex >= 0 && focusedCompIndex < count)
+ {
+ int i = focusedCompIndex - 1;
+ boolean focusRequested = false;
+ // Find component to focus and request focus on it.
+ while (i != focusedCompIndex && ! focusRequested)
+ {
+ if (i < 0)
+ i = count - 1;
+ Component comp = toolBar.getComponentAtIndex(i--);
+ if (comp != null && comp.isFocusable()
+ && comp.isEnabled())
+ {
+ comp.requestFocus();
+ focusRequested = true;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
}
/**
@@ -925,9 +1046,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
* This method uninstalls keyboard actions installed by the UI.
*/
protected void uninstallKeyboardActions()
- throws NotImplementedException
{
- // FIXME: implement.
+ SwingUtilities.replaceUIInputMap(toolBar, JComponent.
+ WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
+ SwingUtilities.replaceUIActionMap(toolBar, null);
}
/**
@@ -935,8 +1057,13 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
protected void uninstallListeners()
{
- toolBar.removeFocusListener(toolBarFocusListener);
- toolBarFocusListener = null;
+ if (toolBarFocusListener != null)
+ {
+ int count = toolBar.getComponentCount();
+ for (int i = 0; i < count; i++)
+ toolBar.getComponent(i).removeFocusListener(toolBarFocusListener);
+ toolBarFocusListener = null;
+ }
floatFrame.removeWindowListener(windowListener);
windowListener = null;
@@ -998,7 +1125,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseClicked(MouseEvent e)
{
- // Don't care.
+ // Nothing to do here.
}
/**
@@ -1020,7 +1147,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseEntered(MouseEvent e)
{
- // Don't care (yet).
+ // Nothing to do here.
}
/**
@@ -1030,7 +1157,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseExited(MouseEvent e)
{
- // Don't care (yet).
+ // Nothing to do here.
}
/**
@@ -1040,7 +1167,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
public void mouseMoved(MouseEvent e)
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -1203,13 +1330,17 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
}
/**
- * FIXME: Do something.
+ * Sets the orientation of the toolbar and the
+ * drag window.
*
- * @param o DOCUMENT ME!
+ * @param o - the new orientation of the toolbar and drag
+ * window.
*/
public void setOrientation(int o)
{
- // FIXME: implement.
+ toolBar.setOrientation(o);
+ if (dragWindow != null)
+ dragWindow.setOrientation(o);
}
}
@@ -1290,6 +1421,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
cachedBounds = toolBar.getPreferredSize();
cachedOrientation = toolBar.getOrientation();
+
+ Component c = e.getChild();
+ if (toolBarFocusListener != null)
+ c.addFocusListener(toolBarFocusListener);
}
/**
@@ -1303,6 +1438,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
setBorderToNormal(e.getChild());
cachedBounds = toolBar.getPreferredSize();
cachedOrientation = toolBar.getOrientation();
+
+ Component c = e.getChild();
+ if (toolBarFocusListener != null)
+ c.removeFocusListener(toolBarFocusListener);
}
}
@@ -1332,27 +1471,30 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants
*/
protected ToolBarFocusListener()
{
- // FIXME: implement.
+ // Nothing to do here.
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Receives notification when the toolbar or one of it's component
+ * receives the keyboard input focus.
+ *
+ * @param e the focus event
*/
public void focusGained(FocusEvent e)
{
- // FIXME: implement.
+ Component c = e.getComponent();
+ focusedCompIndex = toolBar.getComponentIndex(c);
}
/**
- * DOCUMENT ME!
- *
- * @param e DOCUMENT ME!
+ * Receives notification when the toolbar or one of it's component
+ * looses the keyboard input focus.
+ *
+ * @param e the focus event
*/
public void focusLost(FocusEvent e)
{
- // FIXME: implement.
+ // Do nothing here.
}
}
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
index 4c139fe465b..9a193986ac5 100644
--- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
+++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java
@@ -174,6 +174,9 @@ public class BasicTreeUI
/**
* Set to false when editing and shouldSelectCall() returns true meaning the
* node should be selected before editing, used in completeEditing.
+ * GNU Classpath editing is implemented differently, so this value is not
+ * actually read anywhere. However it is always set correctly to maintain
+ * interoperability with the derived classes that read this field.
*/
protected boolean stopEditingInCompleteEditing;
@@ -235,9 +238,6 @@ public class BasicTreeUI
/** Set to true if the editor has a different size than the renderer. */
protected boolean editorHasDifferentSize;
- /** The action bound to KeyStrokes. */
- TreeAction action;
-
/** Boolean to keep track of editing. */
boolean isEditing;
@@ -474,8 +474,18 @@ public class BasicTreeUI
*/
protected void setCellRenderer(TreeCellRenderer tcr)
{
- currentCellRenderer = tcr;
+ // Finish editing before changing the renderer.
+ completeEditing();
+
+ // The renderer is set in updateRenderer.
updateRenderer();
+
+ // Refresh the layout if necessary.
+ if (treeState != null)
+ {
+ treeState.invalidateSizes();
+ updateSize();
+ }
}
/**
@@ -845,9 +855,9 @@ public class BasicTreeUI
updateRenderer();
updateDepthOffset();
setSelectionModel(tree.getSelectionModel());
- treeState = createLayoutCache();
- treeSelectionModel.setRowMapper(treeState);
configureLayoutCache();
+ treeState.setRootVisible(tree.isRootVisible());
+ treeSelectionModel.setRowMapper(treeState);
updateSize();
}
@@ -1068,7 +1078,6 @@ public class BasicTreeUI
*/
protected void uninstallKeyboardActions()
{
- action = null;
tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
null);
tree.getActionMap().setParent(null);
@@ -1169,10 +1178,26 @@ public class BasicTreeUI
protected void updateRenderer()
{
if (tree != null)
- currentCellRenderer = tree.getCellRenderer();
-
- if (currentCellRenderer == null)
- currentCellRenderer = createDefaultCellRenderer();
+ {
+ TreeCellRenderer rend = tree.getCellRenderer();
+ if (rend != null)
+ {
+ createdRenderer = false;
+ currentCellRenderer = rend;
+ if (createdCellEditor)
+ tree.setCellEditor(null);
+ }
+ else
+ {
+ tree.setCellRenderer(createDefaultCellRenderer());
+ createdRenderer = true;
+ }
+ }
+ else
+ {
+ currentCellRenderer = null;
+ createdRenderer = false;
+ }
updateCellEditor();
}
@@ -1237,6 +1262,11 @@ public class BasicTreeUI
{
LookAndFeel.installColorsAndFont(tree, "Tree.background",
"Tree.foreground", "Tree.font");
+
+ hashColor = UIManager.getColor("Tree.hash");
+ if (hashColor == null)
+ hashColor = Color.black;
+
tree.setOpaque(true);
rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
@@ -1264,8 +1294,6 @@ public class BasicTreeUI
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
ancestorInputMap);
- action = new TreeAction();
-
SwingUtilities.replaceUIActionMap(tree, getActionMap());
}
@@ -1295,9 +1323,6 @@ public class BasicTreeUI
ActionMapUIResource am = new ActionMapUIResource();
Action action;
- action = new TreeAction();
- am.put(action.getValue(Action.NAME), action);
-
// TreeHomeAction.
action = new TreeHomeAction(-1, "selectFirst");
am.put(action.getValue(Action.NAME), action);
@@ -1349,6 +1374,13 @@ public class BasicTreeUI
am.put(action.getValue(Action.NAME), action);
action = new TreePageAction(1, "scrollDownChangeLead");
am.put(action.getValue(Action.NAME), action);
+
+ // Tree editing actions
+ action = new TreeStartEditingAction("startEditing");
+ am.put(action.getValue(Action.NAME), action);
+ action = new TreeCancelEditingAction("cancel");
+ am.put(action.getValue(Action.NAME), action);
+
return am;
}
@@ -1703,9 +1735,10 @@ public class BasicTreeUI
protected void completeEditing(boolean messageStop, boolean messageCancel,
boolean messageTree)
{
- if (! stopEditingInCompleteEditing || editingComponent == null)
+ // Make no attempt to complete the non existing editing session.
+ if (!isEditing(tree))
return;
-
+
if (messageStop)
{
getCellEditor().stopCellEditing();
@@ -1812,14 +1845,25 @@ public class BasicTreeUI
boolean cntlClick = false;
if (! treeModel.isLeaf(path.getLastPathComponent()))
{
- int width = 8; // Only guessing.
+ int width;
Icon expandedIcon = getExpandedIcon();
if (expandedIcon != null)
width = expandedIcon.getIconWidth();
+ else
+ // Only guessing. This is the width of
+ // the tree control icon in Metal L&F.
+ width = 18;
Insets i = tree.getInsets();
- int left = getRowX(tree.getRowForPath(path), path.getPathCount() - 1)
- - getRightChildIndent() - width / 2 + i.left;
+
+ int depth;
+ if (isRootVisible())
+ depth = path.getPathCount()-1;
+ else
+ depth = path.getPathCount()-2;
+
+ int left = getRowX(tree.getRowForPath(path), depth)
+ - width + i.left;
cntlClick = mouseX >= left && mouseX <= left + width;
}
return cntlClick;
@@ -1848,7 +1892,8 @@ public class BasicTreeUI
*/
protected void toggleExpandState(TreePath path)
{
- if (tree.isExpanded(path))
+ // tree.isExpanded(path) would do the same, but treeState knows faster.
+ if (treeState.isExpanded(path))
tree.collapsePath(path);
else
tree.expandPath(path);
@@ -1975,94 +2020,35 @@ public class BasicTreeUI
Object node = pathForRow.getLastPathComponent();
return treeModel.isLeaf(node);
}
-
+
/**
- * This class implements the actions that we want to happen when specific keys
- * are pressed for the JTree. The actionPerformed method is called when a key
- * that has been registered for the JTree is received.
+ * The action to start editing at the current lead selection path.
*/
- class TreeAction
+ class TreeStartEditingAction
extends AbstractAction
{
-
/**
- * What to do when this action is called.
+ * Creates the new tree cancel editing action.
+ *
+ * @param name the name of the action (used in toString).
+ */
+ public TreeStartEditingAction(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Start editing at the current lead selection path.
*
* @param e the ActionEvent that caused this action.
*/
public void actionPerformed(ActionEvent e)
{
- String command = e.getActionCommand();
TreePath lead = tree.getLeadSelectionPath();
-
- if (command.equals("selectPreviousChangeLead")
- || command.equals("selectPreviousExtendSelection")
- || command.equals("selectPrevious") || command.equals("selectNext")
- || command.equals("selectNextExtendSelection")
- || command.equals("selectNextChangeLead"))
- (new TreeIncrementAction(0, "")).actionPerformed(e);
- else if (command.equals("selectParent") || command.equals("selectChild"))
- (new TreeTraverseAction(0, "")).actionPerformed(e);
- else if (command.equals("selectAll"))
- {
- TreePath[] paths = new TreePath[treeState.getRowCount()];
- for (int i = 0; i < paths.length; i++)
- paths[i] = treeState.getPathForRow(i);
- tree.addSelectionPaths(paths);
- }
- else if (command.equals("startEditing"))
+ if (!tree.isEditing())
tree.startEditingAtPath(lead);
- else if (command.equals("toggle"))
- {
- if (tree.isEditing())
- tree.stopEditing();
- else
- {
- Object last = lead.getLastPathComponent();
- TreePath path = new TreePath(getPathToRoot(last, 0));
- if (! treeModel.isLeaf(last))
- toggleExpandState(path);
- }
- }
- else if (command.equals("clearSelection"))
- tree.clearSelection();
-
- if (tree.isEditing() && ! command.equals("startEditing"))
- tree.stopEditing();
-
- tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
- }
-
- /**
- * This class is used to mimic the behaviour of the JDK when registering
- * keyboard actions. It is the same as the private class used in JComponent
- * for the same reason. This class receives an action event and dispatches it
- * to the true receiver after altering the actionCommand property of the
- * event.
- */
- private static class ActionListenerProxy
- extends AbstractAction
- {
- ActionListener target;
-
- String bindingCommandName;
-
- public ActionListenerProxy(ActionListener li, String cmd)
- {
- target = li;
- bindingCommandName = cmd;
- }
-
- public void actionPerformed(ActionEvent e)
- {
- ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
- bindingCommandName,
- e.getModifiers());
-
- target.actionPerformed(derivedEvent);
- }
- }
+ }
/**
* Updates the preferred size when scrolling, if necessary.
@@ -2290,9 +2276,49 @@ public class BasicTreeUI
* @param e the key typed
*/
public void keyTyped(KeyEvent e)
- throws NotImplementedException
{
- // TODO: What should be done here, if anything?
+ char typed = Character.toLowerCase(e.getKeyChar());
+ for (int row = tree.getLeadSelectionRow() + 1;
+ row < tree.getRowCount(); row++)
+ {
+ if (checkMatch(row, typed))
+ {
+ tree.setSelectionRow(row);
+ tree.scrollRowToVisible(row);
+ return;
+ }
+ }
+
+ // Not found below, search above:
+ for (int row = 0; row < tree.getLeadSelectionRow(); row++)
+ {
+ if (checkMatch(row, typed))
+ {
+ tree.setSelectionRow(row);
+ tree.scrollRowToVisible(row);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Check if the given tree row starts with this character
+ *
+ * @param row the tree row
+ * @param typed the typed char, must be converted to lowercase
+ * @return true if the given tree row starts with this character
+ */
+ boolean checkMatch(int row, char typed)
+ {
+ TreePath path = treeState.getPathForRow(row);
+ String node = path.getLastPathComponent().toString();
+ if (node.length() > 0)
+ {
+ char x = node.charAt(0);
+ if (typed == Character.toLowerCase(x))
+ return true;
+ }
+ return false;
}
/**
@@ -2301,9 +2327,8 @@ public class BasicTreeUI
* @param e the key pressed
*/
public void keyPressed(KeyEvent e)
- throws NotImplementedException
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
/**
@@ -2312,9 +2337,8 @@ public class BasicTreeUI
* @param e the key released
*/
public void keyReleased(KeyEvent e)
- throws NotImplementedException
{
- // TODO: What should be done here, if anything?
+ // Nothing to do here.
}
}
@@ -2341,14 +2365,23 @@ public class BasicTreeUI
*/
public void mousePressed(MouseEvent e)
{
+ // Any mouse click cancels the previous waiting edit action, initiated
+ // by the single click on the selected node.
+ if (startEditTimer != null)
+ {
+ startEditTimer.stop();
+ startEditTimer = null;
+ }
if (tree != null && tree.isEnabled())
{
- // Maybe stop editing and return.
- if (isEditing(tree) && tree.getInvokesStopCellEditing()
- && !stopEditing(tree))
- return;
-
+ // Always end the current editing session if clicked on the
+ // tree and outside the bounds of the editing component.
+ if (isEditing(tree))
+ if (!stopEditing(tree))
+ // Return if we have failed to cancel the editing session.
+ return;
+
int x = e.getX();
int y = e.getY();
TreePath path = getClosestPathForLocation(tree, x, y);
@@ -2361,11 +2394,47 @@ public class BasicTreeUI
if (x > bounds.x && x <= (bounds.x + bounds.width))
{
- if (! startEditing(path, e))
- selectPathForEvent(path, e);
+ TreePath currentLead = tree.getLeadSelectionPath();
+ if (currentLead != null && currentLead.equals(path)
+ && e.getClickCount() == 1 && tree.isEditable())
+ {
+ // Schedule the editing session.
+ final TreePath editPath = path;
+
+ // The code below handles the required click-pause-click
+ // functionality which must be present in the tree UI.
+ // If the next click comes after the
+ // time longer than the double click interval AND
+ // the same node stays focused for the WAIT_TILL_EDITING
+ // duration, the timer starts the editing session.
+ if (startEditTimer != null)
+ startEditTimer.stop();
+
+ startEditTimer = new Timer(WAIT_TILL_EDITING,
+ new ActionListener()
+ {
+ public void actionPerformed(ActionEvent e)
+ {
+ startEditing(editPath, EDIT);
+ }
+ });
+
+ startEditTimer.setRepeats(false);
+ startEditTimer.start();
+ }
+ else
+ {
+ if (e.getClickCount() == 2)
+ toggleExpandState(path);
+ else
+ selectPathForEvent(path, e);
+ }
}
}
}
+
+ // We need to request the focus.
+ tree.requestFocusInWindow();
}
/**
@@ -2830,6 +2899,9 @@ public class BasicTreeUI
}
}
}
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
/**
@@ -2945,6 +3017,9 @@ public class BasicTreeUI
tree.setAnchorSelectionPath(newPath);
tree.setLeadSelectionPath(newPath);
}
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
/**
@@ -3249,6 +3324,9 @@ public class BasicTreeUI
// and anchor.
tree.setLeadSelectionPath(leadPath);
tree.setAnchorSelectionPath(anchorPath);
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
}
@@ -3336,6 +3414,9 @@ public class BasicTreeUI
tree.expandPath(current);
}
}
+
+ // Ensure that the lead path is visible after the increment action.
+ tree.scrollPathToVisible(tree.getLeadSelectionPath());
}
/**
@@ -3644,7 +3725,13 @@ public class BasicTreeUI
{
Rectangle bounds = getPathBounds(tree, path);
TreePath parent = path.getParentPath();
- if (parent != null)
+
+ boolean paintLine;
+ if (isRootVisible())
+ paintLine = parent != null;
+ else
+ paintLine = parent != null && parent.getPathCount() > 1;
+ if (paintLine)
{
Rectangle parentBounds = getPathBounds(tree, parent);
paintVerticalLine(g, tree, parentBounds.x + 2 * gap,
diff --git a/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java b/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
index 47876491160..34278052bc1 100644
--- a/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
+++ b/libjava/classpath/javax/swing/plaf/basic/SharedUIDefaults.java
@@ -38,6 +38,7 @@ exception statement from your version. */
package javax.swing.plaf.basic;
+import java.awt.Color;
import java.util.HashMap;
import javax.swing.UIManager;
@@ -75,4 +76,16 @@ public class SharedUIDefaults
}
return o;
}
+
+ /**
+ * Returns a shared UI color.
+ *
+ * @param key the key
+ *
+ * @return the shared color instance
+ */
+ static Color getColor(String key)
+ {
+ return (Color) get(key);
+ }
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java
index 6a528de2b6b..265ea7ef6ae 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalComboBoxButton.java
@@ -259,7 +259,9 @@ public class MetalComboBoxButton
Component comp = renderer.getListCellRendererComponent(listBox,
comboBox.getSelectedItem(), -1, false, false);
comp.setFont(rendererPane.getFont());
- if (model.isArmed() && model.isPressed())
+
+ if ((model.isArmed() && model.isPressed())
+ || (comboBox.isFocusOwner() && !comboBox.isPopupVisible()))
{
if (isOpaque())
{
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
index 1219ad9fd11..824f1d8021b 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
@@ -42,6 +42,7 @@ import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
+import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
@@ -303,8 +304,9 @@ public class MetalFileChooserUI
if (file == null)
setFileName(null);
- else
- setFileName(file.getName());
+ else if (file.isFile() || filechooser.getFileSelectionMode()
+ != JFileChooser.FILES_ONLY)
+ setFileName(file.getName());
int index = -1;
index = getModel().indexOf(file);
if (index >= 0)
@@ -567,10 +569,17 @@ public class MetalFileChooserUI
extends DefaultListCellRenderer
{
/**
+ * This is the icon that is displayed in the combobox. This wraps
+ * the standard icon and adds indendation.
+ */
+ private IndentIcon indentIcon;
+
+ /**
* Creates a new renderer.
*/
public DirectoryComboBoxRenderer(JFileChooser fc)
- {
+ {
+ indentIcon = new IndentIcon();
}
/**
@@ -586,31 +595,86 @@ public class MetalFileChooserUI
* @return The list cell renderer.
*/
public Component getListCellRendererComponent(JList list, Object value,
- int index, boolean isSelected, boolean cellHasFocus)
+ int index,
+ boolean isSelected,
+ boolean cellHasFocus)
{
- FileView fileView = getFileView(getFileChooser());
+ super.getListCellRendererComponent(list, value, index, isSelected,
+ cellHasFocus);
File file = (File) value;
- setIcon(fileView.getIcon(file));
- setText(fileView.getName(file));
-
- if (isSelected)
- {
- setBackground(list.getSelectionBackground());
- setForeground(list.getSelectionForeground());
- }
- else
- {
- setBackground(list.getBackground());
- setForeground(list.getForeground());
- }
+ setText(getFileChooser().getName(file));
+
+ // Install indented icon.
+ Icon icon = getFileChooser().getIcon(file);
+ indentIcon.setIcon(icon);
+ int depth = directoryModel.getDepth(index);
+ indentIcon.setDepth(depth);
+ setIcon(indentIcon);
- setEnabled(list.isEnabled());
- setFont(list.getFont());
return this;
}
}
/**
+ * An icon that wraps another icon and adds indentation.
+ */
+ class IndentIcon
+ implements Icon
+ {
+
+ /**
+ * The indentation level.
+ */
+ private static final int INDENT = 10;
+
+ /**
+ * The wrapped icon.
+ */
+ private Icon icon;
+
+ /**
+ * The current depth.
+ */
+ private int depth;
+
+ /**
+ * Sets the icon to be wrapped.
+ *
+ * @param i the icon
+ */
+ void setIcon(Icon i)
+ {
+ icon = i;
+ }
+
+ /**
+ * Sets the indentation depth.
+ *
+ * @param d the depth to set
+ */
+ void setDepth(int d)
+ {
+ depth = d;
+ }
+
+ public int getIconHeight()
+ {
+ return icon.getIconHeight();
+ }
+
+ public int getIconWidth()
+ {
+ return icon.getIconWidth() + depth * INDENT;
+ }
+
+ public void paintIcon(Component c, Graphics g, int x, int y)
+ {
+ icon.paintIcon(c, g, x + depth * INDENT, y);
+ }
+
+ }
+
+ /**
* A renderer for the files and directories in the file chooser.
*/
protected class FileRenderer
@@ -956,9 +1020,12 @@ public class MetalFileChooserUI
{
String text = editField.getText();
if (text != null && text != "" && !text.equals(fc.getName(editFile)))
- if (editFile.renameTo(fc.getFileSystemView().createFileObject(
- fc.getCurrentDirectory(), text)))
+ {
+ File f = fc.getFileSystemView().
+ createFileObject(fc.getCurrentDirectory(), text);
+ if ( editFile.renameTo(f) )
rescanCurrentDirectory(fc);
+ }
list.remove(editField);
}
startEditing = false;
@@ -982,17 +1049,8 @@ public class MetalFileChooserUI
*/
public void actionPerformed(ActionEvent e)
{
- if (e.getActionCommand().equals("notify-field-accept"))
+ if (editField != null)
completeEditing();
- else if (editField != null)
- {
- list.remove(editField);
- startEditing = false;
- editFile = null;
- lastSelected = null;
- editField = null;
- list.repaint();
- }
}
}
}
@@ -1101,7 +1159,7 @@ public class MetalFileChooserUI
lastSelected = selVal;
if (f.isFile())
setFileName(path.substring(path.lastIndexOf("/") + 1));
- else if (fc.getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY)
+ else if (fc.getFileSelectionMode() != JFileChooser.FILES_ONLY)
setFileName(path);
}
fileTable.repaint();
@@ -1171,16 +1229,8 @@ public class MetalFileChooserUI
*/
public void actionPerformed(ActionEvent e)
{
- if (e.getActionCommand().equals("notify-field-accept"))
+ if (editField != null)
completeEditing();
- else if (editField != null)
- {
- table.remove(editField);
- startEditing = false;
- editFile = null;
- editField = null;
- table.repaint();
- }
}
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java
index a317e3fc00d..30ec7e72b28 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalIconFactory.java
@@ -1,5 +1,5 @@
/* MetalIconFactory.java --
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -54,6 +54,7 @@ import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
+import javax.swing.plaf.IconUIResource;
import javax.swing.plaf.UIResource;
@@ -78,7 +79,8 @@ public class MetalIconFactory implements Serializable
/**
* An icon displayed for {@link JCheckBoxMenuItem} components.
*/
- private static class CheckBoxMenuItemIcon implements Icon, Serializable
+ private static class CheckBoxMenuItemIcon
+ implements Icon, UIResource, Serializable
{
/**
* Creates a new icon instance.
@@ -153,7 +155,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getFileChooserDetailViewIcon()
*/
- private static class FileChooserDetailViewIcon implements Icon, Serializable
+ private static class FileChooserDetailViewIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -233,7 +236,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getFileChooserHomeFolderIcon()
*/
- private static class FileChooserHomeFolderIcon implements Icon, Serializable
+ private static class FileChooserHomeFolderIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -322,7 +326,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getFileChooserListViewIcon()
*/
- private static class FileChooserListViewIcon implements Icon, Serializable
+ private static class FileChooserListViewIcon
+ implements Icon, UIResource, Serializable
{
/**
* Creates a new icon.
@@ -418,7 +423,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getFileChooserNewFolderIcon()
*/
- private static class FileChooserNewFolderIcon implements Icon, Serializable
+ private static class FileChooserNewFolderIcon
+ implements Icon, UIResource, Serializable
{
/**
* Creates a new icon.
@@ -490,8 +496,7 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getFileChooserNewFolderIcon()
*/
- private static class FileChooserUpFolderIcon extends FileChooserNewFolderIcon
- implements Icon, Serializable
+ private static class FileChooserUpFolderIcon extends FileChooserNewFolderIcon
{
/**
* Creates a new icon.
@@ -883,7 +888,8 @@ public class MetalIconFactory implements Serializable
/**
* An icon displayed for {@link JRadioButtonMenuItem} components.
*/
- private static class RadioButtonMenuItemIcon implements Icon, Serializable
+ private static class RadioButtonMenuItemIcon
+ implements Icon, UIResource, Serializable
{
/**
* Creates a new icon instance.
@@ -960,7 +966,8 @@ public class MetalIconFactory implements Serializable
* The icon used to display the thumb control on a horizontally oriented
* {@link JSlider} component.
*/
- private static class HorizontalSliderThumbIcon implements Icon, Serializable
+ private static class HorizontalSliderThumbIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -1102,7 +1109,8 @@ public class MetalIconFactory implements Serializable
* An icon used for the 'close' button in the title frame of a
* {@link JInternalFrame}.
*/
- private static class InternalFrameCloseIcon implements Icon, Serializable
+ private static class InternalFrameCloseIcon
+ implements Icon, UIResource, Serializable
{
/** The icon size in pixels. */
private int size;
@@ -1219,7 +1227,7 @@ public class MetalIconFactory implements Serializable
* The icon displayed at the top-left corner of a {@link JInternalFrame}.
*/
private static class InternalFrameDefaultMenuIcon
- implements Icon, Serializable
+ implements Icon, UIResource, Serializable
{
/**
@@ -1291,7 +1299,7 @@ public class MetalIconFactory implements Serializable
* provide a 'restore' option.
*/
private static class InternalFrameAltMaximizeIcon
- implements Icon, Serializable
+ implements Icon, UIResource, Serializable
{
/** The icon size in pixels. */
private int size;
@@ -1401,7 +1409,8 @@ public class MetalIconFactory implements Serializable
* An icon used for the 'maximize' button in the title frame of a
* {@link JInternalFrame}.
*/
- private static class InternalFrameMaximizeIcon implements Icon, Serializable
+ private static class InternalFrameMaximizeIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -1513,7 +1522,8 @@ public class MetalIconFactory implements Serializable
/**
* An icon used in the title frame of a {@link JInternalFrame}.
*/
- private static class InternalFrameMinimizeIcon implements Icon, Serializable
+ private static class InternalFrameMinimizeIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -1617,7 +1627,8 @@ public class MetalIconFactory implements Serializable
* The icon used to display the thumb control on a horizontally oriented
* {@link JSlider} component.
*/
- private static class VerticalSliderThumbIcon implements Icon, Serializable
+ private static class VerticalSliderThumbIcon
+ implements Icon, UIResource, Serializable
{
/**
* This mask is used to paint the gradient in the shape of the thumb.
@@ -1801,78 +1812,36 @@ public class MetalIconFactory implements Serializable
/**
* Paints the icon at the location (x, y).
*
- * @param c the component.
- * @param g the graphics device.
- * @param x the x coordinate.
- * @param y the y coordinate.
+ * @param c the component.
+ * @param g the graphics device.
+ * @param x the x coordinate.
+ * @param y the y coordinate.
*/
- public void paintIcon(Component c, Graphics g, int x, int y)
+ public void paintIcon(Component c, Graphics g, int x, int y)
{
- x = x + 5;
- y = y + 5;
- if (collapsed)
- {
- // TODO: pick up appropriate UI colors
- g.setColor(Color.black);
- g.drawLine(x + 2, y, x + 5, y);
- g.drawLine(x + 6, y + 1, x + 7, y + 2);
- g.fillRect(x + 7, y + 3, 5, 2);
- g.drawLine(x + 7, y + 5, x + 6, y + 6);
- g.drawLine(x + 1, y + 1, x + 1, y + 1);
- g.drawLine(x, y + 2, x, y + 5);
- g.drawLine(x + 1, y + 6, x + 1, y + 6);
- g.drawLine(x + 2, y + 7, x + 5, y + 7);
- g.fillRect(x + 3, y + 3, 2, 2);
-
- g.setColor(new Color(204, 204, 255));
- g.drawLine(x + 3, y + 2, x + 4, y + 2);
- g.drawLine(x + 2, y + 3, x + 2, y + 4);
- g.drawLine(x + 3, y + 5, x + 3, y + 5);
- g.drawLine(x + 5, y + 3, x + 5, y + 3);
-
- g.setColor(new Color(153, 153, 204));
- g.drawLine(x + 2, y + 2, x + 2, y + 2);
- g.drawLine(x + 2, y + 5, x + 2, y + 5);
- g.drawLine(x + 2, y + 6, x + 5, y + 6);
- g.drawLine(x + 5, y + 2, x + 5, y + 2);
- g.drawLine(x + 6, y + 2, x + 6, y + 5);
-
- g.setColor(new Color(102, 102, 153));
- g.drawLine(x + 2, y + 1, x + 5, y + 1);
- g.drawLine(x + 1, y + 2, x + 1, y + 5);
- }
+ // TODO: pick up appropriate UI colors
+ Color dark = new Color(99, 130, 191);
+ Color light = new Color(163, 184, 204);
+ Color white = Color.white;
+
+ x += 8;
+ y += 6;
+
+ final int w = 6;
+ final int wHalf = (w >> 2);
+ g.setColor(light);
+ g.drawOval(x, y, w, w);
+ g.setColor(dark);
+ g.fillOval(x + 1, y + 1, w - 1, w - 1);
+
+ if (collapsed)
+ g.fillRect(x + w, y + wHalf + 1, w, 2);
else
- {
- // TODO: pick up appropriate UI colors
- g.setColor(Color.black);
- g.drawLine(x + 2, y, x + 5, y);
- g.drawLine(x + 6, y + 1, x + 7, y + 2);
- g.drawLine(x + 7, y + 2, x + 7, y + 5);
- g.fillRect(x + 3, y + 7, 2, 5);
- g.drawLine(x + 7, y + 5, x + 6, y + 6);
- g.drawLine(x + 1, y + 1, x + 1, y + 1);
- g.drawLine(x, y + 2, x, y + 5);
- g.drawLine(x + 1, y + 6, x + 1, y + 6);
- g.drawLine(x + 2, y + 7, x + 5, y + 7);
- g.fillRect(x + 3, y + 3, 2, 2);
-
- g.setColor(new Color(204, 204, 255));
- g.drawLine(x + 3, y + 2, x + 4, y + 2);
- g.drawLine(x + 2, y + 3, x + 2, y + 4);
- g.drawLine(x + 3, y + 5, x + 3, y + 5);
- g.drawLine(x + 5, y + 3, x + 5, y + 3);
-
- g.setColor(new Color(153, 153, 204));
- g.drawLine(x + 2, y + 2, x + 2, y + 2);
- g.drawLine(x + 2, y + 5, x + 2, y + 5);
- g.drawLine(x + 2, y + 6, x + 5, y + 6);
- g.drawLine(x + 5, y + 2, x + 5, y + 2);
- g.drawLine(x + 6, y + 2, x + 6, y + 5);
-
- g.setColor(new Color(102, 102, 153));
- g.drawLine(x + 2, y + 1, x + 5, y + 1);
- g.drawLine(x + 1, y + 2, x + 1, y + 5);
- }
+ g.fillRect(x + wHalf + 1, y + w, 2, w);
+
+ g.setColor(white);
+ g.fillRect(x + wHalf + 1, y + wHalf + 1, 2, 2);
+
}
/**
@@ -1964,7 +1933,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getTreeHardDriveIcon()
*/
- private static class TreeHardDriveIcon implements Icon, Serializable
+ private static class TreeHardDriveIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -2074,7 +2044,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getTreeFloppyDriveIcon()
*/
- private static class TreeFloppyDriveIcon implements Icon, Serializable
+ private static class TreeFloppyDriveIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -2150,7 +2121,8 @@ public class MetalIconFactory implements Serializable
*
* @see MetalIconFactory#getTreeComputerIcon()
*/
- private static class TreeComputerIcon implements Icon, Serializable
+ private static class TreeComputerIcon
+ implements Icon, UIResource, Serializable
{
/**
@@ -2255,6 +2227,12 @@ public class MetalIconFactory implements Serializable
/** The icon instance returned by {@link #getTreeHardDriveIcon()}. */
private static Icon treeHardDriveIcon;
+ /** The icon instance returned by {@link #getHorizontalSliderThumbIcon()}. */
+ private static Icon horizontalSliderThumbIcon;
+
+ /** The icon instance returned by {@link #getVerticalSliderThumbIcon()}. */
+ private static Icon verticalSliderThumbIcon;
+
/**
* Creates a new instance. All the methods are static, so creating an
* instance isn't necessary.
@@ -2383,7 +2361,9 @@ public class MetalIconFactory implements Serializable
*/
public static Icon getHorizontalSliderThumbIcon()
{
- return new HorizontalSliderThumbIcon();
+ if (horizontalSliderThumbIcon == null)
+ horizontalSliderThumbIcon = new HorizontalSliderThumbIcon();
+ return horizontalSliderThumbIcon;
}
/**
@@ -2462,7 +2442,9 @@ public class MetalIconFactory implements Serializable
*/
public static Icon getVerticalSliderThumbIcon()
{
- return new VerticalSliderThumbIcon();
+ if (verticalSliderThumbIcon == null)
+ verticalSliderThumbIcon = new VerticalSliderThumbIcon();
+ return verticalSliderThumbIcon;
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java
index 09eafd40fe9..8a5a61107c1 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java
@@ -85,7 +85,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
}
/**
- * Sets the current theme to a new instance of {@link DefaultMetalTheme}.
+ * Sets the current theme to a new instance of {@link OceanTheme}.
*/
protected void createDefaultTheme()
{
@@ -709,6 +709,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel
* @param theme the theme (<code>null</code> not permitted).
*
* @throws NullPointerException if <code>theme</code> is <code>null</code>.
+ *
+ * @see #getCurrentTheme()
*/
public static void setCurrentTheme(MetalTheme theme)
{
@@ -1183,20 +1185,26 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"SplitPaneDivider.draggingColor", Color.DARK_GRAY,
"TabbedPane.background", getControlShadow(),
+ "TabbedPane.contentBorderInsets", new InsetsUIResource(2, 2, 3, 3),
+ "TabbedPane.contentOpaque", Boolean.TRUE,
"TabbedPane.darkShadow", getControlDarkShadow(),
"TabbedPane.focus", getPrimaryControlDarkShadow(),
"TabbedPane.font", new FontUIResource("Dialog", Font.BOLD, 12),
"TabbedPane.foreground", getControlTextColor(),
"TabbedPane.highlight", getControlHighlight(),
"TabbedPane.light", getControl(),
- "TabbedPane.selected", getControl(),
+ "TabbedPane.selected", getControl(), // overridden in OceanTheme
"TabbedPane.selectHighlight", getControlHighlight(),
"TabbedPane.selectedTabPadInsets", new InsetsUIResource(2, 2, 2, 1),
"TabbedPane.shadow", getControlShadow(),
- "TabbedPane.tabAreaBackground", getControl(),
- "TabbedPane.tabAreaInsets", new InsetsUIResource(4, 2, 0, 6),
+ "TabbedPane.tabAreaBackground", getControl(), // overridden in OceanTheme
+ "TabbedPane.tabAreaInsets", new InsetsUIResource(4, 2, 0, 6), // dito
"TabbedPane.tabInsets", new InsetsUIResource(0, 9, 1, 9),
+ // new properties in OceanTheme:
+ // TabbedPane.contentAreaColor
+ // TabbedPane.unselectedBackground
+
"Table.background", getWindowBackground(),
"Table.focusCellBackground", getWindowBackground(),
"Table.focusCellForeground", getControlTextColor(),
@@ -1243,6 +1251,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel
"TextPane.selectionBackground", getTextHighlightColor(),
"TextPane.selectionForeground", getHighlightedTextColor(),
+ "TitledBorder.border", new LineBorderUIResource(getPrimaryControl(), 1),
"TitledBorder.font", new FontUIResource("Dialog", Font.BOLD, 12),
"TitledBorder.titleColor", getSystemTextColor(),
@@ -1335,12 +1344,17 @@ public class MetalLookAndFeel extends BasicLookAndFeel
}
/**
- * Returns the current theme setting for the Metal L&amp;F.
+ * Returns the current theme for the Metal look and feel. The default is
+ * an instance of {@link OceanTheme}.
*
- * @return the current theme setting for the Metal L&amp;F
+ * @return The current theme (never <code>null</code>).
+ *
+ * @see #setCurrentTheme(MetalTheme)
*/
public static MetalTheme getCurrentTheme()
{
+ if (theme == null)
+ theme = new OceanTheme();
return theme;
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java
index 31d8d671fa1..ff763ea9da9 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalMenuBarUI.java
@@ -44,6 +44,7 @@ import javax.swing.JComponent;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicMenuBarUI;
/**
@@ -75,7 +76,9 @@ public class MetalMenuBarUI extends BasicMenuBarUI
*/
public void update(Graphics g, JComponent c)
{
- if (c.isOpaque() && UIManager.get("MenuBar.gradient") != null)
+ if (c.isOpaque()
+ && UIManager.get("MenuBar.gradient") != null
+ && c.getBackground() instanceof UIResource)
{
MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(),
SwingConstants.VERTICAL, "MenuBar.gradient");
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java b/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java
index 84f9cfe494e..a55dc091665 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalScrollButton.java
@@ -84,6 +84,7 @@ public class MetalScrollButton extends BasicArrowButton
super(direction);
buttonWidth = width;
this.freeStanding = freeStanding;
+ setFocusable(false);
}
/**
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java
index c49abe832e4..20135fc857e 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalTabbedPaneUI.java
@@ -1,5 +1,5 @@
/* MetalTabbedPaneUI.java
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -170,7 +170,9 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
*/
protected LayoutManager createLayoutManager()
{
- return new TabbedPaneLayout();
+ return (tabPane.getTabLayoutPolicy() == JTabbedPane.WRAP_TAB_LAYOUT)
+ ? new MetalTabbedPaneUI.TabbedPaneLayout()
+ : super.createLayoutManager();
}
/**
@@ -326,7 +328,6 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
int bottom = h - 1;
int right = w - 1;
-
int tabCount = tabPane.getTabCount();
int currentRun = getRunForTab(tabCount, tabIndex);
int firstIndex = tabRuns[currentRun];
@@ -396,14 +397,17 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
{
if (tabPane.getSelectedIndex() == tabIndex - 1)
{
- g.drawLine(0, 5, 0, bottom);
- g.setColor(oceanSelectedBorder);
- g.drawLine(0, 0, 0, 5);
+ g.drawLine(0, 6, 0, bottom);
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(oceanSelectedBorder);
+ g.drawLine(0, 0, 0, 5);
+ }
}
else if (isSelected)
{
g.drawLine(0, 5, 0, bottom);
- if (tabIndex != 0)
+ if (tabIndex != firstIndex)
{
g.setColor(darkShadow);
g.drawLine(0, 0, 0, 5);
@@ -463,9 +467,10 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
{
Color c;
if (tabPane.getSelectedIndex() == tabIndex - 1)
- c = UIManager.getColor("TabbedPane.tabAreaBackground");
+ c = selectColor;
else
c = getUnselectedBackground(tabIndex - 1);
+ g.setColor(c);
g.fillRect(right - 5, 0, 5, 3);
g.fillRect(right - 2, 3, 2, 2);
}
@@ -522,10 +527,13 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
}
else if (isOcean && tabPane.getSelectedIndex() == tabIndex - 1)
{
- g.setColor(oceanSelectedBorder);
- g.drawLine(right, 0, right, 6);
+ if (tabIndex != firstIndex)
+ {
+ g.setColor(oceanSelectedBorder);
+ g.drawLine(right, 0, right, 6);
+ }
g.setColor(darkShadow);
- g.drawLine(right, 6, right, bottom);
+ g.drawLine(right, 7, right, bottom);
}
else if (tabIndex != firstIndex)
{
@@ -598,8 +606,10 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
if (isOcean && isSelected)
{
g.drawLine(0, 0, 0, bottom - 5);
- if ((currentRun == 0 && tabIndex != 0)
- || (currentRun > 0 && tabIndex != tabRuns[currentRun - 1]))
+
+ // Paint a connecting line to the tab below for all
+ // but the first tab in the last run.
+ if (tabIndex != tabRuns[runCount-1])
{
g.setColor(darkShadow);
g.drawLine(0, bottom - 5, 0, bottom);
@@ -688,6 +698,103 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
}
/**
+ * This method paints the focus rectangle around the selected tab.
+ *
+ * @param g The Graphics object to paint with.
+ * @param tabPlacement The JTabbedPane's tab placement.
+ * @param rects The array of rectangles keeping track of size and position.
+ * @param tabIndex The tab index.
+ * @param iconRect The icon bounds.
+ * @param textRect The text bounds.
+ * @param isSelected Whether this tab is selected.
+ */
+ protected void paintFocusIndicator(Graphics g, int tabPlacement,
+ Rectangle[] rects, int tabIndex,
+ Rectangle iconRect, Rectangle textRect,
+ boolean isSelected)
+ {
+ if (tabPane.hasFocus() && isSelected)
+ {
+ Rectangle rect = rects[tabIndex];
+
+ g.setColor(focus);
+ g.translate(rect.x, rect.y);
+
+ switch (tabPlacement)
+ {
+ case LEFT:
+ // Top line
+ g.drawLine(7, 2, rect.width-2, 2);
+
+ // Right line
+ g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3);
+
+ // Bottom line
+ g.drawLine(rect.width-2, rect.height-2, 3, rect.height-2);
+
+ // Left line
+ g.drawLine(2, rect.height-3, 2, 7);
+
+ // Slant
+ g.drawLine(2, 6, 6, 2);
+ break;
+ case RIGHT:
+ // Top line
+ g.drawLine(1, 2, rect.width-8, 2);
+
+ // Slant
+ g.drawLine(rect.width-7, 2, rect.width-3, 6);
+
+ // Right line
+ g.drawLine(rect.width-3, 7, rect.width-3, rect.height-3);
+
+ // Bottom line
+ g.drawLine(rect.width-3, rect.height-2, 2, rect.height-2);
+
+ // Left line
+ g.drawLine(1, rect.height-2, 1, 2);
+ break;
+ case BOTTOM:
+ // Top line
+ g.drawLine(2, 1, rect.width-2, 1);
+
+ // Right line
+ g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3);
+
+ // Bottom line
+ g.drawLine(7, rect.height-3, rect.width-2, rect.height-3);
+
+ // Slant
+ g.drawLine(6, rect.height-3, 2, rect.height-7);
+
+ // Left line
+ g.drawLine(2, rect.height-8, 2, 2);
+
+ break;
+ case TOP:
+ default:
+ // Top line
+ g.drawLine(6, 2, rect.width-2, 2);
+
+ // Right line
+ g.drawLine(rect.width-1, 2, rect.width-1, rect.height-3);
+
+ // Bottom line
+ g.drawLine(3, rect.height-3, rect.width-2, rect.height-3);
+
+ // Left line
+ g.drawLine(2, rect.height-3, 2, 7);
+
+ // Slant
+ g.drawLine(2, 6, 6, 2);
+
+ }
+
+ g.translate(-rect.x, -rect.y);
+ }
+ }
+
+ /**
* Returns <code>true</code> if the tabs in the specified run should be
* padded to make the run fill the width/height of the {@link JTabbedPane}.
*
@@ -1144,4 +1251,19 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI
bg = unselectedBackground;
return bg;
}
+
+ protected int getTabLabelShiftX(int tabPlacement,
+ int index,
+ boolean isSelected)
+ {
+ return 0;
+ }
+
+ protected int getTabLabelShiftY(int tabPlacement,
+ int index,
+ boolean isSelected)
+ {
+ return 0;
+ }
+
}
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java
index 72cbb34a6dc..0c3a38d5cc3 100644
--- a/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalUtils.java
@@ -41,6 +41,7 @@ import gnu.classpath.SystemProperties;
import java.awt.Color;
import java.awt.Component;
+import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.TexturePaint;
@@ -106,7 +107,7 @@ class MetalUtils
for (int mX = x + xOff; mX < (x + w); mX += 4)
{
- g.drawLine(mX, mY, mX, mY);
+ g.fillRect(mX, mY, 1, 1);
}
// increase x offset
@@ -305,6 +306,15 @@ class MetalUtils
float g1, float g2, Color c1, Color c2,
Color c3, int[][] mask)
{
+
+ if (g instanceof Graphics2D
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null)
+ {
+ paintHorizontalGradient2D((Graphics2D) g, x, y, w, h, g1, g2, c1, c2,
+ c3, mask);
+ return;
+ }
+
// Calculate the coordinates.
int y0 = y;
int y1 = y + h;
@@ -339,7 +349,7 @@ class MetalUtils
y0 = mask[xc - x0][0] + y;
y1 = mask[xc - x0][1] + y;
}
- g.drawLine(xc, y0, xc, y1);
+ g.fillRect(xc, y0, 1, y1 - y0);
}
// Paint solid c2 area.
g.setColor(c2);
@@ -353,7 +363,7 @@ class MetalUtils
{
y0 = mask[xc - x0][0] + y;
y1 = mask[xc - x0][1] + y;
- g.drawLine(xc, y0, xc, y1);
+ g.fillRect(xc, y0, 1, y1 - y0);
}
}
@@ -377,7 +387,7 @@ class MetalUtils
y0 = mask[xc - x0][0] + y;
y1 = mask[xc - x0][1] + y;
}
- g.drawLine(xc, y0, xc, y1);
+ g.fillRect(xc, y0, 1, y1 - y0);
}
// Paint third gradient area (c1->c3).
@@ -421,9 +431,17 @@ class MetalUtils
* described above
*/
static void paintVerticalGradient(Graphics g, int x, int y, int w, int h,
- double g1, double g2, Color c1, Color c2,
+ float g1, float g2, Color c1, Color c2,
Color c3, int[][] mask)
{
+ if (g instanceof Graphics2D
+ && SystemProperties.getProperty("gnu.javax.swing.noGraphics2D") == null)
+ {
+ paintVerticalGradient2D((Graphics2D) g, x, y, w, h, g1, g2, c1, c2,
+ c3, mask);
+ return;
+ }
+
// Calculate the coordinates.
int x0 = x;
int x1 = x + w;
@@ -458,7 +476,7 @@ class MetalUtils
x0 = mask[yc - y0][0] + x;
x1 = mask[yc - y0][1] + x;
}
- g.drawLine(x0, yc, x1, yc);
+ g.fillRect(x0, yc, x1 - x0, 1);
}
// Paint solid c2 area.
g.setColor(c2);
@@ -472,7 +490,7 @@ class MetalUtils
{
x0 = mask[yc - y0][0] + x;
x1 = mask[yc - y0][1] + x;
- g.drawLine(x0, yc, x1, yc);
+ g.fillRect(x0, yc, x1 - x0, 1);
}
}
@@ -496,7 +514,7 @@ class MetalUtils
x0 = mask[yc - y0][0] + x;
x1 = mask[yc - y0][1] + x;
}
- g.drawLine(x0, yc, x1, yc);
+ g.fillRect(x0, yc, x1 - x0, 1);
}
// Paint third gradient area (c1->c3).
@@ -519,7 +537,61 @@ class MetalUtils
x0 = mask[yc - y0][0] + x;
x1 = mask[yc - y0][1] + x;
}
- g.drawLine(x0, yc, x1, yc);
+ g.fillRect(x0, yc, x1 - x0, 1);
}
}
+
+ /**
+ * Paints a horizontal gradient using Graphics2D functionality.
+ *
+ * @param g the Graphics2D instance
+ * @param x the X coordinate of the upper left corner of the rectangle
+ * @param y the Y coordinate of the upper left corner of the rectangle
+ * @param w the width of the rectangle
+ * @param h the height of the rectangle
+ * @param g1 the relative width of the c1->c2 gradients
+ * @param g2 the relative width of the c2 solid area
+ * @param c1 the color 1
+ * @param c2 the color 2
+ * @param c3 the color 3
+ * @param mask the mask that should be used when painting the gradient as
+ * described above
+ */
+ private static void paintHorizontalGradient2D(Graphics2D g, int x, int y,
+ int w, int h, float g1,
+ float g2, Color c1,
+ Color c2, Color c3,
+ int[][] mask)
+ {
+ // FIXME: Handle the mask somehow, or do Graphics2D clipping instead.
+ GradientPaint p1 = new GradientPaint(x, y, c1, x + w * g1, y, c2);
+ g.setPaint(p1);
+ // This fills the first gradient and the solid area in one go.
+ g.fillRect(x, y, (int) (w * (g1 + g2)), h);
+
+ GradientPaint p2 = new GradientPaint(x + (w * (g1 + g2)), y, c2, x + w, y,
+ c3);
+ g.setPaint(p2);
+ g.fillRect((int) (x + (w * (g1 + g2))), y,
+ (int) (w * (1. - (g1 + g2))), h);
+ }
+
+ private static void paintVerticalGradient2D(Graphics2D g, int x, int y,
+ int w, int h, float g1,
+ float g2, Color c1,
+ Color c2, Color c3,
+ int[][] mask)
+ {
+ // FIXME: Handle the mask somehow, or do Graphics2D clipping instead.
+ GradientPaint p1 = new GradientPaint(x, y, c1, x, y + h * g1, c2);
+ g.setPaint(p1);
+ // This fills the first gradient and the solid area in one go.
+ g.fillRect(x, y, w, (int) (h * (g1 + g2)));
+
+ GradientPaint p2 = new GradientPaint(x, y + (h * (g1 + g2)), c2, x, y + h,
+ c3);
+ g.setPaint(p2);
+ g.fillRect(x, (int) (y + (h * (g1 + g2))), w,
+ (int) (h * (1. - (g1 + g2))));
+ }
}
diff --git a/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java b/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java
index 24ac8fc9c39..33e68ea9fcd 100644
--- a/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java
+++ b/libjava/classpath/javax/swing/table/DefaultTableColumnModel.java
@@ -91,10 +91,10 @@ public class DefaultTableColumnModel
/**
* A change event used when notifying listeners of a change to the
* <code>columnMargin</code> field. This single event is reused for all
- * notifications.
+ * notifications (it is lazily instantiated within the
+ * {@link #fireColumnMarginChanged()} method).
*/
- // FIXME: use lazy instantiation
- protected transient ChangeEvent changeEvent = new ChangeEvent(this);
+ protected transient ChangeEvent changeEvent;
/**
* A flag that indicates whether or not columns can be selected.
@@ -580,7 +580,9 @@ public class DefaultTableColumnModel
*/
protected void fireColumnMarginChanged()
{
- EventListener [] listeners = getListeners(TableColumnModelListener.class);
+ EventListener[] listeners = getListeners(TableColumnModelListener.class);
+ if (changeEvent == null && listeners.length > 0)
+ changeEvent = new ChangeEvent(this);
for (int i = 0; i < listeners.length; ++i)
((TableColumnModelListener) listeners[i]).columnMarginChanged(changeEvent);
}
diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java
index 1ef81732fed..eb46a8c42f6 100644
--- a/libjava/classpath/javax/swing/text/AbstractDocument.java
+++ b/libjava/classpath/javax/swing/text/AbstractDocument.java
@@ -147,14 +147,19 @@ public abstract class AbstractDocument implements Document, Serializable
/**
* A condition variable that readers and writers wait on.
*/
- Object documentCV = new Object();
+ private Object documentCV = new Object();
/** An instance of a DocumentFilter.FilterBypass which allows calling
* the insert, remove and replace method without checking for an installed
* document filter.
*/
- DocumentFilter.FilterBypass bypass;
-
+ private DocumentFilter.FilterBypass bypass;
+
+ /**
+ * The bidi root element.
+ */
+ private Element bidiRoot;
+
/**
* Creates a new <code>AbstractDocument</code> with the specified
* {@link Content} model.
@@ -185,6 +190,13 @@ public abstract class AbstractDocument implements Document, Serializable
{
content = doc;
context = ctx;
+
+ // FIXME: This is determined using a Mauve test. Make the document
+ // actually use this.
+ putProperty("i18n", Boolean.FALSE);
+
+ // FIXME: Fully implement bidi.
+ bidiRoot = new BranchElement(null, null);
}
/** Returns the DocumentFilter.FilterBypass instance for this
@@ -360,7 +372,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Element getBidiRootElement()
{
- return null;
+ return bidiRoot;
}
/**
@@ -477,8 +489,9 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Element[] getRootElements()
{
- Element[] elements = new Element[1];
+ Element[] elements = new Element[2];
elements[0] = getDefaultRootElement();
+ elements[1] = getBidiRootElement();
return elements;
}
@@ -739,29 +752,36 @@ public abstract class AbstractDocument implements Document, Serializable
void removeImpl(int offset, int length) throws BadLocationException
{
- // Prevent some unneccessary method invocation (observed in the RI).
- if (length <= 0)
- return;
-
- DefaultDocumentEvent event =
- new DefaultDocumentEvent(offset, length,
- DocumentEvent.EventType.REMOVE);
-
- try
+ // The RI silently ignores all requests that have a negative length.
+ // Don't ask my why, but that's how it is.
+ if (length > 0)
{
- writeLock();
+ if (offset < 0 || offset > getLength())
+ throw new BadLocationException("Invalid remove position", offset);
+
+ if (offset + length > getLength())
+ throw new BadLocationException("Invalid remove length", offset);
+
+ DefaultDocumentEvent event =
+ new DefaultDocumentEvent(offset, length,
+ DocumentEvent.EventType.REMOVE);
+
+ try
+ {
+ writeLock();
- // The order of the operations below is critical!
- removeUpdate(event);
- UndoableEdit temp = content.remove(offset, length);
+ // The order of the operations below is critical!
+ removeUpdate(event);
+ UndoableEdit temp = content.remove(offset, length);
- postRemoveUpdate(event);
- fireRemoveUpdate(event);
+ postRemoveUpdate(event);
+ fireRemoveUpdate(event);
+ }
+ finally
+ {
+ writeUnlock();
+ }
}
- finally
- {
- writeUnlock();
- }
}
/**
@@ -1674,20 +1694,15 @@ public abstract class AbstractDocument implements Document, Serializable
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = -6037216547466333183L;
- /** The child elements of this BranchElement. */
- private Element[] children = new Element[0];
-
/**
- * The cached startOffset value. This is used in the case when a
- * BranchElement (temporarily) has no child elements.
+ * The child elements of this BranchElement.
*/
- private int startOffset;
+ private Element[] children;;
/**
- * The cached endOffset value. This is used in the case when a
- * BranchElement (temporarily) has no child elements.
+ * The number of children in the branch element.
*/
- private int endOffset;
+ private int numChildren;
/**
* Creates a new <code>BranchElement</code> with the specified
@@ -1700,8 +1715,8 @@ public abstract class AbstractDocument implements Document, Serializable
public BranchElement(Element parent, AttributeSet attributes)
{
super(parent, attributes);
- startOffset = -1;
- endOffset = -1;
+ children = new Element[1];
+ numChildren = 0;
}
/**
@@ -1716,8 +1731,8 @@ public abstract class AbstractDocument implements Document, Serializable
Vector tmp = new Vector();
- for (int index = 0; index < children.length; ++index)
- tmp.add(children[index]);
+ for (int index = 0; index < numChildren; ++index)
+ tmp.add(children[index]);
return tmp.elements();
}
@@ -1743,8 +1758,8 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public Element getElement(int index)
{
- if (index < 0 || index >= children.length)
- return null;
+ if (index < 0 || index >= numChildren)
+ return null;
return children[index];
}
@@ -1756,7 +1771,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getElementCount()
{
- return children.length;
+ return numChildren;
}
/**
@@ -1777,7 +1792,7 @@ public abstract class AbstractDocument implements Document, Serializable
// XXX: There is surely a better algorithm
// as beginning from first element each time.
- for (int index = 0; index < children.length - 1; ++index)
+ for (int index = 0; index < numChildren - 1; ++index)
{
Element elem = children[index];
@@ -1814,15 +1829,11 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getEndOffset()
{
- if (children.length == 0)
- {
- if (endOffset == -1)
- throw new NullPointerException("BranchElement has no children.");
- }
- else
- endOffset = children[children.length - 1].getEndOffset();
-
- return endOffset;
+ // This might accss one cached element or trigger an NPE for
+ // numChildren == 0. This is checked by a Mauve test.
+ Element child = numChildren > 0 ? children[numChildren - 1]
+ : children[0];
+ return child.getEndOffset();
}
/**
@@ -1848,15 +1859,13 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getStartOffset()
{
- if (children.length == 0)
- {
- if (startOffset == -1)
- throw new NullPointerException("BranchElement has no children.");
- }
- else
- startOffset = children[0].getStartOffset();
-
- return startOffset;
+ // Do not explicitly throw an NPE here. If the first element is null
+ // then the NPE gets thrown anyway. If it isn't, then it either
+ // holds a real value (for numChildren > 0) or a cached value
+ // (for numChildren == 0) as we don't fully remove elements in replace()
+ // when removing single elements.
+ // This is checked by a Mauve test.
+ return children[0].getStartOffset();
}
/**
@@ -1884,7 +1893,7 @@ public abstract class AbstractDocument implements Document, Serializable
{
// XXX: There is surely a better algorithm
// as beginning from first element each time.
- for (int index = 0; index < children.length; ++index)
+ for (int index = 0; index < numChildren; ++index)
{
Element elem = children[index];
@@ -1905,14 +1914,26 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public void replace(int offset, int length, Element[] elements)
{
- Element[] target = new Element[children.length - length
- + elements.length];
- System.arraycopy(children, 0, target, 0, offset);
- System.arraycopy(elements, 0, target, offset, elements.length);
- System.arraycopy(children, offset + length, target,
- offset + elements.length,
- children.length - offset - length);
- children = target;
+ int delta = elements.length - length;
+ int copyFrom = offset + length; // From where to copy.
+ int copyTo = copyFrom + delta; // Where to copy to.
+ int numMove = numChildren - copyFrom; // How many elements are moved.
+ if (numChildren + delta > children.length)
+ {
+ // Gotta grow the array.
+ int newSize = Math.max(2 * children.length, numChildren + delta);
+ Element[] target = new Element[newSize];
+ System.arraycopy(children, 0, target, 0, offset);
+ System.arraycopy(elements, 0, target, offset, elements.length);
+ System.arraycopy(children, copyFrom, target, copyTo, numMove);
+ children = target;
+ }
+ else
+ {
+ System.arraycopy(children, copyFrom, children, copyTo, numMove);
+ System.arraycopy(elements, 0, children, offset, elements.length);
+ }
+ numChildren += delta;
}
/**
@@ -2165,18 +2186,6 @@ public abstract class AbstractDocument implements Document, Serializable
private Position endPos;
/**
- * This gets possible added to the startOffset when a startOffset
- * outside the document range is requested.
- */
- private int startDelta;
-
- /**
- * This gets possible added to the endOffset when a endOffset
- * outside the document range is requested.
- */
- private int endDelta;
-
- /**
* Creates a new <code>LeafElement</code>.
*
* @param parent the parent of this <code>LeafElement</code>
@@ -2188,28 +2197,21 @@ public abstract class AbstractDocument implements Document, Serializable
int end)
{
super(parent, attributes);
- int len = content.length();
- startDelta = 0;
- if (start > len)
- startDelta = start - len;
- endDelta = 0;
- if (end > len)
- endDelta = end - len;
try
- {
- startPos = createPosition(start - startDelta);
- endPos = createPosition(end - endDelta);
- }
- catch (BadLocationException ex)
- {
- AssertionError as;
- as = new AssertionError("BadLocationException thrown "
- + "here. start=" + start
- + ", end=" + end
- + ", length=" + getLength());
- as.initCause(ex);
- throw as;
- }
+ {
+ startPos = createPosition(start);
+ endPos = createPosition(end);
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError as;
+ as = new AssertionError("BadLocationException thrown "
+ + "here. start=" + start
+ + ", end=" + end
+ + ", length=" + getLength());
+ as.initCause(ex);
+ throw as;
+ }
}
/**
@@ -2281,7 +2283,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getEndOffset()
{
- return endPos.getOffset() + endDelta;
+ return endPos.getOffset();
}
/**
@@ -2307,7 +2309,7 @@ public abstract class AbstractDocument implements Document, Serializable
*/
public int getStartOffset()
{
- return startPos.getOffset() + startDelta;
+ return startPos.getOffset();
}
/**
diff --git a/libjava/classpath/javax/swing/text/BoxView.java b/libjava/classpath/javax/swing/text/BoxView.java
index a184a813152..27e3c0f9a1b 100644
--- a/libjava/classpath/javax/swing/text/BoxView.java
+++ b/libjava/classpath/javax/swing/text/BoxView.java
@@ -67,6 +67,11 @@ public class BoxView
private boolean[] layoutValid = new boolean[2];
/**
+ * Indicates if the requirements for an axis are valid.
+ */
+ private boolean[] requirementsValid = new boolean[2];
+
+ /**
* The spans along the X_AXIS and Y_AXIS.
*/
private int[][] spans = new int[2][];
@@ -265,8 +270,10 @@ public class BoxView
super.replace(offset, length, views);
// Invalidate layout information.
- layoutChanged(X_AXIS);
- layoutChanged(Y_AXIS);
+ layoutValid[X_AXIS] = false;
+ requirementsValid[X_AXIS] = false;
+ layoutValid[Y_AXIS] = false;
+ requirementsValid[Y_AXIS] = false;
}
/**
@@ -278,19 +285,26 @@ public class BoxView
*/
public void paint(Graphics g, Shape a)
{
- Rectangle inside = getInsideAllocation(a);
- // TODO: Used for debugging.
- //g.drawRect(inside.x, inside.y, inside.width, inside.height);
+ Rectangle alloc;
+ if (a instanceof Rectangle)
+ alloc = (Rectangle) a;
+ else
+ alloc = a.getBounds();
+
+ int x = alloc.x + getLeftInset();
+ int y = alloc.y + getTopInset();
- Rectangle copy = new Rectangle(inside);
+ Rectangle clip = g.getClipBounds();
+ Rectangle tmp = new Rectangle();
int count = getViewCount();
for (int i = 0; i < count; ++i)
{
- copy.setBounds(inside);
- childAllocation(i, copy);
- if (!copy.isEmpty()
- && g.hitClip(copy.x, copy.y, copy.width, copy.height))
- paintChild(g, copy, i);
+ tmp.x = x + getOffset(X_AXIS, i);
+ tmp.y = y + getOffset(Y_AXIS, i);
+ tmp.width = getSpan(X_AXIS, i);
+ tmp.height = getSpan(Y_AXIS, i);
+ if (tmp.intersects(clip))
+ paintChild(g, tmp, i);
}
}
@@ -305,7 +319,13 @@ public class BoxView
public float getPreferredSpan(int axis)
{
updateRequirements(axis);
- return requirements[axis].preferred;
+ // Add margin.
+ float margin;
+ if (axis == X_AXIS)
+ margin = getLeftInset() + getRightInset();
+ else
+ margin = getTopInset() + getBottomInset();
+ return requirements[axis].preferred + margin;
}
/**
@@ -319,12 +339,14 @@ public class BoxView
*/
public float getMaximumSpan(int axis)
{
- float max;
- if (axis == myAxis)
- max = getPreferredSpan(axis);
+ updateRequirements(axis);
+ // Add margin.
+ float margin;
+ if (axis == X_AXIS)
+ margin = getLeftInset() + getRightInset();
else
- max = Integer.MAX_VALUE;
- return max;
+ margin = getTopInset() + getBottomInset();
+ return requirements[axis].maximum + margin;
}
/**
@@ -341,7 +363,13 @@ public class BoxView
public float getMinimumSpan(int axis)
{
updateRequirements(axis);
- return requirements[axis].minimum;
+ // Add margin.
+ float margin;
+ if (axis == X_AXIS)
+ margin = getLeftInset() + getRightInset();
+ else
+ margin = getTopInset() + getBottomInset();
+ return requirements[axis].minimum + margin;
}
/**
@@ -435,34 +463,29 @@ public class BoxView
protected SizeRequirements calculateMajorAxisRequirements(int axis,
SizeRequirements sr)
{
- updateChildRequirements(axis);
+ SizeRequirements res = sr;
+ if (res == null)
+ res = new SizeRequirements();
- SizeRequirements result = sr;
- if (result == null)
- result = new SizeRequirements();
+ float min = 0;
+ float pref = 0;
+ float max = 0;
- long minimum = 0;
- long preferred = 0;
- long maximum = 0;
- for (int i = 0; i < children.length; i++)
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
{
- minimum += childReqs[axis][i].minimum;
- preferred += childReqs[axis][i].preferred;
- maximum += childReqs[axis][i].maximum;
+ View child = getView(i);
+ min += child.getMinimumSpan(axis);
+ pref = child.getPreferredSpan(axis);
+ max = child.getMaximumSpan(axis);
}
- // Overflow check.
- if (minimum > Integer.MAX_VALUE)
- minimum = Integer.MAX_VALUE;
- if (preferred > Integer.MAX_VALUE)
- preferred = Integer.MAX_VALUE;
- if (maximum > Integer.MAX_VALUE)
- maximum = Integer.MAX_VALUE;
-
- result.minimum = (int) minimum;
- result.preferred = (int) preferred;
- result.maximum = (int) maximum;
- result.alignment = 0.5F;
- return result;
+
+ res.minimum = (int) min;
+ res.preferred = (int) pref;
+ res.maximum = (int) max;
+ res.alignment = 0.5F;
+
+ return res;
}
/**
@@ -480,44 +503,24 @@ public class BoxView
protected SizeRequirements calculateMinorAxisRequirements(int axis,
SizeRequirements sr)
{
- updateChildRequirements(axis);
-
SizeRequirements res = sr;
if (res == null)
res = new SizeRequirements();
- float minLeft = 0;
- float minRight = 0;
- float prefLeft = 0;
- float prefRight = 0;
- float maxLeft = 0;
- float maxRight = 0;
- for (int i = 0; i < childReqs[axis].length; i++)
+ res.minimum = 0;
+ res.preferred = 0;
+ res.maximum = 0;
+ res.alignment = 0.5F;
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
{
- float myMinLeft = childReqs[axis][i].minimum * childReqs[axis][i].alignment;
- float myMinRight = childReqs[axis][i].minimum - myMinLeft;
- minLeft = Math.max(myMinLeft, minLeft);
- minRight = Math.max(myMinRight, minRight);
- float myPrefLeft = childReqs[axis][i].preferred * childReqs[axis][i].alignment;
- float myPrefRight = childReqs[axis][i].preferred - myPrefLeft;
- prefLeft = Math.max(myPrefLeft, prefLeft);
- prefRight = Math.max(myPrefRight, prefRight);
- float myMaxLeft = childReqs[axis][i].maximum * childReqs[axis][i].alignment;
- float myMaxRight = childReqs[axis][i].maximum - myMaxLeft;
- maxLeft = Math.max(myMaxLeft, maxLeft);
- maxRight = Math.max(myMaxRight, maxRight);
+ View child = getView(i);
+ res.minimum = Math.max((int) child.getMinimumSpan(axis), res.minimum);
+ res.preferred = Math.max((int) child.getPreferredSpan(axis),
+ res.preferred);
+ res.maximum = Math.max((int) child.getMaximumSpan(axis), res.maximum);
}
- int minSize = (int) (minLeft + minRight);
- int prefSize = (int) (prefLeft + prefRight);
- int maxSize = (int) (maxLeft + maxRight);
- float align = prefLeft / (prefRight + prefLeft);
- if (Float.isNaN(align))
- align = 0;
- res.alignment = align;
- res.maximum = maxSize;
- res.preferred = prefSize;
- res.minimum = minSize;
return res;
}
@@ -697,15 +700,62 @@ public class BoxView
protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- updateChildRequirements(axis);
- updateRequirements(axis);
+ // Set the spans to the preferred sizes. Determine the space
+ // that we have to adjust the sizes afterwards.
+ long sumPref = 0;
+ int n = getViewCount();
+ for (int i = 0; i < n; i++)
+ {
+ View child = getView(i);
+ spans[i] = (int) child.getPreferredSpan(axis);
+ sumPref = spans[i];
+ }
- // Calculate the spans and offsets using the SizeRequirements uility
- // methods.
- SizeRequirements.calculateTiledPositions(targetSpan, requirements[axis],
- childReqs[axis],
- offsets, spans);
+ // Try to adjust the spans so that we fill the targetSpan.
+ long diff = targetSpan - sumPref;
+ float factor = 0.0F;
+ int[] diffs = null;
+ if (diff != 0)
+ {
+ long total = 0;
+ diffs = new int[n];
+ for (int i = 0; i < n; i++)
+ {
+ View child = getView(i);
+ int span;
+ if (diff < 0)
+ {
+ span = (int) child.getMinimumSpan(axis);
+ diffs[i] = spans[i] - span;
+ }
+ else
+ {
+ span = (int) child.getMaximumSpan(axis);
+ diffs[i] = span - spans[i];
+ }
+ total += span;
+ }
+ float maxAdjust = Math.abs(total - sumPref);
+ factor = diff / maxAdjust;
+ factor = Math.min(factor, 1.0F);
+ factor = Math.max(factor, -1.0F);
+ }
+
+ // Actually perform adjustments.
+ int totalOffs = 0;
+ for (int i = 0; i < n; i++)
+ {
+ offsets[i] = totalOffs;
+ if (diff != 0)
+ {
+ float adjust = factor * diffs[i];
+ spans[i] += Math.round(adjust);
+ }
+ // Avoid overflow here.
+ totalOffs = (int) Math.min((long) totalOffs + (long) spans[i],
+ Integer.MAX_VALUE);
+ }
}
/**
@@ -720,14 +770,26 @@ public class BoxView
protected void layoutMinorAxis(int targetSpan, int axis, int[] offsets,
int[] spans)
{
- updateChildRequirements(axis);
- updateRequirements(axis);
-
- // Calculate the spans and offsets using the SizeRequirements uility
- // methods.
- SizeRequirements.calculateAlignedPositions(targetSpan, requirements[axis],
- childReqs[axis], offsets,
- spans);
+ int count = getViewCount();
+ for (int i = 0; i < count; i++)
+ {
+ View child = getView(i);
+ int max = (int) child.getMaximumSpan(axis);
+ if (max < targetSpan)
+ {System.err.println("align: " + child);
+ // Align child when it can't be made as wide as the target span.
+ float align = child.getAlignment(axis);
+ offsets[i] = (int) ((targetSpan - max) * align);
+ spans[i] = max;
+ }
+ else
+ {
+ // Expand child to target width if possible.
+ int min = (int) child.getMinimumSpan(axis);
+ offsets[i] = 0;
+ spans[i] = Math.max(min, targetSpan);
+ }
+ }
}
/**
@@ -822,15 +884,8 @@ public class BoxView
*/
public float getAlignment(int axis)
{
- float align;
- if (axis == myAxis)
- align = 0.5F;
- else
- {
- updateRequirements(axis);
- align = requirements[axis].alignment;
- }
- return align;
+ updateRequirements(axis);
+ return requirements[axis].alignment;
}
/**
@@ -843,9 +898,15 @@ public class BoxView
public void preferenceChanged(View child, boolean width, boolean height)
{
if (width)
- layoutValid[X_AXIS] = false;
+ {
+ layoutValid[X_AXIS] = false;
+ requirementsValid[X_AXIS] = false;
+ }
if (height)
- layoutValid[Y_AXIS] = false;
+ {
+ layoutValid[Y_AXIS] = false;
+ requirementsValid[Y_AXIS] = false;
+ }
super.preferenceChanged(child, width, height);
}
@@ -862,7 +923,7 @@ public class BoxView
if (! isAllocationValid())
{
Rectangle bounds = a.getBounds();
- layout(bounds.width, bounds.height);
+ setSize(bounds.width, bounds.height);
}
return super.modelToView(pos, a, bias);
}
@@ -963,7 +1024,7 @@ public class BoxView
*/
private void updateRequirements(int axis)
{
- if (! layoutValid[axis])
+ if (! requirementsValid[axis])
{
if (axis == myAxis)
requirements[axis] = calculateMajorAxisRequirements(axis,
@@ -971,6 +1032,7 @@ public class BoxView
else
requirements[axis] = calculateMinorAxisRequirements(axis,
requirements[axis]);
+ requirementsValid[axis] = true;
}
}
}
diff --git a/libjava/classpath/javax/swing/text/CompositeView.java b/libjava/classpath/javax/swing/text/CompositeView.java
index 17f13dbedd6..6f487b8981e 100644
--- a/libjava/classpath/javax/swing/text/CompositeView.java
+++ b/libjava/classpath/javax/swing/text/CompositeView.java
@@ -217,25 +217,43 @@ public abstract class CompositeView
public Shape modelToView(int pos, Shape a, Position.Bias bias)
throws BadLocationException
{
- int childIndex = getViewIndex(pos, bias);
- if (childIndex == -1)
- throw new BadLocationException("Position " + pos + " is not represented by view.", pos);
-
- Shape ret = null;
-
- View child = getView(childIndex);
- Shape childAlloc = getChildAllocation(childIndex, a);
-
- if (childAlloc == null)
- ret = createDefaultLocation(a, bias);
-
- Shape result = child.modelToView(pos, childAlloc, bias);
-
- if (result != null)
- ret = result;
- else
- ret = createDefaultLocation(a, bias);
+ boolean backward = bias == Position.Bias.Backward;
+ int testpos = backward ? Math.max(0, pos - 1) : pos;
+ Shape ret = null;
+ if (! backward || testpos >= getStartOffset())
+ {
+ int childIndex = getViewIndexAtPosition(testpos);
+ if (childIndex != -1 && childIndex < getViewCount())
+ {
+ View child = getView(childIndex);
+ if (child != null && testpos >= child.getStartOffset()
+ && testpos < child.getEndOffset())
+ {
+ Shape childAlloc = getChildAllocation(childIndex, a);
+ if (childAlloc != null)
+ {
+ ret = child.modelToView(pos, childAlloc, bias);
+ // Handle corner case.
+ if (ret == null && child.getEndOffset() == pos)
+ {
+ childIndex++;
+ if (childIndex < getViewCount())
+ {
+ child = getView(childIndex);
+ childAlloc = getChildAllocation(childIndex, a);
+ ret = child.modelToView(pos, childAlloc, bias);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ throw new BadLocationException("Position " + pos
+ + " is not represented by view.", pos);
+ }
+ }
return ret;
}
@@ -378,7 +396,10 @@ public abstract class CompositeView
{
if (b == Position.Bias.Backward && pos != 0)
pos -= 1;
- return getViewIndexAtPosition(pos);
+ int i = -1;
+ if (pos >= getStartOffset() && pos < getEndOffset())
+ i = getViewIndexAtPosition(pos);
+ return i;
}
/**
@@ -446,9 +467,13 @@ public abstract class CompositeView
*/
protected View getViewAtPosition(int pos, Rectangle a)
{
+ View view = null;
int i = getViewIndexAtPosition(pos);
- View view = children[i];
- childAllocation(i, a);
+ if (i >= 0 && i < getViewCount() && a != null)
+ {
+ view = getView(i);
+ childAllocation(i, a);
+ }
return view;
}
@@ -464,17 +489,10 @@ public abstract class CompositeView
*/
protected int getViewIndexAtPosition(int pos)
{
- int index = -1;
- for (int i = 0; i < children.length; i++)
- {
- if (children[i].getStartOffset() <= pos
- && children[i].getEndOffset() > pos)
- {
- index = i;
- break;
- }
- }
- return index;
+ // We have a 1:1 mapping of elements to views here, so we forward
+ // this to the element.
+ Element el = getElement();
+ return el.getElementIndex(pos);
}
/**
diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java
index 4ad204c00c9..84f47f120de 100644
--- a/libjava/classpath/javax/swing/text/DefaultCaret.java
+++ b/libjava/classpath/javax/swing/text/DefaultCaret.java
@@ -221,9 +221,12 @@ public class DefaultCaret extends Rectangle
if (name.equals("document"))
{
Document oldDoc = (Document) e.getOldValue();
- oldDoc.removeDocumentListener(documentListener);
+ if (oldDoc != null)
+ oldDoc.removeDocumentListener(documentListener);
+
Document newDoc = (Document) e.getNewValue();
- newDoc.addDocumentListener(documentListener);
+ if (newDoc != null)
+ newDoc.addDocumentListener(documentListener);
}
else if (name.equals("editable"))
{
@@ -549,7 +552,6 @@ public class DefaultCaret extends Rectangle
*/
public void mousePressed(MouseEvent event)
{
- int button = event.getButton();
// The implementation assumes that consuming the event makes the AWT event
// mechanism forget about this event instance and not transfer focus.
@@ -562,23 +564,37 @@ public class DefaultCaret extends Rectangle
// - a middle-click positions the caret and pastes the clipboard
// contents.
// - a middle-click when shift is held down is ignored
-
- if (button == MouseEvent.BUTTON1)
- if (event.isShiftDown())
- moveCaret(event);
- else
- positionCaret(event);
- else if(button == MouseEvent.BUTTON2)
- if (event.isShiftDown())
- event.consume();
+
+ if (SwingUtilities.isLeftMouseButton(event))
+ {
+ // Handle the caret.
+ if (event.isShiftDown() && getDot() != -1)
+ {
+ moveCaret(event);
+ }
else
{
positionCaret(event);
-
+ }
+
+ // Handle the focus.
+ if (textComponent != null && textComponent.isEnabled()
+ && textComponent.isRequestFocusEnabled())
+ {
+ textComponent.requestFocus();
+ }
+
+ // TODO: Handle double click for selecting words.
+ }
+ else if(event.getButton() == MouseEvent.BUTTON2)
+ {
+ // Special handling for X11-style pasting.
+ if (! event.isShiftDown())
+ {
+ positionCaret(event);
textComponent.paste();
}
- else
- event.consume();
+ }
}
/**
@@ -708,7 +724,11 @@ public class DefaultCaret extends Rectangle
propertyChangeListener = new PropertyChangeHandler();
textComponent.addPropertyChangeListener(propertyChangeListener);
documentListener = new DocumentHandler();
- textComponent.getDocument().addDocumentListener(documentListener);
+
+ Document doc = textComponent.getDocument();
+ if (doc != null)
+ doc.addDocumentListener(documentListener);
+
active = textComponent.isEditable() && textComponent.isEnabled();
repaint();
@@ -891,10 +911,10 @@ public class DefaultCaret extends Rectangle
}
catch (BadLocationException e)
{
- AssertionError ae;
- ae = new AssertionError("Unexpected bad caret location: " + dot);
- ae.initCause(e);
- throw ae;
+ // Let's ignore that. This shouldn't really occur. But if it
+ // does (it seems that this happens when the model is mutating),
+ // it causes no real damage. Uncomment this for debugging.
+ // e.printStackTrace();
}
if (rect == null)
@@ -1128,10 +1148,10 @@ public class DefaultCaret extends Rectangle
}
catch (BadLocationException e)
{
- AssertionError ae;
- ae = new AssertionError("Unexpected bad caret location: " + dot);
- ae.initCause(e);
- throw ae;
+ // Let's ignore that. This shouldn't really occur. But if it
+ // does (it seems that this happens when the model is mutating),
+ // it causes no real damage. Uncomment this for debugging.
+ // e.printStackTrace();
}
if (area != null)
damage(area);
@@ -1140,6 +1160,24 @@ public class DefaultCaret extends Rectangle
}
/**
+ * Returns <code>true</code> if this <code>Caret</code> is blinking,
+ * and <code>false</code> if not. The returned value is independent of
+ * the visiblity of this <code>Caret</code> as returned by {@link #isVisible()}.
+ *
+ * @return <code>true</code> if this <code>Caret</code> is blinking,
+ * and <code>false</code> if not.
+ * @see #isVisible()
+ * @since 1.5
+ */
+ public boolean isActive()
+ {
+ if (blinkTimer != null)
+ return blinkTimer.isRunning();
+
+ return false;
+ }
+
+ /**
* Returns <code>true</code> if this <code>Caret</code> is currently visible,
* and <code>false</code> if it is not.
*
diff --git a/libjava/classpath/javax/swing/text/EmptyAttributeSet.java b/libjava/classpath/javax/swing/text/EmptyAttributeSet.java
new file mode 100644
index 00000000000..98fb8828c89
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/EmptyAttributeSet.java
@@ -0,0 +1,153 @@
+/* EmptyAttributeSet.java -- An empty attribute set
+ Copyright (C) 2006 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.text;
+
+import java.util.Enumeration;
+import java.util.NoSuchElementException;
+
+/**
+ * An immutable, empty attribute set.
+ *
+ * @see SimpleAttributeSet#EMPTY
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+final class EmptyAttributeSet
+ implements AttributeSet
+{
+
+ /**
+ * Always return false as this AttributeSet doesn't contain any attributes.
+ */
+ public boolean containsAttribute(Object name, Object value)
+ {
+ return false;
+ }
+
+ /**
+ * Return true only if the attributes argument also contains no attributes.
+ */
+ public boolean containsAttributes(AttributeSet attributes)
+ {
+ return attributes.getAttributeCount() == 0;
+ }
+
+ /**
+ * Return this, as this is immutable.
+ */
+ public AttributeSet copyAttributes()
+ {
+ return this;
+ }
+
+ /**
+ * Always return null as this AttributeSet doesn't contain any attributes.
+ */
+ public Object getAttribute(Object key)
+ {
+ return null;
+ }
+
+ /**
+ * Always return 0.
+ */
+ public int getAttributeCount()
+ {
+ return 0;
+ }
+
+ /**
+ * Returns an empty Enumeration.
+ */
+ public Enumeration getAttributeNames()
+ {
+ return new Enumeration()
+ {
+ public boolean hasMoreElements()
+ {
+ return false;
+ }
+
+ public Object nextElement()
+ {
+ throw new NoSuchElementException("No more elements");
+ }
+
+ };
+ }
+
+ /**
+ * Always return null as this has no resolve parent.
+ */
+ public AttributeSet getResolveParent()
+ {
+ return null;
+ }
+
+ /**
+ * Always return false as this AttributeSet doesn't contain any attributes.
+ */
+ public boolean isDefined(Object attrName)
+ {
+ return false;
+ }
+
+ /**
+ * Other attribute sets are equal if they are empty too.
+ */
+ public boolean isEqual(AttributeSet attr)
+ {
+ return attr.getAttributeCount() == 0;
+ }
+
+ /**
+ * Other objects are equal if it's the same instance as this, or if
+ * it's another attribute set without attributes.
+ */
+ public boolean equals(Object o)
+ {
+ boolean eq = o == this;
+ if (! eq)
+ {
+ eq = (o instanceof AttributeSet)
+ && ((AttributeSet) o).getAttributeCount() == 0;
+ }
+ return eq;
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/FlowView.java b/libjava/classpath/javax/swing/text/FlowView.java
index 8ca55d8347a..3de95ed7f8d 100644
--- a/libjava/classpath/javax/swing/text/FlowView.java
+++ b/libjava/classpath/javax/swing/text/FlowView.java
@@ -159,20 +159,18 @@ public abstract class FlowView extends BoxView
}
/**
- * Lays out one row of the flow view. This is called by {@link #layout}
- * to fill one row with child views until the available span is exhausted.
- *
- * The default implementation fills the row by calling
- * {@link #createView(FlowView, int, int, int)} until the available space
- * is exhausted, a forced break is encountered or there are no more views
- * in the logical view. If the available space is exhausted,
- * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row
- * into the available span.
- *
+ * Lays out one row of the flow view. This is called by {@link #layout} to
+ * fill one row with child views until the available span is exhausted. The
+ * default implementation fills the row by calling
+ * {@link #createView(FlowView, int, int, int)} until the available space is
+ * exhausted, a forced break is encountered or there are no more views in
+ * the logical view. If the available space is exhausted,
+ * {@link #adjustRow(FlowView, int, int, int)} is called to fit the row into
+ * the available span.
+ *
* @param fv the flow view for which we perform the layout
* @param rowIndex the index of the row
* @param pos the model position for the beginning of the row
- *
* @return the start position of the next row
*/
protected int layoutRow(FlowView fv, int rowIndex, int pos)
@@ -188,34 +186,39 @@ public abstract class FlowView extends BoxView
if (span == 0)
span = Integer.MAX_VALUE;
- while (span > 0)
+ Row: while (span > 0)
{
- if (logicalView.getViewIndex(offset, Position.Bias.Forward) == -1)
+ if (logicalView.getViewIndex(offset, Position.Bias.Forward) == - 1)
break;
View view = createView(fv, offset, span, rowIndex);
if (view == null)
break;
+
int viewSpan = (int) view.getPreferredSpan(axis);
- row.append(view);
int breakWeight = view.getBreakWeight(axis, x, span);
- if (breakWeight >= View.ForcedBreakWeight)
- break;
+
+ row.append(view);
+ offset += (view.getEndOffset() - view.getStartOffset());
x += viewSpan;
span -= viewSpan;
- offset += (view.getEndOffset() - view.getStartOffset());
- }
- if (span < 0)
- {
- int flowStart = fv.getFlowStart(axis);
- int flowSpan = fv.getFlowSpan(axis);
- adjustRow(fv, rowIndex, flowSpan, flowStart);
- int rowViewCount = row.getViewCount();
- if (rowViewCount > 0)
- offset = row.getView(rowViewCount - 1).getEndOffset();
- else
- offset = -1;
+
+ // Break if the line if the view does not fit in this row or the
+ // line just must be broken.
+ if (span < 0 || breakWeight >= View.ForcedBreakWeight)
+ {
+ int flowStart = fv.getFlowStart(axis);
+ int flowSpan = fv.getFlowSpan(axis);
+ adjustRow(fv, rowIndex, flowSpan, flowStart);
+ int rowViewCount = row.getViewCount();
+ if (rowViewCount > 0)
+ offset = row.getView(rowViewCount - 1).getEndOffset();
+ else
+ offset = - 1;
+ break Row;
+ }
}
- return offset != pos ? offset : -1;
+
+ return offset != pos ? offset : - 1;
}
/**
@@ -521,6 +524,7 @@ public abstract class FlowView extends BoxView
*/
public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
{
+ layoutPool.removeUpdate(changes, a, vf);
strategy.removeUpdate(this, changes, getInsideAllocation(a));
layoutDirty = true;
}
@@ -536,6 +540,7 @@ public abstract class FlowView extends BoxView
*/
public void changedUpdate(DocumentEvent changes, Shape a, ViewFactory vf)
{
+ layoutPool.changedUpdate(changes, a, vf);
strategy.changedUpdate(this, changes, getInsideAllocation(a));
layoutDirty = true;
}
@@ -594,12 +599,14 @@ public abstract class FlowView extends BoxView
protected SizeRequirements calculateMinorAxisRequirements(int axis,
SizeRequirements r)
{
- // We need to call super here so that the alignment is properly
- // calculated.
- SizeRequirements res = super.calculateMinorAxisRequirements(axis, r);
+ SizeRequirements res = r;
+ if (res == null)
+ res = new SizeRequirements();
res.minimum = (int) layoutPool.getMinimumSpan(axis);
- res.preferred = (int) layoutPool.getPreferredSpan(axis);
- res.maximum = (int) layoutPool.getMaximumSpan(axis);
+ res.preferred = Math.max(res.minimum,
+ (int) layoutPool.getMinimumSpan(axis));
+ res.maximum = Integer.MAX_VALUE;
+ res.alignment = 0.5F;
return res;
}
}
diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java
index 4f06003b458..760e396a223 100644
--- a/libjava/classpath/javax/swing/text/GapContent.java
+++ b/libjava/classpath/javax/swing/text/GapContent.java
@@ -39,7 +39,13 @@ exception statement from your version. */
package javax.swing.text;
import java.io.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.WeakHashMap;
@@ -73,30 +79,39 @@ public class GapContent
* The index to the positionMarks array entry, which in turn holds the
* mark into the buffer array.
*/
- int index;
+ Mark mark;
/**
* Creates a new GapContentPosition object.
*
- * @param mark the mark of this Position
+ * @param offset the offset of this Position
*/
- GapContentPosition(int mark)
+ GapContentPosition(int offset)
{
// Try to find the mark in the positionMarks array, and store the index
// to it.
synchronized (GapContent.this)
{
- int i = binarySearch(positionMarks, mark, numMarks);
+ // Try to make space.
+ garbageCollect();
+ Mark m = new Mark(offset);
+ int i = search(marks, m);
if (i >= 0) // mark found
{
- index = i;
+ m = (Mark) marks.get(i);
}
else
{
- index = -i - 1;
- insertMark(index, mark);
+ i = -i - 1;
+ marks.add(i, m);
}
+ m.refCount++;
+ mark = m;
}
+
+ // Register this position in the death queue, so we can cleanup the marks
+ // when this position object gets GC'ed.
+ new WeakReference(this, queueOfDeath);
}
/**
@@ -106,19 +121,77 @@ public class GapContent
*/
public int getOffset()
{
- synchronized (GapContent.this)
- {
- // Fetch the actual mark.
- int mark = positionMarks[index];
- // Check precondition.
- assert mark <= gapStart || mark >= gapEnd : "mark: " + mark
- + ", gapStart: " + gapStart
- + ", gapEnd: " + gapEnd;
- int res = mark;
- if (mark > gapStart)
- res -= (gapEnd - gapStart);
- return res;
- }
+ return mark.getOffset();
+ }
+ }
+
+ /**
+ * Holds a mark into the buffer that is used by GapContentPosition to find
+ * the actual offset of the position. This is pulled out of the
+ * GapContentPosition object so that the mark and position can be handled
+ * independently, and most important, so that the GapContentPosition can
+ * be garbage collected while we still hold a reference to the Mark object.
+ */
+ private class Mark
+ implements Comparable
+ {
+ /**
+ * The actual mark into the buffer.
+ */
+ int mark;
+
+ /**
+ * The number of GapContentPosition object that reference this mark. If
+ * it reaches zero, it get's deleted by {@link GapContent#garbageCollect()}.
+ */
+ int refCount;
+
+ /**
+ * Creates a new Mark object for the specified offset.
+ *
+ * @param offset the offset
+ */
+ Mark(int offset)
+ {
+ mark = offset;
+ if (mark >= gapStart && mark != 0)
+ mark += (gapEnd - gapStart);
+ }
+
+ /**
+ * Returns the offset of the mark.
+ *
+ * @return the offset of the mark
+ */
+ int getOffset()
+ {
+ assert mark == 0 || mark < gapStart || mark >= gapEnd :
+ "Invalid mark: " + mark + ", gapStart: " + gapStart
+ + ", gapEnd: " + gapEnd;
+
+ int res = mark;
+ if (mark >= gapEnd)
+ res -= (gapEnd - gapStart);
+ return res;
+ }
+
+ /**
+ * Implementation of Comparable.
+ */
+ public int compareTo(Object o)
+ {
+ Mark other = (Mark) o;
+ return mark - other.mark;
+ }
+ /**
+ * Adjustment for equals().
+ */
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof Mark))
+ return false;
+ else
+ return ((Mark) o).mark == mark;
}
}
@@ -230,19 +303,21 @@ public class GapContent
/**
* Holds the marks for positions. These marks are referenced by the
* GapContentPosition instances by an index into this array.
+ *
+ * This is package private to avoid accessor synthetic methods.
*/
- int[] positionMarks;
+ ArrayList marks;
- /**
- * The number of elements in the positionMarks array. The positionMarks array
- * might be bigger than the actual number of elements.
- */
- int numMarks;
+ WeakHashMap positions;
/**
- * (Weakly) Stores the GapContentPosition instances.
+ * Queues all references to GapContentPositions that are about to be
+ * GC'ed. This is used to remove the corresponding marks from the
+ * positionMarks array if the number of references to that mark reaches zero.
+ *
+ * This is package private to avoid accessor synthetic methods.
*/
- WeakHashMap positions;
+ ReferenceQueue queueOfDeath;
/**
* Creates a new GapContent object.
@@ -265,8 +340,8 @@ public class GapContent
gapEnd = size;
buffer[0] = '\n';
positions = new WeakHashMap();
- positionMarks = new int[10];
- numMarks = 0;
+ marks = new ArrayList();
+ queueOfDeath = new ReferenceQueue();
}
/**
@@ -417,6 +492,8 @@ public class GapContent
if ((where + len) > length)
throw new BadLocationException("len plus where cannot be greater"
+ " than the content length", len + where);
+ if (len < 0)
+ throw new BadLocationException("negative length not allowed: ", len);
// check if requested segment is contiguous
if ((where < gapStart) && ((gapStart - where) < len))
@@ -455,6 +532,11 @@ public class GapContent
*/
public Position createPosition(final int offset) throws BadLocationException
{
+ // Implementation note: We used to perform explicit check on the offset
+ // here. However, this makes some Mauve and Intel/Harmony tests fail
+ // and luckily enough the GapContent can very well deal with offsets
+ // outside the buffer bounds. So I removed that check.
+
// We try to find a GapContentPosition at the specified offset and return
// that. Otherwise we must create a new one.
GapContentPosition pos = null;
@@ -472,10 +554,7 @@ public class GapContent
// If none was found, then create and return a new one.
if (pos == null)
{
- int mark = offset;
- if (mark >= gapStart)
- mark += (gapEnd - gapStart);
- pos = new GapContentPosition(mark);
+ pos = new GapContentPosition(offset);
positions.put(pos, null);
}
@@ -497,7 +576,7 @@ public class GapContent
int delta = newSize - gapEnd + gapStart;
// Update the marks after the gapEnd.
- adjustPositionsInRange(gapEnd, buffer.length - gapEnd, delta);
+ adjustPositionsInRange(gapEnd, -1, delta);
// Copy the data around.
char[] newBuf = (char[]) allocateArray(length() + newSize);
@@ -523,7 +602,7 @@ public class GapContent
{
// Update the positions between newGapStart and (old) gapStart. The marks
// must be shifted by (gapEnd - gapStart).
- adjustPositionsInRange(newGapStart, gapStart - newGapStart, gapEnd - gapStart);
+ adjustPositionsInRange(newGapStart, gapStart, gapEnd - gapStart);
System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart
- newGapStart);
gapStart = newGapStart;
@@ -533,14 +612,13 @@ public class GapContent
{
// Update the positions between newGapEnd and (old) gapEnd. The marks
// must be shifted by (gapEnd - gapStart).
- adjustPositionsInRange(gapEnd, newGapEnd - gapEnd, -(gapEnd - gapStart));
+ adjustPositionsInRange(gapEnd, newGapEnd, -(gapEnd - gapStart));
System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart
- gapStart);
gapStart = newGapStart;
gapEnd = newGapEnd;
}
- if (gapStart == 0)
- resetMarksAtZero();
+ resetMarksAtZero();
}
/**
@@ -560,6 +638,7 @@ public class GapContent
+ "old gap start.";
setPositionsInRange(newGapStart, gapStart, false);
gapStart = newGapStart;
+ resetMarksAtZero();
}
/**
@@ -579,6 +658,7 @@ public class GapContent
+ "old gap end.";
setPositionsInRange(gapEnd, newGapEnd, false);
gapEnd = newGapEnd;
+ resetMarksAtZero();
}
/**
@@ -617,10 +697,6 @@ public class GapContent
if (addItems != null)
{
System.arraycopy(addItems, 0, buffer, gapStart, addSize);
-
-
- resetMarksAtZero();
-
gapStart += addSize;
}
}
@@ -689,102 +765,61 @@ public class GapContent
*/
private void setPositionsInRange(int start, int end, boolean toStart)
{
- // We slump together all the GapContentPositions to point to
- // one mark. So this is implemented as follows:
- // 1. Remove all the marks in the specified range.
- // 2. Insert one new mark at the correct location.
- // 3. Adjust all affected GapContentPosition instances to point to
- // this new mark.
-
synchronized (this)
{
- int startIndex = binarySearch(positionMarks, start, numMarks);
+ // Find the start and end indices in the positionMarks array.
+ Mark m = new Mark(0); // For comparison / search only.
+ m.mark = start;
+ int startIndex = search(marks, m);
if (startIndex < 0) // Translate to insertion index, if not found.
startIndex = - startIndex - 1;
- int endIndex = binarySearch(positionMarks, end, numMarks);
+ m.mark = end;
+ int endIndex = search(marks, m);
if (endIndex < 0) // Translate to insertion index - 1, if not found.
endIndex = - endIndex - 2;
- // Update the marks.
- // We have inclusive interval bounds, but let one element over for
- // filling in the new value.
- int removed = endIndex - startIndex;
- if (removed <= 0)
- return;
- System.arraycopy(positionMarks, endIndex + 1, positionMarks,
- startIndex + 1, positionMarks.length - endIndex - 1);
- numMarks -= removed;
- if (toStart)
- {
- positionMarks[startIndex] = start;
- }
- else
- {
- positionMarks[startIndex] = end;
- }
+ // Actually adjust the marks.
+ for (int i = startIndex; i <= endIndex; i++)
+ ((Mark) marks.get(i)).mark = toStart ? start : end;
+ }
- // Update all affected GapContentPositions to point to the new index
- // and all GapContentPositions that come after the interval to
- // have their index moved by -removed.
- Set positionSet = positions.keySet();
- for (Iterator i = positionSet.iterator(); i.hasNext();)
- {
- GapContentPosition p = (GapContentPosition) i.next();
- if (p.index > startIndex || p.index <= endIndex)
- p.index = startIndex;
- else if (p.index > endIndex)
- p.index -= removed;
- }
- }
}
-
+
/**
* Adjusts the mark of all <code>Position</code>s that are in the range
* specified by <code>offset</code> and </code>length</code> within
* the buffer array by <code>increment</code>
*
- * @param offset the start offset of the range to search
- * @param length the length of the range to search
+ * @param startOffs the start offset of the range to search
+ * @param endOffs the length of the range to search, -1 means all to the end
* @param incr the increment
*/
- private void adjustPositionsInRange(int offset, int length, int incr)
+ private void adjustPositionsInRange(int startOffs, int endOffs, int incr)
{
- int endMark = offset + length;
-
synchronized (this)
{
// Find the start and end indices in the positionMarks array.
- int startIndex = binarySearch(positionMarks, offset, numMarks);
+ Mark m = new Mark(0); // For comparison / search only.
+
+ m.mark = startOffs;
+ int startIndex = search(marks, m);
if (startIndex < 0) // Translate to insertion index, if not found.
startIndex = - startIndex - 1;
- int endIndex = binarySearch(positionMarks, endMark, numMarks);
- if (endIndex < 0) // Translate to insertion index - 1, if not found.
- endIndex = - endIndex - 2;
-
- // We must not change the order of the marks, this would have
- // unpredictable results while binary-searching the marks.
- assert (startIndex <= 0
- || positionMarks[startIndex - 1]
- <= positionMarks [startIndex] + incr)
- && (endIndex >= numMarks - 1
- || positionMarks[endIndex + 1]
- >= positionMarks[endIndex] + incr)
- : "Adjusting the marks must not change their order";
-
- // Some debug helper output to determine if the start or end of the
- // should ever be coalesced together with adjecent marks.
- if (startIndex > 0 && positionMarks[startIndex - 1]
- == positionMarks[startIndex] + incr)
- System.err.println("DEBUG: We could coalesce the start of the region"
- + " in GapContent.adjustPositionsInRange()");
- if (endIndex < numMarks - 1 && positionMarks[endIndex + 1]
- == positionMarks[endIndex] + incr)
- System.err.println("DEBUG: We could coalesce the end of the region"
- + " in GapContent.adjustPositionsInRange()");
+ m.mark = endOffs;
+ int endIndex;
+ if (endOffs == -1)
+ endIndex = marks.size() - 1;
+ else
+ {
+ endIndex = search(marks, m);
+ if (endIndex < 0) // Translate to insertion index - 1, if not found.
+ endIndex = - endIndex - 2;
+ }
// Actually adjust the marks.
- for (int i = startIndex; i <= endIndex; i++)
- positionMarks[i] += incr;
+ for (int i = startIndex; i <= endIndex; i++) {
+ ((Mark) marks.get(i)).mark += incr;
+ }
}
}
@@ -800,7 +835,12 @@ public class GapContent
if (gapStart != 0)
return;
- positionMarks[0] = 0;
+ for (int i = 0; i < marks.size(); i++)
+ {
+ Mark m = (Mark) marks.get(i);
+ if (m.mark <= gapEnd)
+ m.mark = 0;
+ }
}
/**
@@ -845,89 +885,60 @@ public class GapContent
*/
private void dumpMarks()
{
- System.err.print("positionMarks: ");
- for (int i = 0; i < numMarks; i++)
- System.err.print(positionMarks[i] + ", ");
- System.err.println();
+ System.out.print("positionMarks: ");
+ for (int i = 0; i < marks.size(); i++)
+ System.out.print(((Mark) marks.get(i)).mark + ", ");
+ System.out.println();
}
/**
- * Inserts a mark into the positionMarks array. This must update all the
- * GapContentPosition instances in positions that come after insertionPoint.
+ * Polls the queue of death for GapContentPositions, updates the
+ * corresponding reference count and removes the corresponding mark
+ * if the refcount reaches zero.
*
- * This is package private to avoid synthetic accessor methods.
- *
- * @param insertionPoint the index at which to insert the mark
- * @param mark the mark to insert
+ * This is package private to avoid accessor synthetic methods.
*/
- void insertMark(int insertionPoint, int mark)
+ void garbageCollect()
{
- synchronized (this)
+ Reference ref = queueOfDeath.poll();
+ while (ref != null)
{
- // Update the positions.
- Set positionSet = positions.keySet();
- for (Iterator i = positionSet.iterator(); i.hasNext();)
- {
- GapContentPosition p = (GapContentPosition) i.next();
- if (p.index >= insertionPoint)
- p.index++;
- }
-
- // Update the position marks.
- if (positionMarks.length <= numMarks)
+ if (ref != null)
{
- int[] newMarks = new int[positionMarks.length + 10];
- System.arraycopy(positionMarks, 0, newMarks, 0, insertionPoint);
- newMarks[insertionPoint] = mark;
- System.arraycopy(positionMarks, insertionPoint, newMarks,
- insertionPoint + 1,
- numMarks - insertionPoint);
- positionMarks = newMarks;
+ GapContentPosition pos = (GapContentPosition) ref.get();
+ Mark m = pos.mark;
+ m.refCount--;
+ if (m.refCount == 0)
+ marks.remove(m);
}
- else
- {
- System.arraycopy(positionMarks, insertionPoint, positionMarks,
- insertionPoint + 1,
- numMarks - insertionPoint);
- positionMarks[insertionPoint] = mark;
- }
- numMarks++;
+ ref = queueOfDeath.poll();
}
}
/**
- * An adaption of {@link java.util.Arrays#binarySearch(int[], int)} to
- * specify a maximum index up to which the array is searched. This allows
- * us to have some trailing entries that we ignore.
- *
- * This is package private to avoid synthetic accessor methods.
- *
- * @param a the array
- * @param key the key to search for
- * @param maxIndex the maximum index up to which the search is performed
+ * Searches the first occurance of object <code>o</code> in list
+ * <code>l</code>. This performs a binary search by calling
+ * {@link Collections#binarySearch(List, Object)} and when an object has been
+ * found, it searches backwards to the first occurance of that object in the
+ * list. The meaning of the return value is the same as in
+ * <code>Collections.binarySearch()</code>.
*
- * @return the index of the found entry, or (-(index)-1) for the
- * insertion point when not found
+ * @param l the list to search through
+ * @param o the object to be searched
*
- * @see java.util.Arrays#binarySearch(int[], int)
+ * @return the index of the first occurance of o in l, or -i + 1 if not found
*/
- int binarySearch(int[] a, int key, int maxIndex)
+ private int search(List l, Object o)
{
- int low = 0;
- int hi = maxIndex - 1;
- int mid = 0;
- while (low <= hi)
+ int i = Collections.binarySearch(l, o);
+ while (i > 0)
{
- mid = (low + hi) >>> 1;
- final int d = a[mid];
- if (d == key)
- return mid;
- else if (d > key)
- hi = mid - 1;
+ Object o2 = l.get(i - 1);
+ if (o2.equals(o))
+ i--;
else
- // This gets the insertion point right on the last loop.
- low = ++mid;
+ break;
}
- return -mid - 1;
+ return i;
}
}
diff --git a/libjava/classpath/javax/swing/text/IconView.java b/libjava/classpath/javax/swing/text/IconView.java
index 699cda90eba..7bb7635b4e7 100644
--- a/libjava/classpath/javax/swing/text/IconView.java
+++ b/libjava/classpath/javax/swing/text/IconView.java
@@ -44,7 +44,6 @@ import java.awt.Shape;
import javax.swing.Icon;
import javax.swing.JTextPane;
-import javax.swing.SwingConstants;
/**
* A View that can render an icon. This view is created by the
@@ -156,4 +155,21 @@ public class IconView
return el.getStartOffset();
}
+ /**
+ * Returns the alignment for this view. This will be 1.0 for the Y_AXIS,
+ * and the super behaviour for the X_AXIS.
+ *
+ * @param axis the axis for which to calculate the alignment
+ *
+ * @return the alignment
+ */
+ public float getAlignment(int axis)
+ {
+ float align;
+ if (axis == Y_AXIS)
+ align = 1.0F;
+ else
+ align = super.getAlignment(axis);
+ return align;
+ }
}
diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java
index 9de151dfbac..6da84bfe7d8 100644
--- a/libjava/classpath/javax/swing/text/JTextComponent.java
+++ b/libjava/classpath/javax/swing/text/JTextComponent.java
@@ -42,6 +42,7 @@ import gnu.classpath.NotImplementedException;
import java.awt.AWTEvent;
import java.awt.Color;
+import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Point;
@@ -90,9 +91,10 @@ public abstract class JTextComponent extends JComponent
implements Scrollable, Accessible
{
/**
- * This class implements accessibility support for the JTextComponent class.
- * It provides an implementation of the Java Accessibility API appropriate
- * to menu user-interface elements.
+ * AccessibleJTextComponent implements accessibility hooks for
+ * JTextComponent. It allows an accessibility driver to read and
+ * manipulate the text component's contents as well as update UI
+ * elements such as the caret.
*/
public class AccessibleJTextComponent extends AccessibleJComponent implements
AccessibleText, CaretListener, DocumentListener, AccessibleAction,
@@ -100,15 +102,18 @@ public abstract class JTextComponent extends JComponent
{
private static final long serialVersionUID = 7664188944091413696L;
- /** The caret's offset. */
+ /**
+ * The caret's offset.
+ */
int dot = 0;
-
- /** The current JTextComponent. */
+
+ /**
+ * The current JTextComponent.
+ */
JTextComponent textComp = JTextComponent.this;
-
+
/**
- * Constructs an AccessibleJTextComponent.
- * Adds a listener to track caret change.
+ * Construct an AccessibleJTextComponent.
*/
public AccessibleJTextComponent()
{
@@ -117,11 +122,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the zero-based offset of the caret. Note: The character
- * to the right of the caret will have the same index value as the
- * offset (the caret is between two characters).
- *
- * @return offset of caret
+ * Retrieve the current caret position. The index of the first
+ * caret position is 0.
+ *
+ * @return caret position
*/
public int getCaretPosition()
{
@@ -130,9 +134,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the portion of the text that is selected.
- *
- * @return null if no text is selected.
+ * Retrieve the current text selection. If no text is selected
+ * this method returns null.
+ *
+ * @return the currently selected text or null
*/
public String getSelectedText()
{
@@ -140,11 +145,14 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the start offset within the selected text. If there is no
- * selection, but there is a caret, the start and end offsets will be
- * the same. Return 0 if the text is empty, or the caret position if no selection.
- *
- * @return index of the start of the text >= 0.
+ * Retrieve the index of the first character in the current text
+ * selection. If there is no text in the text component, this
+ * method returns 0. If there is text in the text component, but
+ * there is no selection, this method returns the current caret
+ * position.
+ *
+ * @return the index of the first character in the selection, the
+ * current caret position or 0
*/
public int getSelectionStart()
{
@@ -154,12 +162,14 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the end offset within the selected text. If there is no
- * selection, but there is a caret, the start and end offsets will
- * be the same. Return 0 if the text is empty, or the caret position
- * if no selection.
- *
- * @return index of the end of the text >= 0.
+ * Retrieve the index of the last character in the current text
+ * selection. If there is no text in the text component, this
+ * method returns 0. If there is text in the text component, but
+ * there is no selection, this method returns the current caret
+ * position.
+ *
+ * @return the index of the last character in the selection, the
+ * current caret position or 0
*/
public int getSelectionEnd()
{
@@ -169,13 +179,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Handles caret updates (fire appropriate property change event, which are
- * AccessibleContext.ACCESSIBLE_CARET_PROPERTY and
- * AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY). This keeps track of
- * the dot position internally. When the caret moves, the internal position
- * is updated after firing the event.
- *
- * @param e - caret event
+ * Handle a change in the caret position and fire any applicable
+ * property change events.
+ *
+ * @param e - the caret update event
*/
public void caretUpdate(CaretEvent e)
throws NotImplementedException
@@ -185,7 +192,7 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the accessible state set of this component.
+ * Retreive the accessible state set of this component.
*
* @return the accessible state set of this component
*/
@@ -198,7 +205,7 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the accessible role of this component.
+ * Retrieve the accessible role of this component.
*
* @return the accessible role of this component
*
@@ -210,20 +217,19 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the AccessibleEditableText interface for this text component.
- *
+ * Retrieve an AccessibleEditableText object that controls this
+ * text component.
+ *
* @return this
*/
public AccessibleEditableText getAccessibleEditableText()
{
return this;
}
-
+
/**
- * Get the AccessibleText associated with this object. In the implementation
- * of the Java Accessibility API for this class, return this object,
- * which is responsible for implementing the AccessibleText interface on
- * behalf of itself.
+ * Retrieve an AccessibleText object that controls this text
+ * component.
*
* @return this
*
@@ -235,10 +241,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Insert update. Fire appropriate property change event which
- * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
- *
- * @param e - document event
+ * Handle a text insertion event and fire an
+ * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
+ * event.
+ *
+ * @param e - the insertion event
*/
public void insertUpdate(DocumentEvent e)
throws NotImplementedException
@@ -247,10 +254,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Remove update. Fire appropriate property change event which
- * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
- *
- * @param e - document event
+ * Handle a text removal event and fire an
+ * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
+ * event.
+ *
+ * @param e - the removal event
*/
public void removeUpdate(DocumentEvent e)
throws NotImplementedException
@@ -259,10 +267,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Changed update. Fire appropriate property change event which
- * is AccessibleContext.ACCESSIBLE_TEXT_PROPERTY.
- *
- * @param e - document event
+ * Handle a text change event and fire an
+ * AccessibleContext.ACCESSIBLE_TEXT_PROPERTY property change
+ * event.
+ *
+ * @param e - text change event
*/
public void changedUpdate(DocumentEvent e)
throws NotImplementedException
@@ -271,11 +280,13 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Given a point in the coordinate system of this object, return the
- * 0-based index of the character at that point, or -1 if there is none.
+ * Get the index of the character at the given point, in component
+ * pixel co-ordinates. If the point argument is invalid this
+ * method returns -1.
*
- * @param p the point to look at
- * @return the character index, or -1
+ * @param p - a point in component pixel co-ordinates
+ *
+ * @return a character index, or -1
*/
public int getIndexAtPoint(Point p)
throws NotImplementedException
@@ -284,17 +295,14 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Determines the bounding box of the indexed character. Returns an empty
- * rectangle if the index is out of bounds. The bounds are returned in local coordinates.
- * If the index is invalid a null rectangle is returned. The screen coordinates returned are
- * "unscrolled coordinates" if the JTextComponent is contained in a JScrollPane in which
- * case the resulting rectangle should be composed with the parent coordinates.
- * Note: the JTextComponent must have a valid size (e.g. have been added to a parent
- * container whose ancestor container is a valid top-level window) for this method to
- * be able to return a meaningful (non-null) value.
+ * Calculate the bounding box of the character at the given index.
+ * The returned x and y co-ordinates are relative to this text
+ * component's top-left corner. If the index is invalid this
+ * method returns null.
+ *
+ * @param index - the character index
*
- * @param index the 0-based character index
- * @return the bounding box, may be empty or null.
+ * @return a character's bounding box, or null
*/
public Rectangle getCharacterBounds(int index)
throws NotImplementedException
@@ -303,9 +311,9 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Return the number of characters.
+ * Return the length of the text in this text component.
*
- * @return the character count
+ * @return a character length
*/
public int getCharCount()
{
@@ -313,10 +321,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the attributes of a character at an index, or null if the index
- * is out of bounds.
+ * Gets the character attributes of the character at index. If
+ * the index is out of bounds, null is returned.
*
- * @param index the 0-based character index
+ * @param index - index of the character
+ *
* @return the character's attributes
*/
public AttributeSet getCharacterAttribute(int index)
@@ -326,26 +335,28 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the section of text at the index, or null if the index or part
- * is invalid.
- *
- * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
- * @param index the 0-based character index
- * @return the selection of text at that index, or null
+ * Gets the text located at index. null is returned if the index
+ * or part is invalid.
+ *
+ * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index - index of the part
+ *
+ * @return the part of text at that index, or null
*/
public String getAtIndex(int part, int index)
throws NotImplementedException
{
return null; // TODO
}
-
+
/**
- * Returns the section of text after the index, or null if the index or part
- * is invalid.
- *
- * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
- * @param index the 0-based character index
- * @return the selection of text after that index, or null
+ * Gets the text located after index. null is returned if the index
+ * or part is invalid.
+ *
+ * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index - index after the part
+ *
+ * @return the part of text after that index, or null
*/
public String getAfterIndex(int part, int index)
throws NotImplementedException
@@ -354,12 +365,13 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Returns the section of text before the index, or null if the index or part
- * is invalid.
- *
- * @param part {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
- * @param index the 0-based character index
- * @return the selection of text before that index, or null
+ * Gets the text located before index. null is returned if the index
+ * or part is invalid.
+ *
+ * @param part - {@link #CHARACTER}, {@link #WORD}, or {@link #SENTENCE}
+ * @param index - index before the part
+ *
+ * @return the part of text before that index, or null
*/
public String getBeforeIndex(int part, int index)
throws NotImplementedException
@@ -368,10 +380,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Get the number possible actions for this object, with the zeroth
- * representing the default action.
+ * Returns the number of actions for this object. The zero-th
+ * object represents the default action.
*
- * @return the 0-based number of actions
+ * @return the number of actions (0-based).
*/
public int getAccessibleActionCount()
throws NotImplementedException
@@ -380,11 +392,12 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Get a description for the specified action. Returns null if out of
- * bounds.
+ * Returns the description of the i-th action. Null is returned if
+ * i is out of bounds.
*
- * @param i the action to describe, 0-based
- * @return description of the action
+ * @param i - the action to get the description for
+ *
+ * @return description of the i-th action
*/
public String getAccessibleActionDescription(int i)
throws NotImplementedException
@@ -394,10 +407,12 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Perform the specified action. Does nothing if out of bounds.
+ * Performs the i-th action. Nothing happens if i is
+ * out of bounds.
*
- * @param i the action to perform, 0-based
- * @return true if the action was performed
+ * @param i - the action to perform
+ *
+ * @return true if the action was performed successfully
*/
public boolean doAccessibleAction(int i)
throws NotImplementedException
@@ -406,9 +421,9 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Set the text contents to the given string.
+ * Sets the text contents.
*
- * @param s the new text
+ * @param s - the new text contents.
*/
public void setTextContents(String s)
throws NotImplementedException
@@ -417,10 +432,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Inserts the given string at the specified location.
+ * Inserts the text at the given index.
*
- * @param index the index for insertion
- * @param s the new text
+ * @param index - the index to insert the new text at.
+ * @param s - the new text
*/
public void insertTextAtIndex(int index, String s)
throws NotImplementedException
@@ -429,10 +444,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Return the text between two points.
+ * Gets the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public String getTextRange(int start, int end)
{
@@ -447,10 +462,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Delete the text between two points.
+ * Deletes the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public void delete(int start, int end)
{
@@ -458,10 +473,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Cut the text between two points to the system clipboard.
+ * Cuts the text between two indexes. The text is put
+ * into the system clipboard.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public void cut(int start, int end)
{
@@ -470,9 +486,9 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Paste the text from the system clipboard at the given index.
+ * Pastes the text from the system clipboard to the given index.
*
- * @param start the start position
+ * @param start - the starting index
*/
public void paste(int start)
{
@@ -481,11 +497,12 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Replace the text between two points with the given string.
+ * Replaces the text between two indexes with the given text.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
- * @param s the string to paste
+ *
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
+ * @param s - the text to paste
*/
public void replaceText(int start, int end, String s)
{
@@ -494,10 +511,10 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Select the text between two points.
+ * Selects the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
*/
public void selectText(int start, int end)
{
@@ -505,11 +522,11 @@ public abstract class JTextComponent extends JComponent
}
/**
- * Set the attributes of text between two points.
+ * Sets the attributes of all the text between two indexes.
*
- * @param start the start position, inclusive
- * @param end the end position, exclusive
- * @param s the new attribute set for the range
+ * @param start - the starting index (inclusive)
+ * @param end - the ending index (exclusive)
+ * @param s - the new attribute set for the text in the range
*/
public void setAttributes(int start, int end, AttributeSet s)
throws NotImplementedException
@@ -1163,8 +1180,19 @@ public abstract class JTextComponent extends JComponent
public void setDocument(Document newDoc)
{
Document oldDoc = doc;
- doc = newDoc;
- firePropertyChange("document", oldDoc, newDoc);
+ try
+ {
+ if (oldDoc instanceof AbstractDocument)
+ ((AbstractDocument) oldDoc).readLock();
+
+ doc = newDoc;
+ firePropertyChange("document", oldDoc, newDoc);
+ }
+ finally
+ {
+ if (oldDoc instanceof AbstractDocument)
+ ((AbstractDocument) oldDoc).readUnlock();
+ }
revalidate();
repaint();
}
@@ -1641,10 +1669,12 @@ public abstract class JTextComponent extends JComponent
public boolean getScrollableTracksViewportWidth()
{
- if (getParent() instanceof JViewport)
- return getParent().getWidth() > getPreferredSize().width;
+ boolean res = false;;
+ Container c = getParent();
+ if (c instanceof JViewport)
+ res = ((JViewport) c).getExtentSize().width > getPreferredSize().width;
- return false;
+ return res;
}
/**
diff --git a/libjava/classpath/javax/swing/text/ParagraphView.java b/libjava/classpath/javax/swing/text/ParagraphView.java
index 15bed781825..c4857863d35 100644
--- a/libjava/classpath/javax/swing/text/ParagraphView.java
+++ b/libjava/classpath/javax/swing/text/ParagraphView.java
@@ -74,6 +74,39 @@ public class ParagraphView extends FlowView implements TabExpander
return align;
}
+ /**
+ * Allows rows to span the whole parent view.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ float max;
+ if (axis == X_AXIS)
+ max = Float.MAX_VALUE;
+ else
+ max = super.getMaximumSpan(axis);
+ return max;
+ }
+
+ /**
+ * Overridden because child views are not necessarily laid out in model
+ * order.
+ */
+ protected int getViewIndexAtPosition(int pos)
+ {
+ int index = -1;
+ if (pos >= getStartOffset() && pos < getEndOffset())
+ {
+ int nviews = getViewCount();
+ for (int i = 0; i < nviews && index == -1; i++)
+ {
+ View child = getView(i);
+ if (pos >= child.getStartOffset() && pos < child.getEndOffset())
+ index = i;
+ }
+ }
+ return index;
+ }
+
protected void loadChildren(ViewFactory vf)
{
// Do nothing here. The children are added while layouting.
@@ -140,7 +173,7 @@ public class ParagraphView extends FlowView implements TabExpander
{
float align;
if (axis == X_AXIS)
- align = super.getAlignment(axis);
+ align = 0.5F;
else if (getViewCount() > 0)
{
float prefHeight = getPreferredSpan(Y_AXIS);
@@ -148,7 +181,7 @@ public class ParagraphView extends FlowView implements TabExpander
align = (firstRowHeight / 2.F) / prefHeight;
}
else
- align = 0.0F;
+ align = 0.5F;
return align;
}
diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java
index c699dcad2aa..730a619da9f 100644
--- a/libjava/classpath/javax/swing/text/PlainDocument.java
+++ b/libjava/classpath/javax/swing/text/PlainDocument.java
@@ -56,8 +56,12 @@ public class PlainDocument extends AbstractDocument
public static final String lineLimitAttribute = "lineLimit";
public static final String tabSizeAttribute = "tabSize";
- private BranchElement rootElement;
- private int tabSize;
+ /**
+ * The default root element of this document. This is made type Element
+ * because the RI seems to accept other types of elements as well from
+ * createDefaultRoot() (when overridden by a subclass).
+ */
+ private Element rootElement;
public PlainDocument()
{
@@ -67,8 +71,10 @@ public class PlainDocument extends AbstractDocument
public PlainDocument(AbstractDocument.Content content)
{
super(content);
- tabSize = 8;
- rootElement = (BranchElement) createDefaultRoot();
+ rootElement = createDefaultRoot();
+
+ // This property has been determined using a Mauve test.
+ putProperty("tabSize", new Integer(8));
}
private void reindex()
@@ -105,10 +111,10 @@ public class PlainDocument extends AbstractDocument
protected AbstractDocument.AbstractElement createDefaultRoot()
{
BranchElement root =
- (BranchElement) createBranchElement(null, SimpleAttributeSet.EMPTY);
+ (BranchElement) createBranchElement(null, null);
Element[] array = new Element[1];
- array[0] = createLeafElement(root, SimpleAttributeSet.EMPTY, 0, 1);
+ array[0] = createLeafElement(root, null, 0, 1);
root.replace(0, 0, array);
return root;
@@ -117,116 +123,97 @@ public class PlainDocument extends AbstractDocument
protected void insertUpdate(DefaultDocumentEvent event,
AttributeSet attributes)
{
+
+ String text = null;
int offset = event.getOffset();
- int eventLength = event.getLength();
- int end = offset + event.getLength();
- int oldElementIndex, elementIndex = rootElement.getElementIndex(offset);
- Element firstElement = rootElement.getElement(elementIndex);
- oldElementIndex = elementIndex;
-
- // If we're inserting immediately after a newline we have to fix the
- // Element structure (but only if we are dealing with a line which
- // has not existed as Element before).
- if (offset > 0 && firstElement.getStartOffset() != offset)
+ int length = event.getLength();
+ try
{
- try
- {
- String s = getText(offset - 1, 1);
- if (s.equals("\n") )
- {
- int newEl2EndOffset = end;
- boolean replaceNext = false;
- if (rootElement.getElementCount() > elementIndex + 1)
- {
- replaceNext = true;
- newEl2EndOffset =
- rootElement.getElement(elementIndex + 1).getEndOffset();
- }
- Element newEl1 =
- createLeafElement(rootElement, firstElement.getAttributes(),
- firstElement.getStartOffset(), offset);
- Element newEl2 =
- createLeafElement (rootElement, firstElement.getAttributes(),
- offset, newEl2EndOffset);
- if (replaceNext)
- rootElement.replace(elementIndex, 2, new Element[] { newEl1, newEl2 });
- else
- rootElement.replace(elementIndex, 1, new Element[] { newEl1, newEl2 });
- firstElement = newEl2;
- elementIndex ++;
- }
- }
- catch (BadLocationException ble)
- {
- // This shouldn't happen.
- AssertionError ae = new AssertionError();
- ae.initCause(ble);
- throw ae;
- }
+ text = getText(offset, length);
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError();
+ err.initCause(ex);
+ throw err;
}
- // added and removed are Element arrays used to add an ElementEdit
- // to the DocumentEvent if there were entire lines added or removed.
- Element[] removed = new Element[1];
- Element[] added;
- try
+ boolean hasLineBreak = text.indexOf('\n') != -1;
+ boolean prevCharIsLineBreak = false;
+ try
{
- String str = content.getString(offset, eventLength);
- ArrayList elts = new ArrayList();
+ prevCharIsLineBreak =
+ offset > 0 && getText(offset - 1, 1).charAt(0) == '\n';
+ }
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError();
+ err.initCause(ex);
+ throw err;
+ }
+ boolean lastCharIsLineBreak = text.charAt(text.length() - 1) == '\n';
+ int lineIndex = -1;
+ int lineStart = -1;
+ int lineEnd = -1;
+ Element[] removed = null;
+ BranchElement root = (BranchElement) rootElement;
+ boolean updateStructure = true;
- // Determine how many NEW lines were added by finding the newline
- // characters within the newly inserted text
- int j = firstElement.getStartOffset();
- int i = str.indexOf('\n', 0);
- int contentLength = content.length();
-
- while (i != -1 && i <= eventLength)
- {
- // For each new line, create a new element
- elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY,
- j, offset + i + 1));
-
- j = offset + i + 1;
- if (j >= contentLength)
- break;
- i = str.indexOf('\n', i + 1);
- }
+ if (prevCharIsLineBreak && ! lastCharIsLineBreak)
+ {
+ // We must fix the structure a little if the previous char
+ // is a linebreak and the last char isn't.
+ lineIndex = root.getElementIndex(offset - 1);
+ Element prevLine = root.getElement(lineIndex);
+ Element nextLine = root.getElement(lineIndex + 1);
+ lineStart = prevLine.getStartOffset();
+ lineEnd = nextLine.getEndOffset();
+ removed = new Element[]{ prevLine, nextLine };
+ }
+ else if (hasLineBreak)
+ {
+ lineIndex = root.getElementIndex(offset);
+ Element line = root.getElement(lineIndex);
+ lineStart = line.getStartOffset();
+ lineEnd = line.getEndOffset();
+ removed = new Element[]{ line };
+ }
+ else
+ {
+ updateStructure = false;
+ }
- // If there were new lines added we have to add an ElementEdit to
- // the DocumentEvent and we have to call rootElement.replace to
- // insert the new lines
- if (elts.size() != 0)
+ if (updateStructure)
+ {
+ // Break the lines between lineStart and lineEnd.
+ ArrayList lines = new ArrayList();
+ int len = lineEnd - lineStart;
+ try
{
- // If we have created new lines test whether there are remaining
- // characters in firstElement after the inserted text and if so
- // create a new element for them.
- if (j < firstElement.getEndOffset())
- elts.add(createLeafElement(rootElement, SimpleAttributeSet.EMPTY, j, firstElement.getEndOffset()));
-
- // Set up the ElementEdit by filling the added and removed
- // arrays with the proper Elements
- added = new Element[elts.size()];
- elts.toArray(added);
-
- removed[0] = firstElement;
-
- // Now create and add the ElementEdit
- ElementEdit e = new ElementEdit(rootElement, elementIndex, removed,
- added);
- event.addEdit(e);
-
- // And call replace to actually make the changes
- ((BranchElement) rootElement).replace(elementIndex, 1, added);
+ text = getText(lineStart, len);
}
+ catch (BadLocationException ex)
+ {
+ AssertionError err = new AssertionError();
+ err.initCause(ex);
+ throw err;
+ }
+ int prevLineBreak = 0;
+ int lineBreak = text.indexOf('\n');
+ do
+ {
+ lineBreak++;
+ lines.add(createLeafElement(root, null, lineStart + prevLineBreak,
+ lineStart + lineBreak));
+ prevLineBreak = lineBreak;
+ lineBreak = text.indexOf('\n', prevLineBreak);
+ } while (prevLineBreak < len);
+
+ // Update the element structure and prepare document event.
+ Element[] added = (Element[]) lines.toArray(new Element[lines.size()]);
+ event.addEdit(new ElementEdit(root, lineIndex, removed, added));
+ root.replace(lineIndex, removed.length, added);
}
- catch (BadLocationException e)
- {
- // This shouldn't happen so we throw an AssertionError
- AssertionError ae = new AssertionError();
- ae.initCause(e);
- throw ae;
- }
-
super.insertUpdate(event, attributes);
}
@@ -264,7 +251,7 @@ public class PlainDocument extends AbstractDocument
event.addEdit(e);
// collapse elements if the removal spans more than 1 line
- rootElement.replace(i1, i2 - i1 + 1, added);
+ ((BranchElement) rootElement).replace(i1, i2 - i1 + 1, added);
}
}
diff --git a/libjava/classpath/javax/swing/text/Segment.java b/libjava/classpath/javax/swing/text/Segment.java
index d2364e05a10..63c5fa09dbc 100644
--- a/libjava/classpath/javax/swing/text/Segment.java
+++ b/libjava/classpath/javax/swing/text/Segment.java
@@ -165,8 +165,9 @@ public class Segment implements Cloneable, CharacterIterator
/**
* Sets the current index to point to the last character in the segment and
- * returns that character. If the segment contains zero characters, this
- * method returns {@link #DONE}.
+ * returns that character. If the segment contains zero characters, the
+ * current index is set to {@link #getEndIndex()} and this method returns
+ * {@link #DONE}.
*
* @return The last character in the segment, or {@link #DONE} if the
* segment contains zero characters.
@@ -174,7 +175,10 @@ public class Segment implements Cloneable, CharacterIterator
public char last()
{
if (count == 0)
- return DONE;
+ {
+ current = getEndIndex();
+ return DONE;
+ }
current = getEndIndex() - 1;
return array[current];
diff --git a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
index 8dbcb0c6a14..8684ef87d34 100644
--- a/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
+++ b/libjava/classpath/javax/swing/text/SimpleAttributeSet.java
@@ -51,8 +51,10 @@ public class SimpleAttributeSet
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 8267656273837665219L;
- /** An empty attribute set. */
- public static final AttributeSet EMPTY = new SimpleAttributeSet();
+ /**
+ * An empty attribute set.
+ */
+ public static final AttributeSet EMPTY = new EmptyAttributeSet();
/** Storage for the attributes. */
Hashtable tab;
diff --git a/libjava/classpath/javax/swing/text/StringContent.java b/libjava/classpath/javax/swing/text/StringContent.java
index 0a31505f3a6..8014dc3bce6 100644
--- a/libjava/classpath/javax/swing/text/StringContent.java
+++ b/libjava/classpath/javax/swing/text/StringContent.java
@@ -178,11 +178,13 @@ public final class StringContent
}
/**
- * Creates a new instance containing the string "\n".
+ * Creates a new instance containing the string "\n". This is equivalent
+ * to calling {@link #StringContent(int)} with an <code>initialLength</code>
+ * of 10.
*/
public StringContent()
{
- this(1);
+ this(10);
}
/**
diff --git a/libjava/classpath/javax/swing/text/TabSet.java b/libjava/classpath/javax/swing/text/TabSet.java
index ecad9444ea5..0f2c8c7c1ee 100644
--- a/libjava/classpath/javax/swing/text/TabSet.java
+++ b/libjava/classpath/javax/swing/text/TabSet.java
@@ -1,5 +1,5 @@
/* TabSet.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2006, Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,23 +39,54 @@ package javax.swing.text;
import java.io.Serializable;
+/**
+ * A set of tab stops. Instances of this class are immutable.
+ */
public class TabSet implements Serializable
{
/** The serialization UID (compatible with JDK1.5). */
private static final long serialVersionUID = 2367703481999080593L;
+ /** Storage for the tab stops. */
TabStop[] tabs;
+ /**
+ * Creates a new <code>TabSet</code> containing the specified tab stops.
+ *
+ * @param t the tab stops (<code>null</code> permitted).
+ */
public TabSet(TabStop[] t)
{
- tabs = t;
+ if (t != null)
+ tabs = (TabStop[]) t.clone();
+ else
+ tabs = new TabStop[0];
}
+ /**
+ * Returns the tab stop with the specified index.
+ *
+ * @param i the index.
+ *
+ * @return The tab stop.
+ *
+ * @throws IllegalArgumentException if <code>i</code> is not in the range
+ * <code>0</code> to <code>getTabCount() - 1</code>.
+ */
public TabStop getTab(int i)
{
+ if (i < 0 || i >= tabs.length)
+ throw new IllegalArgumentException("Index out of bounds.");
return tabs[i];
}
+ /**
+ * Returns the tab following the specified location.
+ *
+ * @param location the location.
+ *
+ * @return The tab following the specified location (or <code>null</code>).
+ */
public TabStop getTabAfter(float location)
{
int idx = getTabIndexAfter(location);
@@ -65,11 +96,23 @@ public class TabSet implements Serializable
return tabs[idx];
}
+ /**
+ * Returns the number of tab stops in this tab set.
+ *
+ * @return The number of tab stops in this tab set.
+ */
public int getTabCount()
{
return tabs.length;
}
+ /**
+ * Returns the index of the specified tab, or -1 if the tab is not found.
+ *
+ * @param tab the tab (<code>null</code> permitted).
+ *
+ * @return The index of the specified tab, or -1.
+ */
public int getTabIndex(TabStop tab)
{
for (int i = 0; i < tabs.length; ++i)
@@ -78,28 +121,88 @@ public class TabSet implements Serializable
return -1;
}
+ /**
+ * Returns the index of the tab at or after the specified location.
+ *
+ * @param location the tab location.
+ *
+ * @return The index of the tab stop, or -1.
+ */
public int getTabIndexAfter(float location)
{
- int idx = -1;
- for (int i = 0; i < tabs.length; ++i)
+ for (int i = 0; i < tabs.length; i++)
+ {
+ if (location <= tabs[i].getPosition())
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Tests this <code>TabSet</code> for equality with an arbitrary object.
+ *
+ * @param obj the object (<code>null</code> permitted).
+ *
+ * @return <code>true</code> if this <code>TabSet</code> is equal to
+ * <code>obj</code>, and <code>false</code> otherwise.
+ *
+ * @since 1.5
+ */
+ public boolean equals(Object obj)
+ {
+ if (obj == this)
+ return true;
+ if (!(obj instanceof TabSet))
+ return false;
+ TabSet that = (TabSet) obj;
+ int tabCount = getTabCount();
+ if (tabCount != that.getTabCount())
+ return false;
+ for (int i = 0; i < tabCount; i++)
+ {
+ if (!this.getTab(i).equals(that.getTab(i)))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns a hash code for this <code>TabSet</code>.
+ *
+ * @return A hash code.
+ *
+ * @since 1.5
+ */
+ public int hashCode()
+ {
+ // this hash code won't match Sun's, but that shouldn't matter...
+ int result = 193;
+ int tabs = getTabCount();
+ for (int i = 0; i < tabs; i++)
{
- if (location < tabs[i].getPosition())
- idx = i;
+ TabStop t = getTab(i);
+ if (t != null)
+ result = 37 * result + t.hashCode();
}
- return idx;
+ return result;
}
+ /**
+ * Returns a string representation of this <code>TabSet</code>.
+ *
+ * @return A string representation of this <code>TabSet</code>.
+ */
public String toString()
{
StringBuffer sb = new StringBuffer();
- sb.append("[");
+ sb.append("[ ");
for (int i = 0; i < tabs.length; ++i)
{
if (i != 0)
sb.append(" - ");
sb.append(tabs[i].toString());
}
- sb.append("]");
+ sb.append(" ]");
return sb.toString();
}
}
diff --git a/libjava/classpath/javax/swing/text/TabStop.java b/libjava/classpath/javax/swing/text/TabStop.java
index 56f862fdae4..f4c3f851406 100644
--- a/libjava/classpath/javax/swing/text/TabStop.java
+++ b/libjava/classpath/javax/swing/text/TabStop.java
@@ -1,5 +1,5 @@
-/* TabSet.java --
- Copyright (C) 2004 Free Software Foundation, Inc.
+/* TabStop.java --
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,6 +39,9 @@ package javax.swing.text;
import java.io.Serializable;
+/**
+ * Represents a tab position in some text.
+ */
public class TabStop implements Serializable
{
/** The serialization UID (compatible with JDK1.5). */
@@ -61,18 +64,42 @@ public class TabStop implements Serializable
int align;
int leader;
+ /**
+ * Creates a new <code>TabStop</code> for the specified tab position.
+ *
+ * @param pos the tab position.
+ */
public TabStop(float pos)
{
this(pos, ALIGN_LEFT, LEAD_NONE);
}
+ /**
+ * Creates a new <code>TabStop</code> with the specified attributes.
+ *
+ * @param pos the tab position.
+ * @param align the alignment (one of {@link #ALIGN_LEFT},
+ * {@link #ALIGN_CENTER}, {@link #ALIGN_RIGHT}, {@link #ALIGN_DECIMAL}
+ * or {@link #ALIGN_BAR}).
+ * @param leader the leader (one of {@link #LEAD_NONE}, {@link #LEAD_DOTS},
+ * {@link #LEAD_EQUALS}, {@link #LEAD_HYPHENS}, {@link #LEAD_THICKLINE}
+ * or {@link #LEAD_UNDERLINE}).
+ */
public TabStop(float pos, int align, int leader)
{
this.pos = pos;
this.align = align;
this.leader = leader;
}
-
+
+ /**
+ * Tests this <code>TabStop</code> for equality with an arbitrary object.
+ *
+ * @param other the other object (<code>null</code> permitted).
+ *
+ * @return <code>true</code> if this <code>TabStop</code> is equal to
+ * the specified object, and <code>false</code> otherwise.
+ */
public boolean equals(Object other)
{
return (other != null)
@@ -82,34 +109,60 @@ public class TabStop implements Serializable
&& (((TabStop)other).getAlignment() == this.getAlignment());
}
+ /**
+ * Returns the tab alignment. This should be one of {@link #ALIGN_LEFT},
+ * {@link #ALIGN_CENTER}, {@link #ALIGN_RIGHT}, {@link #ALIGN_DECIMAL} or
+ * {@link #ALIGN_BAR}.
+ *
+ * @return The tab alignment.
+ */
public int getAlignment()
{
return align;
}
+ /**
+ * Returns the leader type. This should be one of {@link #LEAD_NONE},
+ * {@link #LEAD_DOTS}, {@link #LEAD_EQUALS}, {@link #LEAD_HYPHENS},
+ * {@link #LEAD_THICKLINE} or {@link #LEAD_UNDERLINE}.
+ *
+ * @return The leader type.
+ */
public int getLeader()
{
return leader;
}
+ /**
+ * Returns the tab position.
+ *
+ * @return The tab position.
+ */
public float getPosition()
{
return pos;
}
+ /**
+ * Returns a hash code for this <code>TabStop</code>.
+ *
+ * @return A hash code.
+ */
public int hashCode()
{
return (int) pos + (int) leader + (int) align;
}
+ /**
+ * Returns a string describing this <code>TabStop</code>.
+ *
+ * @return A string describing this <code>TabStop</code>.
+ */
public String toString()
{
String prefix = "";
switch (align)
{
- case ALIGN_LEFT:
- prefix = "left ";
- break;
case ALIGN_RIGHT:
prefix = "right ";
break;
@@ -130,7 +183,8 @@ public class TabStop implements Serializable
break;
}
- return (prefix + "tab @" + pos + ((leader == LEAD_NONE) ? "" : "(w/leaders)"));
+ return prefix + "tab @" + pos
+ + ((leader == LEAD_NONE) ? "" : " (w/leaders)");
}
}
diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java
index d8ad5f5858e..55a63f6b668 100644
--- a/libjava/classpath/javax/swing/text/View.java
+++ b/libjava/classpath/javax/swing/text/View.java
@@ -401,7 +401,10 @@ public abstract class View implements SwingConstants
Element el = getElement();
DocumentEvent.ElementChange ec = ev.getChange(el);
if (ec != null)
- updateChildren(ec, ev, vf);
+ {
+ if (! updateChildren(ec, ev, vf))
+ ec = null;
+ }
forwardUpdate(ec, ev, shape, vf);
updateLayout(ec, ev, shape);
}
@@ -493,27 +496,66 @@ public abstract class View implements SwingConstants
int count = getViewCount();
if (count > 0)
{
+ // Determine start index.
int startOffset = ev.getOffset();
- int endOffset = startOffset + ev.getLength();
int startIndex = getViewIndex(startOffset, Position.Bias.Backward);
- int endIndex = getViewIndex(endOffset, Position.Bias.Forward);
- int index = -1;
- int addLength = -1;
- if (ec != null)
+
+ // For REMOVE events we have to forward the event to the last element,
+ // for the case that an Element has been removed that represente
+ // the offset.
+ if (startIndex == -1 && ev.getType() == DocumentEvent.EventType.REMOVE
+ && startOffset >= getEndOffset())
{
- index = ec.getIndex();
- addLength = ec.getChildrenAdded().length;
+ startIndex = getViewCount() - 1;
}
- if (startIndex >= 0 && endIndex >= 0)
+ // When startIndex is on a view boundary, forward event to the
+ // previous view too.
+ if (startIndex >= 0)
{
- for (int i = startIndex; i <= endIndex; i++)
+ View v = getView(startIndex);
+ if (v != null)
+ {
+ if (v.getStartOffset() == startOffset && startOffset > 0)
+ startIndex = Math.max(0, startIndex - 1);
+ }
+ }
+ startIndex = Math.max(0, startIndex);
+
+ // Determine end index.
+ int endIndex = startIndex;
+ if (ev.getType() != DocumentEvent.EventType.REMOVE)
+ {
+ endIndex = getViewIndex(startOffset + ev.getLength(),
+ Position.Bias.Forward);
+ if (endIndex < 0)
+ endIndex = getViewCount() - 1;
+ }
+
+ // Determine hole that comes from added elements (we don't forward
+ // the event to newly added views.
+ int startAdded = endIndex + 1;
+ int endAdded = startAdded;
+ Element[] added = (ec != null) ? ec.getChildrenAdded() : null;
+ if (added != null && added.length > 0)
+ {
+ startAdded = ec.getIndex();
+ endAdded = startAdded + added.length - 1;
+ }
+
+ // Forward event to all views between startIndex and endIndex,
+ // and leave out all views in the hole.
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ // Skip newly added child views.
+ if (! (i >= startAdded && i <= endAdded))
{
- // Skip newly added child views.
- if (index >= 0 && i >= index && i < (index+addLength))
- continue;
View child = getView(i);
- forwardUpdateToView(child, ev, shape, vf);
+ if (child != null)
+ {
+ Shape childAlloc = getChildAllocation(i, shape);
+ forwardUpdateToView(child, ev, childAlloc, vf);
+ }
}
}
}
@@ -611,9 +653,46 @@ public abstract class View implements SwingConstants
if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward)
throw new IllegalArgumentException
("b2 must be either Position.Bias.Forward or Position.Bias.Backward");
- Rectangle s1 = (Rectangle) modelToView(p1, a, b1);
- Rectangle s2 = (Rectangle) modelToView(p2, a, b2);
- return SwingUtilities.computeUnion(s1.x, s1.y, s1.width, s1.height, s2);
+
+ Shape s1 = modelToView(p1, a, b1);
+ // Special case for p2 == end index.
+ Shape s2;
+ if (p2 != getEndOffset())
+ {
+ s2 = modelToView(p2, a, b2);
+ }
+ else
+ {
+ try
+ {
+ s2 = modelToView(p2, a, b2);
+ }
+ catch (BadLocationException ex)
+ {
+ // Assume the end rectangle to be at the right edge of the
+ // view.
+ Rectangle aRect = a instanceof Rectangle ? (Rectangle) a
+ : a.getBounds();
+ s2 = new Rectangle(aRect.x + aRect.width - 1, aRect.y, 1,
+ aRect.height);
+ }
+ }
+
+ // Need to modify the rectangle, so we create a copy in all cases.
+ Rectangle r1 = s1.getBounds();
+ Rectangle r2 = s2 instanceof Rectangle ? (Rectangle) s2
+ : s2.getBounds();
+
+ // For multiline view, let the resulting rectangle span the whole view.
+ if (r1.y != r2.y)
+ {
+ Rectangle aRect = a instanceof Rectangle ? (Rectangle) a
+ : a.getBounds();
+ r1.x = aRect.x;
+ r1.width = aRect.width;
+ }
+
+ return SwingUtilities.computeUnion(r2.x, r2.y, r2.width, r2.height, r1);
}
/**
diff --git a/libjava/classpath/javax/swing/text/html/HTMLTableView.java b/libjava/classpath/javax/swing/text/html/BRView.java
index cac44d8dc27..5521fed8edf 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLTableView.java
+++ b/libjava/classpath/javax/swing/text/html/BRView.java
@@ -1,4 +1,4 @@
-/* HTMLTableView.java -- A table view for HTML tables
+/* BRView.java -- HTML BR tag view
Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -39,44 +39,33 @@ exception statement from your version. */
package javax.swing.text.html;
import javax.swing.text.Element;
-import javax.swing.text.TableView;
-import javax.swing.text.View;
-import javax.swing.text.ViewFactory;
/**
- * A conrete implementation of TableView that renders HTML tables.
- *
- * @author Roman Kennke (kennke@aicas.com)
+ * Handled the HTML BR tag.
*/
-class HTMLTableView
- extends TableView
-{
+class BRView
+ extends NullView
+{
/**
- * Creates a new HTMLTableView for the specified element.
- *
- * @param el the element for the table view
+ * Creates the new BR view.
+ *
+ * @param elem the HTML element, representing the view.
*/
- public HTMLTableView(Element el)
+ public BRView(Element elem)
{
- super(el);
+ super(elem);
}
-
+
/**
- * Loads the children of the Table. This completely bypasses the ViewFactory
- * and creates instances of TableRow instead.
- *
- * @param vf ignored
+ * Always return ForcedBreakWeight for the X_AXIS, BadBreakWeight for the
+ * Y_AXIS.
*/
- protected void loadChildren(ViewFactory vf)
+ public int getBreakWeight(int axis, float pos, float len)
{
- Element el = getElement();
- int numChildren = el.getElementCount();
- View[] rows = new View[numChildren];
- for (int i = 0; i < numChildren; ++i)
- {
- rows[i] = createTableRow(el.getElement(i));
- }
- replace(0, getViewCount(), rows);
+ if (axis == X_AXIS)
+ return ForcedBreakWeight;
+ else
+ return BadBreakWeight;
}
}
diff --git a/libjava/classpath/javax/swing/text/html/HRuleView.java b/libjava/classpath/javax/swing/text/html/HRuleView.java
new file mode 100644
index 00000000000..3bae5eb8e83
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/HRuleView.java
@@ -0,0 +1,189 @@
+/* HRuleView.java -- Horizontal dash in HTML documents.
+ Copyright (C) 2006 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.text.html;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.awt.Shape;
+
+import javax.swing.text.Element;
+import javax.swing.text.View;
+
+/**
+ * Represents the long horizontal separating dash that can be inserted into the
+ * HTML documents with HR tag.
+ */
+class HRuleView extends InlineView
+{
+ /**
+ * The null view, indicating, that nothing should be painted ahead the
+ * breaking point.
+ */
+ View nullView;
+
+ /**
+ * The height of the horizontal dash area.
+ */
+ static int HEIGHT = 4;
+
+ /**
+ * The imaginary invisible view that stays after end of line after the
+ * breaking procedure. It occupies on character.
+ */
+ class Beginning extends NullView
+ {
+ /**
+ * The break offset that becomes the views start offset.
+ */
+ int breakOffset;
+
+ /**
+ * Return the end offset that is always one char after the break offset.
+ */
+ public int getEndOffset()
+ {
+ return breakOffset + 1;
+ }
+
+ /**
+ * Return the start offset that has been passed in a constructor.
+ */
+ public int getStartOffset()
+ {
+ return breakOffset;
+ }
+
+ /**
+ * Create the new instance of this view.
+ *
+ * @param element the element (inherited from the HR view)
+ * @param offset the position where the HR view has been broken
+ */
+ public Beginning(Element element, int offset)
+ {
+ super(element);
+ breakOffset = offset;
+ }
+ }
+
+ /**
+ * Creates the new HR view.
+ */
+ public HRuleView(Element element)
+ {
+ super(element);
+ }
+
+ /**
+ * Returns the ForcedBreakWeight for the vertical axis, indicating, the the
+ * view must be broken to be displayed correctly. The horizontal dash is
+ * not breakeable along the Y axis.
+ */
+ public int getBreakWeight(int axis, float pos, float len)
+ {
+ if (axis == X_AXIS && ((getEndOffset() - getStartOffset()) > 1))
+ return ForcedBreakWeight;
+ else
+ return BadBreakWeight;
+ }
+
+ /**
+ * Draws the double line, upped black and the lower light gray.
+ */
+ public void paint(Graphics g, Shape a)
+ {
+ Rectangle bounds = a.getBounds();
+
+ int x = bounds.x;
+ int y = bounds.y;
+
+ int w = bounds.x + bounds.width;
+
+ // We move "half pixel up" from the actual horizontal position -
+ // this will be rounded to the closest actual int co-ordinate.
+ int h = bounds.y + (int) Math.round(bounds.height * 0.5 - 0.5);
+
+ g.setColor(Color.black);
+ g.drawLine(x, y++, w, h++);
+ g.setColor(Color.lightGray);
+ g.drawLine(x, y, w, h);
+ }
+
+ /**
+ * Break the view into this view and the invisible imaginary view that
+ * stays on the end of line that is broken by HR dash. The view is broken
+ * only if its length is longer than one (the two characters are expected
+ * in the initial length).
+ */
+ public View breakView(int axis, int offset, float pos, float len)
+ {
+ if (getEndOffset() - getStartOffset() > 1)
+ return new Beginning(getElement(), offset);
+ else
+ return this;
+ }
+
+ /**
+ * Returns the width of the container for the horizontal axis and the
+ * thickness of the dash area for the vertical axis.
+ */
+ public float getMaximumSpan(int axis)
+ {
+ if (axis == X_AXIS)
+ {
+ Component container = getContainer();
+ if (container != null)
+ return getContainer().getWidth();
+ else
+ return 640;
+ }
+ else
+ return HEIGHT;
+ }
+
+ /**
+ * Returns the same values as {@link #getMaximumSpan(int)}
+ */
+ public float getPreferredSpan(int axis)
+ {
+ return getMaximumSpan(axis);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLDocument.java b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
index e714a857b61..0bfc338df45 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLDocument.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLDocument.java
@@ -40,14 +40,18 @@ package javax.swing.text.html;
import gnu.classpath.NotImplementedException;
import gnu.javax.swing.text.html.CharacterAttributeTranslator;
+import gnu.javax.swing.text.html.parser.htmlAttributeSet;
import java.io.IOException;
+import java.io.StringReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Stack;
import java.util.Vector;
import javax.swing.JEditorPane;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.HyperlinkEvent.EventType;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
@@ -515,19 +519,23 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public class HTMLReader extends HTMLEditorKit.ParserCallback
{
- /** Holds the current character attribute set **/
+ /**
+ * Holds the current character attribute set *
+ */
protected MutableAttributeSet charAttr = new SimpleAttributeSet();
protected Vector parseBuffer = new Vector();
- /** A stack for character attribute sets **/
+ /**
+ * A stack for character attribute sets *
+ */
Stack charAttrStack = new Stack();
/**
* The parse stack. This stack holds HTML.Tag objects that reflect the
* current position in the parsing process.
*/
- private Stack parseStack = new Stack();
+ Stack parseStack = new Stack();
/** A mapping between HTML.Tag objects and the actions that handle them **/
HashMap tagToAction;
@@ -535,10 +543,31 @@ public class HTMLDocument extends DefaultStyledDocument
/** Tells us whether we've received the '</html>' tag yet **/
boolean endHTMLEncountered = false;
- /** Variables related to the constructor with explicit insertTag **/
- int popDepth, pushDepth, offset;
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int popDepth;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int pushDepth;
+
+ /**
+ * Related to the constructor with explicit insertTag
+ */
+ int offset;
+
+ /**
+ * The tag (inclusve), after that the insertion should start.
+ */
HTML.Tag insertTag;
- boolean insertTagEncountered = false;
+
+ /**
+ * This variable becomes true after the insert tag has been encountered.
+ */
+ boolean insertTagEncountered;
+
/** A temporary variable that helps with the printing out of debug information **/
boolean debug = false;
@@ -1139,8 +1168,21 @@ public class HTMLDocument extends DefaultStyledDocument
}
/**
- * This method is called by the parser and should route the call to
- * the proper handler for the tag.
+ * Checks if the HTML tag should be inserted. The tags before insert tag (if
+ * specified) are not inserted. Also, the tags after the end of the html are
+ * not inserted.
+ *
+ * @return true if the tag should be inserted, false otherwise.
+ */
+ private boolean shouldInsert()
+ {
+ return ! endHTMLEncountered
+ && (insertTagEncountered || insertTag == null);
+ }
+
+ /**
+ * This method is called by the parser and should route the call to the
+ * proper handler for the tag.
*
* @param t the HTML.Tag
* @param a the attribute set
@@ -1148,13 +1190,15 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- TagAction action = (TagAction) tagToAction.get(t);
- if (action != null)
- action.start(t, a);
+ if (t == insertTag)
+ insertTagEncountered = true;
+
+ if (shouldInsert())
+ {
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.start(t, a);
+ }
}
/**
@@ -1165,42 +1209,41 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleComment(char[] data, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
- if (action != null)
+ if (shouldInsert())
{
- action.start(HTML.Tag.COMMENT, new SimpleAttributeSet());
- action.end (HTML.Tag.COMMENT);
+ TagAction action = (TagAction) tagToAction.get(HTML.Tag.COMMENT);
+ if (action != null)
+ {
+ action.start(HTML.Tag.COMMENT,
+ htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET);
+ action.end(HTML.Tag.COMMENT);
+ }
}
}
/**
- * This method is called by the parser and should route the call to
- * the proper handler for the tag.
+ * This method is called by the parser and should route the call to the
+ * proper handler for the tag.
*
* @param t the HTML.Tag
* @param pos the position at which the tag was encountered
*/
public void handleEndTag(HTML.Tag t, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- // If this is the </html> tag we need to stop calling the Actions
- if (t == HTML.Tag.HTML)
- endHTMLEncountered = true;
-
- TagAction action = (TagAction) tagToAction.get(t);
- if (action != null)
- action.end(t);
+ if (shouldInsert())
+ {
+ // If this is the </html> tag we need to stop calling the Actions
+ if (t == HTML.Tag.HTML)
+ endHTMLEncountered = true;
+
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ action.end(t);
+ }
}
/**
- * This is a callback from the parser that should be routed to the
+ * This is a callback from the parser that should be routed to the
* appropriate handler for the tag.
*
* @param t the HTML.Tag that was encountered
@@ -1209,15 +1252,17 @@ public class HTMLDocument extends DefaultStyledDocument
*/
public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos)
{
- // Don't call the Action if we've already seen </html>.
- if (endHTMLEncountered)
- return;
-
- TagAction action = (TagAction) tagToAction.get (t);
- if (action != null)
+ if (t == insertTag)
+ insertTagEncountered = true;
+
+ if (shouldInsert())
{
- action.start(t, a);
- action.end(t);
+ TagAction action = (TagAction) tagToAction.get(t);
+ if (action != null)
+ {
+ action.start(t, a);
+ action.end(t);
+ }
}
}
@@ -1230,7 +1275,6 @@ public class HTMLDocument extends DefaultStyledDocument
* @since 1.3
*/
public void handleEndOfLineString(String eol)
- throws NotImplementedException
{
// FIXME: Implement.
print ("HTMLReader.handleEndOfLineString not implemented yet");
@@ -1273,16 +1317,6 @@ public class HTMLDocument extends DefaultStyledDocument
printBuffer();
DefaultStyledDocument.ElementSpec element;
- // If the previous tag is content and the parent is p-implied, then
- // we must also close the p-implied.
- if (parseStack.size() > 0 && parseStack.peek() == HTML.Tag.IMPLIED)
- {
- element = new DefaultStyledDocument.ElementSpec(null,
- DefaultStyledDocument.ElementSpec.EndTagType);
- parseBuffer.addElement(element);
- parseStack.pop();
- }
-
parseStack.push(t);
AbstractDocument.AttributeContext ctx = getAttributeContext();
AttributeSet copy = attr.copyAttributes();
@@ -1320,16 +1354,6 @@ public class HTMLDocument extends DefaultStyledDocument
new char[0], 0, 0);
parseBuffer.add(element);
}
- // If the previous tag is content and the parent is p-implied, then
- // we must also close the p-implied.
- else if (parseStack.peek() == HTML.Tag.IMPLIED)
- {
- element = new DefaultStyledDocument.ElementSpec(null,
- DefaultStyledDocument.ElementSpec.EndTagType);
- parseBuffer.addElement(element);
- if (parseStack.size() > 0)
- parseStack.pop();
- }
element = new DefaultStyledDocument.ElementSpec(null,
DefaultStyledDocument.ElementSpec.EndTagType);
@@ -1369,27 +1393,6 @@ public class HTMLDocument extends DefaultStyledDocument
DefaultStyledDocument.ElementSpec element;
AttributeSet attributes = null;
- // Content must always be embedded inside a paragraph element,
- // so we create this if the previous element is not one of
- // <p>, <h1> .. <h6>.
- boolean createImpliedParagraph = false;
- HTML.Tag parent = (HTML.Tag) parseStack.peek();
- if (parent != HTML.Tag.P && parent != HTML.Tag.H1
- && parent != HTML.Tag.H2
- && parent != HTML.Tag.H3 && parent != HTML.Tag.H4
- && parent != HTML.Tag.H5 && parent != HTML.Tag.H6
- && parent != HTML.Tag.TD)
- {
- attributes = ctx.getEmptySet();
- attributes = ctx.addAttribute(attributes,
- StyleConstants.NameAttribute,
- HTML.Tag.IMPLIED);
- element = new DefaultStyledDocument.ElementSpec(attributes,
- DefaultStyledDocument.ElementSpec.StartTagType);
- parseBuffer.add(element);
- parseStack.push(HTML.Tag.IMPLIED);
- }
-
// Copy the attribute set, don't use the same object because
// it may change
if (charAttr != null)
@@ -1433,14 +1436,14 @@ public class HTMLDocument extends DefaultStyledDocument
// Migrate from the rather htmlAttributeSet to the faster, lighter and
// unchangeable alternative implementation.
AttributeSet copy = a.copyAttributes();
-
- // TODO: Figure out why we must always insert this single character
- // (otherwise the element does not appear). Either fix or add explaining
- // comment or at least report a normal bug.
- DefaultStyledDocument.ElementSpec spec;
- spec = new DefaultStyledDocument.ElementSpec(copy,
- DefaultStyledDocument.ElementSpec.ContentType,
- new char[] {' '}, 0, 1 );
+
+ // The two spaces are required because some special elements like HR
+ // must be broken. At least two characters are needed to break into the
+ // two parts.
+ DefaultStyledDocument.ElementSpec spec =
+ new DefaultStyledDocument.ElementSpec(copy,
+ DefaultStyledDocument.ElementSpec.ContentType,
+ new char[] {' ', ' '}, 0, 2 );
parseBuffer.add(spec);
}
@@ -1481,7 +1484,61 @@ public class HTMLDocument extends DefaultStyledDocument
HTML.Tag insertTag)
{
return new HTMLReader(pos, popDepth, pushDepth, insertTag);
- }
+ }
+
+ /**
+ * Gets the reader for the parser to use when inserting the HTML fragment into
+ * the document. Checks if the parser is present, sets the parent in the
+ * element stack and removes any actions for BODY (it can be only one body in
+ * a HTMLDocument).
+ *
+ * @param pos - the starting position
+ * @param popDepth - the number of EndTagTypes to generate before inserting
+ * @param pushDepth - the number of StartTagTypes with a direction of
+ * JoinNextDirection that should be generated before inserting, but
+ * after the end tags have been generated.
+ * @param insertTag - the first tag to start inserting into document
+ * @param parent the element that will be the parent in the document. HTML
+ * parsing includes checks for the parent, so it must be available.
+ * @return - the reader
+ * @throws IllegalStateException if the parsert is not set.
+ */
+ public HTMLEditorKit.ParserCallback getInsertingReader(int pos, int popDepth,
+ int pushDepth,
+ HTML.Tag insertTag,
+ final Element parent)
+ throws IllegalStateException
+ {
+ if (parser == null)
+ throw new IllegalStateException("Parser has not been set");
+
+ HTMLReader reader = new HTMLReader(pos, popDepth, pushDepth, insertTag)
+ {
+ /**
+ * Ignore BODY.
+ */
+ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos)
+ {
+ if (t != HTML.Tag.BODY)
+ super.handleStartTag(t, a, pos);
+ }
+
+ /**
+ * Ignore BODY.
+ */
+ public void handleEndTag(HTML.Tag t, int pos)
+ {
+ if (t != HTML.Tag.BODY)
+ super.handleEndTag(t, pos);
+ }
+ };
+
+ // Set the parent HTML tag.
+ reader.parseStack.push(parent.getAttributes().getAttribute(
+ StyleConstants.NameAttribute));
+
+ return reader;
+ }
/**
* Gets the child element that contains the attribute with the value or null.
@@ -1490,8 +1547,8 @@ public class HTMLDocument extends DefaultStyledDocument
* @param e - the element to begin search at
* @param attribute - the desired attribute
* @param value - the desired value
- * @return the element found with the attribute and value specified or null
- * if it is not found.
+ * @return the element found with the attribute and value specified or null if
+ * it is not found.
*/
public Element getElement(Element e, Object attribute, Object value)
{
@@ -1516,16 +1573,17 @@ public class HTMLDocument extends DefaultStyledDocument
}
/**
- * Returns the element that has the given id Attribute. If it is not found,
- * null is returned. This method works on an Attribute, not a character tag.
- * This is not thread-safe.
+ * Returns the element that has the given id Attribute (for instance, &lt;p id
+ * ='my paragraph &gt;'). If it is not found, null is returned. The HTML tag,
+ * having this attribute, is not checked by this method and can be any. The
+ * method is not thread-safe.
*
- * @param attrId - the Attribute id to look for
+ * @param attrId - the value of the attribute id to look for
* @return the element that has the given id.
*/
public Element getElement(String attrId)
{
- return getElement(getDefaultRootElement(), HTML.getAttributeKey(attrId),
+ return getElement(getDefaultRootElement(), HTML.Attribute.ID,
attrId);
}
@@ -1542,22 +1600,30 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if an HTMLEditorKit.Parser has not been set
*/
public void setInnerHTML(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
if (elem.isLeaf())
throw new IllegalArgumentException("Element is a leaf");
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("setInnerHTML not implemented");
+
+ int start = elem.getStartOffset();
+ int end = elem.getEndOffset();
+
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ end, 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+
+ // Remove the previous content
+ remove(start, end - start);
}
/**
- * Replaces the given element in the parent with the string. When replacing
- * a leaf, this will attempt to make sure there is a newline present if one is
- * needed. This may result in an additional element being inserted.
- * This will be seen as at least two events, n inserts followed by a remove.
- * The HTMLEditorKit.Parser must be set.
+ * Replaces the given element in the parent with the string. When replacing a
+ * leaf, this will attempt to make sure there is a newline present if one is
+ * needed. This may result in an additional element being inserted. This will
+ * be seen as at least two events, n inserts followed by a remove. The
+ * HTMLEditorKit.Parser must be set.
*
* @param elem - the branch element whose parent will be replaced
* @param htmlText - the string to be parsed and assigned to elem
@@ -1565,18 +1631,25 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IOException
* @throws IllegalStateException - if parser is not set
*/
- public void setOuterHTML(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
- {
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("setOuterHTML not implemented");
- }
+public void setOuterHTML(Element elem, String htmlText)
+ throws BadLocationException, IOException
+ {
+ // Remove the current element:
+ int start = elem.getStartOffset();
+ int end = elem.getEndOffset();
+
+ remove(start, end-start);
+
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ start, 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+ }
/**
- * Inserts the string before the start of the given element.
- * The parser must be set.
+ * Inserts the string before the start of the given element. The parser must
+ * be set.
*
* @param elem - the element to be the root for the new text.
* @param htmlText - the string to be parsed and assigned to elem
@@ -1585,18 +1658,19 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser has not been set
*/
public void insertBeforeStart(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertBeforeStart not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
}
/**
- * Inserts the string at the end of the element. If elem's children
- * are leaves, and the character at elem.getEndOffset() - 1 is a newline,
- * then it will be inserted before the newline. The parser must be set.
+ * Inserts the string at the end of the element. If elem's children are
+ * leaves, and the character at elem.getEndOffset() - 1 is a newline, then it
+ * will be inserted before the newline. The parser must be set.
*
* @param elem - the element to be the root for the new text
* @param htmlText - the text to insert
@@ -1605,12 +1679,14 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser is not set
*/
public void insertBeforeEnd(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertBeforeEnd not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
+
}
/**
@@ -1624,12 +1700,13 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser is not set
*/
public void insertAfterEnd(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertAfterEnd not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getEndOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
}
/**
@@ -1643,11 +1720,12 @@ public class HTMLDocument extends DefaultStyledDocument
* @throws IllegalStateException - if parser is not set
*/
public void insertAfterStart(Element elem, String htmlText)
- throws BadLocationException, IOException, NotImplementedException
+ throws BadLocationException, IOException
{
- if (parser == null)
- throw new IllegalStateException("Parser has not been set");
- // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit?
- System.out.println("insertAfterStart not implemented");
+ HTMLEditorKit.ParserCallback reader = getInsertingReader(
+ elem.getStartOffset(), 0, 0, HTML.Tag.BODY, elem);
+
+ // TODO charset
+ getParser().parse(new StringReader(htmlText), reader, true);
}
}
diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
index adda4922d57..5d77be8fdd4 100644
--- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
+++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java
@@ -71,6 +71,11 @@ import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import javax.swing.text.html.parser.ParserDelegator;
+/* Move these imports here after javax.swing.text.html to make it compile
+ with jikes. */
+import gnu.javax.swing.text.html.parser.GnuParserDelegator;
+import gnu.javax.swing.text.html.parser.HTML_401Swing;
+
/**
* @author Lillian Angel (langel at redhat dot com)
*/
@@ -557,19 +562,18 @@ public class HTMLEditorKit
else if (tag == HTML.Tag.HEAD)
view = new NullView(element);
else if (tag.equals(HTML.Tag.TABLE))
- view = new HTMLTableView(element);
+ view = new javax.swing.text.html.TableView(element);
else if (tag.equals(HTML.Tag.TD))
view = new ParagraphView(element);
-
+ else if (tag.equals(HTML.Tag.HR))
+ view = new HRuleView(element);
+ else if (tag.equals(HTML.Tag.BR))
+ view = new BRView(element);
/*
else if (tag.equals(HTML.Tag.MENU) || tag.equals(HTML.Tag.DIR)
|| tag.equals(HTML.Tag.UL) || tag.equals(HTML.Tag.OL))
view = new ListView(element);
- else if (tag.equals(HTML.Tag.HR))
- view = new HRuleView(element);
- else if (tag.equals(HTML.Tag.BR))
- view = new BRView(element);
else if (tag.equals(HTML.Tag.INPUT) || tag.equals(HTML.Tag.SELECT)
|| tag.equals(HTML.Tag.TEXTAREA))
view = new FormView(element);
@@ -887,7 +891,9 @@ public class HTMLEditorKit
protected Parser getParser()
{
if (parser == null)
- parser = new ParserDelegator();
+ {
+ parser = new GnuParserDelegator(HTML_401Swing.getInstance());
+ }
return parser;
}
diff --git a/libjava/classpath/javax/swing/text/html/StyleSheet.java b/libjava/classpath/javax/swing/text/html/StyleSheet.java
index 2466a2808fe..d92abde7825 100644
--- a/libjava/classpath/javax/swing/text/html/StyleSheet.java
+++ b/libjava/classpath/javax/swing/text/html/StyleSheet.java
@@ -38,6 +38,8 @@ exception statement from your version. */
package javax.swing.text.html;
+import gnu.javax.swing.text.html.CharacterAttributeTranslator;
+
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
@@ -585,47 +587,15 @@ public class StyleSheet extends StyleContext
}
/**
- * Converst a color string to a color. If it is not found, null is returned.
- *
- * @param color - the color string such as "RED" or "#NNNNNN"
- * @return the Color, or null if not found.
- */
- public Color stringToColor(String color)
- {
- color = color.toLowerCase();
- if (color.equals("black") || color.equals("#000000"))
- return Color.BLACK;
- else if (color.equals("aqua") || color.equals("#00FFFF"))
- return new Color(127, 255, 212);
- else if (color.equals("gray") || color.equals("#808080"))
- return Color.GRAY;
- else if (color.equals("navy") || color.equals("#000080"))
- return new Color(0, 0, 128);
- else if (color.equals("silver") || color.equals("#C0C0C0"))
- return Color.LIGHT_GRAY;
- else if (color.equals("green") || color.equals("#008000"))
- return Color.GREEN;
- else if (color.equals("olive") || color.equals("#808000"))
- return new Color(128, 128, 0);
- else if (color.equals("teal") || color.equals("#008080"))
- return new Color(0, 128, 128);
- else if (color.equals("blue") || color.equals("#0000FF"))
- return Color.BLUE;
- else if (color.equals("lime") || color.equals("#00FF00"))
- return new Color(0, 255, 0);
- else if (color.equals("purple") || color.equals("#800080"))
- return new Color(128, 0, 128);
- else if (color.equals("white") || color.equals("#FFFFFF"))
- return Color.WHITE;
- else if (color.equals("fuchsia") || color.equals("#FF00FF"))
- return Color.MAGENTA;
- else if (color.equals("maroon") || color.equals("#800000"))
- return new Color(128, 0, 0);
- else if (color.equals("Red") || color.equals("#FF0000"))
- return Color.RED;
- else if (color.equals("Yellow") || color.equals("#FFFF00"))
- return Color.YELLOW;
- return null;
+ * Convert the color string represenation into java.awt.Color. The valid
+ * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)".
+ *
+ * @param colorName the color to convert.
+ * @return the matching java.awt.color
+ */
+ public Color stringToColor(String colorName)
+ {
+ return CharacterAttributeTranslator.getColor(colorName);
}
/**
diff --git a/libjava/classpath/javax/swing/text/html/TableView.java b/libjava/classpath/javax/swing/text/html/TableView.java
new file mode 100644
index 00000000000..c2edc8cdd64
--- /dev/null
+++ b/libjava/classpath/javax/swing/text/html/TableView.java
@@ -0,0 +1,137 @@
+/* TableView.java -- A table view for HTML tables
+ Copyright (C) 2006 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.text.html;
+
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+/**
+ * A conrete implementation of TableView that renders HTML tables.
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+class TableView
+ extends javax.swing.text.TableView
+{
+ /**
+ * Represents a single table row.
+ */
+ public class RowView extends TableRow
+ {
+ /**
+ * Creates a new instance of the <code>RowView</code>.
+ *
+ * @param el the element for which to create a row view
+ */
+ public RowView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Get the associated style sheet from the document.
+ *
+ * @return the associated style sheet.
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document d = getElement().getDocument();
+ if (d instanceof HTMLDocument)
+ return ((HTMLDocument) d).getStyleSheet();
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Creates a new HTML table view for the specified element.
+ *
+ * @param el the element for the table view
+ */
+ public TableView(Element el)
+ {
+ super(el);
+ }
+
+ /**
+ * Get the associated style sheet from the document.
+ *
+ * @return the associated style sheet.
+ */
+ protected StyleSheet getStyleSheet()
+ {
+ Document d = getElement().getDocument();
+ if (d instanceof HTMLDocument)
+ return ((HTMLDocument) d).getStyleSheet();
+ else
+ return null;
+ }
+
+ /**
+ * Creates a view for a table row.
+ *
+ * @param el the element that represents the table row
+ * @return a view for rendering the table row
+ * (and instance of {@link RowView}).
+ */
+ protected TableRow createTableRow(Element el)
+ {
+ return new RowView(el);
+ }
+
+ /**
+ * Loads the children of the Table. This completely bypasses the ViewFactory
+ * and creates instances of TableRow instead.
+ *
+ * @param vf ignored
+ */
+ protected void loadChildren(ViewFactory vf)
+ {
+ Element el = getElement();
+ int numChildren = el.getElementCount();
+ View[] rows = new View[numChildren];
+ for (int i = 0; i < numChildren; ++i)
+ {
+ rows[i] = createTableRow(el.getElement(i));
+ }
+ replace(0, getViewCount(), rows);
+ }
+}
diff --git a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
index e5d2db4df7c..70636d92923 100644
--- a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
+++ b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java
@@ -52,9 +52,6 @@ import javax.swing.text.html.HTMLEditorKit.ParserCallback;
* This class instantiates and starts the working instance of
* html parser, being responsible for providing the default DTD.
*
- * TODO Later this class must be derived from the totally abstract class
- * HTMLEditorKit.Parser. HTMLEditorKit that does not yet exist.
- *
* @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
*/
public class ParserDelegator
diff --git a/libjava/classpath/javax/swing/text/rtf/RTFParser.java b/libjava/classpath/javax/swing/text/rtf/RTFParser.java
index 4f0f967c117..de1b1c6ff15 100644
--- a/libjava/classpath/javax/swing/text/rtf/RTFParser.java
+++ b/libjava/classpath/javax/swing/text/rtf/RTFParser.java
@@ -140,9 +140,17 @@ class RTFParser
parseHeader();
parseDocument();
- Token t2 = scanner.readToken();
- if (t2.type != Token.RCURLY)
- throw new RTFParseException("expected right curly braces");
+ Token t2 = scanner.peekToken();
+ if (t2.type == Token.RCURLY)
+ {
+ // Eat the token.
+ scanner.readToken();
+ }
+ else
+ {
+ // Ignore this for maximum robustness when file is broken.
+ System.err.println("RTF warning: expected right curly braces");
+ }
}
diff --git a/libjava/classpath/javax/swing/text/rtf/RTFScanner.java b/libjava/classpath/javax/swing/text/rtf/RTFScanner.java
index 3cdd6e8e0b9..060e087eb67 100644
--- a/libjava/classpath/javax/swing/text/rtf/RTFScanner.java
+++ b/libjava/classpath/javax/swing/text/rtf/RTFScanner.java
@@ -71,6 +71,11 @@ class RTFScanner
private StringBuffer buffer;
/**
+ * Lookahead token.
+ */
+ private Token lastToken;
+
+ /**
* Constructs a new RTFScanner without initializing the {@link Reader}.
*/
private RTFScanner()
@@ -120,7 +125,7 @@ class RTFScanner
*
* @throws IOException if the underlying stream has problems
*/
- public Token readToken()
+ private Token readTokenImpl()
throws IOException
{
Token token = null;
@@ -156,6 +161,27 @@ class RTFScanner
return token;
}
+ Token peekToken()
+ throws IOException
+ {
+ lastToken = readTokenImpl();
+ return lastToken;
+ }
+
+ Token readToken()
+ throws IOException
+ {
+ Token token;
+ if (lastToken != null)
+ {
+ token = lastToken;
+ lastToken = null;
+ }
+ else
+ token = readTokenImpl();
+ return token;
+ }
+
/**
* Reads in a control word and optional parameter.
*
diff --git a/libjava/classpath/javax/swing/tree/TreePath.java b/libjava/classpath/javax/swing/tree/TreePath.java
index 93b59b07edf..1c4d78787f4 100644
--- a/libjava/classpath/javax/swing/tree/TreePath.java
+++ b/libjava/classpath/javax/swing/tree/TreePath.java
@@ -174,7 +174,7 @@ public class TreePath implements Serializable
return false;
for (index = 0; index < path.length; index++)
{
- if (!treepath[index].equals(path[index]))
+ if (!path[index].equals(treepath[index]))
return false;
}