diff options
author | Mark Wielaard <mark@gcc.gnu.org> | 2006-03-10 21:46:48 +0000 |
---|---|---|
committer | Mark Wielaard <mark@gcc.gnu.org> | 2006-03-10 21:46:48 +0000 |
commit | 8aa540d2f783474d1d2e06f16744bf67b9c1facc (patch) | |
tree | ea38c56431c5d4528fb54254c3f8e50f517bede3 /libjava/classpath/javax/swing/plaf/basic | |
parent | 27079765d00123f8e53d0e1ef7f9d46559266e6d (diff) | |
download | gcc-8aa540d2f783474d1d2e06f16744bf67b9c1facc.tar.gz |
Imported GNU Classpath 0.90
Imported GNU Classpath 0.90
* scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore.
* gnu/classpath/jdwp/VMFrame.java (SIZE): New constant.
* java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5.
* java/lang/Math.java: New override file.
* java/lang/Character.java: Merged from Classpath.
(start, end): Now 'int's.
(canonicalName): New field.
(CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants.
(UnicodeBlock): Added argument.
(of): New overload.
(forName): New method.
Updated unicode blocks.
(sets): Updated.
* sources.am: Regenerated.
* Makefile.in: Likewise.
From-SVN: r111942
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/basic')
22 files changed, 1475 insertions, 973 deletions
diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java index 5d4ce18932b..5e2cf2e48ca 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicBorders.java @@ -299,9 +299,7 @@ public class BasicBorders public static Border getSplitPaneDividerBorder() { /* See comment in methods above for why this border is not shared. */ - return new SplitPaneDividerBorder( - UIManager.getColor("SplitPane.highlight"), - UIManager.getColor("SplitPane.darkShadow")); + return new SplitPaneDividerBorder(); } @@ -1518,34 +1516,15 @@ public class BasicBorders implements Border, UIResource, Serializable { /** - * The highlight color, which is drawn on the left or top edge - * depending on the orientation of the JSplitPanel. - */ - protected Color highlight; - - - /** - * The highlight color, which is drawn on the right or bottom edge - * depending on the orientation of the JSplitPanel. - */ - protected Color shadow; - - - /** * Constructs a new border for drawing the divider of a JSplitPane * in the Basic look and feel. The outer parts of the JSplitPane have * their own border class, <code>SplitPaneBorder</code>. - * - * @param shadow the shadow color. - * @param highlight the highlight color. */ - public SplitPaneDividerBorder(Color highlight, Color shadow) + public SplitPaneDividerBorder() { - this.highlight = (highlight != null) ? highlight : Color.white; - this.shadow = (shadow != null) ? shadow : Color.black; + // Nothing to do here. } - /** * Paints the border around the divider of a <code>JSplitPane</code>. * @@ -1564,6 +1543,8 @@ public class BasicBorders public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color highlight = UIManager.getColor("SplitPane.highlight"); + Color shadow = UIManager.getColor("SplitPane.shadow"); Color oldColor, dcol; int x2, y2; JSplitPane sp; @@ -1624,17 +1605,15 @@ public class BasicBorders return new Insets(1, 1, 1, 1); } - /** * Determines whether this border fills every pixel in its area * when painting. * - * @return <code>true</code> if both highlight and shadow - * color are fully opaque. + * @return <code>true</code> */ public boolean isBorderOpaque() { - return (highlight.getAlpha() == 255) && (shadow.getAlpha() == 255); + return true; } @@ -1785,4 +1764,5 @@ public class BasicBorders return insets; } } + } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java index 95e0dc98257..e45970ed02c 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicCheckBoxMenuItemUI.java @@ -45,7 +45,6 @@ import javax.swing.JMenuItem; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java index 5a872ae6368..f37cbd7b838 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicColorChooserUI.java @@ -141,10 +141,9 @@ public class BasicColorChooserUI extends ColorChooserUI protected PropertyChangeListener propertyChangeListener; /** - * The JColorChooser. - * This is package-private to avoid an accessor method. + * The JColorChooser this is installed on. */ - JColorChooser chooser; + protected JColorChooser chooser; /** The JTabbedPane that is used. */ JTabbedPane pane; diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java index 08dab7f9f36..798101d0d85 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicComboPopup.java @@ -69,6 +69,7 @@ import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; +import javax.swing.UIManager; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; import javax.swing.event.ListSelectionEvent; @@ -193,8 +194,23 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup if (selectedIndex > comboBox.getMaximumRowCount()) scrollbar.setValue(getPopupHeightForRowCount(selectedIndex)); + // We put the autoclose-registration inside an InvocationEvent, so that + // the same event that triggered this show() call won't hide the popup + // immediately. + SwingUtilities.invokeLater + (new Runnable() + { + public void run() + { + // Register this popup to be autoclosed when user clicks outside the + // popup. + BasicLookAndFeel laf = (BasicLookAndFeel) UIManager.getLookAndFeel(); + laf.registerForAutoClose(BasicComboPopup.this); + }}); + // location specified is relative to comboBox super.show(comboBox, 0, cbBounds.height); + } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java b/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java index b9891e14401..98c9cb277f4 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicHTML.java @@ -38,12 +38,21 @@ exception statement from your version. */ package javax.swing.plaf.basic; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.Shape; import java.io.IOException; import java.io.StringReader; import javax.swing.JComponent; +import javax.swing.SwingConstants; +import javax.swing.event.DocumentEvent; import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.EditorKit; import javax.swing.text.Element; +import javax.swing.text.Position; import javax.swing.text.View; import javax.swing.text.ViewFactory; import javax.swing.text.html.HTMLDocument; @@ -59,6 +68,287 @@ public class BasicHTML { /** + * This class serves as the root view for HTML rendering components. + * Its purpose and implementation is similar to the BasicTextUI.RootView + * class, only that is implements some stuff differently due to the nature + * of not beeing inside a JTextComponent. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private static class HTMLRootView extends View + { + /** + * The real root view. + */ + private View view; + + /** + * The component on which to render the view. + */ + private JComponent component; + + /** + * The EditorKit. + */ + private EditorKit editorKit; + + /** + * The document to use. + */ + private Document document; + + /** + * Creates a new RootView. + */ + public HTMLRootView(JComponent c, View view, EditorKit kit, Document doc) + { + super(null); + component = c; + editorKit = kit; + document = doc; + setView(view); + } + + /** + * Returns the ViewFactory for this RootView. If the current EditorKit + * provides a ViewFactory, this is used. Otherwise the TextUI itself + * is returned as a ViewFactory. + * + * @return the ViewFactory for this RootView + */ + public ViewFactory getViewFactory() + { + return editorKit.getViewFactory(); + } + + /** + * Indicates that the preferences of one of the child view has changed. + * This calls revalidate on the text component. + * + * @param v the child view which's preference has changed + * @param width <code>true</code> if the width preference has changed + * @param height <code>true</code> if the height preference has changed + */ + public void preferenceChanged(View v, boolean width, boolean height) + { + component.revalidate(); + } + + /** + * Sets the real root view. + * + * @param v the root view to set + */ + public void setView(View v) + { + if (view != null) + view.setParent(null); + + if (v != null) + v.setParent(this); + + view = v; + } + + /** + * Returns the real root view, regardless of the index. + * + * @param index not used here + * + * @return the real root view, regardless of the index. + */ + public View getView(int index) + { + return view; + } + + /** + * Returns <code>1</code> since the RootView always contains one + * child, that is the real root of the View hierarchy. + * + * @return <code>1</code> since the RootView always contains one + * child, that is the real root of the View hierarchy + */ + public int getViewCount() + { + int count = 0; + if (view != null) + count = 1; + return count; + } + + /** + * Returns the <code>Container</code> that contains this view. This + * normally will be the text component that is managed by this TextUI. + * + * @return the <code>Container</code> that contains this view + */ + public Container getContainer() + { + return component; + } + + /** + * Returns the preferred span along the specified <code>axis</code>. + * This is delegated to the real root view. + * + * @param axis the axis for which the preferred span is queried + * + * @return the preferred span along the axis + */ + public float getPreferredSpan(int axis) + { + if (view != null) + return view.getPreferredSpan(axis); + + return Integer.MAX_VALUE; + } + + /** + * Paints the view. This is delegated to the real root view. + * + * @param g the <code>Graphics</code> context to paint to + * @param s the allocation for the View + */ + public void paint(Graphics g, Shape s) + { + if (view != null) + { + Rectangle b = s.getBounds(); + view.setSize(b.width, b.height); + view.paint(g, s); + } + } + + + /** + * Maps a position in the document into the coordinate space of the View. + * The output rectangle usually reflects the font height but has a width + * of zero. + * + * This is delegated to the real root view. + * + * @param position the position of the character in the model + * @param a the area that is occupied by the view + * @param bias either {@link Position.Bias#Forward} or + * {@link Position.Bias#Backward} depending on the preferred + * direction bias. If <code>null</code> this defaults to + * <code>Position.Bias.Forward</code> + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if <code>pos</code> is invalid + * @throws IllegalArgumentException if b is not one of the above listed + * valid values + */ + public Shape modelToView(int position, Shape a, Position.Bias bias) + throws BadLocationException + { + return view.modelToView(position, a, bias); + } + + /** + * Maps coordinates from the <code>View</code>'s space into a position + * in the document model. + * + * @param x the x coordinate in the view space + * @param y the y coordinate in the view space + * @param a the allocation of this <code>View</code> + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates <code>x, y</code> + */ + public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + { + return view.viewToModel(x, y, a, b); + } + + /** + * Notification about text insertions. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.insertUpdate(ev, shape, vf); + } + + /** + * Notification about text removals. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.removeUpdate(ev, shape, vf); + } + + /** + * Notification about text changes. These are forwarded to the + * real root view. + * + * @param ev the DocumentEvent describing the change + * @param shape the current allocation of the view's display + * @param vf the ViewFactory to use for creating new Views + */ + public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) + { + view.changedUpdate(ev, shape, vf); + } + + /** + * Returns the document position that is (visually) nearest to the given + * document position <code>pos</code> in the given direction <code>d</code>. + * + * @param pos the document position + * @param b the bias for <code>pos</code> + * @param a the allocation for the view + * @param d the direction, must be either {@link SwingConstants#NORTH}, + * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or + * {@link SwingConstants#EAST} + * @param biasRet an array of {@link Position.Bias} that can hold at least + * one element, which is filled with the bias of the return position + * on method exit + * + * @return the document position that is (visually) nearest to the given + * document position <code>pos</code> in the given direction + * <code>d</code> + * + * @throws BadLocationException if <code>pos</code> is not a valid offset in + * the document model + */ + public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, + int d, Position.Bias[] biasRet) + throws BadLocationException + { + return view.getNextVisualPositionFrom(pos, b, a, d, biasRet); + } + + public int getStartOffset() + { + return 0; + } + + public int getEndOffset() + { + return getDocument().getLength(); + } + + public Document getDocument() + { + return document; + } + } + + /** * The key that is used to store a HTML view in a JComponent's client * properties. */ @@ -116,7 +406,8 @@ public class BasicHTML ViewFactory vf = kit.getViewFactory(); Element root = doc.getDefaultRootElement(); View view = vf.create(root); - return view; + HTMLRootView rootView = new HTMLRootView(c, view, kit, doc); + return rootView; } /** @@ -132,13 +423,13 @@ public class BasicHTML { // We consider a string to be HTML if it contains both the '<' and '>' // character at least once. - return s.contains("<") && s.contains(">"); + return (s != null) && s.contains("<") && s.contains(">"); } /** * Stores a HTML renderer in <code>c</code>'s client property if * <code>text</code> is HTML, otherwise it clears the corresponding client - * property. This is useful for {@link java.swing.plaf.ComponentUI} + * property. This is useful for {@link javax.swing.plaf.ComponentUI} * implementations that are shared between it's components. * * @param c the component to update the renderer for diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java index f9653bd2edd..f6cbeec8879 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -54,8 +54,6 @@ import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.beans.PropertyVetoException; -import java.beans.VetoableChangeListener; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; @@ -94,7 +92,7 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void internalFrameActivated(InternalFrameEvent e) { - // FIXME: Implement. + frame.getGlassPane().setVisible(false); } /** @@ -124,7 +122,7 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void internalFrameDeactivated(InternalFrameEvent e) { - // FIXME: Implement. + frame.getGlassPane().setVisible(true); } /** @@ -464,8 +462,6 @@ public class BasicInternalFrameUI extends InternalFrameUI dims.width -= insets.left + insets.right; dims.height -= insets.top + insets.bottom; - frame.getRootPane().getGlassPane().setBounds(0, 0, dims.width, - dims.height); int nh = 0; int sh = 0; int ew = 0; @@ -526,18 +522,6 @@ public class BasicInternalFrameUI extends InternalFrameUI } /** - * This method returns the maximum layout size. - * - * @param c - * The Container to find a maximum layout size for. - * @return The maximum dimensions for the JInternalFrame. - */ - public Dimension maximumLayoutSize(Container c) - { - return preferredLayoutSize(c); - } - - /** * Th8is method returns the preferred layout size. * * @param c @@ -891,40 +875,12 @@ public class BasicInternalFrameUI extends InternalFrameUI * This helper class listens for PropertyChangeEvents from the * JInternalFrame. */ - public class InternalFramePropertyChangeListener implements - PropertyChangeListener, VetoableChangeListener + public class InternalFramePropertyChangeListener + implements PropertyChangeListener { /** * This method is called when one of the JInternalFrame's properties change. - * This method is to allow JInternalFrame to veto an attempt to close the - * internal frame. This allows JInternalFrame to honour its - * defaultCloseOperation if that is DO_NOTHING_ON_CLOSE. - */ - public void vetoableChange(PropertyChangeEvent e) - throws PropertyVetoException - { - if (e.getPropertyName().equals(JInternalFrame.IS_CLOSED_PROPERTY)) - { - if (frame.getDefaultCloseOperation() == JInternalFrame.HIDE_ON_CLOSE) - { - frame.setVisible(false); - frame.getDesktopPane().repaint(); - throw new PropertyVetoException( - "close operation is HIDE_ON_CLOSE\n", - e); - } - else if (frame.getDefaultCloseOperation() == JInternalFrame.DISPOSE_ON_CLOSE) - closeFrame(frame); - else - throw new PropertyVetoException( - "close operation is DO_NOTHING_ON_CLOSE\n", - e); - } - } - - /** - * This method is called when one of the JInternalFrame's properties change. * * @param evt * The PropertyChangeEvent. @@ -1091,13 +1047,6 @@ public class BasicInternalFrameUI extends InternalFrameUI */ protected PropertyChangeListener propertyChangeListener; - /** - * The VetoableChangeListener. Listens to PropertyChangeEvents - * from the JInternalFrame and allows the JInternalFrame to - * veto attempts to close it. - */ - private VetoableChangeListener internalFrameVetoableChangeListener; - /** The InternalFrameListener that listens to the JInternalFrame. */ private transient BasicInternalFrameListener internalFrameListener; @@ -1165,14 +1114,15 @@ public class BasicInternalFrameUI extends InternalFrameUI { frame = (JInternalFrame) c; - ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); - frame.getRootPane().getGlassPane().setVisible(true); - installDefaults(); installListeners(); installComponents(); installKeyboardActions(); + ((JComponent) frame.getRootPane().getGlassPane()).setOpaque(false); + if (! frame.isSelected()) + frame.getRootPane().getGlassPane().setVisible(true); + frame.setOpaque(true); frame.invalidate(); } @@ -1205,8 +1155,6 @@ public class BasicInternalFrameUI extends InternalFrameUI frame.setLayout(internalFrameLayout); LookAndFeel.installBorder(frame, "InternalFrame.border"); frame.setFrameIcon(UIManager.getIcon("InternalFrame.icon")); - // InternalFrames are invisible by default. - frame.setVisible(false); } /** @@ -1238,13 +1186,11 @@ public class BasicInternalFrameUI extends InternalFrameUI borderListener = createBorderListener(frame); componentListener = createComponentListener(); propertyChangeListener = createPropertyChangeListener(); - internalFrameVetoableChangeListener = new InternalFramePropertyChangeListener(); frame.addMouseListener(borderListener); frame.addMouseMotionListener(borderListener); frame.addInternalFrameListener(internalFrameListener); frame.addPropertyChangeListener(propertyChangeListener); - frame.addVetoableChangeListener(internalFrameVetoableChangeListener); frame.getRootPane().getGlassPane().addMouseListener(glassPaneDispatcher); frame.getRootPane().getGlassPane().addMouseMotionListener(glassPaneDispatcher); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java index fd4cff56895..d0964f4733e 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLabelUI.java @@ -53,6 +53,7 @@ import javax.swing.LookAndFeel; import javax.swing.SwingUtilities; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.LabelUI; +import javax.swing.text.View; /** * This is the Basic Look and Feel class for the JLabel. One BasicLabelUI @@ -64,11 +65,22 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener protected static BasicLabelUI labelUI; /** + * These fields hold the rectangles for the whole label, + * the icon and the text. + */ + private Rectangle vr; + private Rectangle ir; + private Rectangle tr; + + /** * Creates a new BasicLabelUI object. */ public BasicLabelUI() { super(); + vr = new Rectangle(); + ir = new Rectangle(); + tr = new Rectangle(); } /** @@ -99,13 +111,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener public Dimension getPreferredSize(JComponent c) { JLabel lab = (JLabel) c; - Rectangle vr = new Rectangle(); - Rectangle ir = new Rectangle(); - Rectangle tr = new Rectangle(); Insets insets = lab.getInsets(); FontMetrics fm = lab.getFontMetrics(lab.getFont()); layoutCL(lab, fm, lab.getText(), lab.getIcon(), vr, ir, tr); - Rectangle cr = tr.union(ir); + Rectangle cr = SwingUtilities.computeUnion(tr.x, tr.y, tr.width, tr.height, + ir); return new Dimension(insets.left + cr.width + insets.right, insets.top + cr.height + insets.bottom); @@ -148,11 +158,6 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener public void paint(Graphics g, JComponent c) { JLabel b = (JLabel) c; - - Rectangle tr = new Rectangle(); - Rectangle ir = new Rectangle(); - Rectangle vr = new Rectangle(); - FontMetrics fm = g.getFontMetrics(); vr = SwingUtilities.calculateInnerArea(c, vr); @@ -168,13 +173,21 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener if (icon != null) icon.paintIcon(b, g, ir.x, ir.y); - if (text != null && !text.equals("")) - { - if (b.isEnabled()) - paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); - else - paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); - } + Object htmlRenderer = b.getClientProperty(BasicHTML.propertyKey); + if (htmlRenderer == null) + { + if (text != null && !text.equals("")) + { + if (b.isEnabled()) + paintEnabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + else + paintDisabledText(b, g, text, tr.x, tr.y + fm.getAscent()); + } + } + else + { + ((View) htmlRenderer).paint(g, tr); + } } /** @@ -312,7 +325,7 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener */ protected void installComponents(JLabel c) { - //FIXME: fix javadoc + implement. + BasicHTML.updateRenderer(c, c.getText()); } /** @@ -322,7 +335,8 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener */ protected void uninstallComponents(JLabel c) { - //FIXME: fix javadoc + implement. + c.putClientProperty(BasicHTML.propertyKey, null); + c.putClientProperty(BasicHTML.documentBaseKey, null); } /** @@ -402,6 +416,11 @@ public class BasicLabelUI extends LabelUI implements PropertyChangeListener */ public void propertyChange(PropertyChangeEvent e) { - // What to do here? + if (e.getPropertyName().equals("text")) + { + String text = (String) e.getNewValue(); + JLabel l = (JLabel) e.getSource(); + BasicHTML.updateRenderer(l, text); + } } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java index 00d157a62c4..19dfe21f889 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicListUI.java @@ -64,6 +64,7 @@ import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.event.ListDataEvent; @@ -135,6 +136,7 @@ public class BasicListUI extends ListUI */ public void contentsChanged(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } @@ -145,6 +147,7 @@ public class BasicListUI extends ListUI */ public void intervalAdded(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } @@ -155,6 +158,7 @@ public class BasicListUI extends ListUI */ public void intervalRemoved(ListDataEvent e) { + updateLayoutStateNeeded |= modelChanged; list.revalidate(); } } @@ -541,17 +545,21 @@ public class BasicListUI extends ListUI */ public void propertyChange(PropertyChangeEvent e) { - if (e.getSource() == BasicListUI.this.list) + if (e.getPropertyName().equals("model")) { if (e.getOldValue() != null && e.getOldValue() instanceof ListModel) - ((ListModel) e.getOldValue()).removeListDataListener(BasicListUI.this.listDataListener); - + { + ListModel oldModel = (ListModel) e.getOldValue(); + oldModel.removeListDataListener(listDataListener); + } if (e.getNewValue() != null && e.getNewValue() instanceof ListModel) - ((ListModel) e.getNewValue()).addListDataListener(BasicListUI.this.listDataListener); + { + ListModel newModel = (ListModel) e.getNewValue(); + newModel.addListDataListener(BasicListUI.this.listDataListener); + } + + updateLayoutStateNeeded |= modelChanged; } - // Update the updateLayoutStateNeeded flag. - if (e.getPropertyName().equals("model")) - updateLayoutStateNeeded |= modelChanged; else if (e.getPropertyName().equals("selectionModel")) updateLayoutStateNeeded |= selectionModelChanged; else if (e.getPropertyName().equals("font")) @@ -720,14 +728,20 @@ public class BasicListUI extends ListUI int minIndex = Math.min(index1, index2); int maxIndex = Math.max(index1, index2); Point loc = indexToLocation(list, minIndex); - Rectangle bounds = new Rectangle(loc.x, loc.y, cellWidth, + + // When the layoutOrientation is VERTICAL, then the width == the list + // width. Otherwise the cellWidth field is used. + int width = cellWidth; + if (l.getLayoutOrientation() == JList.VERTICAL) + width = l.getWidth(); + + Rectangle bounds = new Rectangle(loc.x, loc.y, width, getCellHeight(minIndex)); for (int i = minIndex + 1; i <= maxIndex; i++) { Point hiLoc = indexToLocation(list, i); - Rectangle hibounds = new Rectangle(hiLoc.x, hiLoc.y, cellWidth, - getCellHeight(i)); - bounds = bounds.union(hibounds); + bounds = SwingUtilities.computeUnion(hiLoc.x, hiLoc.y, width, + getCellHeight(i), bounds); } return bounds; @@ -883,8 +897,6 @@ public class BasicListUI extends ListUI Dimension dim = flyweight.getPreferredSize(); cellWidth = Math.max(cellWidth, dim.width); } - if (list.getLayoutOrientation() == JList.VERTICAL) - cellWidth = Math.max(cellWidth, list.getSize().width); } } @@ -894,7 +906,7 @@ public class BasicListUI extends ListUI */ protected void maybeUpdateLayoutState() { - if (updateLayoutStateNeeded != 0 || !list.isValid()) + if (updateLayoutStateNeeded != 0) { updateLayoutState(); updateLayoutStateNeeded = 0; diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java index f5217be1ff6..3451224beeb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -38,15 +38,24 @@ 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; import java.awt.Dimension; import java.awt.Font; +import java.awt.Toolkit; +import java.awt.event.AWTEventListener; import java.awt.event.ActionEvent; +import java.awt.event.MouseEvent; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Enumeration; +import java.util.Iterator; import java.util.ResourceBundle; +import java.util.Set; +import java.util.WeakHashMap; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; @@ -57,8 +66,11 @@ import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; +import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.LookAndFeel; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; import javax.swing.border.BevelBorder; @@ -77,6 +89,96 @@ import javax.swing.plaf.InsetsUIResource; public abstract class BasicLookAndFeel extends LookAndFeel implements Serializable { + + /** + * Helps closing menu popups when the user clicks outside of any menu area. + * This is implemented as an AWTEventListener that listens on the event + * queue directly, grabs all mouse events from there and finds out of they + * are targetted at a menu/submenu/menubar or not. If not, + * the MenuSelectionManager is messaged to close the currently opened menus, + * if any. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class PopupHelper implements AWTEventListener + { + + /** + * Registered popups for autoclose. + */ + private WeakHashMap autoClosePopups = new WeakHashMap(); + + /** + * Receives an event from the event queue. + * + * @param event + */ + public void eventDispatched(AWTEvent event) + { + if (event instanceof MouseEvent) + { + MouseEvent mouseEvent = (MouseEvent) event; + if (mouseEvent.getID() == MouseEvent.MOUSE_PRESSED) + mousePressed(mouseEvent); + } + } + + /** + * Handles mouse pressed events from the event queue. + * + * @param ev the mouse pressed event + */ + private void mousePressed(MouseEvent ev) + { + // Autoclose all menus managed by the MenuSelectionManager. + MenuSelectionManager m = MenuSelectionManager.defaultManager(); + Component target = ev.getComponent(); + if (target instanceof Container) + target = ((Container) target).findComponentAt(ev.getPoint()); + if (! m.isComponentPartOfCurrentMenu(target)) + m.clearSelectedPath(); + + // Handle other registered popup instances, like ComboBox popups. + autoClosePopups(ev, target); + } + + /** + * Registers Popup and its content to be autoclosed when a mouseclick + * occurs outside of the popup. + * + * @param popup the popup to be autoclosed when clicked outside + */ + void registerForAutoClose(JPopupMenu popup) + { + autoClosePopups.put(popup, null); + } + + /** + * Automatically closes all popups that are not 'hit' by the mouse event. + * + * @param ev the mouse event + * @param target the target of the mouse event + */ + private void autoClosePopups(MouseEvent ev, Component target) + { + if (autoClosePopups.size() != 0) + { + Set popups = autoClosePopups.keySet(); + Iterator i = popups.iterator(); + while (i.hasNext()) + { + JPopupMenu popup = (JPopupMenu) i.next(); + if (!(target == popup + || SwingUtilities.isDescendingFrom(target, popup))) + { + popup.setVisible(false); + i.remove(); + } + } + } + } + } + /** * An action that can play an audio file. * @@ -137,6 +239,11 @@ public abstract class BasicLookAndFeel extends LookAndFeel static final long serialVersionUID = -6096995660290287879L; + /** + * Helps closing menu popups when user clicks outside of the menu area. + */ + private transient PopupHelper popupHelper; + private ActionMap audioActionMap; /** @@ -1023,6 +1130,8 @@ public abstract class BasicLookAndFeel extends LookAndFeel "SplitPane.dividerSize", new Integer(7), "SplitPane.highlight", new ColorUIResource(highLight), "SplitPane.shadow", new ColorUIResource(shadow), + "SplitPaneDivider.border", BasicBorders.getSplitPaneDividerBorder(), + "SplitPaneDivider.draggingColor", new ColorUIResource(Color.DARK_GRAY), "TabbedPane.ancestorInputMap", new UIDefaults.LazyInputMap(new Object[] { "ctrl PAGE_DOWN","navigatePageDown", "ctrl PAGE_UP", "navigatePageUp", @@ -1520,4 +1629,36 @@ public abstract class BasicLookAndFeel extends LookAndFeel } } + /** + * Initializes the Look and Feel. + */ + public void initialize() + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + popupHelper = new PopupHelper(); + toolkit.addAWTEventListener(popupHelper, AWTEvent.MOUSE_EVENT_MASK); + } + + /** + * Uninitializes the Look and Feel. + */ + public void uninitialize() + { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + toolkit.removeAWTEventListener(popupHelper); + popupHelper = null; + } + + /** + * Registers a JPopupMenu for autoclosing when a mouseclick occurs outside + * of the JPopupMenu. This must be called when the popup gets opened. The + * popup is unregistered from autoclosing as soon as it either got closed + * by this helper, or when it has been garbage collected. + * + * @param popup the popup menu to autoclose + */ + void registerForAutoClose(JPopupMenu popup) + { + popupHelper.registerForAutoClose(popup); + } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java index 63f0ce2068b..9166c49ee83 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicMenuItemUI.java @@ -610,8 +610,7 @@ public class BasicMenuItemUI extends MenuItemUI Font f = m.getFont(); g.setFont(f); FontMetrics fm = g.getFontMetrics(f); - SwingUtilities.calculateInnerArea(m, br); - SwingUtilities.calculateInsetArea(br, m.getInsets(), vr); + SwingUtilities.calculateInnerArea(m, vr); paintBackground(g, m, background); /* diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java index e15a17bab28..6ecd06b3988 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -37,28 +37,20 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import java.awt.AWTEvent; import java.awt.Component; -import java.awt.Container; -import java.awt.Cursor; import java.awt.Dimension; -import java.awt.Point; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import javax.swing.BoxLayout; import javax.swing.JComponent; -import javax.swing.JLayeredPane; -import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.LookAndFeel; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; -import javax.swing.RootPaneContainer; import javax.swing.SwingUtilities; -import javax.swing.event.MouseInputListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.ComponentUI; @@ -73,9 +65,6 @@ public class BasicPopupMenuUI extends PopupMenuUI /* popupMenu for which this UI delegate is for*/ protected JPopupMenu popupMenu; - /* MouseInputListener listens to mouse events. Package private for inner classes. */ - static transient MouseInputListener mouseInputListener; - /* PopupMenuListener listens to popup menu events fired by JPopupMenu*/ private transient PopupMenuListener popupMenuListener; @@ -270,30 +259,9 @@ public class BasicPopupMenuUI extends PopupMenuUI // remove listener that listens to component events fired // by the top - level window that this popup belongs to. Component invoker = popupMenu.getInvoker(); - - RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities - .getRoot(invoker); + Component rootContainer = SwingUtilities.getRoot(invoker); if (rootContainer != null) - { - ((Container) rootContainer).removeComponentListener(topWindowListener); - - // If this popup menu is the last popup menu visible on the screen, - // then - // stop interrupting mouse events in the glass pane before hiding this - // last popup menu. - boolean topLevelMenu = (popupMenu.getInvoker() instanceof JMenu) - && ((JMenu) popupMenu.getInvoker()).isTopLevelMenu(); - - if (topLevelMenu || !(popupMenu.getInvoker() instanceof MenuElement)) - { - // set glass pane not to interrupt mouse events and remove - // mouseInputListener - Container glassPane = (Container) rootContainer.getGlassPane(); - glassPane.setVisible(false); - glassPane.removeMouseListener(mouseInputListener); - mouseInputListener = null; - } - } + rootContainer.removeComponentListener(topWindowListener); } /** @@ -307,20 +275,8 @@ public class BasicPopupMenuUI extends PopupMenuUI // 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(); - RootPaneContainer rootContainer = (RootPaneContainer) SwingUtilities - .getRoot(invoker); - ((Container) rootContainer).addComponentListener(topWindowListener); - - // Set the glass pane to interrupt all mouse events originating in root - // container - if (mouseInputListener == null) - { - Container glassPane = (Container) rootContainer.getGlassPane(); - glassPane.setVisible(true); - mouseInputListener = new MouseInputHandler(rootContainer); - glassPane.addMouseListener(mouseInputListener); - glassPane.addMouseMotionListener(mouseInputListener); - } + Component rootContainer = SwingUtilities.getRoot(invoker); + rootContainer.addComponentListener(topWindowListener); // if this popup menu is a free floating popup menu, // then by default its first element should be always selected when @@ -399,275 +355,4 @@ public class BasicPopupMenuUI extends PopupMenuUI } } - /** - * MouseInputHandler listens to all mouse events originated in the root - * container. This class is responsible for closing menu hierarchy when the - * user presses mouse over any component that do not belong to the current - * menu hierarchy. This is acomplished by interrupting all mouse event in - * the glass pane and checking if other component was pressed while menu - * was open, before redestributing events further to intended components - */ - private class MouseInputHandler implements MouseInputListener - { - private JLayeredPane layeredPane; - private Container glassPane; - private Cursor nativeCursor; - private transient Component mouseEventTarget; - private transient Component pressedComponent; - private transient Component lastComponentEntered; - private transient Component tempComponent; - private transient int pressCount; - - /** - * Creates a new MouseInputHandler object. - * - * @param c the top most root container - */ - public MouseInputHandler(RootPaneContainer c) - { - layeredPane = c.getLayeredPane(); - glassPane = (Container) c.getGlassPane(); - } - - /** - * Handles mouse clicked event - * - * @param e Mouse event - */ - public void mouseClicked(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseDragged event - * - * @param e MouseEvent - */ - public void mouseDragged(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseEntered event - * - * @param e MouseEvent - */ - public void mouseEntered(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouseExited event - * - * @param e MouseEvent - */ - public void mouseExited(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse moved event - * - * @param e MouseEvent - */ - public void mouseMoved(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse pressed event - * - * @param e MouseEvent - */ - public void mousePressed(MouseEvent e) - { - handleEvent(e); - } - - /** - * Handles mouse released event - * - * @param e MouseEvent - */ - public void mouseReleased(MouseEvent e) - { - handleEvent(e); - } - - /* - * This method determines component that was intended to received mouse - * event, before it was interrupted within the glass pane. This method - * also redispatches mouse entered and mouse exited events to the - * appropriate components. This code is slightly modified code from - * Container.LightweightDispatcher class, which is private inside - * Container class and cannot be used here. - */ - public void acquireComponentForMouseEvent(MouseEvent me) - { - int x = me.getX(); - int y = me.getY(); - - // Find the candidate which should receive this event. - Component parent = layeredPane; - Component candidate = null; - Point p = me.getPoint(); - while ((candidate == null) && (parent != null)) - { - p = SwingUtilities.convertPoint(glassPane, p.x, p.y, parent); - 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 == layeredPane) - candidate = null; - - // If our candidate is new, inform the old target we're leaving. - if ((lastComponentEntered != null) && lastComponentEntered.isShowing() - && (lastComponentEntered != candidate)) - { - // Old candidate could have been removed from - // the layeredPane so we check first. - if (SwingUtilities.isDescendingFrom(lastComponentEntered, layeredPane)) - { - Point tp = SwingUtilities.convertPoint(layeredPane, 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); - } - - lastComponentEntered = null; - } - - // If we have a candidate, maybe enter it. - if (candidate != null) - { - mouseEventTarget = candidate; - - if (candidate.isLightweight() && candidate.isShowing() - && (candidate != layeredPane) - && (candidate != lastComponentEntered)) - { - lastComponentEntered = mouseEventTarget; - - Point cp = SwingUtilities.convertPoint(layeredPane, 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 - if (SwingUtilities.isDescendingFrom(pressedComponent, layeredPane)) - 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; - } - } - } - - /* - * This method handles mouse events interrupted by glassPane. It - * redispatches the mouse events appropriately to the intended components. - * The code in this method is also taken from - * Container.LightweightDispatcher class. The code is slightly modified - * to handle the case when mouse is released over non-menu component. In - * this case this method closes current menu hierarchy before - * redispatching the event further. - */ - public void handleEvent(AWTEvent e) - { - if (e instanceof MouseEvent) - { - MouseEvent me = (MouseEvent) e; - - acquireComponentForMouseEvent(me); - - // Avoid dispatching ENTERED and EXITED events twice. - if (mouseEventTarget != null && mouseEventTarget.isShowing() - && (e.getID() != MouseEvent.MOUSE_ENTERED) - && (e.getID() != MouseEvent.MOUSE_EXITED)) - { - MouseEvent newEvt = SwingUtilities.convertMouseEvent(glassPane, - me, - mouseEventTarget); - - mouseEventTarget.dispatchEvent(newEvt); - - // If mouse was clicked over the component that is not part - // of menu hierarchy,then must close the menu hierarchy */ - if (e.getID() == MouseEvent.MOUSE_RELEASED) - { - boolean partOfMenuHierarchy = false; - MenuSelectionManager manager = MenuSelectionManager - .defaultManager(); - - partOfMenuHierarchy = manager.isComponentPartOfCurrentMenu(mouseEventTarget); - - if (! partOfMenuHierarchy) - manager.clearSelectedPath(); - } - - 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; - } - } - } - } - } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java index 8af5ff7f95c..f8f62e15651 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRadioButtonMenuItemUI.java @@ -45,7 +45,6 @@ import javax.swing.JMenuItem; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.UIDefaults; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java index 2a698e8a162..28e3b67c1a5 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicRootPaneUI.java @@ -1,4 +1,4 @@ -/* BasicPanelUI.java -- +/* BasicRootPaneUI.java -- Copyright (C) 2002, 2004 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,7 +43,6 @@ import java.beans.PropertyChangeListener; import javax.swing.JComponent; import javax.swing.JRootPane; -import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.RootPaneUI; @@ -75,8 +74,7 @@ public class BasicRootPaneUI extends RootPaneUI */ protected void installDefaults(JRootPane rp) { - // Is this ok? - rp.setBackground(UIManager.getColor("control")); + // TODO: What to do here, if anything? (might be a hook method) } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java index a2f5b82dbec..c8713c934dd 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicScrollBarUI.java @@ -653,19 +653,17 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, if (scrollbar.getOrientation() == SwingConstants.HORIZONTAL) { - width += incrButton.getPreferredSize().getWidth(); - width += decrButton.getPreferredSize().getWidth(); - - width += (scrollbar.getMaximum() - scrollbar.getMinimum()); - height = UIManager.getInt("ScrollBar.width"); + width += incrButton.getPreferredSize().getWidth(); + width += decrButton.getPreferredSize().getWidth(); + width += 16; + height = UIManager.getInt("ScrollBar.width"); } else { - height += incrButton.getPreferredSize().getHeight(); - height += decrButton.getPreferredSize().getHeight(); - - height += (scrollbar.getMaximum() - scrollbar.getMinimum()); - width = UIManager.getInt("ScrollBar.width"); + height += incrButton.getPreferredSize().getHeight(); + height += decrButton.getPreferredSize().getHeight(); + height += 16; + width = UIManager.getInt("ScrollBar.width"); } Insets insets = scrollbar.getInsets(); @@ -721,18 +719,6 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, */ protected void installComponents() { - if (incrButton != null) - scrollbar.add(incrButton); - if (decrButton != null) - scrollbar.add(decrButton); - } - - /** - * This method installs the defaults for the scrollbar specified by the - * Basic Look and Feel. - */ - protected void installDefaults() - { int orientation = scrollbar.getOrientation(); switch (orientation) { @@ -746,6 +732,18 @@ public class BasicScrollBarUI extends ScrollBarUI implements LayoutManager, break; } + if (incrButton != null) + scrollbar.add(incrButton); + if (decrButton != null) + scrollbar.add(decrButton); + } + + /** + * This method installs the defaults for the scrollbar specified by the + * Basic Look and Feel. + */ + protected void installDefaults() + { LookAndFeel.installColors(scrollbar, "ScrollBar.background", "ScrollBar.foreground"); LookAndFeel.installBorder(scrollbar, "ScrollBar.border"); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java index 3b7399eafaa..6f7a41a1d96 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSpinnerUI.java @@ -1,5 +1,5 @@ -/* SpinnerUI.java -- - Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +/* BasicSpinnerUI.java -- + Copyright (C) 2003, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -41,6 +41,7 @@ package javax.swing.plaf.basic; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.Font; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; @@ -59,22 +60,21 @@ import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SpinnerUI; /** - * DOCUMENT ME! + * A UI delegate for the {@link JSpinner} component. * * @author Ka-Hing Cheung * - * @see javax.swing.JSpinner * @since 1.4 */ public class BasicSpinnerUI extends SpinnerUI { /** - * Creates a new <code>ComponentUI</code> for the specified + * Creates a new <code>BasicSpinnerUI</code> for the specified * <code>JComponent</code> * - * @param c DOCUMENT ME! + * @param c the component (ignored). * - * @return a ComponentUI + * @return A new instance of {@link BasicSpinnerUI}. */ public static ComponentUI createUI(JComponent c) { @@ -144,14 +144,15 @@ public class BasicSpinnerUI extends SpinnerUI { return new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) - { - // FIXME: Add check for enabled property change. Need to - // disable the buttons. - if ("editor".equals(evt.getPropertyName())) - BasicSpinnerUI.this.replaceEditor((JComponent) evt.getOldValue(), - (JComponent) evt.getNewValue()); - } + public void propertyChange(PropertyChangeEvent event) + { + // FIXME: Add check for enabled property change. Need to + // disable the buttons. + if ("editor".equals(event.getPropertyName())) + BasicSpinnerUI.this.replaceEditor((JComponent) event.getOldValue(), + (JComponent) event.getNewValue()); + // FIXME: Handle 'font' property change + } }; } @@ -169,6 +170,12 @@ public class BasicSpinnerUI extends SpinnerUI LookAndFeel.installColorsAndFont(spinner, "Spinner.background", "Spinner.foreground", "Spinner.font"); LookAndFeel.installBorder(spinner, "Spinner.border"); + JComponent e = spinner.getEditor(); + if (e instanceof JSpinner.DefaultEditor) + { + JSpinner.DefaultEditor de = (JSpinner.DefaultEditor) e; + de.getTextField().setBorder(null); + } spinner.setLayout(createLayout()); spinner.setOpaque(true); } @@ -352,7 +359,8 @@ public class BasicSpinnerUI extends SpinnerUI private PropertyChangeListener listener = createPropertyChangeListener(); /** - * DOCUMENT ME! + * A layout manager for the {@link JSpinner} component. The spinner has + * three subcomponents: an editor, a 'next' button and a 'previous' button. */ private class DefaultLayoutManager implements LayoutManager { @@ -365,58 +373,52 @@ public class BasicSpinnerUI extends SpinnerUI { synchronized (parent.getTreeLock()) { - Insets i = parent.getInsets(); - boolean l2r = parent.getComponentOrientation().isLeftToRight(); - /* - -------------- -------------- - | | n | | n | | - | e | - | or | - | e | - | | p | | p | | - -------------- -------------- - */ - Dimension e = minSize(editor); - Dimension n = minSize(next); - Dimension p = minSize(previous); - Dimension s = spinner.getPreferredSize(); - - int x = l2r ? i.left : i.right; - int y = i.top; - int w = Math.max(p.width, n.width); - int h = Math.max(p.height, n.height); - h = Math.max(h, e.height / 2); - int e_width = s.width - w; - - if (l2r) - { - setBounds(editor, x, y + (s.height - e.height) / 2, e_width, - e.height); - x += e_width; - - setBounds(next, x, y, w, h); - y += h; - - setBounds(previous, x, y, w, h); - } - else - { - setBounds(next, x, y + (s.height - e.height) / 2, w, h); - y += h; - - setBounds(previous, x, y, w, h); - x += w; - y -= h; - - setBounds(editor, x, y, e_width, e.height); - } + Insets i = parent.getInsets(); + boolean l2r = parent.getComponentOrientation().isLeftToRight(); + /* + -------------- -------------- + | | n | | n | | + | e | - | or | - | e | + | | p | | p | | + -------------- -------------- + */ + Dimension e = prefSize(editor); + Dimension n = prefSize(next); + Dimension p = prefSize(previous); + Dimension s = spinner.getPreferredSize(); + + int x = l2r ? i.left : i.right; + int y = i.top; + int w = Math.max(p.width, n.width); + int h = e.height / 2; + int e_width = s.width - w - i.left - i.right; + + if (l2r) + { + setBounds(editor, x, y, e_width, 2 * h); + x += e_width; + setBounds(next, x, y, w, h); + y += h; + setBounds(previous, x, y, w, h); + } + else + { + setBounds(next, x, y + (s.height - e.height) / 2, w, h); + y += h; + setBounds(previous, x, y + (s.height - e.height) / 2, w, h); + x += w; + y -= h; + setBounds(editor, x, y, e_width, e.height); + } } } /** - * DOCUMENT ME! + * Calculates the minimum layout size. * - * @param parent DOCUMENT ME! + * @param parent the parent. * - * @return DOCUMENT ME! + * @return The minimum layout size. */ public Dimension minimumLayoutSize(Container parent) { @@ -424,36 +426,32 @@ public class BasicSpinnerUI extends SpinnerUI if (editor != null) { - Dimension tmp = editor.getMinimumSize(); - d.width += tmp.width; - d.height = tmp.height; + Dimension tmp = editor.getMinimumSize(); + d.width += tmp.width; + d.height = tmp.height; } int nextWidth = 0; int previousWidth = 0; - int otherHeight = 0; if (next != null) { - Dimension tmp = next.getMinimumSize(); - nextWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = next.getMinimumSize(); + nextWidth = tmp.width; } if (previous != null) { - Dimension tmp = previous.getMinimumSize(); - previousWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = previous.getMinimumSize(); + previousWidth = tmp.width; } - d.height = Math.max(d.height, otherHeight); d.width += Math.max(nextWidth, previousWidth); return d; } /** - * DOCUMENT ME! + * Returns the preferred layout size of the container. * * @param parent DOCUMENT ME! * @@ -465,31 +463,29 @@ public class BasicSpinnerUI extends SpinnerUI if (editor != null) { - Dimension tmp = editor.getPreferredSize(); - d.width += Math.max(tmp.width, 40); - d.height = tmp.height; + Dimension tmp = editor.getPreferredSize(); + d.width += Math.max(tmp.width, 40); + d.height = tmp.height; } int nextWidth = 0; int previousWidth = 0; - int otherHeight = 0; if (next != null) { - Dimension tmp = next.getPreferredSize(); - nextWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = next.getPreferredSize(); + nextWidth = tmp.width; } if (previous != null) { - Dimension tmp = previous.getPreferredSize(); - previousWidth = tmp.width; - otherHeight += tmp.height; + Dimension tmp = previous.getPreferredSize(); + previousWidth = tmp.width; } - d.height = Math.max(d.height, otherHeight); d.width += Math.max(nextWidth, previousWidth); - + Insets insets = parent.getInsets(); + d.width = d.width + insets.left + insets.right; + d.height = d.height + insets.top + insets.bottom; return d; } @@ -501,11 +497,11 @@ public class BasicSpinnerUI extends SpinnerUI public void removeLayoutComponent(Component child) { if (child == editor) - editor = null; + editor = null; else if (child == next) - next = null; + next = null; else if (previous == child) - previous = null; + previous = null; } /** @@ -517,11 +513,11 @@ public class BasicSpinnerUI extends SpinnerUI public void addLayoutComponent(String name, Component child) { if ("Editor".equals(name)) - editor = child; + editor = child; else if ("Next".equals(name)) - next = child; + next = child; else if ("Previous".equals(name)) - previous = child; + previous = child; } /** @@ -531,36 +527,36 @@ public class BasicSpinnerUI extends SpinnerUI * * @return DOCUMENT ME! */ - private Dimension minSize(Component c) + private Dimension prefSize(Component c) { if (c == null) - return new Dimension(); + return new Dimension(); else - return c.getMinimumSize(); + return c.getPreferredSize(); } /** - * DOCUMENT ME! + * Sets the bounds for the specified component. * - * @param c DOCUMENT ME! - * @param x DOCUMENT ME! - * @param y DOCUMENT ME! - * @param w DOCUMENT ME! - * @param h DOCUMENT ME! + * @param c the component. + * @param x the x-coordinate for the top-left of the component bounds. + * @param y the y-coordinate for the top-left of the component bounds. + * @param w the width of the bounds. + * @param h the height of the bounds. */ private void setBounds(Component c, int x, int y, int w, int h) { if (c != null) - c.setBounds(x, y, w, h); + c.setBounds(x, y, w, h); } - /** DOCUMENT ME! */ + /** The editor component. */ private Component editor; - /** DOCUMENT ME! */ + /** The next button. */ private Component next; - /** DOCUMENT ME! */ + /** The previous button. */ private Component previous; } } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java index ff17ff084c2..06d32984efb 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -38,7 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; @@ -161,31 +160,6 @@ public class BasicSplitPaneDivider extends Container */ transient int currentDividerLocation = 1; - /** DOCUMENT ME! */ - private transient Border tmpBorder = new Border() - { - public Insets getBorderInsets(Component c) - { - return new Insets(2, 2, 2, 2); - } - - public boolean isBorderOpaque() - { - return false; - } - - public void paintBorder(Component c, Graphics g, int x, int y, - int width, int height) - { - Color saved = g.getColor(); - g.setColor(Color.BLACK); - - g.drawRect(x + 2, y + 2, width - 4, height - 4); - - g.setColor(saved); - } - }; - /** * Constructs a new divider. * @@ -196,7 +170,6 @@ public class BasicSplitPaneDivider extends Container setLayout(new DividerLayout()); setBasicSplitPaneUI(ui); setDividerSize(splitPane.getDividerSize()); - setBorder(tmpBorder); } /** @@ -212,8 +185,6 @@ public class BasicSplitPaneDivider extends Container if (splitPane != null) { splitPane.removePropertyChangeListener(this); - splitPane.removeMouseListener(mouseHandler); - splitPane.removeMouseMotionListener(mouseHandler); removeMouseListener(mouseHandler); removeMouseMotionListener(mouseHandler); splitPane = null; @@ -227,8 +198,6 @@ public class BasicSplitPaneDivider extends Container if (splitPane != null) { splitPane.addPropertyChangeListener(this); - splitPane.addMouseListener(mouseHandler); - splitPane.addMouseMotionListener(mouseHandler); addMouseListener(mouseHandler); addMouseMotionListener(mouseHandler); hiddenDivider = splitPaneUI.getNonContinuousLayoutDivider(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java index cf31e8b5df1..8a7c9d2a290 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicSplitPaneUI.java @@ -62,6 +62,7 @@ import javax.swing.LookAndFeel; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.SplitPaneUI; +import javax.swing.plaf.UIResource; /** * This is the Basic Look and Feel implementation of the SplitPaneUI class. @@ -253,20 +254,21 @@ public class BasicSplitPaneUI extends SplitPaneUI JSplitPane split = (JSplitPane) container; distributeExtraSpace(); Insets insets = split.getInsets(); - int width = getInitialLocation(insets); Dimension dims = split.getSize(); - for (int i = 0; i < components.length; i += 2) - { - if (components[i] == null) - continue; - setComponentToSize(components[i], sizes[i], width, insets, dims); - width += sizes[i]; - } - if (components[1] != null) - { - setComponentToSize(components[1], sizes[1], width, insets, dims); - width += sizes[1]; - } + int loc = getInitialLocation(insets); + int available = getAvailableSize(dims, insets); + sizes[0] = getDividerLocation(split) - loc; + sizes[1] = available - sizes[0] - sizes[2]; + // The size of the divider won't change. + + // Layout component#1. + setComponentToSize(components[0], sizes[0], loc, insets, dims); + // Layout divider. + loc += sizes[0]; + setComponentToSize(components[2], sizes[2], loc, insets, dims); + // Layout component#2. + loc += sizes[2]; + setComponentToSize(components[1], sizes[1], loc, insets, dims); } } @@ -388,6 +390,8 @@ public class BasicSplitPaneUI extends SplitPaneUI { for (int i = 0; i < components.length; i++) resetSizeAt(i); + setDividerLocation(splitPane, + getInitialLocation(splitPane.getInsets()) + sizes[0]); } /** @@ -451,21 +455,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ void distributeExtraSpace() { - int availSize = getAvailableSize(splitPane.getSize(), - splitPane.getInsets()); - int[] newSizes = new int[3]; - double weight = splitPane.getResizeWeight(); - - int oldLen = sizes[0] + sizes[1]; - - // dividers don't change size. - availSize -= sizes[2] + oldLen; - - int rightAlloc = (int) (availSize * (1 - weight)); - int leftAlloc = availSize - rightAlloc; - - sizes[0] += leftAlloc; - sizes[1] += rightAlloc; + // FIXME: This needs to be reimplemented correctly. } /** @@ -835,8 +825,6 @@ public class BasicSplitPaneUI extends SplitPaneUI if (prop <= 1 && prop >= 0) splitPane.setDividerLocation(prop); } - layoutManager.layoutContainer(splitPane); - splitPane.repaint(); // Don't have to deal with continuous_layout - only // necessary in dragging modes (and it's checked // every time you drag there) @@ -933,6 +921,8 @@ public class BasicSplitPaneUI extends SplitPaneUI /** The JSplitPane that this UI draws. */ protected JSplitPane splitPane; + private int dividerLocation; + /** * Creates a new BasicSplitPaneUI object. */ @@ -992,6 +982,7 @@ public class BasicSplitPaneUI extends SplitPaneUI "SplitPane.foreground"); LookAndFeel.installBorder(splitPane, "SplitPane.border"); divider = createDefaultDivider(); + divider.setBorder(UIManager.getBorder("SplitPaneDivider.border")); resetLayoutManager(); nonContinuousLayoutDivider = createDefaultNonContinuousLayoutDivider(); splitPane.add(divider, JSplitPane.DIVIDER); @@ -1012,8 +1003,10 @@ public class BasicSplitPaneUI extends SplitPaneUI divider = null; nonContinuousLayoutDivider = null; - splitPane.setBackground(null); - splitPane.setBorder(null); + if (splitPane.getBackground() instanceof UIResource) + splitPane.setBackground(null); + if (splitPane.getBorder() instanceof UIResource) + splitPane.setBorder(null); } /** @@ -1219,7 +1212,8 @@ public class BasicSplitPaneUI extends SplitPaneUI if (nonContinuousLayoutDivider == null) { nonContinuousLayoutDivider = new Canvas(); - nonContinuousLayoutDivider.setBackground(Color.DARK_GRAY); + Color c = UIManager.getColor("SplitPaneDivider.draggingColor"); + nonContinuousLayoutDivider.setBackground(c); } return nonContinuousLayoutDivider; } @@ -1298,44 +1292,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public void setDividerLocation(JSplitPane jc, int location) { - location = validLocation(location); - Container p = jc.getParent(); - Component right = jc.getRightComponent(); - Dimension rightPrefSize = right == null ? new Dimension(0, 0) - : right.getPreferredSize(); - Dimension size = jc.getSize(); - // check if the size has been set for the splitpane - if (size.width == 0 && size.height == 0) - size = jc.getPreferredSize(); - - if (getOrientation() == 0 && location > size.height) - { - location = size.height; - while (p != null) - { - p.setSize(p.getWidth(), p.getHeight() + rightPrefSize.height); - p = p.getParent(); - } - } - else if (location > size.width) - { - location = size.width; - while (p != null) - { - p.setSize(p.getWidth() + rightPrefSize.width, p.getHeight()); - p = p.getParent(); - } - } - - setLastDragLocation(getDividerLocation(splitPane)); - splitPane.setLastDividerLocation(getDividerLocation(splitPane)); - int[] tmpSizes = layoutManager.getSizes(); - tmpSizes[0] = location - - layoutManager.getInitialLocation(splitPane.getInsets()); - tmpSizes[1] = layoutManager.getAvailableSize(splitPane.getSize(), - splitPane.getInsets()) - - tmpSizes[0]; - layoutManager.setSizes(tmpSizes); + dividerLocation = location; splitPane.revalidate(); splitPane.repaint(); } @@ -1349,8 +1306,7 @@ public class BasicSplitPaneUI extends SplitPaneUI */ public int getDividerLocation(JSplitPane jc) { - return layoutManager.sizes[0] - + layoutManager.getInitialLocation(splitPane.getInsets()); + return dividerLocation; } /** @@ -1365,7 +1321,7 @@ public class BasicSplitPaneUI extends SplitPaneUI { int value = layoutManager.getInitialLocation(jc.getInsets()); if (layoutManager.components[0] != null) - value -= layoutManager.minimumSizeOfComponent(0); + value += layoutManager.minimumSizeOfComponent(0); return value; } @@ -1501,8 +1457,6 @@ public class BasicSplitPaneUI extends SplitPaneUI nonContinuousLayoutDivider.setVisible(true); nonContinuousLayoutDivider.setBounds(divider.getBounds()); } - splitPane.revalidate(); - splitPane.repaint(); } /** @@ -1544,11 +1498,9 @@ public class BasicSplitPaneUI extends SplitPaneUI nonContinuousLayoutDivider.setVisible(false); draggingHW = false; location = validLocation(location); - dragDividerTo(location); splitPane.setDividerLocation(location); splitPane.setLastDividerLocation(beginDragDividerLocation); beginDragDividerLocation = -1; - splitPane.repaint(); } /** diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java index a8f52cef617..5b1e1ff0f60 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -451,6 +451,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } } runCount = runs; + if (runCount > tabRuns.length) + expandTabRunsArray(); tabRuns[0] = 0; normalizeTabRuns(tabPlacement, tabCount, start, max); @@ -1025,6 +1027,8 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants } } runCount = runs; + if (runCount > tabRuns.length) + expandTabRunsArray(); padSelectedTab(tabPlacement, tabPane.getSelectedIndex()); } @@ -1733,9 +1737,6 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants int tabCount = tabPane.getTabCount(); int currRun = 1; - if (tabCount > runCount) - runCount = tabCount; - if (tabCount < 1) return; diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java index 9c8a5ef9598..1e8e39f38c2 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -39,14 +39,18 @@ exception statement from your version. */ package javax.swing.plaf.basic; import java.awt.Component; +import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.CellRendererPane; import javax.swing.JComponent; import javax.swing.LookAndFeel; +import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.event.MouseInputListener; @@ -57,62 +61,346 @@ import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; +/** + * Basic pluggable look and feel interface for JTableHeader. + */ public class BasicTableHeaderUI extends TableHeaderUI { - + /** + * The width of the space (in both direction) around the column boundary, + * where mouse cursor changes shape into "resize" + */ + static int COLUMN_BOUNDARY_TOLERANCE = 3; + public static ComponentUI createUI(JComponent h) { return new BasicTableHeaderUI(); } - + + /** + * The table header that is using this interface. + */ protected JTableHeader header; + + /** + * The mouse input listener, responsible for mouse manipulations with + * the table header. + */ protected MouseInputListener mouseInputListener; + + /** + * Paint the header cell. + */ protected CellRendererPane rendererPane; + + /** + * The header cell border. + */ protected Border cellBorder; - - public class MouseInputHandler implements MouseInputListener + + /** + * If not null, one of the columns is currently being dragged. + */ + Rectangle draggingHeaderRect; + + /** + * Handles column movement and rearrangement by mouse. The same instance works + * both as mouse listener and the mouse motion listner. + */ + public class MouseInputHandler + implements MouseInputListener { + /** + * If true, the cursor is being already shown in the alternative "resize" + * shape. + */ + boolean showingResizeCursor; + + /** + * The position, from where the cursor is dragged during resizing. Double + * purpose field (absolute value during resizing and relative offset during + * column dragging). + */ + int draggingFrom = - 1; + + /** + * The number of the column being dragged. + */ + int draggingColumnNumber; + + /** + * The previous preferred width of the column. + */ + int prevPrefWidth = - 1; + + /** + * The timer to coalesce column resizing events. + */ + Timer timer; + + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseClicked(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * If being in the resizing mode, handle resizing. + */ public void mouseDragged(MouseEvent e) { - // TODO: Implement this properly. + TableColumn resizeIt = header.getResizingColumn(); + if (resizeIt != null && header.getResizingAllowed()) + { + // The timer is intialised on demand. + if (timer == null) + { + // The purpose of timer is to coalesce events. If the queue + // is free, the repaint event is fired immediately. + timer = new Timer(1, new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + header.getTable().doLayout(); + } + }); + timer.setRepeats(false); + timer.setCoalesce(true); + } + resizeIt.setPreferredWidth(prevPrefWidth + e.getX() - draggingFrom); + timer.restart(); + } + else if (draggingHeaderRect != null && header.getReorderingAllowed()) + { + draggingHeaderRect.x = e.getX() + draggingFrom; + header.repaint(); + } } + /** + * Returns without action, part of the MouseInputListener interface. + */ public void mouseEntered(MouseEvent e) { - // TODO: Implement this properly. + // Nothing to do. } + /** + * Reset drag information of the column resizing. + */ public void mouseExited(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(null); } + /** + * Change the mouse cursor if the mouse if above the column boundary. + */ public void mouseMoved(MouseEvent e) { - // TODO: Implement this properly. + // When dragging, the functionality is handled by the mouseDragged. + if (e.getButton() == 0 && header.getResizingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to have at least one boundary. + // Otherwise, nothing to do. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int a = x - COLUMN_BOUNDARY_TOLERANCE; + int b = x + COLUMN_BOUNDARY_TOLERANCE; + + int p = 0; + + Scan: for (int i = 0; i < n - 1; i++) + { + p += model.getColumn(i).getWidth(); + + if (p >= a && p <= b) + { + TableColumn column = model.getColumn(i); + onBoundary = true; + + draggingFrom = x; + prevPrefWidth = column.getWidth(); + header.setResizingColumn(column); + break Scan; + } + } + + if (onBoundary != showingResizeCursor) + { + // Change the cursor shape, if needed. + if (onBoundary) + { + + if (p < x) + header.setCursor(Cursor.getPredefinedCursor + (Cursor.W_RESIZE_CURSOR)); + else + header.setCursor(Cursor.getPredefinedCursor + (Cursor.E_RESIZE_CURSOR)); + } + else + { + header.setCursor(Cursor.getDefaultCursor()); + header.setResizingColumn(null); + } + + showingResizeCursor = onBoundary; + } + } } + /** + * Starts the dragging/resizing procedure. + */ public void mousePressed(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingAllowed()) + { + TableColumn resizingColumn = header.getResizingColumn(); + if (resizingColumn != null) + { + resizingColumn.setPreferredWidth(resizingColumn.getWidth()); + return; + } + } + + if (header.getReorderingAllowed()) + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n < 2) + // It must be at least two columns to change the column location. + return; + + boolean onBoundary = false; + + int x = e.getX(); + int p = 0; + int col = - 1; + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col < 0) + return; + + TableColumn dragIt = model.getColumn(col); + header.setDraggedColumn(dragIt); + + draggingFrom = (p - dragIt.getWidth()) - x; + draggingHeaderRect = new Rectangle(header.getHeaderRect(col)); + draggingColumnNumber = col; + } } + /** + * Set all column preferred width to the current width to prevend abrupt + * width changes during the next resize. + */ public void mouseReleased(MouseEvent e) { - // TODO: Implement this properly. + if (header.getResizingColumn() != null && header.getResizingAllowed()) + endResizing(); + if (header.getDraggedColumn() != null && header.getReorderingAllowed()) + endDragging(e); + } + + /** + * Stop resizing session. + */ + void endResizing() + { + TableColumnModel model = header.getColumnModel(); + int n = model.getColumnCount(); + if (n > 2) + { + TableColumn c; + for (int i = 0; i < n; i++) + { + c = model.getColumn(i); + c.setPreferredWidth(c.getWidth()); + } + } + header.setResizingColumn(null); + showingResizeCursor = false; + if (timer != null) + timer.stop(); + header.setCursor(Cursor.getDefaultCursor()); } - } + /** + * Stop the dragging session. + * + * @param e the "mouse release" mouse event, needed to determing the final + * location for the dragged column. + */ + void endDragging(MouseEvent e) + { + header.setDraggedColumn(null); + + // Return if the mouse have left the header area while pressed. + if (e == null) + { + header.repaint(draggingHeaderRect); + draggingHeaderRect = null; + return; + } + else + draggingHeaderRect = null; + + TableColumnModel model = header.getColumnModel(); + + // Find where have we dragged the column. + int x = e.getX(); + int p = 0; + int col = - 1; + int n = model.getColumnCount(); + + Scan: for (int i = 0; i < n; i++) + { + p += model.getColumn(i).getWidth(); + if (p > x) + { + col = i; + break Scan; + } + } + if (col >= 0) + header.getTable().moveColumn(draggingColumnNumber, col); + } + } + + /** + * Create and return the mouse input listener. + * + * @return the mouse listener ({@link MouseInputHandler}, if not overridden. + */ protected MouseInputListener createMouseInputListener() { return new MouseInputHandler(); } - + + /** + * Construct a new BasicTableHeaderUI, create mouse listeners. + */ public BasicTableHeaderUI() { mouseInputListener = createMouseInputListener(); @@ -131,9 +419,15 @@ public class BasicTableHeaderUI extends TableHeaderUI // TODO: Implement this properly. } + /** + * Add the mouse listener and the mouse motion listener to the table + * header. The listeners support table column resizing and rearrangement + * by mouse. + */ protected void installListeners() { header.addMouseListener(mouseInputListener); + header.addMouseMotionListener(mouseInputListener); } public void installUI(JComponent c) @@ -156,10 +450,14 @@ public class BasicTableHeaderUI extends TableHeaderUI { // TODO: Implement this properly. } - + + /** + * Remove the previously installed listeners. + */ protected void uninstallListeners() { header.removeMouseListener(mouseInputListener); + header.removeMouseMotionListener(mouseInputListener); } public void uninstallUI(JComponent c) @@ -168,7 +466,10 @@ public class BasicTableHeaderUI extends TableHeaderUI uninstallKeyboardActions(); uninstallDefaults(); } - + + /** + * Repaint the table header. + */ public void paint(Graphics gfx, JComponent c) { TableColumnModel cmod = header.getColumnModel(); @@ -206,10 +507,26 @@ public class BasicTableHeaderUI extends TableHeaderUI bounds.width, bounds.height); } } - + + // This displays a running rectangle that is much simplier than the total + // animation, as it is seen in Sun's application. + // TODO animate the collumn dragging like in Sun's jre. + if (draggingHeaderRect!=null) + { + gfx.setColor(header.getForeground()); + gfx.drawRect(draggingHeaderRect.x, draggingHeaderRect.y+2, + draggingHeaderRect.width-1, draggingHeaderRect.height-6); + } } - public Dimension getPreferredSize(JComponent c) + /** + * Get the preferred header size. + * + * @param ignored unused + * + * @return the preferred size of the associated header. + */ + public Dimension getPreferredSize(JComponent ignored) { TableColumnModel cmod = header.getColumnModel(); TableCellRenderer defaultRend = header.getDefaultRenderer(); diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java index 18b69120d11..8360a9ec771 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTableUI.java @@ -58,11 +58,11 @@ import java.beans.PropertyChangeListener; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.CellRendererPane; +import javax.swing.DefaultCellEditor; import javax.swing.DefaultListSelectionModel; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JTable; -import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.LookAndFeel; @@ -74,8 +74,8 @@ 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; -import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; @@ -193,10 +193,31 @@ public class BasicTableUI extends TableUI colModel.setSelectionInterval(lo_col, hi_col); } } - - public void mouseClicked(MouseEvent e) + + /** + * For the double click, start the cell editor. + */ + public void mouseClicked(MouseEvent e) { - // TODO: What should be done here, if anything? + Point p = e.getPoint(); + int row = table.rowAtPoint(p); + int col = table.columnAtPoint(p); + if (table.isCellEditable(row, col)) + { + // If the cell editor is the default editor, we request the + // number of the required clicks from it. Otherwise, + // require two clicks (double click). + TableCellEditor editor = table.getCellEditor(row, col); + if (editor instanceof DefaultCellEditor) + { + DefaultCellEditor ce = (DefaultCellEditor) editor; + if (e.getClickCount() < ce.getClickCountToStart()) + return; + } + else if (e.getClickCount() < 2) + return; + table.editCellAt(row, col); + } } public void mouseDragged(MouseEvent e) @@ -354,7 +375,8 @@ public class BasicTableUI extends TableUI maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth(); if (maxTotalColumnWidth == 0 || table.getRowCount() == 0) return null; - return new Dimension(maxTotalColumnWidth, table.getRowCount()*table.getRowHeight()); + return new Dimension(maxTotalColumnWidth, table.getRowCount()* + (table.getRowHeight()+table.getRowMargin())); } /** @@ -380,7 +402,7 @@ public class BasicTableUI extends TableUI public Dimension getPreferredSize(JComponent comp) { int width = table.getColumnModel().getTotalColumnWidth(); - int height = table.getRowCount() * table.getRowHeight(); + int height = table.getRowCount() * (table.getRowHeight()+table.getRowMargin()); return new Dimension(width, height); } @@ -854,6 +876,10 @@ public class BasicTableUI extends TableUI rowModel.setAnchorSelectionIndex(rowLead); colModel.setAnchorSelectionIndex(colLead); } + else if (command.equals("stopEditing")) + { + table.editingStopped(new ChangeEvent(command)); + } else { // If we're here that means we bound this TableAction class @@ -1185,30 +1211,17 @@ public class BasicTableUI extends TableUI * system beginning at <code>(0,0)</code> in the upper left corner of the * table * @param rend A cell renderer to paint with - * @param data The data to provide to the cell renderer - * @param rowLead The lead selection for the rows of the table. - * @param colLead The lead selection for the columns of the table. */ void paintCell(Graphics g, int row, int col, Rectangle bounds, - TableCellRenderer rend, TableModel data, - int rowLead, int colLead) + TableCellRenderer rend) { Component comp = table.prepareRenderer(rend, row, col); rendererPane.paintComponent(g, comp, table, bounds); - - // FIXME: this is manual painting of the Caret, why doesn't the - // JTextField take care of this itself? - if (comp instanceof JTextField) - { - Rectangle oldClip = g.getClipBounds(); - g.translate(bounds.x, bounds.y); - g.clipRect(0, 0, bounds.width, bounds.height); - ((JTextField)comp).getCaret().paint(g); - g.translate(-bounds.x, -bounds.y); - g.setClip(oldClip); - } } + /** + * Paint the associated table. + */ public void paint(Graphics gfx, JComponent ignored) { int ncols = table.getColumnCount(); @@ -1217,59 +1230,72 @@ public class BasicTableUI extends TableUI return; Rectangle clip = gfx.getClipBounds(); - TableColumnModel cols = table.getColumnModel(); - - int height = table.getRowHeight(); - int x0 = 0, y0 = 0; - int x = x0; - int y = y0; - - Dimension gap = table.getIntercellSpacing(); - int ymax = clip.y + clip.height; - int xmax = clip.x + clip.width; + // Determine the range of cells that are within the clip bounds. + Point p1 = new Point(clip.x, clip.y); + int c0 = table.columnAtPoint(p1); + if (c0 == -1) + c0 = 0; + int r0 = table.rowAtPoint(p1); + if (r0 == -1) + r0 = 0; + Point p2 = new Point(clip.x + clip.width, clip.y + clip.height); + int cn = table.columnAtPoint(p2); + if (cn == -1) + cn = table.getColumnCount() - 1; + int rn = table.rowAtPoint(p2); + if (rn == -1) + rn = table.getRowCount() - 1; + + TableColumnModel cmodel = table.getColumnModel(); + int [] widths = new int[cn+1]; + for (int i = c0; i <=cn ; i++) + { + widths[i] = cmodel.getColumn(i).getWidth(); + } + + Rectangle bounds = table.getCellRect(r0, c0, false); + bounds.height = table.getRowHeight()+table.getRowMargin(); + + // The left boundary of the area being repainted. + int left = bounds.x; + + // The top boundary of the area being repainted. + int top = bounds.y; + + // The bottom boundary of the area being repainted. + int bottom; + + // The cell height. + int height = bounds.height; + // paint the cell contents - for (int c = 0; c < ncols && x < xmax; ++c) + Color grid = table.getGridColor(); + for (int r = r0; r <= rn; ++r) { - y = y0; - TableColumn col = cols.getColumn(c); - int width = col.getWidth(); - int halfGapWidth = gap.width / 2; - int halfGapHeight = gap.height / 2; - for (int r = 0; r < nrows && y < ymax; ++r) + for (int c = c0; c <= cn; ++c) { - Rectangle bounds = new Rectangle(x + halfGapWidth, - y + halfGapHeight + 1, - width - gap.width + 1, - height - gap.height); - if (bounds.intersects(clip)) - { - paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c), - table.getModel(), - table.getSelectionModel().getLeadSelectionIndex(), - table.getColumnModel().getSelectionModel().getLeadSelectionIndex()); - } - y += height; + bounds.width = widths[c]; + paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c)); + bounds.x += widths[c]; } - x += width; + bounds.y += height; + bounds.x = left; } - - // tighten up the x and y max bounds - ymax = y; - xmax = x; - - Color grid = table.getGridColor(); + + bottom = bounds.y; // paint vertical grid lines if (grid != null && table.getShowVerticalLines()) { - x = x0; Color save = gfx.getColor(); gfx.setColor(grid); - for (int c = 0; c < ncols && x < xmax; ++c) + int x = left; + + for (int c = c0; c <= cn; ++c) { - x += cols.getColumn(c).getWidth(); - gfx.drawLine(x, y0, x, ymax); + gfx.drawLine(x, top, x, bottom); + x += widths[c]; } gfx.setColor(save); } @@ -1277,13 +1303,13 @@ public class BasicTableUI extends TableUI // paint horizontal grid lines if (grid != null && table.getShowHorizontalLines()) { - y = y0; Color save = gfx.getColor(); gfx.setColor(grid); - for (int r = 0; r < nrows && y < ymax; ++r) + int y = top; + for (int r = r0; r <= rn; ++r) { + gfx.drawLine(left, y, p2.x, y); y += height; - gfx.drawLine(x0, y, xmax, y); } gfx.setColor(save); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java index fc388948419..beb1a6dfeac 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTextUI.java @@ -1,5 +1,5 @@ /* BasicTextUI.java -- - Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -46,15 +46,11 @@ import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; -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; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -70,6 +66,7 @@ import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.InputMapUIResource; import javax.swing.plaf.TextUI; import javax.swing.plaf.UIResource; +import javax.swing.text.AbstractDocument; import javax.swing.text.BadLocationException; import javax.swing.text.Caret; import javax.swing.text.DefaultCaret; @@ -82,6 +79,7 @@ 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; @@ -161,11 +159,11 @@ public abstract class BasicTextUI extends TextUI * Indicates that the preferences of one of the child view has changed. * This calls revalidate on the text component. * - * @param view the child view which's preference has changed + * @param v the child view which's preference has changed * @param width <code>true</code> if the width preference has changed * @param height <code>true</code> if the height preference has changed */ - public void preferenceChanged(View view, boolean width, boolean height) + public void preferenceChanged(View v, boolean width, boolean height) { textComponent.revalidate(); } @@ -181,7 +179,7 @@ public abstract class BasicTextUI extends TextUI view.setParent(null); if (v != null) - v.setParent(null); + v.setParent(this); view = v; } @@ -207,10 +205,10 @@ public abstract class BasicTextUI extends TextUI */ public int getViewCount() { + int count = 0; if (view != null) - return 1; - else - return 0; + count = 1; + return count; } /** @@ -249,7 +247,11 @@ public abstract class BasicTextUI extends TextUI public void paint(Graphics g, Shape s) { if (view != null) - view.paint(g, s); + { + Rectangle b = s.getBounds(); + view.setSize(b.width, b.height); + view.paint(g, s); + } } @@ -277,7 +279,7 @@ public abstract class BasicTextUI extends TextUI public Shape modelToView(int position, Shape a, Position.Bias bias) throws BadLocationException { - return ((View) view).modelToView(position, a, bias); + return view.modelToView(position, a, bias); } /** @@ -363,12 +365,44 @@ public abstract class BasicTextUI extends TextUI { return view.getNextVisualPositionFrom(pos, b, a, d, biasRet); } + + /** + * Returns the startOffset of this view, which is always the beginning + * of the document. + * + * @return the startOffset of this view + */ + public int getStartOffset() + { + return 0; + } + + /** + * Returns the endOffset of this view, which is always the end + * of the document. + * + * @return the endOffset of this view + */ + public int getEndOffset() + { + return getDocument().getLength(); + } + + /** + * Returns the document associated with this view. + * + * @return the document associated with this view + */ + public Document getDocument() + { + return textComponent.getDocument(); + } } /** * Receives notifications when properties of the text component change. */ - class PropertyChangeHandler implements PropertyChangeListener + private class PropertyChangeHandler implements PropertyChangeListener { /** * Notifies when a property of the text component changes. @@ -448,7 +482,7 @@ public abstract class BasicTextUI extends TextUI /** * Receives notification when the model changes. */ - PropertyChangeHandler updateHandler = new PropertyChangeHandler(); + private PropertyChangeHandler updateHandler = new PropertyChangeHandler(); /** The DocumentEvent handler. */ DocumentHandler documentHandler = new DocumentHandler(); @@ -515,20 +549,19 @@ public abstract class BasicTextUI extends TextUI c.setOpaque(true); textComponent = (JTextComponent) c; - Document doc = textComponent.getDocument(); if (doc == null) { - doc = getEditorKit(textComponent).createDefaultDocument(); - textComponent.setDocument(doc); + doc = getEditorKit(textComponent).createDefaultDocument(); + textComponent.setDocument(doc); } - - textComponent.addPropertyChangeListener(updateHandler); - modelChanged(); - installDefaults(); installListeners(); installKeyboardActions(); + + // We need to trigger this so that the view hierarchy gets initialized. + modelChanged(); + } /** @@ -584,6 +617,7 @@ public abstract class BasicTextUI extends TextUI protected void installListeners() { textComponent.addFocusListener(focuslistener); + textComponent.addPropertyChangeListener(updateHandler); installDocumentListeners(); } @@ -621,6 +655,11 @@ public abstract class BasicTextUI extends TextUI */ protected Keymap createKeymap() { + // FIXME: It seems to me that this method implementation is wrong. It seems + // to fetch the focusInputMap and transform it to the KeyBinding/Keymap + // implemenation. I would think that it should be done the other way, + // fetching the keybindings (from prefix + ".bindings") and transform + // it to the newer InputMap/ActionMap implementation. JTextComponent.KeyBinding[] bindings = null; String prefix = getPropertyPrefix(); InputMapUIResource m = (InputMapUIResource) UIManager.get(prefix + ".focusInputMap"); @@ -637,10 +676,7 @@ public abstract class BasicTextUI extends TextUI } } if (bindings == null) - { - bindings = new JTextComponent.KeyBinding[0]; - UIManager.put(prefix + ".focusInputMap", bindings); - } + bindings = new JTextComponent.KeyBinding[0]; Keymap km = JTextComponent.addKeymap(getKeymapName(), JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP)); @@ -726,8 +762,6 @@ public abstract class BasicTextUI extends TextUI super.uninstallUI(component); rootView.setView(null); - textComponent.removePropertyChangeListener(updateHandler); - uninstallDefaults(); uninstallListeners(); uninstallKeyboardActions(); @@ -750,6 +784,7 @@ public abstract class BasicTextUI extends TextUI */ protected void uninstallListeners() { + textComponent.removePropertyChangeListener(updateHandler); textComponent.removeFocusListener(focuslistener); textComponent.getDocument().removeDocumentListener(documentHandler); } @@ -786,7 +821,9 @@ public abstract class BasicTextUI extends TextUI float w = v.getPreferredSpan(View.X_AXIS); float h = v.getPreferredSpan(View.Y_AXIS); - return new Dimension((int) w, (int) h); + Insets i = c.getInsets(); + return new Dimension((int) w + i.left + i.right, + (int) h + i.top + i.bottom); } /** @@ -817,18 +854,49 @@ public abstract class BasicTextUI extends TextUI } /** - * Paints the text component. + * Paints the text component. This acquires a read lock on the model and then + * calls {@link #paintSafely(Graphics)} in order to actually perform the + * painting. * * @param g the <code>Graphics</code> context to paint to * @param c not used here */ public final void paint(Graphics g, JComponent c) { - paintSafely(g); + try + { + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + aDoc.readLock(); + } + + paintSafely(g); + } + finally + { + Document doc = textComponent.getDocument(); + if (doc instanceof AbstractDocument) + { + AbstractDocument aDoc = (AbstractDocument) doc; + aDoc.readUnlock(); + } + } } /** - * Actually performs the painting. + * This paints the text component while beeing sure that the model is not + * modified while painting. + * + * The following is performed in this order: + * <ol> + * <li>If the text component is opaque, the background is painted by + * calling {@link #paintBackground(Graphics)}.</li> + * <li>If there is a highlighter, the highlighter is painted.</li> + * <li>The view hierarchy is painted.</li> + * <li>The Caret is painter.</li> + * </ol> * * @param g the <code>Graphics</code> context to paint to */ @@ -840,9 +908,19 @@ public abstract class BasicTextUI extends TextUI if (textComponent.isOpaque()) paintBackground(g); - if (highlighter != null - && textComponent.getSelectionStart() != textComponent.getSelectionEnd()) - highlighter.paint(g); + // Try painting with the highlighter without checking whether there + // is a selection because a highlighter can be used to do more than + // marking selected text. + if (highlighter != null) + { + // Handle restoring of the color here to prevent + // drawing problems when the Highlighter implementor + // forgets to restore it. + Color oldColor = g.getColor(); + highlighter.paint(g); + g.setColor(oldColor); + } + rootView.paint(g, getVisibleEditorRect()); @@ -857,10 +935,23 @@ public abstract class BasicTextUI extends TextUI */ protected void paintBackground(Graphics g) { - // This method does nothing. All the background filling is done by the - // ComponentUI update method. However, the method is called by paint - // to provide a way for subclasses to draw something different (e.g. - // background images etc) on the background. + Color old = g.getColor(); + g.setColor(textComponent.getBackground()); + g.fillRect(0, 0, textComponent.getWidth(), textComponent.getHeight()); + g.setColor(old); + } + + /** + * Overridden for better control over background painting. This now simply + * calls {@link #paint} and this delegates the background painting to + * {@link #paintBackground}. + * + * @param g the graphics to use + * @param c the component to be painted + */ + public void update(Graphics g, JComponent c) + { + paint(g, c); } /** @@ -895,7 +986,84 @@ public abstract class BasicTextUI extends TextUI public void damageRange(JTextComponent t, int p0, int p1, Position.Bias firstBias, Position.Bias secondBias) { - // TODO: Implement me. + try + { + // 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.y == l2.y) + t.repaint(l1.union(l2)); + else + { + // 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); + if (posBelow < p1 && posBelow != -1 && posBelow != p0) + { + // 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 < p1 && nextPosBelow != -1 && posBelow != nextPosBelow) + { + posBelow = nextPosBelow; + nextPosBelow = Utilities.getPositionBelow(t, posBelow, l1.x); + } + // 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); + } + } + catch (BadLocationException ex) + { + AssertionError err = new AssertionError("Unexpected bad location"); + err.initCause(ex); + throw err; + } } /** @@ -1061,7 +1229,6 @@ public abstract class BasicTextUI extends TextUI */ protected Rectangle getVisibleEditorRect() { - JTextComponent textComponent = getComponent(); int width = textComponent.getWidth(); int height = textComponent.getHeight(); @@ -1082,7 +1249,6 @@ public abstract class BasicTextUI extends TextUI protected final void setView(View view) { rootView.setView(view); - view.setParent(rootView); textComponent.revalidate(); textComponent.repaint(); } diff --git a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java index f2ebcfca9ac..1c6e6c5e502 100644 --- a/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java +++ b/libjava/classpath/javax/swing/plaf/basic/BasicTreeUI.java @@ -45,6 +45,7 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; +import java.awt.Label; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -114,9 +115,18 @@ import javax.swing.tree.TreeSelectionModel; * @see javax.swing.JTree * @author Lillian Angel (langel@redhat.com) * @author Sascha Brawer (brawer@dandelis.ch) + * @author Audrius Meskauskas (audriusa@bioinformatics.org) */ public class BasicTreeUI extends TreeUI { + /** + * The tree cell editing may be started by the single mouse click on the + * selected cell. To separate it from the double mouse click, the editing + * session starts after this time (in ms) after that single click, and only + * no other clicks were performed during that time. + */ + static int WAIT_TILL_EDITING = 900; + /** Collapse Icon for the tree. */ protected transient Icon collapsedIcon; @@ -225,12 +235,6 @@ public class BasicTreeUI extends TreeUI /** Set to true if the editor has a different size than the renderer. */ protected boolean editorHasDifferentSize; - /** The action listener for the editor's Timer. */ - Timer editorTimer = new EditorUpdateTimer(); - - /** The new value of the node after editing. */ - Object newVal; - /** The action bound to KeyStrokes. */ TreeAction action; @@ -266,6 +270,20 @@ public class BasicTreeUI extends TreeUI private TreeExpansionListener treeExpansionListener; private TreeModelListener treeModelListener; + + /** + * This timer fires the editing action after about 1200 ms if not reset during + * that time. It handles the editing start with the single mouse click + * (and not the double mouse click) on the selected tree node. + */ + Timer startEditTimer; + + /** + * The special value of the mouse event is sent indicating that this is not + * just the mouse click, but the mouse click on the selected node. Sending + * such event forces to start the cell editing session. + */ + static final MouseEvent EDIT = new MouseEvent(new Label(), 7,7,7,7,7,7, false); /** * Creates a new BasicTreeUI object. @@ -303,7 +321,7 @@ public class BasicTreeUI extends TreeUI { return new BasicTreeUI(); } - + /** * Returns the Hash color. * @@ -796,7 +814,10 @@ public class BasicTreeUI extends TreeUI public boolean stopEditing(JTree tree) { if (isEditing(tree)) - completeEditing(true, false, false); + { + completeEditing(false, false, true); + finish(); + } return !isEditing(tree); } @@ -807,9 +828,12 @@ public class BasicTreeUI extends TreeUI * is the tree to cancel the editing session on. */ public void cancelEditing(JTree tree) - { - if (isEditing(tree)) - completeEditing(false, true, false); + { + // There is no need to send the cancel message to the editor, + // as the cancellation event itself arrives from it. This would + // only be necessary when cancelling the editing programatically. + completeEditing(false, false, false); + finish(); } /** @@ -1213,6 +1237,7 @@ public class BasicTreeUI extends TreeUI protected void updateCachedPreferredSize() { int maxWidth = 0; + updateCurrentVisiblePath(); boolean isLeaf = false; if (currentVisiblePath != null) { @@ -1246,7 +1271,7 @@ public class BasicTreeUI extends TreeUI protected void pathWasExpanded(TreePath path) { validCachedPreferredSize = false; - tree.repaint(); + tree.repaint(); } /** @@ -1271,7 +1296,6 @@ public class BasicTreeUI extends TreeUI leftChildIndent = UIManager.getInt("Tree.leftChildIndent"); setRowHeight(UIManager.getInt("Tree.rowHeight")); tree.setRowHeight(getRowHeight()); - tree.requestFocusInWindow(false); tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand")); setExpandedIcon(UIManager.getIcon("Tree.expandedIcon")); setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon")); @@ -1621,7 +1645,14 @@ public class BasicTreeUI extends TreeUI } if (messageTree) - treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal); + { + TreeCellEditor editor = getCellEditor(); + if (editor != null) + { + Object value = editor.getCellEditorValue(); + treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value); + } + } } /** @@ -1636,44 +1667,48 @@ public class BasicTreeUI extends TreeUI */ protected boolean startEditing(TreePath path, MouseEvent event) { - int x; - int y; - if (event == null) - { - Rectangle bounds = getPathBounds(tree, path); - x = bounds.x; - y = bounds.y; - } - else - { - x = event.getX(); - y = event.getY(); - } + // Force to recalculate the maximal row height. + maxHeight = 0; + + // Force to recalculate the cached preferred size. + validCachedPreferredSize = false; updateCellEditor(); TreeCellEditor ed = getCellEditor(); - if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event)) + + if (ed != null + && (event == EDIT || ed.shouldSelectCell(event)) + && ed.isCellEditable(event)) { + Rectangle bounds = getPathBounds(tree, path); + + // Extend the right boundary till the tree width. + bounds.width = tree.getWidth() - bounds.x; + editingPath = path; editingRow = tree.getRowForPath(editingPath); - Object val = editingPath.getLastPathComponent(); - cellEditor.addCellEditorListener(cellEditorListener); + Object value = editingPath.getLastPathComponent(); + stopEditingInCompleteEditing = false; boolean expanded = tree.isExpanded(editingPath); isEditing = true; - editingComponent = ed.getTreeCellEditorComponent(tree, val, true, + editingComponent = ed.getTreeCellEditorComponent(tree, value, true, expanded, isLeaf(editingRow), editingRow); - editingComponent.getParent().setVisible(true); - editingComponent.getParent().validate(); - tree.add(editingComponent.getParent()); - editingComponent.getParent().validate(); - validCachedPreferredSize = false; - - ((JTextField) editingComponent).requestFocusInWindow(false); - editorTimer.start(); + + // Remove all previous components (if still present). Only one + // container with the editing component inside is allowed in the tree. + tree.removeAll(); + + // The editing component must be added to its container. We add the + // container, not the editing component itself. + Component container = editingComponent.getParent(); + container.setBounds(bounds); + tree.add(container); + editingComponent.requestFocus(); + return true; } return false; @@ -1922,7 +1957,7 @@ public class BasicTreeUI extends TreeUI tree.clearSelection(); if (tree.isEditing() && !e.getActionCommand().equals("startEditing")) - tree.cancelEditing(); + tree.stopEditing(); tree.scrollPathToVisible(lead); } @@ -1957,51 +1992,7 @@ public class BasicTreeUI extends TreeUI } } - /** - * The timer that updates the editor component. - */ - private class EditorUpdateTimer extends Timer implements ActionListener - { - /** - * Creates a new EditorUpdateTimer object with a default delay of 0.3 - * seconds. - */ - public EditorUpdateTimer() - { - super(300, null); - addActionListener(this); - } - - /** - * Lets the caret blink and repaints the table. - */ - public void actionPerformed(ActionEvent ev) - { - Caret c = ((JTextField) editingComponent).getCaret(); - if (c != null) - c.setVisible(!c.isVisible()); - tree.repaint(); - } - - /** - * Updates the blink delay according to the current caret. - */ - public void update() - { - stop(); - Caret c = ((JTextField) editingComponent).getCaret(); - if (c != null) - { - setDelay(c.getBlinkRate()); - if (((JTextField) editingComponent).isEditable()) - start(); - else - c.setVisible(false); - } - } - } - - /** + /** * Updates the preferred size when scrolling, if necessary. */ public class ComponentHandler extends ComponentAdapter implements @@ -2089,29 +2080,7 @@ public class BasicTreeUI extends TreeUI */ public void editingStopped(ChangeEvent e) { - editingPath = null; - editingRow = -1; - stopEditingInCompleteEditing = false; - if (editingComponent != null) - { - tree.remove(editingComponent.getParent()); - editingComponent = null; - } - if (cellEditor != null) - { - newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText(); - completeEditing(false, false, true); - if (cellEditor instanceof DefaultTreeCellEditor) - tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); - cellEditor.removeCellEditorListener(cellEditorListener); - setCellEditor(null); - createdCellEditor = false; - } - isEditing = false; - tree.requestFocusInWindow(false); - editorTimer.stop(); - validCachedPreferredSize = false; - tree.repaint(); + stopEditing(tree); } /** @@ -2123,25 +2092,7 @@ public class BasicTreeUI extends TreeUI */ public void editingCanceled(ChangeEvent e) { - editingPath = null; - editingRow = -1; - stopEditingInCompleteEditing = false; - if (editingComponent != null) - tree.remove(editingComponent.getParent()); - editingComponent = null; - if (cellEditor != null) - { - if (cellEditor instanceof DefaultTreeCellEditor) - tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor); - cellEditor.removeCellEditorListener(cellEditorListener); - setCellEditor(null); - createdCellEditor = false; - } - tree.requestFocusInWindow(false); - editorTimer.stop(); - isEditing = false; - validCachedPreferredSize = false; - tree.repaint(); + cancelEditing(tree); } }// CellEditorHandler @@ -2261,7 +2212,15 @@ public class BasicTreeUI extends TreeUI * is the mouse event that occured */ public void mousePressed(MouseEvent e) - { + { + // Any mouse click cancels the previous waiting edit action, initiated + // by the single click on the selected node. + if (startEditTimer != null) + { + startEditTimer.stop(); + startEditTimer = null; + } + Point click = e.getPoint(); TreePath path = getClosestPathForLocation(tree, click.x, click.y); @@ -2298,9 +2257,37 @@ public class BasicTreeUI extends TreeUI { if (inBounds) { - selectPath(tree, path); - if (e.getClickCount() == 2 && !isLeaf(row)) - toggleExpandState(path); + TreePath currentLead = tree.getLeadSelectionPath(); + if ( + currentLead != null && + currentLead.equals(path) && + e.getClickCount() == 1 && + tree.isEditable() + ) + { + // Schedule the editing session. + final TreePath editPath = path; + + if (startEditTimer != null) + startEditTimer.stop(); + + startEditTimer = new Timer(WAIT_TILL_EDITING, + new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + startEditing(editPath, EDIT); + } + }); + startEditTimer.setRepeats(false); + startEditTimer.start(); + } + else + { + selectPath(tree, path); + if (e.getClickCount() == 2 && !isLeaf(row)) + toggleExpandState(path); + } } if (cntlClick) @@ -2686,7 +2673,7 @@ public class BasicTreeUI extends TreeUI public class TreeHomeAction extends AbstractAction { - /** direction is either home or end */ + /** The direction, either home or end */ protected int direction; /** @@ -2983,7 +2970,7 @@ public class BasicTreeUI extends TreeUI public void valueChanged(TreeSelectionEvent event) { if (tree.isEditing()) - tree.cancelEditing(); + tree.stopEditing(); } }// TreeSelectionHandler @@ -3650,25 +3637,14 @@ public class BasicTreeUI extends TreeUI if (row != 0) bounds.x += gap; bounds.width = preferredSize.width + bounds.x; - if (editingComponent != null && editingPath != null && isEditing(tree) - && node.equals(editingPath.getLastPathComponent())) - { - rendererPane.paintComponent(g, editingComponent.getParent(), null, - bounds); - } - else - { - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); - - Component c = dtcr.getTreeCellRendererComponent(tree, node, - selected, - isExpanded, isLeaf, - row, - tree.hasFocus()); - rendererPane.paintComponent(g, c, c.getParent(), bounds); - } + TreeCellRenderer dtcr = tree.getCellRenderer(); + if (dtcr == null) + dtcr = createDefaultCellRenderer(); + + Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, + isExpanded, isLeaf, + row, tree.hasFocus()); + rendererPane.paintComponent(g, c, c.getParent(), bounds); } } @@ -3801,4 +3777,21 @@ public class BasicTreeUI extends TreeUI } return null; } + + /** + * Finish the editing session. + */ + void finish() + { + editingPath = null; + editingRow = -1; + stopEditingInCompleteEditing = false; + isEditing = false; + tree.removeAll(); + validCachedPreferredSize = false; + + // Repaint the region, where was the editing component. + tree.repaint(editingComponent.getParent().getBounds()); + editingComponent = null; + } } // BasicTreeUI |