diff options
author | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-05-20 22:55:00 +0000 |
---|---|---|
committer | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2006-05-20 22:55:00 +0000 |
commit | 5418bfcd1dcd18878b4d0910610513c6247632ec (patch) | |
tree | c7e274af46c60dab1174c0b7dc6aedf45a5df6f6 /javax/swing | |
parent | 7eab2896e4bc891612450c50a41d99e1804fc940 (diff) | |
download | classpath-5418bfcd1dcd18878b4d0910610513c6247632ec.tar.gz |
2006-05-20 Andrew John Hughes <gnu_andrew@member.fsf.org>
* Merge of HEAD to generics for 0.91 to
2006/05/20.
Diffstat (limited to 'javax/swing')
84 files changed, 4145 insertions, 2076 deletions
diff --git a/javax/swing/AbstractButton.java b/javax/swing/AbstractButton.java index 348daece1..9b2b526f3 100644 --- a/javax/swing/AbstractButton.java +++ b/javax/swing/AbstractButton.java @@ -1,5 +1,5 @@ /* AbstractButton.java -- Provides basic button functionality. - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -274,7 +274,7 @@ public abstract class AbstractButton extends JComponent protected ChangeListener changeListener; /** - * The time in miliseconds in which clicks get coalesced into a single + * The time in milliseconds in which clicks get coalesced into a single * <code>ActionEvent</code>. */ long multiClickThreshhold; @@ -445,7 +445,7 @@ public abstract class AbstractButton extends JComponent * {@link AccessibleState#FOCUSED}, {@link AccessibleState#PRESSED} and * {@link AccessibleState#CHECKED}. * - * @return the curren state of this accessible object + * @return the current state of this accessible object */ public AccessibleStateSet getAccessibleStateSet() { @@ -651,8 +651,8 @@ public abstract class AbstractButton extends JComponent * Returns the minimum accessible value for the AccessibleAbstractButton, * which is <code>0</code>. * - * @return the maxinimum accessible value for the AccessibleAbstractButton, - * which is <code>1</code> + * @return the minimimum accessible value for the AccessibleAbstractButton, + * which is <code>0</code> */ public Number getMinimumAccessibleValue() { diff --git a/javax/swing/CellRendererPane.java b/javax/swing/CellRendererPane.java index b3d6f6a73..764a4c500 100644 --- a/javax/swing/CellRendererPane.java +++ b/javax/swing/CellRendererPane.java @@ -93,7 +93,7 @@ public class CellRendererPane extends Container implements Accessible */ public CellRendererPane() { - // Nothing to do here. + setVisible(false); } /** diff --git a/javax/swing/DefaultButtonModel.java b/javax/swing/DefaultButtonModel.java index 201ee2a8c..bc2662e65 100644 --- a/javax/swing/DefaultButtonModel.java +++ b/javax/swing/DefaultButtonModel.java @@ -1,5 +1,5 @@ /* DefaultButtonModel.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -63,7 +63,7 @@ import javax.swing.event.EventListenerList; * change to the "selected" property will trigger the firing of an ItemEvent * in addition to ChangeEvent. This is true whether the model is enabled or * not. One other state change is special: the transition from "enabled, - * armed and pressd" to "enabled, armed and not-pressed". This is considered + * armed and pressed" to "enabled, armed and not-pressed". This is considered * the "trailing edge" of a successful mouse click, and therefore fires an * ActionEvent in addition to a ChangeEvent. In all other respects this class * is just a container of boolean flags. @@ -371,7 +371,7 @@ public class DefaultButtonModel implements ButtonModel, Serializable if (e) stateMask = stateMask | ENABLED; else - stateMask = stateMask & (~ENABLED); + stateMask = stateMask & (~ENABLED) & (~ARMED) & (~PRESSED); // notify interested ChangeListeners fireStateChanged(); @@ -555,21 +555,21 @@ public class DefaultButtonModel implements ButtonModel, Serializable * one model in a given group can have their "selected" property be * <code>true</code> at a time. * - * @param g The new "group" property + * @param g The new "group" property (<code>null</code> permitted). + * + * @see #getGroup() */ public void setGroup(ButtonGroup g) { - if (group != g) - { - group = g; - fireStateChanged(); - } + group = g; } /** * Returns the current value of the model's "group" property. * * @return The value of the "group" property + * + * @see #setGroup(ButtonGroup) */ public ButtonGroup getGroup() { diff --git a/javax/swing/DefaultDesktopManager.java b/javax/swing/DefaultDesktopManager.java index 0304461ad..11f03a715 100644 --- a/javax/swing/DefaultDesktopManager.java +++ b/javax/swing/DefaultDesktopManager.java @@ -400,8 +400,8 @@ public class DefaultDesktopManager implements DesktopManager, Serializable dragCache.width, dragCache.height); pane = null; dragCache = null; + component.repaint(); } - component.repaint(); } /** @@ -463,8 +463,8 @@ public class DefaultDesktopManager implements DesktopManager, Serializable dragCache.width, dragCache.height); pane = null; dragCache = null; + component.repaint(); } - component.repaint(); } /** @@ -481,13 +481,6 @@ public class DefaultDesktopManager implements DesktopManager, Serializable int newWidth, int newHeight) { component.setBounds(newX, newY, newWidth, newHeight); - component.revalidate(); - - // If not null, I'd rather repaint the parent - if (component.getParent() != null) - component.getParent().repaint(); - else - component.repaint(); } /** diff --git a/javax/swing/JCheckBoxMenuItem.java b/javax/swing/JCheckBoxMenuItem.java index 815244259..3222d189f 100644 --- a/javax/swing/JCheckBoxMenuItem.java +++ b/javax/swing/JCheckBoxMenuItem.java @@ -1,5 +1,5 @@ /* JCheckBoxMenuItem.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -204,7 +204,7 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, /** * This method overrides JComponent.requestFocus with an empty * implementation, since JCheckBoxMenuItems should not - * receve focus in general. + * receive focus in general. */ public void requestFocus() { @@ -212,16 +212,28 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, } /** - * A string that describes this JCheckBoxMenuItem. Normally only used - * for debugging. + * Returns a string describing the attributes for the + * <code>JCheckBoxMenuItem</code> component, for use in debugging. The + * return value is guaranteed to be non-<code>null</code>, but the format + * of the string may vary between implementations. * - * @return A string describing this JCheckBoxMenuItem + * @return A string describing the attributes of the + * <code>JCheckBoxMenuItem</code>. */ protected String paramString() { - return "JCheckBoxMenuItem"; + // calling super seems to be sufficient to match the reference + // implementation here... + return super.paramString(); } + /** + * Returns the object that provides accessibility features for this + * <code>JCheckBoxMenuItem</code> component. + * + * @return The accessible context (an instance of + * {@link AccessibleJCheckBoxMenuItem}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -231,20 +243,29 @@ public class JCheckBoxMenuItem extends JMenuItem implements SwingConstants, } /** - * Accessibility support for <code>JCheckBoxMenuItem</code>. + * Provides the accessibility features for the <code>JCheckBoxMenuItem</code> + * component. + * + * @see JCheckBoxMenuItem#getAccessibleContext() */ protected class AccessibleJCheckBoxMenuItem extends AccessibleJMenuItem { private static final long serialVersionUID = 1079958073579370777L; /** - * Creates a new AccessibleJCheckBoxMenuItem object. + * Creates a new <code>AccessibleJCheckBoxMenuItem</code> instance. */ protected AccessibleJCheckBoxMenuItem() { // Nothing to do here. } + /** + * Returns the accessible role for the <code>JCheckBoxMenuItem</code> + * component. + * + * @return {@link AccessibleRole#CHECK_BOX}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.CHECK_BOX; diff --git a/javax/swing/JComboBox.java b/javax/swing/JComboBox.java index 17bcf1f99..38776f17f 100644 --- a/javax/swing/JComboBox.java +++ b/javax/swing/JComboBox.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing; -import gnu.classpath.NotImplementedException; - import java.awt.ItemSelectable; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -60,6 +58,8 @@ import javax.swing.event.ListDataListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.ComboBoxUI; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.ComboPopup; /** * A component that allows a user to select any item in its list and @@ -1246,34 +1246,102 @@ public class JComboBox extends JComponent implements ItemSelectable, // Nothing to do here. } + /** + * Returns the number of accessible children of this object. The + * implementation of AccessibleJComboBox delegates this call to the UI + * of the associated JComboBox. + * + * @return the number of accessible children of this object + * + * @see ComponentUI#getAccessibleChildrenCount(JComponent) + */ public int getAccessibleChildrenCount() - throws NotImplementedException { - return 0; + ComponentUI ui = getUI(); + int count; + if (ui != null) + count = ui.getAccessibleChildrenCount(JComboBox.this); + else + count = super.getAccessibleChildrenCount(); + return count; } - public Accessible getAccessibleChild(int value0) - throws NotImplementedException + /** + * Returns the number of accessible children of this object. The + * implementation of AccessibleJComboBox delegates this call to the UI + * of the associated JComboBox. + * + * @param index the index of the accessible child to fetch + * + * @return the number of accessible children of this object + * + * @see ComponentUI#getAccessibleChild(JComponent, int) + */ + public Accessible getAccessibleChild(int index) { - return null; + ComponentUI ui = getUI(); + Accessible child = null; + if (ui != null) + child = ui.getAccessibleChild(JComboBox.this, index); + else + child = super.getAccessibleChild(index); + return child; } + /** + * Returns the AccessibleSelection object associated with this object. + * AccessibleJComboBoxes handle their selection themselves, so this + * always returns <code>this</code>. + * + * @return the AccessibleSelection object associated with this object + */ public AccessibleSelection getAccessibleSelection() - throws NotImplementedException { - return null; + return this; } - public Accessible getAccessibleSelection(int value0) - throws NotImplementedException + /** + * Returns the accessible selection from this AccssibleJComboBox. + * + * @param index the index of the selected child to fetch + * + * @return the accessible selection from this AccssibleJComboBox + */ + public Accessible getAccessibleSelection(int index) { - return null; + // Get hold of the actual popup. + Accessible popup = getUI().getAccessibleChild(JComboBox.this, 0); + Accessible selected = null; + if (popup != null && popup instanceof ComboPopup) + { + ComboPopup cPopup = (ComboPopup) popup; + // Query the list for the currently selected child. + JList l = cPopup.getList(); + AccessibleContext listCtx = l.getAccessibleContext(); + if (listCtx != null) + { + AccessibleSelection s = listCtx.getAccessibleSelection(); + if (s != null) + { + selected = s.getAccessibleSelection(index); + } + } + } + return selected; } - public boolean isAccessibleChildSelected(int value0) - throws NotImplementedException + /** + * Returns <code>true</code> if the accessible child with the specified + * <code>index</code> is selected, <code>false</code> otherwise. + * + * @param index the index of the accessible child + * + * @return <code>true</code> if the accessible child with the specified + * <code>index</code> is selected, <code>false</code> otherwise + */ + public boolean isAccessibleChildSelected(int index) { - return false; + return getSelectedIndex() == index; } /** @@ -1286,58 +1354,121 @@ public class JComboBox extends JComponent implements ItemSelectable, return AccessibleRole.COMBO_BOX; } + /** + * Returns the accessible action associated to this accessible object. + * AccessibleJComboBox implements its own AccessibleAction, so this + * method returns <code>this</code>. + * + * @return the accessible action associated to this accessible object + */ public AccessibleAction getAccessibleAction() - throws NotImplementedException { - return null; + return this; } - public String getAccessibleActionDescription(int value0) - throws NotImplementedException + /** + * Returns the description of the specified action. AccessibleJComboBox + * implements 1 action (toggle the popup menu) and thus returns + * <code>UIManager.getString("ComboBox.togglePopupText")</code> + * + * @param actionIndex the index of the action for which to return the + * description + * + * @return the description of the specified action + */ + public String getAccessibleActionDescription(int actionIndex) { - return null; + return UIManager.getString("ComboBox.togglePopupText"); } + /** + * Returns the number of accessible actions that can be performed by + * this object. AccessibleJComboBox implement s one accessible action + * (toggle the popup menu), so this method always returns <code>1</code>. + * + * @return the number of accessible actions that can be performed by + * this object + */ public int getAccessibleActionCount() - throws NotImplementedException { - return 0; + return 1; } - public boolean doAccessibleAction(int value0) - throws NotImplementedException + /** + * Performs the accessible action with the specified index. + * AccessibleJComboBox has 1 accessible action + * (<code>actionIndex == 0</code>), which is to toggle the + * popup menu. All other action indices have no effect and return + * <code<>false</code>. + * + * @param actionIndex the index of the action to perform + * + * @return <code>true</code> if the action has been performed, + * <code>false</code> otherwise + */ + public boolean doAccessibleAction(int actionIndex) { - return false; + boolean actionPerformed = false; + if (actionIndex == 0) + { + setPopupVisible(! isPopupVisible()); + actionPerformed = true; + } + return actionPerformed; } + /** + * Returns the number of selected accessible children of this object. This + * returns <code>1</code> if the combobox has a selected entry, + * <code>0</code> otherwise. + * + * @return the number of selected accessible children of this object + */ public int getAccessibleSelectionCount() - throws NotImplementedException { - return 0; + Object sel = getSelectedItem(); + int count = 0; + if (sel != null) + count = 1; + return count; } - public void addAccessibleSelection(int value0) - throws NotImplementedException + /** + * Sets the current selection to the specified <code>index</code>. + * + * @param index the index to set as selection + */ + public void addAccessibleSelection(int index) { - // TODO: Implement this properly. + setSelectedIndex(index); } - public void removeAccessibleSelection(int value0) - throws NotImplementedException + /** + * Removes the specified index from the current selection. + * + * @param index the index to remove from the selection + */ + public void removeAccessibleSelection(int index) { - // TODO: Implement this properly. + if (getSelectedIndex() == index) + clearAccessibleSelection(); } + /** + * Clears the current selection. + */ public void clearAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + setSelectedIndex(-1); } + /** + * Multiple selection is not supported by AccessibleJComboBox, so this + * does nothing. + */ public void selectAllAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // Nothing to do here. } } } diff --git a/javax/swing/JComponent.java b/javax/swing/JComponent.java index ba3712b88..dbbad5c21 100644 --- a/javax/swing/JComponent.java +++ b/javax/swing/JComponent.java @@ -760,13 +760,6 @@ public abstract class JComponent extends Container implements Serializable public static final int WHEN_IN_FOCUSED_WINDOW = 2; /** - * Indicates if this component is completely dirty or not. This is used - * by the RepaintManager's - * {@link RepaintManager#isCompletelyDirty(JComponent)} method. - */ - boolean isCompletelyDirty = false; - - /** * Indicates if the opaque property has been set by a client program or by * the UI. * @@ -1763,11 +1756,6 @@ public abstract class JComponent extends Container implements Serializable paintComponent(g2); paintBorder(g2); paintChildren(g2); - Rectangle clip = g2.getClipBounds(); - if (clip == null - || (clip.x == 0 && clip.y == 0 && clip.width == getWidth() - && clip.height == getHeight())) - RepaintManager.currentManager(this).markCompletelyClean(this); } } } @@ -3554,6 +3542,7 @@ public abstract class JComponent extends Container implements Serializable Rectangle currentClip = clip; Component found = this; Container parent = this; + while (parent != null && !(parent instanceof Window)) { Container newParent = parent.getParent(); @@ -3569,15 +3558,42 @@ public abstract class JComponent extends Container implements Serializable parent = newParent; continue; } - // If the parent is not optimizedDrawingEnabled, we must paint the - // parent. + + // If the parent is not optimizedDrawingEnabled, we must check if the + // parent or some neighbor overlaps the current clip. + + // This is the current clip converted to the parent's coordinate + // system. TODO: We can do this more efficiently by succesively + // cumulating the parent-child translations. Rectangle target = SwingUtilities.convertRectangle(found, currentClip, newParent); - found = newParent; - currentClip = target; + + // We have an overlap if either: + // - The new parent itself doesn't completely cover the clip + // (this can be the case with viewports). + // - If some higher-level (than the current) children of the new parent + // intersect the target rectangle. + Rectangle parentRect = SwingUtilities.getLocalBounds(newParent); + boolean haveOverlap = + ! SwingUtilities.isRectangleContainingRectangle(parentRect, target); + if (! haveOverlap) + { + Component[] children = newParent.getComponents(); + for (int i = 0; children[i] != parent && !haveOverlap; i++) + { + Rectangle childRect = children[i].getBounds(); + haveOverlap = target.intersects(childRect); + } + } + if (haveOverlap) + { + found = newParent; + currentClip = target; + } parent = newParent; } + //System.err.println("overlapfree parent: " + found); return found; } diff --git a/javax/swing/JFileChooser.java b/javax/swing/JFileChooser.java index 7da3a132d..64f9bd0f4 100644 --- a/javax/swing/JFileChooser.java +++ b/javax/swing/JFileChooser.java @@ -1,5 +1,5 @@ /* JFileChooser.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,10 +37,9 @@ exception statement from your version. */ package javax.swing; -import gnu.classpath.NotImplementedException; - import java.awt.Component; import java.awt.Frame; +import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -389,6 +388,13 @@ public class JFileChooser extends JComponent implements Accessible * @see #setSelectedFile(File) */ private File selectedFile; + + /** + * The drag enabled property. + * @see #setDragEnabled(boolean) + * @see #getDragEnabled() + */ + private boolean dragEnabled; /** * Creates a new <code>JFileChooser</code> object. @@ -487,26 +493,31 @@ public class JFileChooser extends JComponent implements Accessible } /** - * DOCUMENT ME! - * - * @param b DOCUMENT ME! + * Sets the dragEnabled property, this disables/enables automatic drag + * handling (drag and drop) on this component. The default value of the + * dragEnabled property is false. + * + * Some look and feels might not support automatic drag and drop; they + * will ignore this property. + * + * @param b - the new dragEnabled value */ public void setDragEnabled(boolean b) - throws NotImplementedException { - // FIXME: Implement + if (b && GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + dragEnabled = b; } /** - * DOCUMENT ME! + * Returns true if dragging is enabled. * - * @return DOCUMENT ME! + * @return true if dragging is enabled. */ public boolean getDragEnabled() - throws NotImplementedException { - // FIXME: Implement - return false; + return dragEnabled; } /** @@ -1514,19 +1525,60 @@ public class JFileChooser extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns a string describing the attributes for the + * <code>JFileChooser</code> component, for use in debugging. The return + * value is guaranteed to be non-<code>null</code>, but the format of the + * string may vary between implementations. * - * @return DOCUMENT ME! + * @return A string describing the attributes of the + * <code>JFileChooser</code>. */ protected String paramString() { - return "JFileChooser"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",approveButtonText="); + if (approveButtonText != null) + sb.append(approveButtonText); + sb.append(",currentDirectory="); + if (currentDir != null) + sb.append(currentDir); + sb.append(",dialogTitle="); + if (dialogTitle != null) + sb.append(dialogTitle); + sb.append(",dialogType="); + if (dialogType == OPEN_DIALOG) + sb.append("OPEN_DIALOG"); + if (dialogType == SAVE_DIALOG) + sb.append("SAVE_DIALOG"); + if (dialogType == CUSTOM_DIALOG) + sb.append("CUSTOM_DIALOG"); + sb.append(",fileSelectionMode="); + if (fileSelectionMode == FILES_ONLY) + sb.append("FILES_ONLY"); + if (fileSelectionMode == DIRECTORIES_ONLY) + sb.append("DIRECTORIES_ONLY"); + if (fileSelectionMode == FILES_AND_DIRECTORIES) + sb.append("FILES_AND_DIRECTORIES"); + sb.append(",returnValue="); + if (retval == APPROVE_OPTION) + sb.append("APPROVE_OPTION"); + if (retval == CANCEL_OPTION) + sb.append("CANCEL_OPTION"); + if (retval == ERROR_OPTION) + sb.append("ERROR_OPTION"); + sb.append(",selectedFile="); + if (selectedFile != null) + sb.append(selectedFile); + sb.append(",useFileHiding=").append(fileHiding); + return sb.toString(); } /** - * Returns the accessible context. + * Returns the object that provides accessibility features for this + * <code>JFileChooser</code> component. * - * @return The accessible context. + * @return The accessible context (an instance of + * {@link AccessibleJFileChooser}). */ public AccessibleContext getAccessibleContext() { @@ -1536,16 +1588,26 @@ public class JFileChooser extends JComponent implements Accessible } /** - * Accessibility support for JFileChooser + * Provides the accessibility features for the <code>JFileChooser</code> + * component. */ protected class AccessibleJFileChooser extends JComponent.AccessibleJComponent { + /** + * Creates a new instance of <code>AccessibleJFileChooser</code>. + */ protected AccessibleJFileChooser() { // Nothing to do here. } + /** + * Returns the accessible role for the <code>JFileChooser</code> + * component. + * + * @return {@link AccessibleRole#FILE_CHOOSER}. + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.FILE_CHOOSER; diff --git a/javax/swing/JFrame.java b/javax/swing/JFrame.java index d25120560..11b9c1fd3 100644 --- a/javax/swing/JFrame.java +++ b/javax/swing/JFrame.java @@ -1,5 +1,5 @@ /* JFrame.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -86,6 +86,8 @@ public class JFrame extends Frame /** * A flag for {@link #setDefaultCloseOperation(int)}, indicating that the * application should be exited, when this <code>JFrame</code> is closed. + * Note that in version 1.4, the equivalent constant has been added to + * {@link WindowConstants}. * * @since 1.3 */ @@ -93,7 +95,7 @@ public class JFrame extends Frame private static final long serialVersionUID = -3362141868504252139L; private static boolean defaultLookAndFeelDecorated; - private int close_action = HIDE_ON_CLOSE; + private int closeAction = HIDE_ON_CLOSE; protected AccessibleContext accessibleContext; protected JRootPane rootPane; @@ -102,12 +104,20 @@ public class JFrame extends Frame */ protected boolean rootPaneCheckingEnabled = false; + /** + * Creates a new frame with an empty string for the title. + */ public JFrame() { - super("JFrame"); + super(""); frameInit(); } + /** + * Creates a new <code>JFrame</code> with the specified title. + * + * @param title the frame title (<code>null</code> permitted). + */ public JFrame(String title) { super(title); @@ -289,6 +299,12 @@ public class JFrame extends Frame return defaultLookAndFeelDecorated; } + /** + * Returns the object that provides accessibility features for this + * <code>JFrame</code>. + * + * @return The accessible context (an instance of {@link AccessibleJFrame}). + */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) @@ -296,14 +312,39 @@ public class JFrame extends Frame return accessibleContext; } + /** + * Returns a code for the default operation when the frame is closed. The + * default value is {@link WindowConstants#HIDE_ON_CLOSE}. + * + * @return One of: {@link WindowConstants#DO_NOTHING_ON_CLOSE}, + * {@link WindowConstants#HIDE_ON_CLOSE}, + * {@link WindowConstants#DISPOSE_ON_CLOSE}, {@link #EXIT_ON_CLOSE}. + * + * @see #setDefaultCloseOperation(int) + */ public int getDefaultCloseOperation() { - return close_action; + return closeAction; } + /** + * Returns a string describing the attributes for the <code>JFrame</code>, + * for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format may vary between implementations. + * + * @return A string describing the attributes of the <code>JFrame</code>. + */ protected String paramString() { - return "JFrame"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",defaultCloseOperation="); + sb.append(SwingUtilities.convertWindowConstantToString( + getDefaultCloseOperation())); + sb.append(",rootPane="); + if (rootPane != null) + sb.append(rootPane); + sb.append(",rootPaneCheckingEnabled=").append(rootPaneCheckingEnabled); + return sb.toString(); } protected void processWindowEvent(WindowEvent e) @@ -313,7 +354,7 @@ public class JFrame extends Frame { case WindowEvent.WINDOW_CLOSING: { - switch (close_action) + switch (closeAction) { case EXIT_ON_CLOSE: { @@ -346,17 +387,22 @@ public class JFrame extends Frame } /** - * Defines what happens when this frame is closed. Can be one off - * <code>EXIT_ON_CLOSE</code>, - * <code>DISPOSE_ON_CLOSE</code>, - * <code>HIDE_ON_CLOSE</code> or - * <code>DO_NOTHING_ON_CLOSE</code>. - * The default is <code>HIDE_ON_CLOSE</code>. - * When <code>EXIT_ON_CLOSE</code> is specified this method calls + * Sets the default operation that is performed when this frame is closed. + * The default is <code>HIDE_ON_CLOSE</code>. When + * <code>EXIT_ON_CLOSE</code> is specified this method calls * <code>SecurityManager.checkExit(0)</code> which might throw a - * <code>SecurityException</code>. When the specified operation is - * not one of the above a <code>IllegalArgumentException</code> is - * thrown. + * <code>SecurityException</code>. + * + * @param operation a code for the operation (one of: + * {@link WindowConstants#DO_NOTHING_ON_CLOSE}, + * {@link WindowConstants#HIDE_ON_CLOSE}, + * {@link WindowConstants#DISPOSE_ON_CLOSE} and + * {@link WindowConstants#EXIT_ON_CLOSE}). + * + * @throws IllegalArgumentException if <code>operation</code> is not one of + * the specified codes. + * + * @see #getDefaultCloseOperation() */ public void setDefaultCloseOperation(int operation) { @@ -366,8 +412,9 @@ public class JFrame extends Frame if (operation != EXIT_ON_CLOSE && operation != DISPOSE_ON_CLOSE && operation != HIDE_ON_CLOSE && operation != DO_NOTHING_ON_CLOSE) - throw new IllegalArgumentException("defaultCloseOperation must be EXIT_ON_CLOSE, HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or DO_NOTHING_ON_CLOSE"); + throw new IllegalArgumentException("operation must be EXIT_ON_CLOSE, " + + "HIDE_ON_CLOSE, DISPOSE_ON_CLOSE, or DO_NOTHING_ON_CLOSE"); - close_action = operation; + closeAction = operation; } } diff --git a/javax/swing/JLabel.java b/javax/swing/JLabel.java index a993fb8f3..a2dbb3251 100644 --- a/javax/swing/JLabel.java +++ b/javax/swing/JLabel.java @@ -1,5 +1,5 @@ /* JLabel.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -297,7 +297,6 @@ public class JLabel extends JComponent implements Accessible, SwingConstants } } - /** DOCUMENT ME! */ private static final long serialVersionUID = 5496508283662221534L; static final String LABEL_PROPERTY = "labeledBy"; @@ -452,14 +451,42 @@ public class JLabel extends JComponent implements Accessible, SwingConstants } /** - * This method is used primarily for debugging purposes and returns a string - * that can be used to represent this label. + * Returns a string describing the attributes for the <code>JLabel</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. * - * @return A string to represent this label. + * @return A string describing the attributes of the <code>JLabel</code>. */ protected String paramString() { - return super.paramString(); + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",defaultIcon="); + if (icon != null) + sb.append(icon); + sb.append(",disabledIcon="); + if (disabledIcon != null) + sb.append(disabledIcon); + sb.append(",horizontalAlignment="); + sb.append(SwingUtilities.convertHorizontalAlignmentCodeToString( + horizontalAlignment)); + sb.append(",horizontalTextPosition="); + sb.append(SwingUtilities.convertHorizontalAlignmentCodeToString( + horizontalTextPosition)); + sb.append(",iconTextGap=").append(iconTextGap); + sb.append(",labelFor="); + if (labelFor != null) + sb.append(labelFor); + sb.append(",text="); + if (text != null) + sb.append(text); + sb.append(",verticalAlignment="); + sb.append(SwingUtilities.convertVerticalAlignmentCodeToString( + verticalAlignment)); + sb.append(",verticalTextPosition="); + sb.append(SwingUtilities.convertVerticalAlignmentCodeToString( + verticalTextPosition)); + return sb.toString(); } /** @@ -902,9 +929,10 @@ public class JLabel extends JComponent implements Accessible, SwingConstants } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JLabel</code> component. * - * @return The accessible context. + * @return The accessible context (an instance of {@link AccessibleJLabel}). */ public AccessibleContext getAccessibleContext() { diff --git a/javax/swing/JList.java b/javax/swing/JList.java index 13ca094bb..1710541f4 100644 --- a/javax/swing/JList.java +++ b/javax/swing/JList.java @@ -1475,19 +1475,18 @@ public class JList extends JComponent implements Accessible, Scrollable } /** - * Returns all the values in the list's {@link #model} property which - * are selected, according to the list's {@link #selectionModel} property. - * + * Returns all the values in the list's {@link #model} property which are + * selected, according to the list's {@link #selectionModel} property. + * * @return An array containing all the selected values - * * @see #setSelectedValue */ public Object[] getSelectedValues() { - int [] idx = getSelectedIndices(); - Object [] v = new Object[idx.length]; + int[] idx = getSelectedIndices(); + Object[] v = new Object[idx.length]; for (int i = 0; i < idx.length; ++i) - v[i] = getModel().getElementAt(i); + v[i] = getModel().getElementAt(idx[i]); return v; } diff --git a/javax/swing/JMenu.java b/javax/swing/JMenu.java index 37ed14854..02cb20eab 100644 --- a/javax/swing/JMenu.java +++ b/javax/swing/JMenu.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing; -import gnu.classpath.NotImplementedException; - import java.awt.Component; import java.awt.Point; import java.awt.event.KeyEvent; @@ -48,6 +46,7 @@ import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Serializable; +import java.util.ArrayList; import java.util.EventListener; import javax.accessibility.Accessible; @@ -811,7 +810,9 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement return accessibleContext; } - // FIXME: This inner class is a complete stub and needs to be implemented. + /** + * Implements support for assisitive technologies for <code>JMenu</code>. + */ protected class AccessibleJMenu extends AccessibleJMenuItem implements AccessibleSelection { @@ -822,69 +823,245 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement // Nothing to do here. } + /** + * Returns the number of accessible children of this object. + * + * @return the number of accessible children of this object + */ public int getAccessibleChildrenCount() - throws NotImplementedException { - return 0; + Component[] children = getMenuComponents(); + int count = 0; + for (int i = 0; i < children.length; i++) + { + if (children[i] instanceof Accessible) + count++; + } + return count; } - public Accessible getAccessibleChild(int value0) - throws NotImplementedException + /** + * Returns the accessible child with the specified <code>index</code>. + * + * @param index the index of the child to fetch + * + * @return the accessible child with the specified <code>index</code> + */ + public Accessible getAccessibleChild(int index) { - return null; + Component[] children = getMenuComponents(); + int count = 0; + Accessible found = null; + for (int i = 0; i < children.length; i++) + { + if (children[i] instanceof Accessible) + { + if (count == index) + { + found = (Accessible) children[i]; + break; + } + count++; + } + } + return found; } + /** + * Returns the accessible selection of this object. AccessibleJMenus handle + * their selection themselves, so we always return <code>this</code> here. + * + * @return the accessible selection of this object + */ public AccessibleSelection getAccessibleSelection() - throws NotImplementedException { - return null; + return this; } - public Accessible getAccessibleSelection(int value0) - throws NotImplementedException + /** + * Returns the selected accessible child with the specified + * <code>index</code>. + * + * @param index the index of the accessible selected child to return + * + * @return the selected accessible child with the specified + * <code>index</code> + */ + public Accessible getAccessibleSelection(int index) { - return null; + Accessible selected = null; + // Only one item can be selected, which must therefore have index == 0. + if (index == 0) + { + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] me = msm.getSelectedPath(); + if (me != null) + { + for (int i = 0; i < me.length; i++) + { + if (me[i] == JMenu.this) + { + // This JMenu is selected, find and return the next + // JMenuItem in the path. + do + { + if (me[i] instanceof Accessible) + { + selected = (Accessible) me[i]; + break; + } + i++; + } while (i < me.length); + } + if (selected != null) + break; + } + } + } + return selected; } - public boolean isAccessibleChildSelected(int value0) - throws NotImplementedException + /** + * Returns <code>true</code> if the accessible child with the specified + * index is selected, <code>false</code> otherwise. + * + * @param index the index of the accessible child to check + * + * @return <code>true</code> if the accessible child with the specified + * index is selected, <code>false</code> otherwise + */ + public boolean isAccessibleChildSelected(int index) { - return false; + boolean selected = false; + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] me = msm.getSelectedPath(); + if (me != null) + { + Accessible toBeFound = getAccessibleChild(index); + for (int i = 0; i < me.length; i++) + { + if (me[i] == toBeFound) + { + selected = true; + break; + } + } + } + return selected; } + /** + * Returns the accessible role of this object, which is + * {@link AccessibleRole#MENU} for the AccessibleJMenu. + * + * @return the accessible role of this object + */ public AccessibleRole getAccessibleRole() { return AccessibleRole.MENU; } + /** + * Returns the number of selected accessible children. This will be + * <code>0</code> if no item is selected, or <code>1</code> if an item + * is selected. AccessibleJMenu can have maximum 1 selected item. + * + * @return the number of selected accessible children + */ public int getAccessibleSelectionCount() - throws NotImplementedException { - return 0; + int count = 0; + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] me = msm.getSelectedPath(); + if (me != null) + { + for (int i = 0; i < me.length; i++) + { + if (me[i] == JMenu.this) + { + if (i + 1 < me.length) + { + count = 1; + break; + } + } + } + } + return count; } - public void addAccessibleSelection(int value0) - throws NotImplementedException + /** + * Selects the accessible child with the specified index. + * + * @param index the index of the accessible child to select + */ + public void addAccessibleSelection(int index) { - // TODO: Implement this properly. + Accessible child = getAccessibleChild(index); + if (child != null && child instanceof JMenuItem) + { + JMenuItem mi = (JMenuItem) child; + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + msm.setSelectedPath(createPath(JMenu.this)); + } } - public void removeAccessibleSelection(int value0) - throws NotImplementedException + /** + * Removes the item with the specified index from the selection. + * + * @param index the index of the selected item to remove from the selection + */ + public void removeAccessibleSelection(int index) { - // TODO: Implement this properly. + Accessible child = getAccessibleChild(index); + if (child != null) + { + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] oldSelection = msm.getSelectedPath(); + for (int i = 0; i < oldSelection.length; i++) + { + if (oldSelection[i] == child) + { + // Found the specified child in the selection. Remove it + // from the selection. + MenuElement[] newSel = new MenuElement[i - 1]; + System.arraycopy(oldSelection, 0, newSel, 0, i - 1); + msm.setSelectedPath(newSel); + break; + } + } + } } + /** + * Removes all possibly selected accessible children of this object from + * the selection. + */ public void clearAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + MenuSelectionManager msm = MenuSelectionManager.defaultManager(); + MenuElement[] oldSelection = msm.getSelectedPath(); + for (int i = 0; i < oldSelection.length; i++) + { + if (oldSelection[i] == JMenu.this) + { + // Found this menu in the selection. Remove all children from + // the selection. + MenuElement[] newSel = new MenuElement[i]; + System.arraycopy(oldSelection, 0, newSel, 0, i); + msm.setSelectedPath(newSel); + break; + } + } } + /** + * AccessibleJMenu don't support multiple selection, so this method + * does nothing. + */ public void selectAllAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // Nothing to do here. } } @@ -939,4 +1116,44 @@ public class JMenu extends JMenuItem implements Accessible, MenuElement } } + /** + * Creates an array to be feeded as argument to + * {@link MenuSelectionManager#setSelectedPath(MenuElement[])} for the + * specified element. This has the effect of selecting the specified element + * and all its parents. + * + * @param leaf the leaf element for which to create the selected path + * + * @return the selected path array + */ + MenuElement[] createPath(JMenu leaf) + { + ArrayList path = new ArrayList(); + MenuElement[] array = null; + Component current = leaf.getPopupMenu(); + while (true) + { + if (current instanceof JPopupMenu) + { + JPopupMenu popupMenu = (JPopupMenu) current; + path.add(0, popupMenu); + current = popupMenu.getInvoker(); + } + else if (current instanceof JMenu) + { + JMenu menu = (JMenu) current; + path.add(0, menu); + current = menu.getParent(); + } + else if (current instanceof JMenuBar) + { + JMenuBar menuBar = (JMenuBar) current; + path.add(0, menuBar); + array = new MenuElement[path.size()]; + array = (MenuElement[]) path.toArray(array); + break; + } + } + return array; + } } diff --git a/javax/swing/JMenuItem.java b/javax/swing/JMenuItem.java index 272c1cfe6..f04008bcd 100644 --- a/javax/swing/JMenuItem.java +++ b/javax/swing/JMenuItem.java @@ -673,7 +673,7 @@ public class JMenuItem extends AbstractButton implements Accessible, } /** - * Returns a string describing the attributes for the <code>JToolTip</code> + * Returns a string describing the attributes for the <code>JMenuItem</code> * component, for use in debugging. The return value is guaranteed to be * non-<code>null</code>, but the format of the string may vary between * implementations. diff --git a/javax/swing/JOptionPane.java b/javax/swing/JOptionPane.java index 0bef12b61..f94905538 100644 --- a/javax/swing/JOptionPane.java +++ b/javax/swing/JOptionPane.java @@ -1,5 +1,5 @@ /* JOptionPane.java - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,14 +38,20 @@ exception statement from your version. */ package javax.swing; +import java.awt.AWTEvent; +import java.awt.ActiveEvent; import java.awt.Component; +import java.awt.Container; +import java.awt.EventQueue; import java.awt.Frame; +import java.awt.MenuComponent; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseMotionAdapter; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; -import javax.swing.event.InternalFrameAdapter; -import javax.swing.event.InternalFrameEvent; import javax.swing.plaf.OptionPaneUI; /** @@ -57,17 +63,15 @@ import javax.swing.plaf.OptionPaneUI; public class JOptionPane extends JComponent implements Accessible { /** - * DOCUMENT ME! + * Provides the accessibility features for the <code>JOptionPane</code> + * component. */ - // FIXME: This inner class is a complete stub and needs to be implemented - // properly. protected class AccessibleJOptionPane extends JComponent.AccessibleJComponent { - /** DOCUMENT ME! */ private static final long serialVersionUID = 686071432213084821L; /** - * Creates a new AccessibleJOptionPane object. + * Creates a new <code>AccessibleJOptionPane</code> instance. */ protected AccessibleJOptionPane() { @@ -86,7 +90,6 @@ public class JOptionPane extends JComponent implements Accessible } } - /** DOCUMENT ME! */ private static final long serialVersionUID = 5231143276678566796L; /** The value returned when cancel option is selected. */ @@ -431,9 +434,11 @@ public class JOptionPane extends JComponent implements Accessible } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JOptionPane</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJOptionPane}). */ public AccessibleContext getAccessibleContext() { @@ -1529,31 +1534,64 @@ public class JOptionPane extends JComponent implements Accessible */ private static void startModal(JInternalFrame f) { - synchronized (f) - { - final JInternalFrame tmp = f; - tmp.toFront(); - - f.addInternalFrameListener(new InternalFrameAdapter() - { - public void internalFrameClosed(InternalFrameEvent e) - { - synchronized (tmp) - { - tmp.removeInternalFrameListener(this); - tmp.notifyAll(); - } - } - }); - try - { - while (! f.isClosed()) - f.wait(); - } - catch (InterruptedException ignored) - { - // Ignore this Exception. - } - } + // We need to add an additional glasspane-like component directly + // below the frame, which intercepts all mouse events that are not + // directed at the frame itself. + JPanel modalInterceptor = new JPanel(); + modalInterceptor.setOpaque(false); + JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f); + lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue()); + modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight()); + modalInterceptor.addMouseListener(new MouseAdapter(){}); + modalInterceptor.addMouseMotionListener(new MouseMotionAdapter(){}); + lp.add(modalInterceptor); + f.toFront(); + + // We need to explicitly dispatch events when we are blocking the event + // dispatch thread. + EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); + try + { + while (! f.isClosed()) + { + if (EventQueue.isDispatchThread()) + { + // The getNextEventMethod() issues wait() when no + // event is available, so we don't need do explicitly wait(). + AWTEvent ev = queue.getNextEvent(); + // This mimics EventQueue.dispatchEvent(). We can't use + // EventQueue.dispatchEvent() directly, because it is + // protected, unfortunately. + if (ev instanceof ActiveEvent) + ((ActiveEvent) ev).dispatch(); + else if (ev.getSource() instanceof Component) + ((Component) ev.getSource()).dispatchEvent(ev); + else if (ev.getSource() instanceof MenuComponent) + ((MenuComponent) ev.getSource()).dispatchEvent(ev); + // Other events are ignored as per spec in + // EventQueue.dispatchEvent + } + else + { + // Give other threads a chance to become active. + Thread.yield(); + } + } + } + catch (InterruptedException ex) + { + // If we get interrupted, then leave the modal state. + } + finally + { + // Clean up the modal interceptor. + lp.remove(modalInterceptor); + + // Remove the internal frame from its parent, so it is no longer + // lurking around and clogging memory. + Container parent = f.getParent(); + if (parent != null) + parent.remove(f); + } } } diff --git a/javax/swing/JPopupMenu.java b/javax/swing/JPopupMenu.java index a54bd777f..c7890ea0e 100644 --- a/javax/swing/JPopupMenu.java +++ b/javax/swing/JPopupMenu.java @@ -52,6 +52,7 @@ import java.util.EventListener; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; +import javax.swing.event.MenuKeyListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.plaf.PopupMenuUI; @@ -410,6 +411,36 @@ public class JPopupMenu extends JComponent implements Accessible, MenuElement } /** + * Adds a MenuKeyListener to the popup. + * + * @param l - the listener to add. + */ + public void addMenuKeyListener(MenuKeyListener l) + { + listenerList.add(MenuKeyListener.class, l); + } + + /** + * Removes a MenuKeyListener from the popup. + * + * @param l - the listener to remove. + */ + public void removeMenuKeyListener(MenuKeyListener l) + { + listenerList.remove(MenuKeyListener.class, l); + } + + /** + * Returns array of getMenuKeyListeners that are listening to JPopupMenu. + * + * @return array of getMenuKeyListeners that are listening to JPopupMenu + */ + public MenuKeyListener[] getMenuKeyListeners() + { + return ((MenuKeyListener[]) listenerList.getListeners(MenuKeyListener.class)); + } + + /** * Adds popupMenuListener to listen for PopupMenuEvents fired * by the JPopupMenu * diff --git a/javax/swing/JProgressBar.java b/javax/swing/JProgressBar.java index db936f64a..ed2d0088d 100644 --- a/javax/swing/JProgressBar.java +++ b/javax/swing/JProgressBar.java @@ -53,15 +53,14 @@ import javax.swing.event.ChangeListener; import javax.swing.plaf.ProgressBarUI; /** - * The ProgressBar is a widget that displays in two modes. In - * determinate mode, it displays fills a percentage of its bar - * based on its current value. In indeterminate mode, it creates - * box and bounces it between its bounds. - * + * A component that displays a visual indicator of the progress of a task. The + * component has two modes: determinate and indeterminate. In determinate mode, + * the <code>JProgressBar</code> fills a percentage of its bar based on its + * current value. In indeterminate mode, it creates box and bounces it between + * its bounds. * <p> - * JProgressBars have the following properties: + * This component has the following properties: * </p> - * * <table> * <tr><th> Property </th><th> Stored in </th><th> Bound? </th></tr> * <tr><td> borderPainted </td><td> progressBar </td><td> yes </td></tr> @@ -193,33 +192,67 @@ public class JProgressBar extends JComponent implements SwingConstants, private static final long serialVersionUID = 1980046021813598781L; - /** Whether the ProgressBar is determinate. */ + /** + * A flag that determines the mode (<code>true</code> for indeterminate, + * <code>false</code> for determinate). + */ private transient boolean indeterminate = false; - /** The orientation of the ProgressBar. Always set by constructor. */ + /** + * The orientation of the <code>JProgressBar</code> + * ({@link SwingConstants#HORIZONTAL} or {@link SwingConstants#VERTICAL}). + * Defaults to {@link SwingConstants#HORIZONTAL}. + * @see #setOrientation(int) + */ protected int orientation; - /** Whether borders should be painted. */ + /** + * A flag the controls whether or not the component's border is painted. + * The default is <code>true</code>. + * @see #setBorderPainted(boolean) + */ protected boolean paintBorder = true; - /** The model describing this ProgressBar. */ + /** + * The model defining the bounds and current value for the progress bar. + * @see #setModel(BoundedRangeModel) + */ protected BoundedRangeModel model; - /** The string that is displayed by the ProgressBar. */ + /** + * A custom string for display in the progress bar. If this is + * <code>null</code>, a default string will be generated. + * @see #setString(String) + */ protected String progressString; - /** Whether the string should be painted. */ + /** + * A flag that controls whether a string is displayed within the progress + * bar. + * @see #setStringPainted(boolean) + */ protected boolean paintString = false; - /** The static changeEvent passed to all ChangeListeners. */ + /** + * A single change event reused for all events. + * @see #fireStateChanged() + */ protected transient ChangeEvent changeEvent; - /** The ChangeListener that listens to the model. */ + /** + * The listener that is registered with the model. */ protected ChangeListener changeListener; /** - * Creates a new horizontally oriented JProgressBar object - * with a minimum of 0 and a maximum of 100. + * Creates a new <code>JProgressBar</code> with default attributes. The + * following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: 0;</li> + * <li><code>minimum</code>: 0;</li> + * <li><code>maximum</code>: 100;</li> + * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li> + * </ul> */ public JProgressBar() { @@ -227,13 +260,20 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new JProgressBar object with a minimum of 0, - * a maximum of 100, and the given orientation. - * - * @param orientation The orientation of the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified + * <code>orientation</code>. The following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: 0;</li> + * <li><code>minimum</code>: 0;</li> + * <li><code>maximum</code>: 100;</li> + * </ul> * - * @throws IllegalArgumentException if <code>orientation</code> is not either - * {@link #HORIZONTAL} or {@link #VERTICAL}. + * @param orientation the orientation ({@link #HORIZONTAL} or + * {@link #VERTICAL}). + * + * @throws IllegalArgumentException if <code>orientation</code> is not one of + * the specified values. */ public JProgressBar(int orientation) { @@ -241,11 +281,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new horizontally oriented JProgressBar object - * with the given minimum and maximum. - * - * @param minimum The minimum of the JProgressBar. - * @param maximum The maximum of the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified value range. + * The following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: <code>minimum</code>;</li> + * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li> + * </ul> + * + * @param minimum the lower bound of the value range. + * @param maximum the upper bound of the value range. */ public JProgressBar(int minimum, int maximum) { @@ -253,15 +298,20 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new JProgressBar object with the given minimum, - * maximum, and orientation. - * - * @param minimum The minimum of the JProgressBar. - * @param maximum The maximum of the JProgressBar. - * @param orientation The orientation of the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified range and + * orientation. The following defaults are used: + * <p> + * <ul> + * <li><code>value</code>: <code>minimum</code>;</li> + * </ul> + * + * @param minimum the lower bound of the value range. + * @param maximum the upper bound of the value range. + * @param orientation the orientation ({@link #HORIZONTAL} or + * {@link #VERTICAL}). * - * @throws IllegalArgumentException if <code>orientation</code> is not either - * {@link #HORIZONTAL} or {@link #VERTICAL}. + * @throws IllegalArgumentException if <code>orientation</code> is not one of + * the specified values. */ public JProgressBar(int orientation, int minimum, int maximum) { @@ -276,10 +326,14 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * Creates a new horizontally oriented JProgressBar object - * with the given model. - * - * @param model The model to be used with the JProgressBar. + * Creates a new <code>JProgressBar</code> with the specified model. The + * following defaults are used: + * <p> + * <ul> + * <li><code>orientation</code>: {@link SwingConstants#HORIZONTAL}.</li> + * </ul> + * + * @param model the model (<code>null</code> not permitted). */ public JProgressBar(BoundedRangeModel model) { @@ -291,9 +345,12 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns the current value of the JProgressBar. + * Returns the current value for the <code>JProgressBar</code>. This value + * is fetched from the model. * - * @return The current value of the JProgressBar. + * @return The current value. + * + * @see #setValue(int) */ public int getValue() { @@ -301,9 +358,20 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method sets the value of the JProgressBar. + * Sets the current value for the <code>JProgressBar</code>. The value is + * stored in the component's <code>model</code> (see {@link #getModel()}). + * If the new value is different to the old value, a {@link ChangeEvent} is + * sent to the model's registered listeners. In turn, this triggers a call + * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code> + * to this component's registered listeners. + * <p> + * If <code>value</code> is outside the range <code>minimum</code> to + * <code>maximum</code>, it will be set to the nearest of those boundary + * values. * - * @param value The value of the JProgressBar. + * @param value the new value. + * + * @see #getValue() */ public void setValue(int value) { @@ -311,23 +379,29 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method paints the border of the JProgressBar + * Paints the component's border, but only if {@link #isBorderPainted()} + * returns <code>true</code>. * - * @param graphics The graphics object to paint with. + * @param graphics the graphics object to paint with. + * + * @see #setBorderPainted(boolean) */ protected void paintBorder(Graphics graphics) { Border border = getBorder(); if (paintBorder && border != null) - border.paintBorder(this, graphics, 0, 0, - getWidth(), - getHeight()); + border.paintBorder(this, graphics, 0, 0, getWidth(), getHeight()); } /** - * This method returns the orientation of the JProgressBar. + * Returns the orientation of the <code>JProgressBar</code> component, which + * is either {@link SwingConstants#HORIZONTAL} or + * {@link SwingConstants#VERTICAL}. The default orientation is + * <code>HORIZONTAL</code>. * - * @return The orientation of the JProgressBar. + * @return The orientation. + * + * @see #setOrientation(int) */ public int getOrientation() { @@ -335,12 +409,17 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the orientation property. The orientation of the - * JProgressBar can be either horizontal or vertical. + * Sets the orientation for this <code>JProgressBar</code> component and, + * if the value changes, sends a {@link PropertyChangeEvent} (with the + * property name <code>"orientation"</code>) to all registered listeners. * - * @param orientation The orientation of the JProgressBar. + * @param orientation the orientation ({@link #HORIZONTAL} or + * {@link #VERTICAL}). + * * @throws IllegalArgumentException if <code>orientation</code> is not - * either {@link #HORIZONTAL} or {@link #VERTICAL}. + * one of the listed values. + * + * @see #getOrientation() */ public void setOrientation(int orientation) { @@ -349,17 +428,21 @@ public class JProgressBar extends JComponent implements SwingConstants, + " is not a legal orientation"); if (this.orientation != orientation) { - int oldOrientation = this.orientation; - this.orientation = orientation; - firePropertyChange("orientation", oldOrientation, - this.orientation); + int oldOrientation = this.orientation; + this.orientation = orientation; + firePropertyChange("orientation", oldOrientation, this.orientation); } } /** - * This method returns whether the progressString will be painted. + * Returns the flag that controls whether or not the string returned by + * {@link #getString()} is displayed by the <code>JProgressBar</code> + * component. * - * @return Whether the string is painted. + * @return <code>true</code> if the string should be displayed, and + * <code>false</code> otherwise. + * + * @see #setStringPainted(boolean) */ public boolean isStringPainted() { @@ -367,28 +450,37 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the stringPainted property. + * Sets the flag that controls whether or not the string returned by + * {@link #getString()} is displayed by the <code>JProgressBar</code> + * component. If the flag value changes, a {@link PropertyChangeEvent} (with + * the property name <code>"stringPainted"</code>) is sent to all registered + * listeners. * - * @param painted Whether the string is painted. + * @param painted the new flag value. + * + * @see #isStringPainted() + * @see #setString(String) */ public void setStringPainted(boolean painted) { if (paintString != painted) { - boolean oldPainted = paintString; - paintString = painted; - firePropertyChange("stringPainted", oldPainted, - paintString); + boolean oldPainted = paintString; + paintString = painted; + firePropertyChange("stringPainted", oldPainted, paintString); } } /** - * This method returns the string that is painted if the - * stringPainted property is set to true. If there is no - * string set, it will return a string containing the - * JProgressBar's value as a percent. + * Returns the string that is painted on the <code>JProgressBar</code> if + * {@link #isStringPainted()} returns <code>true</code>. If no string has + * been explicitly set, this method will return a string displaying the + * value of {@link #getPercentComplete()}. * - * @return The string that is painted. + * @return The string. + * + * @see #setString(String) + * @see #setStringPainted(boolean) */ public String getString() { @@ -399,12 +491,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the string property. The string - * given will be the one painted. If you want to - * revert to the default string given, set the - * string to null. + * Sets the string to display within the progress bar and, if the new value + * is different to the old value, sends a {@link PropertyChangeEvent} (with + * the property name <code>"string"</code>) to all registered listeners. If + * the string is set to <code>null</code>, {@link #getString()} will return + * a default string. * - * @param string The string to be painted. + * @param string the string (<code>null</code> permitted). + * + * @see #getString() + * @see #setStringPainted(boolean) */ public void setString(String string) { @@ -412,32 +508,35 @@ public class JProgressBar extends JComponent implements SwingConstants, string != progressString) || (string != null && ! string.equals(progressString))) { - String oldString = progressString; - progressString = string; - firePropertyChange("string", oldString, progressString); + String oldString = progressString; + progressString = string; + firePropertyChange("string", oldString, progressString); } } /** - * This method returns the percent of the bar - * that is "complete". (This is the amount value / (max - min)). + * Returns the current value expressed as a percentage. This is calculated + * as <code>(value - min) / (max - min)</code>. * - * @return DOCUMENT ME! + * @return The percentage (a value in the range 0.0 to 1.0). */ public double getPercentComplete() { if (getMaximum() == getMinimum()) return 1.0; else - return (double) (model.getValue() - model.getMinimum()) / (model - .getMaximum() - - model.getMinimum()); + return (double) (model.getValue() - model.getMinimum()) + / (model.getMaximum() - model.getMinimum()); } /** - * This method returns whether the border is painted. + * Returns a flag that controls whether or not the component's border is + * painted. The default value is <code>true</code>. * - * @return Whether the border is painted. + * @return <code>true</code> if the component's border should be painted, + * and <code>false</code> otherwise. + * + * @see #setBorderPainted(boolean) */ public boolean isBorderPainted() { @@ -445,25 +544,30 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the borderPainted property. + * Sets the flag that controls whether or not the component's border is + * painted. If the flag value is changed, this method sends a + * {@link PropertyChangeEvent} (with the property name "borderPainted") to + * all registered listeners. * - * @param painted Whether the border is painted. + * @param painted the new flag value. + * + * @see #isBorderPainted() + * @see #paintBorder */ public void setBorderPainted(boolean painted) { if (painted != paintBorder) { - boolean oldPainted = paintBorder; - paintBorder = painted; - firePropertyChange("borderPainted", oldPainted, - paintBorder); + boolean oldPainted = paintBorder; + paintBorder = painted; + firePropertyChange("borderPainted", oldPainted, paintBorder); } } /** - * This method returns the JProgressBar's UI delegate. + * Returns the UI delegate for this <code>JProgressBar</code>. * - * @return This JProgressBar's UI delegate. + * @return The UI delegate. */ public ProgressBarUI getUI() { @@ -471,9 +575,9 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the UI property for this JProgressBar. + * Sets the UI delegate for this component. * - * @param ui The new UI delegate. + * @param ui the new UI delegate. */ public void setUI(ProgressBarUI ui) { @@ -481,8 +585,8 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method reverts the UI delegate for this JProgressBar - * to the default for this Look and Feel. + * Sets this <code>JProgressBar</code>'s UI delegate to the default + * (obtained from the {@link UIManager}) for the current look and feel. */ public void updateUI() { @@ -490,11 +594,11 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns the identifier to allow the UIManager - * to pick the correct class to act as the UI for - * this JProgressBar. + * Returns the suffix (<code>"ProgressBarUI"</code> in this case) used to + * determine the class name for a UI delegate that can provide the look and + * feel for a <code>JProgressBar</code>. * - * @return The UIClassID: "ProgressBarUI". + * @return <code>"ProgressBarUI"</code>. */ public String getUIClassID() { @@ -502,27 +606,33 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns a ChangeListener that gets registered - * model. By default, the ChangeListener, propagates the - * ChangeEvents to the ChangeListeners of the JProgressBar. + * Creates a new {@link ChangeListener} that calls + * {@link #fireStateChanged()} whenever it receives a {@link ChangeEvent} + * (typically from the component's <code>model</code>). This listener is + * registered with the progress bar's model, so that changes made to the + * model directly will automatically result in the progress bar's listeners + * being notified also. * - * @return A new ChangeListener. + * @return A new listener. */ protected ChangeListener createChangeListener() { return new ChangeListener() { - public void stateChanged(ChangeEvent ce) - { - fireStateChanged(); - } + public void stateChanged(ChangeEvent ce) + { + fireStateChanged(); + } }; } /** - * This method adds a ChangeListener to this JProgressBar. + * Registers a listener with this component so that it will receive + * notification of component state changes. * - * @param listener The ChangeListener to add to this JProgressBar. + * @param listener the listener. + * + * @see #removeChangeListener(ChangeListener) */ public void addChangeListener(ChangeListener listener) { @@ -530,9 +640,12 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method removes a ChangeListener from this JProgressBar. + * Deregisters a listener so that it no longer receives notification of + * component state changes. * - * @param listener The ChangeListener to remove from this JProgressBar. + * @param listener the listener. + * + * @see #addChangeListener(ChangeListener) */ public void removeChangeListener(ChangeListener listener) { @@ -540,10 +653,12 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns an array of all ChangeListeners listening to this - * progress bar. + * Returns an array of the listeners that are registered with this component. + * The array may be empty, but is never <code>null</code>. * - * @return An array of ChangeListeners listening to this progress bar. + * @return An array of listeners. + * + * @since 1.4 */ public ChangeListener[] getChangeListeners() { @@ -551,9 +666,10 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method is called when the JProgressBar receives a ChangeEvent - * from its model. This simply propagates the event (changing the source - * to the JProgressBar) to the JProgressBar's listeners. + * Sends a {@link ChangeEvent} to all registered listeners to indicate that + * the state of the <code>JProgressBar</code> has changed. + * + * @see #createChangeListener() */ protected void fireStateChanged() { @@ -562,15 +678,17 @@ public class JProgressBar extends JComponent implements SwingConstants, changeEvent = new ChangeEvent(this); for (int i = changeListeners.length - 2; i >= 0; i -= 2) { - if (changeListeners[i] == ChangeListener.class) - ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); + if (changeListeners[i] == ChangeListener.class) + ((ChangeListener) changeListeners[i + 1]).stateChanged(changeEvent); } } /** - * This method returns the model used with this JProgressBar. + * Returns the model for the <code>JProgressBar</code>. * - * @return The model used with this JProgressBar. + * @return The model (never <code>null</code>). + * + * @see #setModel(BoundedRangeModel) */ public BoundedRangeModel getModel() { @@ -578,25 +696,32 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the model property for this JProgressBar. + * Sets the model for the <code>JProgressBar</code> and sends a + * {@link ChangeEvent} to all registered listeners. * - * @param model The model to use with this JProgressBar. + * @param model the model (<code>null</code> not permitted). + * + * @see #getModel() */ public void setModel(BoundedRangeModel model) { if (model != this.model) { this.model.removeChangeListener(changeListener); - this.model = model; - this.model.addChangeListener(changeListener); - fireStateChanged(); + this.model = model; + this.model.addChangeListener(changeListener); + fireStateChanged(); } } /** - * This method returns the minimum value of this JProgressBar. + * Returns the minimum value for the <code>JProgressBar</code>. This defines + * the lower bound for the current value, and is stored in the component's + * <code>model</code>. * - * @return The minimum value of this JProgressBar. + * @return The minimum value. + * + * @see #setMinimum(int) */ public int getMinimum() { @@ -604,9 +729,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method sets the minimum value of this JProgressBar. - * - * @param minimum The minimum value of this JProgressBar. + * Sets the minimum value for the <code>JProgressBar</code>. The value is + * stored in the component's <code>model</code> (see {@link #getModel()}). + * If the new value is different to the old value, a {@link ChangeEvent} is + * sent to the model's registered listeners. In turn, this triggers a call + * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code> + * to this component's registered listeners. + * + * @param minimum the minimum value. + * + * @see #getMinimum() */ public void setMinimum(int minimum) { @@ -614,9 +746,13 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method returns the maximum value of this JProgressBar. + * Returns the maximum value for the <code>JProgressBar</code>. This defines + * the upper bound for the current value, and is stored in the component's + * <code>model</code>. * - * @return The maximum value of this JProgressBar. + * @return The maximum value. + * + * @see #setMaximum(int) */ public int getMaximum() { @@ -624,9 +760,16 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method sets the maximum value of this JProgressBar. + * Sets the maximum value for the <code>JProgressBar</code>. The value is + * stored in the component's <code>model</code> (see {@link #getModel()}). + * If the new value is different to the old value, a {@link ChangeEvent} is + * sent to the model's registered listeners. In turn, this triggers a call + * to {@link #fireStateChanged()} which will send a <code>ChangeEvent</code> + * to this component's registered listeners. * - * @param maximum The maximum value of this JProgressBar. + * @param maximum the maximum value. + * + * @see #getMaximum() */ public void setMaximum(int maximum) { @@ -659,29 +802,40 @@ public class JProgressBar extends JComponent implements SwingConstants, } /** - * This method changes the indeterminate property. If the - * JProgressBar is determinate, it paints a percentage - * of the bar described by its value. If it is indeterminate, - * it simply bounces a box between the ends of the bar; the - * value of the JProgressBar is ignored. + * Sets the flag that controls the mode for this <code>JProgressBar</code> + * (<code>true</code> for indeterminate mode, and <code>false</code> for + * determinate mode). If the flag value changes, this method sends a + * {@link PropertyChangeEvent} (with the property name + * <code>"indeterminate"</code>) to all registered listeners. + * <p> + * If the <code>JProgressBar</code> is determinate, it paints a percentage + * of the bar described by its value. If it is indeterminate, it simply + * bounces a box between the ends of the bar; the value of the + * <code>JProgressBar</code> is ignored. * - * @param newValue Whether the JProgressBar is indeterminate. + * @param flag the new flag value. + * + * @see #isIndeterminate() + * @since 1.4 */ - public void setIndeterminate(boolean newValue) + public void setIndeterminate(boolean flag) { - if (indeterminate != newValue) + if (indeterminate != flag) { - boolean olddeter = indeterminate; - indeterminate = newValue; - firePropertyChange("indeterminate", olddeter, - indeterminate); + indeterminate = flag; + firePropertyChange("indeterminate", !flag, indeterminate); } } /** - * This method returns whether the JProgressBar is indeterminate. + * Returns a flag that indicates the mode for this <code>JProgressBar</code> + * (<code>true</code> for indeterminate mode, and <code>false</code> for + * determinate mode). * - * @return Whether this JProgressBar is indeterminate. + * @return A flag indicating the mode for the <code>JProgressBar</code>. + * + * @see #setIndeterminate(boolean) + * @since 1.4 */ public boolean isIndeterminate() { diff --git a/javax/swing/JScrollBar.java b/javax/swing/JScrollBar.java index bca246873..bf0803ab5 100644 --- a/javax/swing/JScrollBar.java +++ b/javax/swing/JScrollBar.java @@ -643,14 +643,24 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible } /** - * A string that describes this JScrollBar. Normally only used - * for debugging. + * Returns a string describing the attributes for the <code>JScrollBar</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. * - * @return A string describing this JScrollBar. + * @return A string describing the attributes of the <code>JScrollBar</code>. */ protected String paramString() { - return "JScrollBar"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",blockIncrement=").append(blockIncrement); + sb.append(",orientation="); + if (this.orientation == JScrollBar.HORIZONTAL) + sb.append("HORIZONTAL"); + else + sb.append("VERTICAL"); + sb.append(",unitIncrement=").append(unitIncrement); + return sb.toString(); } /** diff --git a/javax/swing/JTabbedPane.java b/javax/swing/JTabbedPane.java index 34ab8eeaa..76cc74eab 100644 --- a/javax/swing/JTabbedPane.java +++ b/javax/swing/JTabbedPane.java @@ -1,5 +1,5 @@ /* JTabbedPane.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -79,8 +79,6 @@ public class JTabbedPane extends JComponent implements Serializable, /** * Accessibility support for <code>JTabbedPane</code>. */ - // FIXME: This inner class is a complete stub and must be implemented - // properly. protected class AccessibleJTabbedPane extends JComponent.AccessibleJComponent implements AccessibleSelection, ChangeListener { @@ -106,7 +104,7 @@ public class JTabbedPane extends JComponent implements Serializable, public void stateChanged(ChangeEvent e) throws NotImplementedException { - // Implement this properly. + // FIXME: Implement this properly. } /** @@ -116,9 +114,8 @@ public class JTabbedPane extends JComponent implements Serializable, * @return the accessible role of the <code>JTabbedPane</code> */ public AccessibleRole getAccessibleRole() - throws NotImplementedException { - return null; + return AccessibleRole.PAGE_TAB_LIST; } /** @@ -129,9 +126,8 @@ public class JTabbedPane extends JComponent implements Serializable, * <code>JTabbedPane</code> */ public int getAccessibleChildrenCount() - throws NotImplementedException { - return 0; + return getTabCount(); } /** @@ -158,9 +154,8 @@ public class JTabbedPane extends JComponent implements Serializable, * @return the current selection state of the <code>JTabbedPane</code> */ public AccessibleSelection getAccessibleSelection() - throws NotImplementedException { - return null; + return this; } /** @@ -175,90 +170,99 @@ public class JTabbedPane extends JComponent implements Serializable, * this location */ public Accessible getAccessibleAt(Point p) - throws NotImplementedException { - return null; + int tabIndex = indexAtLocation(p.x, p.y); + if (tabIndex >= 0) + return getAccessibleChild(tabIndex); + else + return getAccessibleSelection(0); } /** - * The number of selected child components of the - * <code>JTabbedPane</code>. This will be <code>0</code> if the - * <code>JTabbedPane</code> has no children, or <code>1</code> otherwise, - * since there is always exactly one tab selected. + * Returns the number of selected child components of the + * <code>JTabbedPane</code>. The reference implementation appears + * to return <code>1</code> always and we do the same. * - * @return number of selected child components of the - * <code>JTabbedPane</code> + * @return <code>1</code> */ public int getAccessibleSelectionCount() - throws NotImplementedException { - return 0; + return 1; } /** - * DOCUMENT ME! + * Returns the selected tab, or <code>null</code> if there is no + * selection. * - * @param i DOCUMENT ME! + * @param i the selection index (ignored here). * - * @return DOCUMENT ME! + * @return The selected tab, or <code>null</code>. */ public Accessible getAccessibleSelection(int i) - throws NotImplementedException { - return null; + Accessible result = null; + int selected = getSelectedIndex(); + if (selected >= 0) + result = (Page) tabs.get(selected); + return result; } /** - * DOCUMENT ME! + * Returns <code>true</code> if the specified child is selected, + * and <code>false</code> otherwise. * - * @param i DOCUMENT ME! + * @param i the child index. * - * @return DOCUMENT ME! + * @return A boolean. */ public boolean isAccessibleChildSelected(int i) - throws NotImplementedException { - return false; + return i == getSelectedIndex(); } /** - * DOCUMENT ME! + * Selects the specified tab. * - * @param i DOCUMENT ME! + * @param i the index of the item to select. */ public void addAccessibleSelection(int i) - throws NotImplementedException { - // TODO: Implement this properly. + setSelectedIndex(i); } /** - * DOCUMENT ME! + * Does nothing - it makes no sense to remove a selection for a + * tabbed pane, since one tab must always be selected. * - * @param i DOCUMENT ME! + * @param i the item index. + * + * @see #addAccessibleSelection(int) */ public void removeAccessibleSelection(int i) - throws NotImplementedException { - // TODO: Implement this properly. + // do nothing } /** - * DOCUMENT ME! + * Does nothing - it makes no sense to clear the selection for + * a tabbed pane, since one tab must always be selected. + * + * @see #addAccessibleSelection(int) */ public void clearAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // do nothing } /** - * DOCUMENT ME! + * Does nothing - it makes no sense to select all for a tabbed + * pane, since only one tab can be selected at a time. + * + * @see #addAccessibleSelection(int) */ public void selectAllAccessibleSelection() - throws NotImplementedException { - // TODO: Implement this properly. + // do nothing } } @@ -267,7 +271,6 @@ public class JTabbedPane extends JComponent implements Serializable, */ protected class ModelListener implements ChangeListener, Serializable { - /** DOCUMENT ME! */ private static final long serialVersionUID = 497359819958114132L; /** @@ -446,7 +449,6 @@ public class JTabbedPane extends JComponent implements Serializable, return title; } - /** DOCUMENT ME! */ private static final long serialVersionUID = 1614381073220130939L; /** @@ -598,6 +600,19 @@ public class JTabbedPane extends JComponent implements Serializable, } /** + * Returns the accessible name for this tab. + * + * @return The accessible name. + */ + public String getAccessibleName() + { + if (accessibleName != null) + return accessibleName; + else + return title; + } + + /** * Returns the accessible role of this tab, which is always * {@link AccessibleRole#PAGE_TAB}. * @@ -1623,20 +1638,35 @@ public class JTabbedPane extends JComponent implements Serializable, } /** - * This method returns a string representation of this JTabbedPane. It is - * mainly used for debugging purposes. + * Returns a string describing the attributes for the + * <code>JTabbedPane</code> component, for use in debugging. The return + * value is guaranteed to be non-<code>null</code>, but the format of the + * string may vary between implementations. * - * @return A string representation of this JTabbedPane. + * @return A string describing the attributes of the + * <code>JTabbedPane</code>. */ protected String paramString() { - return "JTabbedPane"; + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",tabPlacement="); + if (tabPlacement == TOP) + sb.append("TOP"); + if (tabPlacement == BOTTOM) + sb.append("BOTTOM"); + if (tabPlacement == LEFT) + sb.append("LEFT"); + if (tabPlacement == RIGHT) + sb.append("RIGHT"); + return sb.toString(); } /** - * DOCUMENT ME! + * Returns the object that provides accessibility features for this + * <code>JTabbedPane</code> component. * - * @return DOCUMENT ME! + * @return The accessible context (an instance of + * {@link AccessibleJTabbedPane}). */ public AccessibleContext getAccessibleContext() { diff --git a/javax/swing/JTable.java b/javax/swing/JTable.java index 1298f128d..a4ef6fbcd 100644 --- a/javax/swing/JTable.java +++ b/javax/swing/JTable.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + import java.awt.Color; import java.awt.Component; import java.awt.Cursor; @@ -163,6 +165,7 @@ public class JTable * @return the accessible row for the table cell */ public AccessibleRole getAccessibleRole() + throws NotImplementedException { // TODO: What is the role of the table cell? return AccessibleRole.UNKNOWN; @@ -174,6 +177,7 @@ public class JTable * @return the accessible state set of this accessible table cell */ public AccessibleStateSet getAccessibleStateSet() + throws NotImplementedException { // TODO: What state shoiuld be returned here? return new AccessibleStateSet(); @@ -617,45 +621,47 @@ public class JTable } public Accessible getAccessibleSelection(int i) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public boolean isAccessibleChildSelected(int i) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public void addAccessibleSelection(int i) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public void removeAccessibleSelection(int i) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public void clearAccessibleSelection() + throws NotImplementedException { // TODO Auto-generated method stub - } public void selectAllAccessibleSelection() + throws NotImplementedException { // TODO Auto-generated method stub - } public void valueChanged(ListSelectionEvent event) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } /** @@ -685,6 +691,7 @@ public class JTable * @param event the table model event */ public void tableRowsInserted(TableModelEvent event) + throws NotImplementedException { // TODO: What to do here, if anything? This might be a hook method for // subclasses... @@ -697,51 +704,52 @@ public class JTable * @param event the table model event */ public void tableRowsDeleted(TableModelEvent event) + throws NotImplementedException { // TODO: What to do here, if anything? This might be a hook method for // subclasses... } public void columnAdded(TableColumnModelEvent event) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public void columnMarginChanged(ChangeEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void columnMoved(TableColumnModelEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void columnRemoved(TableColumnModelEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void columnSelectionChanged(ListSelectionEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void editingCanceled(ChangeEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } public void editingStopped(ChangeEvent event) + throws NotImplementedException { // TODO Auto-generated method stub - } /** @@ -785,150 +793,170 @@ public class JTable } public int getAccessibleRow(int index) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleColumn(int index) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleIndex(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public Accessible getAccessibleCaption() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleCaption(Accessible caption) + throws NotImplementedException { // TODO Auto-generated method stub - } public Accessible getAccessibleSummary() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleSummary(Accessible summary) + throws NotImplementedException { // TODO Auto-generated method stub - } public int getAccessibleRowCount() + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleColumnCount() + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public Accessible getAccessibleAt(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public int getAccessibleRowExtentAt(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public int getAccessibleColumnExtentAt(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return 0; } public AccessibleTable getAccessibleRowHeader() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleRowHeader(AccessibleTable header) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public AccessibleTable getAccessibleColumnHeader() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleColumnHeader(AccessibleTable header) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public Accessible getAccessibleRowDescription(int r) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleRowDescription(int r, Accessible description) + throws NotImplementedException { - // TODO Auto-generated method stub - + // TODO Auto-generated method stub } public Accessible getAccessibleColumnDescription(int c) + throws NotImplementedException { // TODO Auto-generated method stub return null; } public void setAccessibleColumnDescription(int c, Accessible description) + throws NotImplementedException { // TODO Auto-generated method stub } public boolean isAccessibleSelected(int r, int c) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public boolean isAccessibleRowSelected(int r) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public boolean isAccessibleColumnSelected(int c) + throws NotImplementedException { // TODO Auto-generated method stub return false; } public int[] getSelectedAccessibleRows() + throws NotImplementedException { // TODO Auto-generated method stub return null; } public int[] getSelectedAccessibleColumns() + throws NotImplementedException { // TODO Auto-generated method stub return null; @@ -1272,17 +1300,6 @@ public class JTable { setBorder(BorderFactory.createLineBorder(getGridColor(), 2)); } - - /** - * With not this method overridden, the scroll pane scrolls to the - * top left cornec (untranslated position of the caret) after the first - * keystroke. - */ - public void scrollRectToVisible(Rectangle r) - { - // Do nothing here. If the editing session starts outside the visible - // bounds, the editCellAt will scroll. - } } @@ -1588,6 +1605,21 @@ public class JTable private boolean clientRowHeightSet = false; /** + * Stores the sizes and positions of each row, when using non-uniform row + * heights. Initially the height of all rows is equal and stored in + * {link #rowHeight}. However, when an application calls + * {@link #setRowHeight(int,int)}, the table switches to non-uniform + * row height mode which stores the row heights in the SizeSequence + * object instead. + * + * @see #setRowHeight(int) + * @see #getRowHeight() + * @see #getRowHeight(int) + * @see #setRowHeight(int, int) + */ + private SizeSequence rowHeights; + + /** * Creates a new <code>JTable</code> instance. */ public JTable () @@ -1727,7 +1759,7 @@ public class JTable createDefaultEditors(); this.autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS; - this.rowHeight = 16; + setRowHeight(16); this.rowMargin = 1; this.rowSelectionAllowed = true; // this.accessibleContext = new AccessibleJTable(); @@ -1958,7 +1990,13 @@ public class JTable // changed and the flag autoCreateColumnsFromModel is set if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW)) && autoCreateColumnsFromModel) - createDefaultColumnsFromModel(); + { + rowHeights = null; + if (getAutoCreateColumnsFromModel()) + createDefaultColumnsFromModel(); + resizeAndRepaint(); + return; + } // If the structure changes, we need to revalidate, since that might // affect the size parameters of the JTable. Otherwise we only need @@ -1975,6 +2013,8 @@ public class JTable if (last < 0) last = getRowCount() - 1; selectionModel.insertIndexInterval(first, last - first + 1, true); + if (rowHeights != null) + rowHeights.insertEntries(first, last - first + 1, rowHeight); } revalidate(); } @@ -1990,6 +2030,8 @@ public class JTable if (last < 0) last = getRowCount() - 1; selectionModel.removeIndexInterval(first, last); + if (rowHeights != null) + rowHeights.removeEntries(first, last - first + 1); } if (dataModel.getRowCount() == 0) clearSelection(); @@ -2004,14 +2046,14 @@ public class JTable */ public void valueChanged (ListSelectionEvent event) { - // Does not make sense for the table with the single row. - if (getRowCount() < 2) - return; - - int y_gap = rowMargin; - int y0 = (getRowHeight() + y_gap) * (event.getFirstIndex()); - int yn = (getRowHeight() + y_gap) * (event.getLastIndex()+1); - repaint(0, y0, getWidth(), yn-y0); + // Repaint the changed region. + int first = Math.max(0, Math.min(getRowCount() - 1, event.getFirstIndex())); + int last = Math.max(0, Math.min(getRowCount() - 1, event.getLastIndex())); + Rectangle rect1 = getCellRect(first, 0, false); + Rectangle rect2 = getCellRect(last, getColumnCount() - 1, false); + SwingUtilities.computeUnion(rect2.x, rect2.y, rect2.width, rect2.height, + rect1); + repaint(rect1); } /** @@ -2053,10 +2095,16 @@ public class JTable if (point != null) { int nrows = getRowCount(); - int height = getRowHeight() + getRowMargin(); + int r; int y = point.y; + if (rowHeights == null) + { + int height = getRowHeight(); + r = y / height; + } + else + r = rowHeights.getIndex(y); - int r = y / height; if (r < 0 || r >= nrows) return -1; else @@ -2086,27 +2134,70 @@ public class JTable int column, boolean includeSpacing) { - int height = getRowHeight(row); - int width = columnModel.getColumn(column).getWidth(); - int x_gap = columnModel.getColumnMargin(); - int y_gap = rowMargin; + Rectangle cellRect = new Rectangle(0, 0, 0, 0); - column = Math.max(0, Math.min(column, getColumnCount() - 1)); - row = Math.max(0, Math.min(row, getRowCount() - 1)); - - int x = 0; - int y = (height + y_gap) * row; + // Check for valid range vertically. + if (row >= getRowCount()) + { + cellRect.height = getHeight(); + } + else if (row >= 0) + { + cellRect.height = getRowHeight(row); + if (rowHeights == null) + cellRect.y = row * cellRect.height; + else + cellRect.y = rowHeights.getPosition(row); - for (int i = 0; i < column; ++i) - x += columnModel.getColumn(i).getWidth(); - - Rectangle rect = new Rectangle(); + if (! includeSpacing) + { + // The rounding here is important. + int rMargin = getRowMargin(); + cellRect.y += rMargin / 2; + cellRect.height -= rMargin; + } + } + // else row < 0, y = height = 0 - if (includeSpacing) - rect.setBounds(x, y, width, height +y_gap); + // Check for valid range horizontally. + if (column < 0) + { + if (! getComponentOrientation().isLeftToRight()) + { + cellRect.x = getWidth(); + } + } + else if (column >= getColumnCount()) + { + if (getComponentOrientation().isLeftToRight()) + { + cellRect.x = getWidth(); + } + } else - rect.setBounds(x, y, width - x_gap, height); - return rect; + { + TableColumnModel tcm = getColumnModel(); + if (getComponentOrientation().isLeftToRight()) + { + for (int i = 0; i < column; i++) + cellRect.x += tcm.getColumn(i).getWidth(); + } + else + { + for (int i = tcm.getColumnCount() - 1; i > column; i--) + cellRect.x += tcm.getColumn(i).getWidth(); + } + cellRect.width = tcm.getColumn(column).getWidth(); + if (! includeSpacing) + { + // The rounding here is important. + int cMargin = tcm.getColumnMargin(); + cellRect.x += cMargin / 2; + cellRect.width -= cMargin; + } + } + + return cellRect; } public void clearSelection() @@ -2354,7 +2445,6 @@ public class JTable int row, int column) { - boolean rowSelAllowed = getRowSelectionAllowed(); boolean colSelAllowed = getColumnSelectionAllowed(); boolean isSel = false; @@ -2418,9 +2508,10 @@ public class JTable */ public int getRowHeight(int row) { - // FIXME: return the height of the specified row - // which may be different from the general rowHeight - return rowHeight; + int rh = rowHeight; + if (rowHeights != null) + rh = rowHeights.getSize(row); + return rh; } @@ -2780,9 +2871,14 @@ public class JTable } /** - * Set the value of the {@link #rowHeight} property. + * Sets the height for all rows in the table. If you want to change the + * height of a single row instead, use {@link #setRowHeight(int, int)}. + * + * @param r the height to set for all rows * - * @param r The new value of the rowHeight property + * @see #getRowHeight() + * @see #setRowHeight(int, int) + * @see #getRowHeight(int) */ public void setRowHeight(int r) { @@ -2792,21 +2888,24 @@ public class JTable clientRowHeightSet = true; rowHeight = r; + rowHeights = null; revalidate(); repaint(); } /** - * Sets the value of the rowHeight property for the specified - * row. + * Sets the height of a single row in the table. * - * @param rh is the new rowHeight - * @param row is the row to change the rowHeight of + * @param rh the new row height + * @param row the row to change the height of */ public void setRowHeight(int row, int rh) { - setRowHeight(rh); - // FIXME: not implemented + if (rowHeights == null) + { + rowHeights = new SizeSequence(getRowCount(), rowHeight); + } + rowHeights.setSize(row, rh); } /** @@ -2878,6 +2977,10 @@ public class JTable // Add table as TableModelListener to new model. dataModel.addTableModelListener(this); + // Notify the tableChanged method. + tableChanged(new TableModelEvent(dataModel, + TableModelEvent.HEADER_ROW)); + // Automatically create columns. if (autoCreateColumnsFromModel) createDefaultColumnsFromModel(); @@ -3866,4 +3969,5 @@ public class JTable super.setUIProperty(propertyName, value); } } + } diff --git a/javax/swing/JToolBar.java b/javax/swing/JToolBar.java index b576b4f2a..fe4d2ae20 100644 --- a/javax/swing/JToolBar.java +++ b/javax/swing/JToolBar.java @@ -1,5 +1,5 @@ /* JToolBar.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -757,14 +757,28 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible } // addImpl() /** - * This method returns a String description of the JToolBar. + * Returns a string describing the attributes for the <code>JToolBar</code> + * component, for use in debugging. The return value is guaranteed to be + * non-<code>null</code>, but the format of the string may vary between + * implementations. * - * @return A String description of the JToolBar. + * @return A string describing the attributes of the <code>JToolBar</code>. */ protected String paramString() { - return "JToolBar"; - } // paramString() + StringBuffer sb = new StringBuffer(super.paramString()); + sb.append(",floatable=").append(floatable); + sb.append(",margin="); + if (margin != null) + sb.append(margin); + sb.append(",orientation="); + if (orientation == HORIZONTAL) + sb.append("HORIZONTAL"); + else + sb.append(VERTICAL); + sb.append(",paintBorder=").append(paintBorder); + return sb.toString(); + } /** * Returns the object that provides accessibility features for this diff --git a/javax/swing/KeyboardManager.java b/javax/swing/KeyboardManager.java index 4f778f733..f7ac9496c 100644 --- a/javax/swing/KeyboardManager.java +++ b/javax/swing/KeyboardManager.java @@ -46,6 +46,7 @@ import java.awt.event.KeyEvent; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; +import java.util.WeakHashMap; /** * This class maintains a mapping from top-level containers to a @@ -65,7 +66,7 @@ class KeyboardManager * A mapping between top level containers and Hashtables that * map KeyStrokes to Components. */ - Hashtable topLevelLookup = new Hashtable(); + WeakHashMap topLevelLookup = new WeakHashMap(); /** * A mapping between top level containers and Vectors of JMenuBars diff --git a/javax/swing/ProgressMonitor.java b/javax/swing/ProgressMonitor.java index 73e36b9ca..28d22e8a6 100644 --- a/javax/swing/ProgressMonitor.java +++ b/javax/swing/ProgressMonitor.java @@ -38,8 +38,10 @@ exception statement from your version. */ package javax.swing; import java.awt.Component; -import java.awt.event.ActionListener; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.accessibility.AccessibleContext; /** * <p>Using this class you can easily monitor tasks where you cannot @@ -62,6 +64,12 @@ import java.awt.event.ActionEvent; */ public class ProgressMonitor { + + /** + * The accessible content for this component + */ + protected AccessibleContext accessibleContext; + /** * parentComponent */ @@ -439,5 +447,14 @@ public class ProgressMonitor timestamp = now; } } - + + /** + * Gets the accessible context. + * + * @return the accessible context. + */ + public AccessibleContext getAccessibleContext() + { + return accessibleContext; + } } diff --git a/javax/swing/RepaintManager.java b/javax/swing/RepaintManager.java index 8508996f5..e1416a422 100644 --- a/javax/swing/RepaintManager.java +++ b/javax/swing/RepaintManager.java @@ -47,9 +47,8 @@ import java.awt.Rectangle; import java.awt.Window; import java.awt.image.VolatileImage; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -63,19 +62,20 @@ import java.util.WeakHashMap; * double buffer surface is used by root components to paint * themselves.</p> * - * <p>In general, painting is very confusing in swing. see <a + * <p>See <a * href="http://java.sun.com/products/jfc/tsc/articles/painting/index.html">this * document</a> for more details.</p> * * @author Roman Kennke (kennke@aicas.com) * @author Graydon Hoare (graydon@redhat.com) + * @author Audrius Meskauskas (audriusa@bioinformatics.org) */ public class RepaintManager { /** * The current repaint managers, indexed by their ThreadGroups. */ - private static WeakHashMap currentRepaintManagers; + static WeakHashMap currentRepaintManagers; /** * A rectangle object to be reused in damaged regions calculation. @@ -134,44 +134,6 @@ public class RepaintManager } - /** - * Compares two components using their depths in the component hierarchy. - * A component with a lesser depth (higher level components) are sorted - * before components with a deeper depth (low level components). This is used - * to order paint requests, so that the higher level components are painted - * before the low level components get painted. - * - * @author Roman Kennke (kennke@aicas.com) - */ - private class ComponentComparator implements Comparator - { - - /** - * Compares two components. - * - * @param o1 the first component - * @param o2 the second component - * - * @return a negative integer, if <code>o1</code> is bigger in than - * <code>o2</code>, zero, if both are at the same size and a - * positive integer, if <code>o1</code> is smaller than - * <code>o2</code> - */ - public int compare(Object o1, Object o2) - { - if (o1 instanceof JComponent && o2 instanceof JComponent) - { - JComponent c1 = (JComponent) o1; - Rectangle d1 = (Rectangle) dirtyComponentsWork.get(c1); - JComponent c2 = (JComponent) o2; - Rectangle d2 = (Rectangle) dirtyComponentsWork.get(c2); - return d2.width * d2.height - d1.width * d1.height; - } - throw new ClassCastException("This comparator can only be used with " - + "JComponents"); - } - } - /** * A table storing the dirty regions of components. The keys of this * table are components, the values are rectangles. Each component maps @@ -187,18 +149,13 @@ public class RepaintManager * @see #markCompletelyClean * @see #markCompletelyDirty */ - HashMap dirtyComponents; + private HashMap dirtyComponents; /** * The dirtyComponents which is used in paintDiryRegions to avoid unnecessary * locking. */ - HashMap dirtyComponentsWork; - - /** - * The comparator used for ordered inserting into the repaintOrder list. - */ - private transient Comparator comparator; + private HashMap dirtyComponentsWork; /** * A single, shared instance of the helper class. Any methods which mark @@ -422,6 +379,9 @@ public class RepaintManager { if (w <= 0 || h <= 0 || !component.isShowing()) return; + + Component parent = component.getParent(); + component.computeVisibleRect(rectCache); SwingUtilities.computeIntersection(x, y, w, h, rectCache); @@ -485,8 +445,7 @@ public class RepaintManager public void markCompletelyDirty(JComponent component) { Rectangle r = component.getBounds(); - addDirtyRegion(component, r.x, r.y, r.width, r.height); - component.isCompletelyDirty = true; + addDirtyRegion(component, 0, 0, r.width, r.height); } /** @@ -506,7 +465,6 @@ public class RepaintManager { dirtyComponents.remove(component); } - component.isCompletelyDirty = false; } /** @@ -525,9 +483,13 @@ public class RepaintManager */ public boolean isCompletelyDirty(JComponent component) { - if (! dirtyComponents.containsKey(component)) - return false; - return component.isCompletelyDirty; + boolean retVal = false; + if (dirtyComponents.containsKey(component)) + { + Rectangle dirtyRegion = (Rectangle) dirtyComponents.get(component); + retVal = dirtyRegion.equals(SwingUtilities.getLocalBounds(component)); + } + return retVal; } /** @@ -554,8 +516,8 @@ public class RepaintManager } /** - * Repaint all regions of all components which have been marked dirty in - * the {@link #dirtyComponents} table. + * Repaint all regions of all components which have been marked dirty in the + * {@link #dirtyComponents} table. */ public void paintDirtyRegions() { @@ -571,29 +533,76 @@ public class RepaintManager dirtyComponentsWork = swap; } - ArrayList repaintOrder = new ArrayList(dirtyComponentsWork.size());; - // We sort the components by their size here. This way we have a good - // chance that painting the bigger components also paints the smaller - // components and we don't need to paint them twice. - repaintOrder.addAll(dirtyComponentsWork.keySet()); + // Compile a set of repaint roots. + HashSet repaintRoots = new HashSet(); + Set components = dirtyComponentsWork.keySet(); + for (Iterator i = components.iterator(); i.hasNext();) + { + JComponent dirty = (JComponent) i.next(); + compileRepaintRoots(dirtyComponentsWork, dirty, repaintRoots); + } - if (comparator == null) - comparator = new ComponentComparator(); - Collections.sort(repaintOrder, comparator); repaintUnderway = true; - for (Iterator i = repaintOrder.iterator(); i.hasNext();) + for (Iterator i = repaintRoots.iterator(); i.hasNext();) { JComponent comp = (JComponent) i.next(); - // If a component is marked completely clean in the meantime, then skip - // it. Rectangle damaged = (Rectangle) dirtyComponentsWork.remove(comp); if (damaged == null || damaged.isEmpty()) continue; comp.paintImmediately(damaged); } + dirtyComponentsWork.clear(); repaintUnderway = false; commitRemainingBuffers(); } + + /** + * Compiles a list of components that really get repainted. This is called + * once for each component in the dirtyComponents HashMap, each time with + * another <code>dirty</code> parameter. This searches up the component + * hierarchy of <code>dirty</code> to find the highest parent that is also + * marked dirty and merges the dirty regions. + * + * @param dirtyRegions the dirty regions + * @param dirty the component for which to find the repaint root + * @param roots the list to which new repaint roots get appended + */ + private void compileRepaintRoots(HashMap dirtyRegions, JComponent dirty, + HashSet roots) + { + Component current = dirty; + Component root = dirty; + + // Search the highest component that is also marked dirty. + Component parent; + while (true) + { + parent = current.getParent(); + if (parent == null || !(parent instanceof JComponent)) + break; + + current = parent; + // We can skip to the next up when this parent is not dirty. + if (dirtyRegions.containsKey(parent)) + { + root = current; + } + } + + // Merge the rectangles of the root and the requested component if + // the are different. + if (root != dirty) + { + Rectangle dirtyRect = (Rectangle) dirtyRegions.get(dirty); + dirtyRect = SwingUtilities.convertRectangle(dirty, dirtyRect, root); + Rectangle rootRect = (Rectangle) dirtyRegions.get(root); + SwingUtilities.computeUnion(dirtyRect.x, dirtyRect.y, dirtyRect.width, + dirtyRect.height, rootRect); + } + + // Adds the root to the roots set. + roots.add(root); + } /** * Get an offscreen buffer for painting a component's image. This image diff --git a/javax/swing/SwingUtilities.java b/javax/swing/SwingUtilities.java index b5ef61bd9..212423a66 100644 --- a/javax/swing/SwingUtilities.java +++ b/javax/swing/SwingUtilities.java @@ -1446,4 +1446,157 @@ public class SwingUtilities KeyboardManager km = KeyboardManager.getManager(); return km.processKeyStroke(c, s, ev); } + + /** + * Returns a string representing one of the horizontal alignment codes + * defined in the {@link SwingConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link SwingConstants#CENTER}</td> + * <td><code>"CENTER"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#LEFT}</td> + * <td><code>"LEFT"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#RIGHT}</td> + * <td><code>"RIGHT"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#LEADING}</td> + * <td><code>"LEADING"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#TRAILING}</td> + * <td><code>"TRAILING"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this methods will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertHorizontalAlignmentCodeToString(int code) + { + switch (code) + { + case SwingConstants.CENTER: + return "CENTER"; + case SwingConstants.LEFT: + return "LEFT"; + case SwingConstants.RIGHT: + return "RIGHT"; + case SwingConstants.LEADING: + return "LEADING"; + case SwingConstants.TRAILING: + return "TRAILING"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Returns a string representing one of the vertical alignment codes + * defined in the {@link SwingConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link SwingConstants#CENTER}</td> + * <td><code>"CENTER"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#TOP}</td> + * <td><code>"TOP"</code></td> + * </tr> + * <tr> + * <td>{@link SwingConstants#BOTTOM}</td> + * <td><code>"BOTTOM"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this methods will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertVerticalAlignmentCodeToString(int code) + { + switch (code) + { + case SwingConstants.CENTER: + return "CENTER"; + case SwingConstants.TOP: + return "TOP"; + case SwingConstants.BOTTOM: + return "BOTTOM"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } + + /** + * Returns a string representing one of the default operation codes + * defined in the {@link WindowConstants} interface. The following table + * lists the constants and return values: + * <p> + * <table border="0"> + * <tr> + * <th>Code:</th><th>Returned String:</th> + * </tr> + * <tr> + * <td>{@link WindowConstants#DO_NOTHING_ON_CLOSE}</td> + * <td><code>"DO_NOTHING_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#HIDE_ON_CLOSE}</td> + * <td><code>"HIDE_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#DISPOSE_ON_CLOSE}</td> + * <td><code>"DISPOSE_ON_CLOSE"</code></td> + * </tr> + * <tr> + * <td>{@link WindowConstants#EXIT_ON_CLOSE}</td> + * <td><code>"EXIT_ON_CLOSE"</code></td> + * </tr> + * </table> + * </p> + * If the supplied code is not one of those listed, this method will throw + * an {@link IllegalArgumentException}. + * + * @param code the code. + * + * @return A string representing the given code. + */ + static String convertWindowConstantToString(int code) + { + switch (code) + { + case WindowConstants.DO_NOTHING_ON_CLOSE: + return "DO_NOTHING_ON_CLOSE"; + case WindowConstants.HIDE_ON_CLOSE: + return "HIDE_ON_CLOSE"; + case WindowConstants.DISPOSE_ON_CLOSE: + return "DISPOSE_ON_CLOSE"; + case WindowConstants.EXIT_ON_CLOSE: + return "EXIT_ON_CLOSE"; + default: + throw new IllegalArgumentException("Unrecognised code: " + code); + } + } } diff --git a/javax/swing/TransferHandler.java b/javax/swing/TransferHandler.java index 830feee83..40a36b27d 100644 --- a/javax/swing/TransferHandler.java +++ b/javax/swing/TransferHandler.java @@ -1,5 +1,5 @@ /* TransferHandler.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,12 +38,14 @@ exception statement from your version. */ package javax.swing; +import gnu.classpath.NotImplementedException; + +import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; -import java.awt.Toolkit; import java.io.Serializable; public class TransferHandler implements Serializable @@ -147,42 +149,48 @@ public class TransferHandler implements Serializable this.sourceActions = property != null ? COPY : NONE; } - public boolean canImport (JComponent c, DataFlavor[] flavors) + public boolean canImport(JComponent c, DataFlavor[] flavors) + throws NotImplementedException { return false; } protected Transferable createTransferable(JComponent c) + throws NotImplementedException { return null; } - public void exportAsDrag (JComponent c, InputEvent e, int action) + public void exportAsDrag(JComponent c, InputEvent e, int action) + throws NotImplementedException { // TODO: Implement this properly } - protected void exportDone (JComponent c, Transferable data, int action) + protected void exportDone(JComponent c, Transferable data, int action) + throws NotImplementedException { // TODO: Implement this properly } public void exportToClipboard(JComponent c, Clipboard clip, int action) + throws NotImplementedException { // TODO: Implement this properly } - public int getSourceActions (JComponent c) + public int getSourceActions(JComponent c) { return sourceActions; } - public Icon getVisualRepresentation (Transferable t) + public Icon getVisualRepresentation(Transferable t) { return visualRepresentation; } - public boolean importData (JComponent c, Transferable t) + public boolean importData(JComponent c, Transferable t) + throws NotImplementedException { return false; } diff --git a/javax/swing/WindowConstants.java b/javax/swing/WindowConstants.java index aaa0cb9a3..598a61e14 100644 --- a/javax/swing/WindowConstants.java +++ b/javax/swing/WindowConstants.java @@ -1,5 +1,5 @@ /* WindowConstants.java -- - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,31 +38,42 @@ exception statement from your version. */ package javax.swing; /** - * Defines some constants that are used in Swing's top-level - * containers. - * + * Defines some constants that are used in Swing's top-level containers. See + * the following methods: + * <ul> + * <li>{@link JFrame#setDefaultCloseOperation(int)};</li> + * <li>{@link JInternalFrame#setDefaultCloseOperation(int)};</li> + * <li>{@link JDialog#setDefaultCloseOperation(int)};</li> + * </ul> + * * @author Andrew Selkirk */ public interface WindowConstants { /** - * DO_NOTHING_ON_CLOSE + * Do nothing when the container is closed. */ int DO_NOTHING_ON_CLOSE = 0; /** - * HIDE_ON_CLOSE + * Hide the container when it is closed. */ int HIDE_ON_CLOSE = 1; /** - * DISPOSE_ON_CLOSE + * Dispose the container when it is closed. + * + * @see Window#dispose() */ int DISPOSE_ON_CLOSE = 2; /** - * EXIT_ON_CLOSE + * Exit the application when the container is closed. + * + * @see System#exit(int) + * + * @since 1.4 */ - int EXIT_ON_CLOSE =3; + int EXIT_ON_CLOSE = 3; } diff --git a/javax/swing/border/AbstractBorder.java b/javax/swing/border/AbstractBorder.java index c995de1c2..16bb238c3 100644 --- a/javax/swing/border/AbstractBorder.java +++ b/javax/swing/border/AbstractBorder.java @@ -194,6 +194,6 @@ public abstract class AbstractBorder implements Border, Serializable height -= borderInsets.top + borderInsets.bottom; } - return new Rectangle (x, y, width, height); + return new Rectangle(x, y, width, height); } } diff --git a/javax/swing/border/BevelBorder.java b/javax/swing/border/BevelBorder.java index 403c35c04..5b4761e9e 100644 --- a/javax/swing/border/BevelBorder.java +++ b/javax/swing/border/BevelBorder.java @@ -479,7 +479,7 @@ public class BevelBorder extends AbstractBorder ((highlightOuter == null) || (highlightOuter.getAlpha() == 255)) && ((highlightInner == null) || (highlightInner.getAlpha() == 255)) && ((shadowInner == null) || (shadowInner.getAlpha() == 255)) - && ((shadowOuter == null) ||(shadowOuter.getAlpha() == 255)); + && ((shadowOuter == null) || (shadowOuter.getAlpha() == 255)); } diff --git a/javax/swing/border/CompoundBorder.java b/javax/swing/border/CompoundBorder.java index a69c5e20a..2ee639cf9 100644 --- a/javax/swing/border/CompoundBorder.java +++ b/javax/swing/border/CompoundBorder.java @@ -178,7 +178,7 @@ public class CompoundBorder extends AbstractBorder Insets borderInsets; if (insets == null) - insets = new Insets (0,0,0,0); + insets = new Insets(0, 0, 0, 0); else insets.left = insets.right = insets.top = insets.bottom = 0; @@ -217,7 +217,7 @@ public class CompoundBorder extends AbstractBorder // the implementation from AbstractBorder. However, we want // to be compatible with the API specification, which overrides // the getBorderInsets(Component) method. - return getBorderInsets (c, null); + return getBorderInsets(c, null); } /** @@ -239,7 +239,7 @@ public class CompoundBorder extends AbstractBorder * * @return The inside border (possibly <code>null</code>). */ - public Border getInsideBorder () + public Border getInsideBorder() { return insideBorder; } diff --git a/javax/swing/border/TitledBorder.java b/javax/swing/border/TitledBorder.java index 38b575423..56146e01d 100644 --- a/javax/swing/border/TitledBorder.java +++ b/javax/swing/border/TitledBorder.java @@ -45,11 +45,10 @@ import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Insets; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.LineMetrics; -import java.awt.geom.AffineTransform; +import java.awt.Point; +import java.awt.Rectangle; +import javax.swing.SwingUtilities; import javax.swing.UIManager; @@ -464,191 +463,238 @@ public class TitledBorder extends AbstractBorder public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - Measurements mes = getMeasurements(c); - Font oldFont = g.getFont(); - Color oldColor = g.getColor(); - - /** - * A local helper class for painting the border without changing - * any pixels inside the rectangle of the title text. - */ - class BorderPainter - { - private Component c; - private Border b; - private int x, y, width, height; - - /** - * Constructs a BorderPainter. - * - * @param c the component whose border is being painted. - * @param b the border object. - * @param x the x coordinate of the rectangle delimiting the border. - * @param y the y coordinate of the rectangle delimiting the border. - * @param width the width of the rectangle delimiting the border. - * @param height the width of the rectangle delimiting the border. - */ - public BorderPainter(Component c, Border b, - int x, int y, int width, int height) - { - this.c = c; - this.b = b; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } + Rectangle borderRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING, + width - (EDGE_SPACING * 2), + height - (EDGE_SPACING * 2)); + Point textLoc = new Point(); + + // Save color and font. + Color savedColor = g.getColor(); + Font savedFont = g.getFont(); + + // The font metrics. + Font font = getFont(c); + g.setFont(font); + FontMetrics fm = c.getFontMetrics(font); + + layoutBorderWithTitle(c, fm, borderRect, textLoc); + paintBorderWithTitle(c, g, x, y, width, height, borderRect, textLoc, fm); + + g.setColor(getTitleColor()); + g.drawString(getTitle(), textLoc.x, textLoc.y); + g.setFont(savedFont); + g.setColor(savedColor); + } + /** + * Calculates the bounding box of the inner border and the location of the + * title string. + * + * @param c the component on which to paint the border + * @param fm the font metrics + * @param borderRect output parameter, holds the bounding box of the inner + * border on method exit + * @param textLoc output parameter, holds the location of the title text + * on method exit + */ + private void layoutBorderWithTitle(Component c, FontMetrics fm, + Rectangle borderRect, + Point textLoc) + { + Border b = getBorder(); + + // The font metrics. + int fontHeight = fm.getHeight(); + int fontDescent = fm.getDescent(); + int fontAscent = fm.getAscent(); + int titleWidth = fm.stringWidth(getTitle()); + + // The base insets. + Insets insets; + if (b == null) + insets = new Insets(0, 0, 0, 0); + else + insets = b.getBorderInsets(c); - /** - * Paints the entire border. - */ - public void paint(Graphics g) - { - if (b != null) - b.paintBorder(c, g, x, y, width, height); - } + // The offset of the border rectangle, dependend on the title placement. + int offset; + // Layout border and text vertically. + int titlePosition = getTitlePosition(); + switch (titlePosition) + { + case ABOVE_BOTTOM: + textLoc.y = borderRect.y + borderRect.height - insets.bottom + - fontDescent - TEXT_SPACING; + break; + case BOTTOM: + borderRect.height -= fontHeight / 2; + textLoc.y = borderRect.y + borderRect.height - fontDescent + + (fontAscent + fontDescent - insets.bottom) / 2; + break; + case BELOW_BOTTOM: + borderRect.height -= fontHeight; + textLoc.y = borderRect.y + borderRect.height + fontAscent + + TEXT_SPACING; + break; + case ABOVE_TOP: + offset = fontAscent + fontDescent + + Math.max(EDGE_SPACING, TEXT_SPACING * 2) - EDGE_SPACING; + borderRect.y += offset; + borderRect.height -= offset; + textLoc.y = borderRect.y - (fontDescent + TEXT_SPACING); + break; + case BELOW_TOP: + textLoc.y = borderRect.y + insets.top + fontAscent + TEXT_SPACING; + break; + case TOP: + case DEFAULT_POSITION: + default: + offset = Math.max(0, ((fontAscent / 2) + TEXT_SPACING) - EDGE_SPACING); + borderRect.y += offset; + borderRect.height -= offset; + textLoc.y = borderRect.y - fontDescent + + (insets.top + fontAscent + fontDescent) / 2; + break; + } - /** - * Paints the border, clipping the drawing operation to a - * given rectangular area. - */ - private void paint(Graphics g, - int clipX, int clipY, int clipWidth, int clipHeight) + // Layout border and text horizontally. + int justification = getTitleJustification(); + // Adjust justification for LEADING and TRAILING depending on the direction + // of the component. + if (c.getComponentOrientation().isLeftToRight()) { - Shape oldClip = g.getClip(); - try - { - g.clipRect(clipX, clipY, clipWidth, clipHeight); - paint(g); - } - finally - { - g.setClip(oldClip); - } + if (justification == LEADING || justification == DEFAULT_JUSTIFICATION) + justification = LEFT; + else if (justification == TRAILING) + justification = RIGHT; } - - - /** - * Paints the border without affecting a given rectangular area. - * This is used for painting the border without drawing anything - * underneath the title text. - * - * <p>Since we do not want to introduce unnecessary dependencies - * on Java 2D, we perform the clipping without constructive geometry - * (provided by java.awt.geom.Area). Instead, the border’s - * bounding rectangle is split into smaller parts, which are then - * clipped and painted individually.: - * - * <p><pre> - * +--------------------+ +--------------------+ - * | | | 1 | - * | +--------+ | +---+--------+-------+ - * | | hole | | |====> | 2 | hole | 3 | - * | +--------+ | |---+--------+-------+ - * | | | 4 | - * +--------------------+ +--------------------+</pre> - * - */ - public void paintExcept(Graphics g, - int holeX, int holeY, int holeWidth, int holeHeight) + else { - int stripeHeight; - - stripeHeight = holeY - y; - if (stripeHeight > 0) - paint(g, x, y, width, stripeHeight); // patch #1 in the image above - - stripeHeight = holeHeight; - if (stripeHeight > 0) - { - paint(g, x, holeY, holeX - x, stripeHeight); // patches #2 and #3 - paint(g, holeX + holeWidth, holeY, x + width - (holeX + holeWidth), stripeHeight); - } - - stripeHeight = height - (holeY - y + holeHeight); - if (stripeHeight > 0) - paint(g, x, y + height - stripeHeight, width, stripeHeight); // #4 + if (justification == LEADING || justification == DEFAULT_JUSTIFICATION) + justification = RIGHT; + else if (justification == TRAILING) + justification = LEFT; } - }; - - BorderPainter bp; - int textX, textY, borderWidth, borderHeight; - - borderWidth = width - (mes.outerSpacing.left + mes.outerSpacing.right); - borderHeight = height - (mes.outerSpacing.top + mes.outerSpacing.bottom); - bp = new BorderPainter(c, getBorder(), - x + mes.outerSpacing.left, y + mes.outerSpacing.top, - borderWidth, borderHeight); - switch (getRealTitleJustification(c)) + switch (justification) { - case LEFT: - textX = x + EDGE_SPACING + TEXT_INSET_H; - break; - - case CENTER: - textX = x + (borderWidth - mes.textWidth) / 2; - break; - - case RIGHT: - textX = x + borderWidth - (mes.textWidth + TEXT_INSET_H); - break; - - default: - throw new IllegalStateException(); + case CENTER: + textLoc.x = borderRect.x + (borderRect.width - titleWidth) / 2; + break; + case RIGHT: + textLoc.x = borderRect.x + borderRect.width - titleWidth + - TEXT_INSET_H - insets.right; + break; + case LEFT: + default: + textLoc.x = borderRect.x + TEXT_INSET_H + insets.left; } + } - switch (titlePosition) - { - case ABOVE_TOP: - textY = y + EDGE_SPACING; - break; - - case TOP: - case DEFAULT_POSITION: - default: - textY = y + mes.outerSpacing.top + mes.borderInsets.top - mes.textAscent - + mes.lineHeight; - break; - - case BELOW_TOP: - textY = y + mes.outerSpacing.top + mes.borderInsets.top + TEXT_SPACING; - break; - - case ABOVE_BOTTOM: - textY = y + height - mes.outerSpacing.bottom - mes.borderInsets.bottom - - TEXT_SPACING - (mes.textAscent + mes.textDescent); - break; - - case BOTTOM: - case BELOW_BOTTOM: - textY = y + height - (mes.textAscent + mes.textDescent); - break; - } + /** + * Paints the border with the title. + * + * @param c the component to paint on + * @param g the graphics context used for paintin + * @param x the upper left corner of the whole border + * @param y the upper left corner of the whole border + * @param width the width of the whole border + * @param height the width of the whole border + * @param borderRect the bounding box of the inner border + * @param textLoc the location of the border title + * @param fm the font metrics of the title + */ + private void paintBorderWithTitle(Component c, Graphics g, int x, int y, + int width, int height, + Rectangle borderRect, Point textLoc, + FontMetrics fm) + { + Border b = getBorder(); + int fontDescent = fm.getDescent(); + int fontAscent = fm.getAscent(); + int titleWidth = fm.stringWidth(getTitle()); - if (mes.trimmedText == null) - bp.paint(g); - else - { - try + if (b != null) { - g.setFont(mes.font); - g.setColor(getTitleColor()); - g.drawString(mes.trimmedText, textX, textY + mes.textAscent); + // Paint border in segments, when the title is painted above the + // border. + if (((titlePosition == TOP || titlePosition == DEFAULT_POSITION) + && (borderRect.y > textLoc.y - fontAscent)) + || (titlePosition == BOTTOM + && borderRect.y + borderRect.height < textLoc.y + fontDescent)) + { + Rectangle clip = new Rectangle(); + Rectangle saved = g.getClipBounds(); + + // Paint border left from the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(x, y, textLoc.x - x - 1, + height, clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + // Paint border right from the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(textLoc.x + titleWidth + 1, y, + x + width - (textLoc.x + titleWidth + 1), height, clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + + if (titlePosition == TOP || titlePosition == DEFAULT_POSITION) + { + // Paint border below the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(textLoc.x - 1, + textLoc.y + fontDescent, + titleWidth + 2, + y + height - textLoc.y - fontDescent, + clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + + } + else + { + // Paint border above the text. + clip.setBounds(saved); + SwingUtilities.computeIntersection(textLoc.x - 1, y, + titleWidth + 2, + textLoc.y - fontDescent - y, + clip); + if (! clip.isEmpty()) + { + g.setClip(clip); + b.paintBorder(c, g, borderRect.x, borderRect.y, + borderRect.width, + borderRect.height); + } + + } + g.setClip(saved); + } + else + { + b.paintBorder(c, g, borderRect.x, borderRect.y, borderRect.width, + borderRect.height); + } } - finally - { - g.setFont(oldFont); - g.setColor(oldColor); - } - bp.paintExcept(g, textX, textY, - mes.textWidth, mes.textAscent + mes.textDescent); - } } - - + /** * Measures the width of this border. * @@ -682,7 +728,72 @@ public class TitledBorder extends AbstractBorder */ public Insets getBorderInsets(Component c, Insets insets) { - return getMeasurements(c).getContentInsets(insets); + // Initialize insets with the insets from our border. + Border border = getBorder(); + if (border != null) + { + if (border instanceof AbstractBorder) + { + AbstractBorder aBorder = (AbstractBorder) border; + aBorder.getBorderInsets(c, insets); + } + else + { + Insets i = border.getBorderInsets(c); + insets.top = i.top; + insets.bottom = i.bottom; + insets.left = i.left; + insets.right = i.right; + } + } + else + { + insets.top = 0; + insets.bottom = 0; + insets.left = 0; + insets.right = 0; + } + + // Add spacing. + insets.top += EDGE_SPACING + TEXT_SPACING; + insets.bottom += EDGE_SPACING + TEXT_SPACING; + insets.left += EDGE_SPACING + TEXT_SPACING; + insets.right += EDGE_SPACING + TEXT_SPACING; + + String title = getTitle(); + if (c != null && title != null && !title.equals("")) + { + Font font = getFont(c); + FontMetrics fm = c.getFontMetrics(font); + int ascent = fm.getAscent(); + int descent = fm.getDescent(); + int height = fm.getHeight(); + switch (getTitlePosition()) + { + case ABOVE_BOTTOM: + insets.bottom += ascent + descent + TEXT_SPACING; + break; + case BOTTOM: + insets.bottom += ascent + descent; + break; + case BELOW_BOTTOM: + insets.bottom += height; + break; + case ABOVE_TOP: + insets.top += ascent + descent + + Math.max(EDGE_SPACING, TEXT_SPACING * 2) + - EDGE_SPACING; + break; + case BELOW_TOP: + insets.top += ascent + descent + TEXT_SPACING; + break; + case TOP: + case DEFAULT_POSITION: + default: + insets.top += ascent + descent; + } + } + return insets; } @@ -919,7 +1030,26 @@ public class TitledBorder extends AbstractBorder */ public Dimension getMinimumSize(Component c) { - return getMeasurements(c).getMinimumSize(); + Insets i = getBorderInsets(c); + Dimension minSize = new Dimension(i.left + i.right, i.top + i.bottom); + Font font = getFont(c); + FontMetrics fm = c.getFontMetrics(font); + int titleWidth = fm.stringWidth(getTitle()); + switch (getTitlePosition()) + { + case ABOVE_TOP: + case BELOW_BOTTOM: + minSize.width = Math.max(minSize.width, titleWidth); + break; + case BELOW_TOP: + case ABOVE_BOTTOM: + case TOP: + case BOTTOM: + case DEFAULT_POSITION: + default: + minSize.width += titleWidth; + } + return minSize; } @@ -943,253 +1073,4 @@ public class TitledBorder extends AbstractBorder return new Font("Dialog", Font.PLAIN, 12); } - - /** - * Returns the horizontal alignment of the title text in relation to - * the border, mapping the component-dependent alignment constants - * {@link #LEADING}, {@link #TRAILING} and {@link #DEFAULT_JUSTIFICATION} - * to the correct value according to the embedded component’s - * orientation. - * - * @param c the Component for which this TitledBorder is the border. - * - * @return one of the values {@link #LEFT}, {@link #CENTER}, or {@link - * #RIGHT}. - */ - private int getRealTitleJustification(Component c) - { - switch (titleJustification) - { - case DEFAULT_JUSTIFICATION: - case LEADING: - if ((c == null) || c.getComponentOrientation().isLeftToRight()) - return LEFT; - else - return RIGHT; - - case TRAILING: - if ((c == null) || c.getComponentOrientation().isLeftToRight()) - return RIGHT; - else - return LEFT; - - default: - return titleJustification; - } - } - - - /** - * Performs various measurements for the current state of this TitledBorder - * and the given Component. - * - * @param c the component (<code>null</code> not permitted). - * - * @return Various measurements. - */ - private Measurements getMeasurements(Component c) - { - Measurements m = new Measurements(); - FontMetrics fmet; - - m.font = getFont(c); - fmet = c.getFontMetrics(m.font); - m.border = getBorder(); - if (m.border != null) - m.borderInsets = m.border.getBorderInsets(c); - else - m.borderInsets = new Insets(0, 0, 0, 0); - - if (title != null) - { - m.trimmedText = title.trim(); - if (m.trimmedText.length() == 0) - m.trimmedText = null; - } - - if (m.trimmedText != null) - { - m.textAscent = fmet.getAscent(); - m.textDescent = fmet.getDescent() + fmet.getLeading(); - - FontRenderContext frc = new FontRenderContext(new AffineTransform(), - false, false); - LineMetrics lmet = m.font.getLineMetrics(m.trimmedText, 0, - m.trimmedText.length(), frc); - m.lineHeight = (int) lmet.getStrikethroughOffset(); - - // Fallback in case that LineMetrics is not available/working. - if (m.lineHeight == 0) - m.lineHeight = (int) (0.3333 * (double) m.textAscent); - m.textWidth = fmet.stringWidth(m.trimmedText) + 3; - } - else - { - m.textAscent = 0; - m.textDescent = 0; - } - - m.innerSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING, - EDGE_SPACING); - m.outerSpacing = new Insets(EDGE_SPACING, EDGE_SPACING, EDGE_SPACING, - EDGE_SPACING); - - switch (titlePosition) - { - case ABOVE_TOP: - m.outerSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING; - break; - - case TOP: - m.outerSpacing.top += m.textDescent + m.lineHeight; - m.innerSpacing.top += m.textAscent - m.lineHeight; - break; - - case BELOW_TOP: - m.innerSpacing.top += m.textAscent + m.textDescent + TEXT_SPACING; - break; - - case ABOVE_BOTTOM: - m.innerSpacing.bottom += m.textAscent + m.textDescent + TEXT_SPACING; - break; - - case BOTTOM: - m.innerSpacing.bottom += Math.max(m.textAscent - m.lineHeight, 0); - m.outerSpacing.bottom += m.textDescent + m.lineHeight; - break; - - case BELOW_BOTTOM: - m.outerSpacing.bottom += m.textAscent + m.textDescent; - break; - - default: - m.outerSpacing.top += m.textAscent; - } - - return m; - } - - - /** - * A private helper class for holding the result of measuring the - * distances of a TitledBorder. While it would be possible to cache - * these objects, it does not seem to be worth the effort. Note that - * invalidating the cache would be tricky, especially since there is - * no notification mechanism that would inform the cache when - * border has changed, so it would return different insets. - */ - private static class Measurements - { - /** - * The font used for displaying the title text. Note that it can - * well be that the TitledBorder’s font is <code>null</code>, - * which means that the font is to be retrieved from the current - * LookAndFeel. In this case, this <code>font</code> field will - * contain the result of the retrieval. Therefore, it is safe - * to assume that this <code>font</code> field will never have - * a <code>null</code> value. - */ - Font font; - - - /** - * The number of pixels between the base line and the top of the - * text box. - */ - int textAscent; - - - /** - * The number of pixels between the base line and the bottom of - * the text box. - */ - int textDescent; - - /** - * The number of pixels between the base line and the height where - * a strike-through would be drawn. - */ - int lineHeight; - - /** - * The title text after removing leading and trailing white space - * characters. If the title consists only of white space, the - * value of <code>trimmedText</code> will be <code>null</code>. - */ - String trimmedText; - - - /** - * The width of the trimmed title text in pixels. - */ - int textWidth; - - - /** - * The border that constitutes the interior border - * underneath the title text. - */ - Border border; - - - /** - * The distance between the TitledBorder and the interior border. - */ - Insets outerSpacing; - - /** - * The width of the interior border, as returned by - * <code>border.getBorderInsets()</code>. - */ - Insets borderInsets; - - - /** - * The distance between the interior border and the nested - * Component for which this TitledBorder is a border. - */ - Insets innerSpacing; - - - /** - * Determines the insets of the nested component when it has a - * TitledBorder as its border. Used by {@link - * TitledBorder#getBorderInsets(Component, Insets)}. - * - * @param i an Insets object for storing the results into, or - * <code>null</code> to cause the creation of a - * new instance. - * - * @return the <code>i</code> object, or a new Insets object - * if <code>null</code> was passed for <code>i</code>. - */ - public Insets getContentInsets(Insets i) - { - if (i == null) - i = new Insets(0, 0, 0, 0); - i.left = outerSpacing.left + borderInsets.left + innerSpacing.left; - i.right = outerSpacing.right + borderInsets.right + innerSpacing.right; - i.top = outerSpacing.top + borderInsets.top + innerSpacing.top; - i.bottom = outerSpacing.bottom + borderInsets.bottom + innerSpacing.bottom; - return i; - } - - - /** - * Calculates the minimum size needed for displaying the border - * and its title. Used by {@link TitledBorder#getMinimumSize(Component)}. - * - * @return The minimum size. - */ - public Dimension getMinimumSize() - { - int width; - Insets insets; - - insets = getContentInsets(null); - width = Math.max(insets.left + insets.right, textWidth + 2 - * TEXT_INSET_H); - return new Dimension(width, insets.top + insets.bottom); - } - } } diff --git a/javax/swing/plaf/basic/BasicCheckBoxUI.java b/javax/swing/plaf/basic/BasicCheckBoxUI.java index 14dadb85c..1010139b8 100644 --- a/javax/swing/plaf/basic/BasicCheckBoxUI.java +++ b/javax/swing/plaf/basic/BasicCheckBoxUI.java @@ -1,5 +1,5 @@ /* BasicCheckBoxUI.java - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -38,25 +38,32 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import javax.swing.Icon; +import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +/** + * A UI delegate for the {@link JCheckBox} component. + */ public class BasicCheckBoxUI extends BasicRadioButtonUI { - public static ComponentUI createUI(final JComponent c) { + /** + * Returns a UI delegate (that is, an instance of this class) for the + * specified component. + * + * @param c the component (this should be a {@link JCheckBox}). + * + * @return A new instance of <code>BasicCheckBoxUI</code>. + */ + public static ComponentUI createUI(JComponent c) { return new BasicCheckBoxUI(); } - public Icon getDefaultIcon() - { - return UIManager.getIcon("CheckBox.icon"); - } - /** - * Returns the prefix for entries in the {@link UIManager} defaults table. + * Returns the prefix for entries in the {@link UIManager} defaults table + * (<code>"CheckBox."</code> in this case). * * @return "CheckBox." */ diff --git a/javax/swing/plaf/basic/BasicComboBoxUI.java b/javax/swing/plaf/basic/BasicComboBoxUI.java index 557eea93f..0f0949543 100644 --- a/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Component; import java.awt.Container; @@ -66,12 +64,14 @@ import javax.swing.CellRendererPane; import javax.swing.ComboBoxEditor; import javax.swing.ComboBoxModel; import javax.swing.DefaultListCellRenderer; +import javax.swing.InputMap; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.ListCellRenderer; import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ListDataEvent; import javax.swing.event.ListDataListener; @@ -974,19 +974,23 @@ public class BasicComboBoxUI extends ComboBoxUI * by the look and feel. */ protected void installKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement. + SwingUtilities.replaceUIInputMap(comboBox, + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, + (InputMap) UIManager.get("ComboBox.ancestorInputMap")); + + // Install any action maps here. } - + /** * Uninstalls the keyboard actions for the {@link JComboBox} there were * installed by in {@link #installListeners}. */ protected void uninstallKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement. + SwingUtilities.replaceUIInputMap(comboBox, + JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null); + // Uninstall any action maps here. } /** diff --git a/javax/swing/plaf/basic/BasicComboPopup.java b/javax/swing/plaf/basic/BasicComboPopup.java index d4eabc602..0d822955b 100644 --- a/javax/swing/plaf/basic/BasicComboPopup.java +++ b/javax/swing/plaf/basic/BasicComboPopup.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -294,9 +292,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup * This method uninstalls keyboard actions installed by the UI. */ protected void uninstallKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement + // Nothing to do here. } /** @@ -559,12 +556,11 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup } /** - * DOCUMENT ME! + * Installs the keyboard actions. */ protected void installKeyboardActions() - throws NotImplementedException { - // FIXME: Need to implement + // Nothing to do here } /** diff --git a/javax/swing/plaf/basic/BasicInternalFrameUI.java b/javax/swing/plaf/basic/BasicInternalFrameUI.java index 7ec3aa074..a5f87653f 100644 --- a/javax/swing/plaf/basic/BasicInternalFrameUI.java +++ b/javax/swing/plaf/basic/BasicInternalFrameUI.java @@ -1,5 +1,5 @@ /* BasicInternalFrameUI.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -57,6 +57,7 @@ import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.beans.PropertyVetoException; import javax.swing.DefaultDesktopManager; import javax.swing.DesktopManager; @@ -168,10 +169,9 @@ public class BasicInternalFrameUI extends InternalFrameUI implements SwingConstants { /** - * If true, the cursor is being already shown in the alternative "resize" - * shape. + * The current shape of the cursor. */ - transient boolean showingResizeCursor; + transient int showingCursor; /** FIXME: Use for something. */ protected final int RESIZE_NONE = 0; @@ -187,7 +187,7 @@ public class BasicInternalFrameUI extends InternalFrameUI /** Cache rectangle that can be reused. */ private transient Rectangle cacheRect = new Rectangle(); - + /** * This method is called when the mouse is clicked. * @@ -195,6 +195,20 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void mouseClicked(MouseEvent e) { + // Do minimization/maximization when double-clicking in the title pane. + if (e.getSource() == titlePane && e.getClickCount() == 2) + try + { + if (frame.isMaximizable() && ! frame.isMaximum()) + frame.setMaximum(true); + else if (frame.isMaximum()) + frame.setMaximum(false); + } + catch (PropertyVetoException pve) + { + // We do nothing if the attempt has been vetoed. + } + // There is nothing to do when the mouse is clicked // on the border. } @@ -223,34 +237,34 @@ public class BasicInternalFrameUI extends InternalFrameUI { switch (direction) { - case NORTH: + case Cursor.N_RESIZE_CURSOR: cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height - min.height), b.width, b.height - y); break; - case NORTH_EAST: + case Cursor.NE_RESIZE_CURSOR: cacheRect.setBounds(b.x, Math.min(b.y + y, b.y + b.height - - min.height), x, + - min.height), x + 1, b.height - y); break; - case EAST: - cacheRect.setBounds(b.x, b.y, x, b.height); + case Cursor.E_RESIZE_CURSOR: + cacheRect.setBounds(b.x, b.y, x + 1, b.height); break; - case SOUTH_EAST: - cacheRect.setBounds(b.x, b.y, x, y); + case Cursor.SE_RESIZE_CURSOR: + cacheRect.setBounds(b.x, b.y, x + 1, y + 1); break; - case SOUTH: - cacheRect.setBounds(b.x, b.y, b.width, y); + case Cursor.S_RESIZE_CURSOR: + cacheRect.setBounds(b.x, b.y, b.width, y + 1); break; - case SOUTH_WEST: + case Cursor.SW_RESIZE_CURSOR: cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), - b.y, b.width - x, y); + b.y, b.width - x, y + 1); break; - case WEST: + case Cursor.W_RESIZE_CURSOR: cacheRect.setBounds(Math.min(b.x + x, b.x + b.width - min.width), b.y, b.width - x, b.height); break; - case NORTH_WEST: + case Cursor.NW_RESIZE_CURSOR: cacheRect.setBounds( Math.min(b.x + x, b.x + b.width - min.width), Math.min(b.y + y, b.y + b.height - min.height), @@ -260,6 +274,7 @@ public class BasicInternalFrameUI extends InternalFrameUI dm.resizeFrame(frame, cacheRect.x, cacheRect.y, Math.max(min.width, cacheRect.width), Math.max(min.height, cacheRect.height)); + setCursor(e); } else if (e.getSource() == titlePane) { @@ -277,11 +292,10 @@ public class BasicInternalFrameUI extends InternalFrameUI */ public void mouseExited(MouseEvent e) { - // Reset the cursor shape. - if (showingResizeCursor) + if (showingCursor != Cursor.DEFAULT_CURSOR) { frame.setCursor(Cursor.getDefaultCursor()); - showingResizeCursor = false; + showingCursor = Cursor.DEFAULT_CURSOR; } } @@ -293,53 +307,36 @@ public class BasicInternalFrameUI extends InternalFrameUI public void mouseMoved(MouseEvent e) { // Turn off the resize cursor if we are in the frame header. - if (showingResizeCursor && e.getSource() != frame) + if (showingCursor != Cursor.DEFAULT_CURSOR && e.getSource() != frame) { frame.setCursor(Cursor.getDefaultCursor()); - showingResizeCursor = false; + showingCursor = Cursor.DEFAULT_CURSOR; } else if (e.getSource()==frame && frame.isResizable()) { - int cursor; - switch (sectionOfClick(e.getX(), e.getY())) - { - case NORTH: - cursor = Cursor.N_RESIZE_CURSOR; - break; - case NORTH_EAST: - cursor = Cursor.NE_RESIZE_CURSOR; - break; - case EAST: - cursor = Cursor.E_RESIZE_CURSOR; - break; - case SOUTH_EAST: - cursor = Cursor.SE_RESIZE_CURSOR; - break; - case SOUTH: - cursor = Cursor.S_RESIZE_CURSOR; - break; - case SOUTH_WEST: - cursor = Cursor.SW_RESIZE_CURSOR; - break; - case WEST: - cursor = Cursor.W_RESIZE_CURSOR; - break; - case NORTH_WEST: - cursor = Cursor.NW_RESIZE_CURSOR; - break; - default: - cursor = Cursor.DEFAULT_CURSOR; - } - + setCursor(e); + } + } + + /** + * Set the mouse cursor, how applicable. + * + * @param e the current mouse event. + */ + void setCursor(MouseEvent e) + { + int cursor = sectionOfClick(e.getX(), e.getY()); + if (cursor != showingCursor) + { Cursor resize = Cursor.getPredefinedCursor(cursor); frame.setCursor(resize); - showingResizeCursor = true; + showingCursor = cursor; } } /** * This method is called when the mouse is pressed. - * + * * @param e The MouseEvent. */ public void mousePressed(MouseEvent e) @@ -383,6 +380,8 @@ public class BasicInternalFrameUI extends InternalFrameUI dm.endDraggingFrame(frame); frame.putClientProperty("bufferedDragging", null); } + + setCursor(e); } /** @@ -392,30 +391,31 @@ public class BasicInternalFrameUI extends InternalFrameUI * @param x The x coordinate of the MouseEvent. * @param y The y coordinate of the MouseEvent. * - * @return The direction of the resize (a SwingConstant direction). + * @return The cursor constant, determining the resizing direction. */ private int sectionOfClick(int x, int y) { - Insets insets = frame.getInsets(); Rectangle b = frame.getBounds(); - if (x < insets.left && y < insets.top) - return NORTH_WEST; - else if (x > b.width - insets.right && y < insets.top) - return NORTH_EAST; - else if (x > b.width - insets.right && y > b.height - insets.bottom) - return SOUTH_EAST; - else if (x < insets.left && y > b.height - insets.bottom) - return SOUTH_WEST; - else if (y < insets.top) - return NORTH; - else if (x < insets.left) - return WEST; - else if (y > b.height - insets.bottom) - return SOUTH; - else if (x > b.width - insets.right) - return EAST; - - return -1; + int corner = InternalFrameBorder.cornerSize; + + if (x < corner && y < corner) + return Cursor.NW_RESIZE_CURSOR; + else if (x > b.width - corner && y < corner) + return Cursor.NE_RESIZE_CURSOR; + else if (x > b.width - corner && y > b.height - corner) + return Cursor.SE_RESIZE_CURSOR; + else if (x < corner && y > b.height - corner) + return Cursor.SW_RESIZE_CURSOR; + else if (y < corner) + return Cursor.N_RESIZE_CURSOR; + else if (x < corner) + return Cursor.W_RESIZE_CURSOR; + else if (y > b.height - corner) + return Cursor.S_RESIZE_CURSOR; + else if (x > b.width - corner) + return Cursor.E_RESIZE_CURSOR; + + return Cursor.DEFAULT_CURSOR; } } @@ -992,14 +992,18 @@ public class BasicInternalFrameUI extends InternalFrameUI /** * This helper class is the border for the JInternalFrame. */ - private class InternalFrameBorder extends AbstractBorder implements + class InternalFrameBorder extends AbstractBorder implements UIResource { - /** The width of the border. */ - private static final int bSize = 5; + /** + * The width of the border. + */ + static final int bSize = 5; - /** The size of the corners. */ - private static final int offset = 10; + /** + * The size of the corners (also used by the mouse listener). + */ + static final int cornerSize = 10; /** * This method returns whether the border is opaque. @@ -1069,10 +1073,12 @@ public class BasicInternalFrameUI extends InternalFrameUI g.fillRect(0, y3, b.width, bSize); g.fillRect(x3, 0, bSize, b.height); - g.fill3DRect(0, offset, bSize, b.height - 2 * offset, false); - g.fill3DRect(offset, 0, b.width - 2 * offset, bSize, false); - g.fill3DRect(offset, b.height - bSize, b.width - 2 * offset, bSize, false); - g.fill3DRect(b.width - bSize, offset, bSize, b.height - 2 * offset, false); + g.fill3DRect(0, cornerSize, bSize, b.height - 2 * cornerSize, false); + g.fill3DRect(cornerSize, 0, b.width - 2 * cornerSize, bSize, false); + g.fill3DRect(cornerSize, b.height - bSize, b.width - 2 * cornerSize, + bSize, false); + g.fill3DRect(b.width - bSize, cornerSize, bSize, + b.height - 2 * cornerSize, false); g.translate(-x, -y); g.setColor(saved); diff --git a/javax/swing/plaf/basic/BasicPanelUI.java b/javax/swing/plaf/basic/BasicPanelUI.java index 4f535f653..458f10204 100644 --- a/javax/swing/plaf/basic/BasicPanelUI.java +++ b/javax/swing/plaf/basic/BasicPanelUI.java @@ -1,5 +1,5 @@ /* BasicPanelUI.java - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,33 +44,68 @@ import javax.swing.LookAndFeel; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.PanelUI; +/** + * A UI delegate for the {@link JPanel} component. + */ public class BasicPanelUI extends PanelUI { - public static ComponentUI createUI(JComponent x) + /** + * A UI delegate that can be shared by all panels (because the delegate is + * stateless). + */ + static BasicPanelUI sharedUI; + + /** + * Returns a UI delegate for the specified component. + * + * @param panel the panel. + */ + public static ComponentUI createUI(JComponent panel) { - return new BasicPanelUI(); + if (sharedUI == null) + sharedUI = new BasicPanelUI(); + return sharedUI; } + /** + * Installs this UI delegate in the specified component. + * + * @param c the component (should be a {@link JPanel}, <code>null</code> not + * permitted). + */ public void installUI(JComponent c) { super.installUI(c); if (c instanceof JPanel) { - JPanel p = (JPanel) c; - installDefaults(p); + JPanel p = (JPanel) c; + installDefaults(p); } } + /** + * Installs the defaults for this UI delegate in the specified panel. + * + * @param p the panel (<code>null</code> not permitted). + */ protected void installDefaults(JPanel p) { LookAndFeel.installColorsAndFont(p, "Panel.background", "Panel.foreground", "Panel.font"); + + // A test against the reference implementation shows that this method will + // install a border if one is defined in the UIDefaults table (even though + // the BasicLookAndFeel doesn't actually define a "Panel.border"). This + // test was written after discovering that a null argument to + // uninstallDefaults throws a NullPointerException in + // LookAndFeel.uninstallBorder()... + LookAndFeel.installBorder(p, "Panel.border"); } /** - * Uninstalls this UI from the JPanel. + * Uninstalls this UI delegate from the specified component. * - * @param c the JPanel from which to uninstall this UI + * @param c the component (<code>null</code> not permitted). */ public void uninstallUI(JComponent c) { @@ -78,13 +113,20 @@ public class BasicPanelUI extends PanelUI } /** - * Uninstalls the UI defaults that have been install through - * {@link #installDefaults}. + * Uninstalls the UI defaults for the specified panel. * - * @param p the panel from which to uninstall the UI defaults + * @param p the panel (<code>null</code> not permitted). */ protected void uninstallDefaults(JPanel p) { - // Nothing to do here. + // Tests on the reference implementation showed this method: + // (1) doesn't actually remove the installed colors and font installed + // by installDefaults(), it isn't necessary; + // (2) throws a NullPointerException in LookAndFeel.uninstallBorder() if + // p is null. Strangely, no border is installed by the + // BasicLookAndFeel - perhaps this is needed by another LAF? + + LookAndFeel.uninstallBorder(p); } + } diff --git a/javax/swing/plaf/basic/BasicRadioButtonUI.java b/javax/swing/plaf/basic/BasicRadioButtonUI.java index a66fa28e6..64a1deca5 100644 --- a/javax/swing/plaf/basic/BasicRadioButtonUI.java +++ b/javax/swing/plaf/basic/BasicRadioButtonUI.java @@ -1,5 +1,5 @@ /* BasicRadioButtonUI.java - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -167,9 +167,8 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI } if (text != null) paintText(g, b, tr, text); - // TODO: Figure out what is the size parameter? if (b.hasFocus() && b.isFocusPainted() && m.isEnabled()) - paintFocus(g, tr, null); + paintFocus(g, tr, c.getSize()); } /** @@ -177,9 +176,8 @@ public class BasicRadioButtonUI extends BasicToggleButtonUI * * @param g the graphics context * @param tr the rectangle for the text label - * @param size the size (??) + * @param size the size of the <code>JRadioButton</code> component. */ - // TODO: Figure out what for is the size parameter. protected void paintFocus(Graphics g, Rectangle tr, Dimension size) { Color focusColor = UIManager.getColor(getPropertyPrefix() + ".focus"); diff --git a/javax/swing/plaf/basic/BasicSliderUI.java b/javax/swing/plaf/basic/BasicSliderUI.java index 137ab55a6..0569768a6 100644 --- a/javax/swing/plaf/basic/BasicSliderUI.java +++ b/javax/swing/plaf/basic/BasicSliderUI.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; @@ -70,6 +68,7 @@ import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.LookAndFeel; +import javax.swing.RepaintManager; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; @@ -209,9 +208,9 @@ public class BasicSliderUI extends SliderUI * @param e A {@link FocusEvent}. */ public void focusGained(FocusEvent e) - throws NotImplementedException { - // FIXME: implement. + slider.repaint(); + hasFocus = true; } /** @@ -221,9 +220,9 @@ public class BasicSliderUI extends SliderUI * @param e A {@link FocusEvent}. */ public void focusLost(FocusEvent e) - throws NotImplementedException { - // FIXME: implement. + slider.repaint(); + hasFocus = false; } } @@ -592,6 +591,9 @@ public class BasicSliderUI extends SliderUI /** The focus color. */ private transient Color focusColor; + + /** True if the slider has focus. */ + private transient boolean hasFocus; /** * Creates a new Basic look and feel Slider UI. @@ -1548,9 +1550,11 @@ public class BasicSliderUI extends SliderUI paintTicks(g); if (slider.getPaintLabels()) paintLabels(g); - - //FIXME: Paint focus. + paintThumb(g); + + if (hasFocus) + paintFocus(g); } /** @@ -1602,7 +1606,7 @@ public class BasicSliderUI extends SliderUI Color saved_color = g.getColor(); g.setColor(getFocusColor()); - + g.drawRect(focusRect.x, focusRect.y, focusRect.width, focusRect.height); g.setColor(saved_color); @@ -1989,7 +1993,7 @@ public class BasicSliderUI extends SliderUI public void paintThumb(Graphics g) { Color saved_color = g.getColor(); - + Point a = new Point(thumbRect.x, thumbRect.y); Point b = new Point(a); Point c = new Point(a); @@ -1997,11 +2001,11 @@ public class BasicSliderUI extends SliderUI Point e = new Point(a); Polygon bright; - Polygon light; // light shadow - Polygon dark; // dark shadow + Polygon light; // light shadow + Polygon dark; // dark shadow Polygon all; - // This will be in X-dimension if the slider is inverted and y if it isn't. + // This will be in X-dimension if the slider is inverted and y if it isn't. int turnPoint; if (slider.getOrientation() == JSlider.HORIZONTAL) @@ -2016,13 +2020,15 @@ public class BasicSliderUI extends SliderUI bright = new Polygon(new int[] { b.x - 1, a.x, e.x, d.x }, new int[] { b.y, a.y, e.y, d.y }, 4); - dark = new Polygon(new int[] { b.x, c.x, d.x + 1 }, - new int[] { b.y, c.y - 1, d.y }, 3); - - light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 }, - new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3); - - all = new Polygon(new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 }, + dark = new Polygon(new int[] { b.x, c.x, d.x + 1 }, new int[] { b.y, + c.y - 1, + d.y }, 3); + + light = new Polygon(new int[] { b.x - 1, c.x - 1, d.x + 1 }, + new int[] { b.y + 1, c.y - 1, d.y - 1 }, 3); + + all = new Polygon( + new int[] { a.x + 1, b.x - 2, c.x - 2, d.x, e.x + 1 }, new int[] { a.y + 1, b.y + 1, c.y - 1, d.y - 1, e.y }, 5); } @@ -2038,15 +2044,16 @@ public class BasicSliderUI extends SliderUI bright = new Polygon(new int[] { c.x - 1, b.x, a.x, e.x }, new int[] { c.y - 1, b.y, a.y, e.y - 1 }, 4); - dark = new Polygon(new int[] { c.x, d.x, e.x }, - new int[] { c.y, d.y, e.y }, 3); + dark = new Polygon(new int[] { c.x, d.x, e.x }, new int[] { c.y, d.y, + e.y }, 3); - light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1}, - new int[] { c.y, d.y - 1, e.y - 1}, 3); - all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, - e.x + 1 }, - new int[] { a.y + 1, b.y + 1, c.y - 1, c.y, d.y - 2, - e.y - 2 }, 6); + light = new Polygon(new int[] { c.x - 1, d.x, e.x + 1 }, + new int[] { c.y, d.y - 1, e.y - 1 }, 3); + all = new Polygon(new int[] { a.x + 1, b.x, c.x - 2, c.x - 2, d.x, + e.x + 1 }, new int[] { a.y + 1, b.y + 1, + c.y - 1, c.y, + d.y - 2, e.y - 2 }, + 6); } g.setColor(Color.WHITE); @@ -2057,7 +2064,7 @@ public class BasicSliderUI extends SliderUI g.setColor(Color.GRAY); g.drawPolyline(light.xpoints, light.ypoints, light.npoints); - + g.setColor(Color.LIGHT_GRAY); g.drawPolyline(all.xpoints, all.ypoints, all.npoints); g.fillPolygon(all); diff --git a/javax/swing/plaf/basic/BasicTableHeaderUI.java b/javax/swing/plaf/basic/BasicTableHeaderUI.java index cfbebda21..ce8846ff8 100644 --- a/javax/swing/plaf/basic/BasicTableHeaderUI.java +++ b/javax/swing/plaf/basic/BasicTableHeaderUI.java @@ -199,10 +199,7 @@ public class BasicTableHeaderUI extends TableHeaderUI */ public void mouseExited(MouseEvent e) { - if (header.getResizingColumn() != null && header.getResizingAllowed()) - endResizing(); - if (header.getDraggedColumn() != null && header.getReorderingAllowed()) - endDragging(null); + // Nothing to do. } /** @@ -363,25 +360,20 @@ public class BasicTableHeaderUI extends TableHeaderUI 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; + draggingHeaderRect = null; TableColumnModel model = header.getColumnModel(); // Find where have we dragged the column. int x = e.getX(); int p = 0; - int col = - 1; + + int col = model.getColumnCount()-1; int n = model.getColumnCount(); + // This loop does not find the column if the mouse if out of the + // right boundary of the table header. Then we make this column the + // rightmost column. Scan: for (int i = 0; i < n; i++) { p += model.getColumn(i).getWidth(); @@ -391,8 +383,8 @@ public class BasicTableHeaderUI extends TableHeaderUI break Scan; } } - if (col >= 0) - header.getTable().moveColumn(draggingColumnNumber, col); + + header.getTable().moveColumn(draggingColumnNumber, col); } } diff --git a/javax/swing/plaf/basic/BasicTableUI.java b/javax/swing/plaf/basic/BasicTableUI.java index ef491cbf1..64638b45a 100644 --- a/javax/swing/plaf/basic/BasicTableUI.java +++ b/javax/swing/plaf/basic/BasicTableUI.java @@ -428,7 +428,6 @@ public class BasicTableUI extends TableUI table.setSelectionForeground(UIManager.getColor("Table.selectionForeground")); table.setSelectionBackground(UIManager.getColor("Table.selectionBackground")); table.setOpaque(true); - rendererPane = new CellRendererPane(); } protected void installKeyboardActions() @@ -1188,6 +1187,9 @@ public class BasicTableUI extends TableUI public void installUI(JComponent comp) { table = (JTable)comp; + rendererPane = new CellRendererPane(); + table.add(rendererPane); + installDefaults(); installKeyboardActions(); installListeners(); @@ -1197,7 +1199,11 @@ public class BasicTableUI extends TableUI { uninstallListeners(); uninstallKeyboardActions(); - uninstallDefaults(); + uninstallDefaults(); + + table.remove(rendererPane); + rendererPane = null; + table = null; } /** @@ -1257,7 +1263,6 @@ public class BasicTableUI extends TableUI } Rectangle bounds = table.getCellRect(r0, c0, false); - // The left boundary of the area being repainted. int left = bounds.x; @@ -1278,9 +1283,9 @@ public class BasicTableUI extends TableUI bounds.x += widths[c] + columnMargin; } bounds.x = left; - bounds.y += table.getRowHeight(r) + rowMargin; + bounds.y += table.getRowHeight(r); // Update row height for tables with custom heights. - bounds.height = table.getRowHeight(r + 1); + bounds.height = table.getRowHeight(r + 1) - rowMargin; } bottom = bounds.y - rowMargin; @@ -1311,7 +1316,7 @@ public class BasicTableUI extends TableUI { // The horizontal grid is draw below the cells, so we // add before drawing. - y += table.getRowHeight(r) + rowMargin; + y += table.getRowHeight(r);// + rowMargin; gfx.drawLine(left, y, p2.x, y); } gfx.setColor(save); diff --git a/javax/swing/plaf/basic/BasicTextUI.java b/javax/swing/plaf/basic/BasicTextUI.java index 3b620f049..6fa37af5c 100644 --- a/javax/swing/plaf/basic/BasicTextUI.java +++ b/javax/swing/plaf/basic/BasicTextUI.java @@ -38,8 +38,6 @@ exception statement from your version. */ package javax.swing.plaf.basic; -import gnu.classpath.NotImplementedException; - import java.awt.Color; import java.awt.Container; import java.awt.Dimension; @@ -831,9 +829,9 @@ public abstract class BasicTextUI extends TextUI * this UI. */ protected void uninstallKeyboardActions() - throws NotImplementedException { - // FIXME: Uninstall keyboard actions here. + SwingUtilities.replaceUIInputMap(textComponent, JComponent.WHEN_FOCUSED, null); + SwingUtilities.replaceUIActionMap(textComponent, null); } /** diff --git a/javax/swing/plaf/basic/BasicToggleButtonUI.java b/javax/swing/plaf/basic/BasicToggleButtonUI.java index 896ea0c89..921648670 100644 --- a/javax/swing/plaf/basic/BasicToggleButtonUI.java +++ b/javax/swing/plaf/basic/BasicToggleButtonUI.java @@ -1,5 +1,5 @@ /* BasicToggleButtonUI.java - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -44,21 +44,35 @@ import java.awt.Rectangle; import javax.swing.AbstractButton; import javax.swing.JComponent; +import javax.swing.JToggleButton; import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +/** + * A UI delegate for the {@link JToggleButton} component. + */ public class BasicToggleButtonUI extends BasicButtonUI { - public static ComponentUI createUI(final JComponent component) + + /** + * Returns a UI delegate for the specified component. + * + * @param component the component (should be an instance of + * {@link JToggleButton}). + * + * @return An instance of <code>BasicToggleButtonUI</code>. + */ + public static ComponentUI createUI(JComponent component) { return new BasicToggleButtonUI(); } /** - * Returns the prefix for the UI defaults property for this UI class. - * This is 'ToggleButton' for this class. + * Returns the prefix for entries in the {@link UIManager} defaults table + * (<code>"ToggleButton."</code> in this case). * - * @return the prefix for the UI defaults property + * @return <code>"ToggleButton."</code> */ protected String getPropertyPrefix() { @@ -89,15 +103,10 @@ public class BasicToggleButtonUI extends BasicButtonUI else vr = SwingUtilities.getLocalBounds(b); String text = SwingUtilities.layoutCompoundLabel(c, g.getFontMetrics(f), - b.getText(), - currentIcon(b), - b.getVerticalAlignment(), - b.getHorizontalAlignment(), - b.getVerticalTextPosition(), - b.getHorizontalTextPosition(), - vr, ir, tr, - b.getIconTextGap() - + defaultTextShiftOffset); + b.getText(), currentIcon(b), b.getVerticalAlignment(), + b.getHorizontalAlignment(), b.getVerticalTextPosition(), + b.getHorizontalTextPosition(), vr, ir, tr, b.getIconTextGap() + + defaultTextShiftOffset); if ((b.getModel().isArmed() && b.getModel().isPressed()) || b.isSelected()) diff --git a/javax/swing/plaf/basic/BasicToolBarUI.java b/javax/swing/plaf/basic/BasicToolBarUI.java index 80fec6a77..eabac1570 100644 --- a/javax/swing/plaf/basic/BasicToolBarUI.java +++ b/javax/swing/plaf/basic/BasicToolBarUI.java @@ -1,5 +1,5 @@ /* BasicToolBarUI.java -- - Copyright (C) 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -75,11 +75,12 @@ import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.Border; -import javax.swing.border.EtchedBorder; +import javax.swing.border.CompoundBorder; import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.ToolBarUI; import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicBorders.ButtonBorder; /** * This is the Basic Look and Feel UI class for JToolBar. @@ -310,8 +311,19 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createNonRolloverBorder() { - return new EtchedBorder(); - } + Border b = UIManager.getBorder("ToolBar.nonrolloverBorder"); + + if (b == null) + { + b = new CompoundBorder( + new ButtonBorder(UIManager.getColor("Button.shadow"), + UIManager.getColor("Button.darkShadow"), + UIManager.getColor("Button.light"), + UIManager.getColor("Button.highlight")), + BasicBorders.getMarginBorder()); + } + + return b; } /** * This method creates a new PropertyChangeListener for the JToolBar. @@ -331,18 +343,19 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected Border createRolloverBorder() { - return new EtchedBorder() + Border b = UIManager.getBorder("ToolBar.rolloverBorder"); + + if (b == null) { - public void paintBorder(Component c, Graphics g, int x, int y, - int width, int height) - { - if (c instanceof JButton) - { - if (((JButton) c).getModel().isRollover()) - super.paintBorder(c, g, x, y, width, height); - } - } - }; + b = new CompoundBorder( + new ButtonBorder(UIManager.getColor("Button.shadow"), + UIManager.getColor("Button.darkShadow"), + UIManager.getColor("Button.light"), + UIManager.getColor("Button.highlight")), + BasicBorders.getMarginBorder()); + } + + return b; } /** @@ -745,6 +758,7 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants * @param direction The direction to give focus to. */ protected void navigateFocusedComp(int direction) + throws NotImplementedException { // FIXME: Implement. } @@ -761,6 +775,10 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants { AbstractButton b = (AbstractButton) c; b.setRolloverEnabled(false); + + // Save old border in hashtable. + borders.put(b, b.getBorder()); + b.setBorder(nonRolloverBorder); } } @@ -772,11 +790,11 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected void setBorderToNormal(Component c) { - if (c instanceof JButton) + if (c instanceof AbstractButton) { - JButton b = (JButton) c; - Border border = (Border) borders.get(b); - b.setBorder(border); + AbstractButton b = (AbstractButton) c; + b.setRolloverEnabled(true); + b.setBorder((Border) borders.remove(b)); } } @@ -787,11 +805,15 @@ public class BasicToolBarUI extends ToolBarUI implements SwingConstants */ protected void setBorderToRollover(Component c) { - if (c instanceof JButton) + if (c instanceof AbstractButton) { - JButton b = (JButton) c; - b.setRolloverEnabled(true); - b.setBorder(rolloverBorder); + AbstractButton b = (AbstractButton) c; + b.setRolloverEnabled(false); + + // Save old border in hashtable. + borders.put(b, b.getBorder()); + + b.setBorder(rolloverBorder); } } diff --git a/javax/swing/plaf/basic/BasicTreeUI.java b/javax/swing/plaf/basic/BasicTreeUI.java index 48ad1b93d..df8fbd01d 100644 --- a/javax/swing/plaf/basic/BasicTreeUI.java +++ b/javax/swing/plaf/basic/BasicTreeUI.java @@ -38,6 +38,7 @@ package javax.swing.plaf.basic; +import gnu.classpath.NotImplementedException; import gnu.javax.swing.tree.GnuPath; import java.awt.Color; @@ -251,6 +252,9 @@ public class BasicTreeUI /** The max height of the nodes in the tree. */ int maxHeight = 0; + + /** The hash color. */ + Color hashColor; /** Listeners */ PropertyChangeListener propertyChangeListener; @@ -279,6 +283,11 @@ public class BasicTreeUI * not the double mouse click) on the selected tree node. */ Timer startEditTimer; + + /** + * The zero size icon, used for expand controls, if they are not visible. + */ + static Icon nullIcon; /** * The special value of the mouse event is sent indicating that this is not @@ -331,7 +340,7 @@ public class BasicTreeUI */ protected Color getHashColor() { - return UIManager.getColor("Tree.hash"); + return hashColor; } /** @@ -341,8 +350,7 @@ public class BasicTreeUI */ protected void setHashColor(Color color) { - // FIXME: Putting something in the UIDefaults map is certainly wrong. - UIManager.put("Tree.hash", color); + hashColor = color; } /** @@ -673,6 +681,20 @@ public class BasicTreeUI treeState.setRowHeight(maxHeight); return maxHeight; } + + /** + * Get the tree node icon. + */ + Icon getNodeIcon(TreePath path) + { + Object node = path.getLastPathComponent(); + if (treeModel.isLeaf(node)) + return UIManager.getIcon("Tree.leafIcon"); + else if (treeState.getExpandedState(path)) + return UIManager.getIcon("Tree.openIcon"); + else + return UIManager.getIcon("Tree.closedIcon"); + } /** * Returns the path for passed in row. If row is not visible null is returned. @@ -800,6 +822,7 @@ public class BasicTreeUI * default/listeners have been installed. */ protected void prepareForUIInstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -809,6 +832,7 @@ public class BasicTreeUI * installed. */ protected void completeUIInstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -818,6 +842,7 @@ public class BasicTreeUI * uninstalled. */ protected void completeUIUninstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -1132,14 +1157,10 @@ public class BasicTreeUI protected void updateRenderer() { if (tree != null) - { - if (tree.getCellRenderer() == null) - { - if (currentCellRenderer == null) - currentCellRenderer = createDefaultCellRenderer(); - tree.setCellRenderer(currentCellRenderer); - } - } + currentCellRenderer = tree.getCellRenderer(); + + if (currentCellRenderer == null) + currentCellRenderer = createDefaultCellRenderer(); } /** @@ -1206,6 +1227,7 @@ public class BasicTreeUI rightChildIndent = UIManager.getInt("Tree.rightChildIndent"); leftChildIndent = UIManager.getInt("Tree.leftChildIndent"); + totalChildIndent = rightChildIndent + leftChildIndent; setRowHeight(UIManager.getInt("Tree.rowHeight")); tree.setRowHeight(getRowHeight()); tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand")); @@ -1332,10 +1354,11 @@ public class BasicTreeUI treeSelectionModel = tree.getSelectionModel(); setRootVisible(tree.isRootVisible()); treeState.setRootVisible(tree.isRootVisible()); + updateExpandedDescendants(new TreePath(new Object[] { treeModel.getRoot() })); completeUIInstall(); } - + /** * Uninstall the defaults for the tree */ @@ -1785,7 +1808,9 @@ public class BasicTreeUI * the event. */ protected boolean isToggleEvent(MouseEvent event) + throws NotImplementedException { + // FIXME: Not implemented. return true; } @@ -1968,6 +1993,7 @@ public class BasicTreeUI * @param e the event that occurs when moving the component */ public void componentMoved(ComponentEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -1977,6 +2003,7 @@ public class BasicTreeUI * the bounds */ protected void startTimer() + throws NotImplementedException { // TODO: Implement this properly. } @@ -1987,7 +2014,9 @@ public class BasicTreeUI * @return JScrollPane housing the JTree, or null if one isn't found. */ protected JScrollPane getScrollPane() + throws NotImplementedException { + // FIXME: Not implemented. return null; } @@ -1998,6 +2027,7 @@ public class BasicTreeUI * @param ae is the action performed */ public void actionPerformed(ActionEvent ae) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2080,7 +2110,7 @@ public class BasicTreeUI { repaintLeadRow(); } - + /** * Repaint the lead row. */ @@ -2122,6 +2152,7 @@ public class BasicTreeUI * @param e the key typed */ public void keyTyped(KeyEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2132,6 +2163,7 @@ public class BasicTreeUI * @param e the key pressed */ public void keyPressed(KeyEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2142,6 +2174,7 @@ public class BasicTreeUI * @param e the key released */ public void keyReleased(KeyEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2271,6 +2304,7 @@ public class BasicTreeUI * @param e is the mouse event that occured */ public void mouseDragged(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2282,6 +2316,7 @@ public class BasicTreeUI * @param e the mouse event that occured */ public void mouseMoved(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2292,6 +2327,7 @@ public class BasicTreeUI * @param e is the mouse event that occured */ public void mouseReleased(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2332,6 +2368,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseClicked(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2342,6 +2379,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mousePressed(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2352,6 +2390,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseReleased(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2362,6 +2401,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseEntered(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2372,6 +2412,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseExited(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2385,6 +2426,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseDragged(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2396,6 +2438,7 @@ public class BasicTreeUI * @param e mouse event that occured */ public void mouseMoved(MouseEvent e) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2404,6 +2447,7 @@ public class BasicTreeUI * Removes event from the source */ protected void removeFromSource() + throws NotImplementedException { // TODO: Implement this properly. } @@ -2450,10 +2494,11 @@ public class BasicTreeUI if (s != null) { + TreePath path = treeState.getPathForRow(row); size.x = getRowX(row, depth); size.width = SwingUtilities.computeStringWidth(fm, s); - size.width = size.width + getCurrentControlIcon(null).getIconWidth() - + gap; + size.width = size.width + getCurrentControlIcon(path).getIconWidth() + + gap + getNodeIcon(path).getIconWidth(); size.height = getMaxHeight(tree); size.y = size.height * row; } @@ -2468,8 +2513,7 @@ public class BasicTreeUI */ protected int getRowX(int row, int depth) { - int iw = getCurrentControlIcon(null).getIconWidth(); - return depth * (rightChildIndent + iw/2); + return BasicTreeUI.this.getRowX(row, depth); } }// NodeDimensionsHandler @@ -2540,6 +2584,7 @@ public class BasicTreeUI * the property that has changed. */ public void propertyChange(PropertyChangeEvent event) + throws NotImplementedException { // TODO: What should be done here, if anything? } @@ -2556,6 +2601,7 @@ public class BasicTreeUI * Constructor */ public TreeCancelEditingAction(String name) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2566,6 +2612,7 @@ public class BasicTreeUI * @param e event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2576,6 +2623,7 @@ public class BasicTreeUI * @return true if the action is enabled, false otherwise */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly. return false; @@ -2606,6 +2654,8 @@ public class BasicTreeUI { validCachedPreferredSize = false; treeState.setExpandedState(event.getPath(), true); + // The maximal cell height may change + maxHeight = 0; tree.revalidate(); tree.repaint(); } @@ -2619,6 +2669,8 @@ public class BasicTreeUI { validCachedPreferredSize = false; treeState.setExpandedState(event.getPath(), false); + // The maximal cell height may change + maxHeight = 0; tree.revalidate(); tree.repaint(); } @@ -2642,6 +2694,7 @@ public class BasicTreeUI * @param name is the name of the direction */ public TreeHomeAction(int direction, String name) + throws NotImplementedException { // TODO: Implement this properly } @@ -2652,6 +2705,7 @@ public class BasicTreeUI * @param e is the event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly } @@ -2662,6 +2716,7 @@ public class BasicTreeUI * @return true if the action is enabled. */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly return false; @@ -2686,6 +2741,7 @@ public class BasicTreeUI * @param name is the name of the direction */ public TreeIncrementAction(int direction, String name) + throws NotImplementedException { // TODO: Implement this properly } @@ -2775,6 +2831,7 @@ public class BasicTreeUI * @return true if the action is enabled. */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly return false; @@ -2891,6 +2948,7 @@ public class BasicTreeUI * @param e is the event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2901,7 +2959,9 @@ public class BasicTreeUI * @return true if the action is enabled. */ public boolean isEnabled() + throws NotImplementedException { + // FIXME: Not implemented. return false; } }// TreePageAction @@ -2973,6 +3033,7 @@ public class BasicTreeUI * @param e the event that occured */ public void actionPerformed(ActionEvent e) + throws NotImplementedException { // TODO: Implement this properly. } @@ -2983,7 +3044,9 @@ public class BasicTreeUI * @return true if the action is enabled, false otherwise */ public boolean isEnabled() + throws NotImplementedException { + // FIXME: Not implemented. return false; } } // TreeToggleAction @@ -3067,6 +3130,7 @@ public class BasicTreeUI * @return true if the action is enabled, false otherwise */ public boolean isEnabled() + throws NotImplementedException { // TODO: Implement this properly return false; @@ -3094,9 +3158,35 @@ public class BasicTreeUI */ Icon getCurrentControlIcon(TreePath path) { - if (tree.isExpanded(path)) - return expandedIcon; - return collapsedIcon; + if (hasControlIcons()) + { + if (tree.isExpanded(path)) + return expandedIcon; + else + return collapsedIcon; + } + else + { + if (nullIcon == null) + nullIcon = new Icon() + { + public int getIconHeight() + { + return 0; + } + + public int getIconWidth() + { + return 0; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + // No action here. + } + }; + return nullIcon; + } } /** @@ -3323,10 +3413,8 @@ public class BasicTreeUI { if (row != 0) { - Icon icon = getCurrentControlIcon(path); - int iconW = icon.getIconWidth(); paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, - bounds.x - iconW/2 - gap, bounds.x - gap); + bounds.x - leftChildIndent - gap, bounds.x - gap); } } @@ -3379,15 +3467,13 @@ public class BasicTreeUI paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf); - TreeCellRenderer dtcr = tree.getCellRenderer(); - if (dtcr == null) - dtcr = createDefaultCellRenderer(); + TreeCellRenderer dtcr = currentCellRenderer; boolean focused = false; - if (treeSelectionModel!= null) - focused = treeSelectionModel.getLeadSelectionRow() == row - && tree.isFocusOwner(); - + if (treeSelectionModel != null) + focused = treeSelectionModel.getLeadSelectionRow() == row + && tree.isFocusOwner(); + Component c = dtcr.getTreeCellRendererComponent(tree, node, selected, isExpanded, isLeaf, row, focused); @@ -3399,6 +3485,7 @@ public class BasicTreeUI * Prepares for the UI to uninstall. */ protected void prepareForUIUninstall() + throws NotImplementedException { // TODO: Implement this properly. } @@ -3440,4 +3527,14 @@ public class BasicTreeUI editingComponent = null; tree.requestFocus(); } + + /** + * Returns the amount to indent the given row + * + * @return amount to indent the given row. + */ + protected int getRowX(int row, int depth) + { + return depth * totalChildIndent; + } } // BasicTreeUI diff --git a/javax/swing/plaf/metal/MetalBorders.java b/javax/swing/plaf/metal/MetalBorders.java index 98a00ee0a..7c41180ae 100644 --- a/javax/swing/plaf/metal/MetalBorders.java +++ b/javax/swing/plaf/metal/MetalBorders.java @@ -103,7 +103,16 @@ public class MetalBorders private static BasicBorders.MarginBorder marginBorder; /** - * A border used for {@link JButton} components. + * <p>A border used for {@link JButton} components.</p> + * + * <p>This {@link Border} implementation can handle only instances of + * {@link AbstractButton} and their subclasses.</p> + * + * <p>If the Metal Look and Feel's current theme is 'Ocean' the border + * will be painted with a special highlight when the mouse cursor if + * over the button (ie. the property <code>rollover</code> of the + * button's model is <code>true</code>) and is not a <b>direct</b> + * child of a {@link JToolBar}.</p> */ public static class ButtonBorder extends AbstractBorder implements UIResource { @@ -157,8 +166,14 @@ public class MetalBorders { ButtonModel bmodel = null; + // The RI will fail with a ClassCastException in such a situation. + // This code tries to be more helpful. if (c instanceof AbstractButton) bmodel = ((AbstractButton) c).getModel(); + else + throw new IllegalStateException("A ButtonBorder is supposed to work " + + "only with AbstractButton and" + + "subclasses."); Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); Color shadow = MetalLookAndFeel.getControlShadow(); @@ -191,7 +206,7 @@ public class MetalBorders { // The normal border. This is used when the button is not // pressed or the button is not armed. - if (! (bmodel.isPressed() && bmodel.isArmed()) ) + if (! (bmodel.isPressed() && bmodel.isArmed())) { // draw light border g.setColor(light); @@ -246,8 +261,14 @@ public class MetalBorders { ButtonModel bmodel = null; + // The RI will fail with a ClassCastException in such a situation. + // This code tries to be more helpful. if (c instanceof AbstractButton) bmodel = ((AbstractButton) c).getModel(); + else + throw new IllegalStateException("A ButtonBorder is supposed to work " + + "only with AbstractButton and" + + "subclasses."); Color darkShadow = MetalLookAndFeel.getControlDarkShadow(); Color shadow = MetalLookAndFeel.getControlShadow(); @@ -267,8 +288,10 @@ public class MetalBorders g.drawRect(x, y, w - 1, h - 1); g.drawRect(x + 1, y + 1, w - 3, h - 3); } - else if (bmodel.isRollover()) + else if (bmodel.isRollover() && !(c.getParent() instanceof JToolBar)) { + // Paint a bigger border when the mouse is over the button but + // only if it is *not* part of a JToolBar. g.setColor(shadow); g.drawRect(x, y, w - 1, h - 1); g.drawRect(x + 2, y + 2, w - 5, h - 5); @@ -568,12 +591,12 @@ public class MetalBorders { boolean enabledTextBorder; if (c instanceof JTextComponent) - { - JTextComponent tc = (JTextComponent) c; - enabledTextBorder = tc.isEnabled() && tc.isEditable(); - } + { + JTextComponent tc = (JTextComponent) c; + enabledTextBorder = tc.isEnabled() && tc.isEditable(); + } else - enabledTextBorder = false; + enabledTextBorder = false; if (enabledTextBorder) super.paintBorder(c, g, x, y, w, h); @@ -829,35 +852,36 @@ public class MetalBorders { Color dark = MetalLookAndFeel.getPrimaryControlDarkShadow(); Color light = MetalLookAndFeel.getPrimaryControlHighlight(); - if (c instanceof JMenu) { - JMenu menu = (JMenu) c; - if (menu.isSelected()) + if (c instanceof JMenu) { - g.setColor(dark); - g.drawLine(x, y, x, y + h); - g.drawLine(x, y, x + w, y); - g.drawLine(x + w - 2, y + 1, x + w - 2, y + h); - g.setColor(light); - g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); + JMenu menu = (JMenu) c; + if (menu.isSelected()) + { + g.setColor(dark); + g.drawLine(x, y, x, y + h); + g.drawLine(x, y, x + w, y); + g.drawLine(x + w - 2, y + 1, x + w - 2, y + h); + g.setColor(light); + g.drawLine(x + w - 1, y + 1, x + w - 1, y + h); + } } - } else if (c instanceof JMenuItem) - { - JMenuItem item = (JMenuItem) c; - if (item.isArmed()) - { - g.setColor(dark); - g.drawLine(x, y, x + w, y); - g.setColor(light); - g.drawLine(x, y + h - 1, x + w, y + h - 1); - } - else - { - // Normally we draw a light line on the left. - g.setColor(light); - g.drawLine(x, y, x, y + h); - } - } + { + JMenuItem item = (JMenuItem) c; + if (item.isArmed()) + { + g.setColor(dark); + g.drawLine(x, y, x + w, y); + g.setColor(light); + g.drawLine(x, y + h - 1, x + w, y + h - 1); + } + else + { + // Normally we draw a light line on the left. + g.setColor(light); + g.drawLine(x, y, x, y + h); + } + } } /** @@ -1469,8 +1493,8 @@ public class MetalBorders { Border outer = new ButtonBorder(); Border inner = getMarginBorder(); - buttonBorder = new BorderUIResource.CompoundBorderUIResource - (outer, inner); + buttonBorder = new BorderUIResource.CompoundBorderUIResource(outer, + inner); } return buttonBorder; } @@ -1488,8 +1512,8 @@ public class MetalBorders { Border outer = new ToggleButtonBorder(); Border inner = getMarginBorder(); - toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource - (outer, inner); + toggleButtonBorder = new BorderUIResource.CompoundBorderUIResource( + outer, inner); } return toggleButtonBorder; } diff --git a/javax/swing/plaf/metal/MetalButtonUI.java b/javax/swing/plaf/metal/MetalButtonUI.java index 83cd33662..d6cc1bc07 100644 --- a/javax/swing/plaf/metal/MetalButtonUI.java +++ b/javax/swing/plaf/metal/MetalButtonUI.java @@ -39,6 +39,7 @@ exception statement from your version. */ package javax.swing.plaf.metal; import java.awt.Color; +import java.awt.Container; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; @@ -48,7 +49,9 @@ import javax.swing.AbstractButton; import javax.swing.ButtonModel; import javax.swing.JButton; import javax.swing.JComponent; +import javax.swing.JToolBar; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; @@ -121,7 +124,8 @@ public class MetalButtonUI * * @return A new instance of <code>MetalButtonUI</code>. */ - public static ComponentUI createUI(JComponent c) { + public static ComponentUI createUI(JComponent c) + { return new MetalButtonUI(); } @@ -187,7 +191,8 @@ public class MetalButtonUI * @param iconRect the icon bounds. */ protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, - Rectangle textRect, Rectangle iconRect) { + Rectangle textRect, Rectangle iconRect) + { if (b.isEnabled() && b.hasFocus() && b.isFocusPainted()) { Color savedColor = g.getColor(); @@ -235,19 +240,63 @@ public class MetalButtonUI public void update(Graphics g, JComponent c) { AbstractButton b = (AbstractButton) c; - ButtonModel m = b.getModel(); if (b.isContentAreaFilled() && (UIManager.get(getPropertyPrefix() + "gradient") != null) - && ! m.isPressed() && ! m.isArmed() && b.isEnabled() && (b.getBackground() instanceof UIResource)) + updateWidthGradient(g, b, b.getParent()); + else + super.update(g, c); + } + + private void updateWidthGradient(Graphics g, AbstractButton b, Container parent) + { + ButtonModel m = b.getModel(); + String gradientPropertyName = getPropertyPrefix() + "gradient"; + + // Gradient painting behavior depends on whether the button is part of a + // JToolBar. + if (parent instanceof JToolBar) + { + if (! m.isPressed() && ! m.isArmed()) + { + if (m.isRollover()) + { + // Paint the gradient when the mouse cursor hovers over the + // button but is not pressed down. + MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(), + SwingConstants.VERTICAL, + gradientPropertyName); + } + else + { + // If mouse does not hover over the button let the JToolBar + // paint itself at the location where the button is (the button + // is transparent). + + // There where cases where the button was not repainted and + // therefore showed its old state. With this statement it does + // not happen. + b.repaint(); + + Rectangle area = new Rectangle(); + SwingUtilities.calculateInnerArea(b, area); + SwingUtilities.convertRectangle(b, area, b.getParent()); + b.getParent().repaint(area.x, area.y, area.width, area.height); + } + } + + } + else if (! m.isPressed() && ! m.isArmed()) { - MetalUtils.paintGradient(g, 0, 0, c.getWidth(), c.getHeight(), + // When the button is not part of a JToolBar just paint itself with a + // gradient and everything is fine. + MetalUtils.paintGradient(g, 0, 0, b.getWidth(), b.getHeight(), SwingConstants.VERTICAL, - getPropertyPrefix() + "gradient"); - paint(g, c); + gradientPropertyName); } - else - super.update(g, c); + + paint(g, b); } + } diff --git a/javax/swing/plaf/metal/MetalCheckBoxUI.java b/javax/swing/plaf/metal/MetalCheckBoxUI.java index b4f6f0a56..c7941642e 100644 --- a/javax/swing/plaf/metal/MetalCheckBoxUI.java +++ b/javax/swing/plaf/metal/MetalCheckBoxUI.java @@ -52,7 +52,7 @@ public class MetalCheckBoxUI // FIXME: maybe replace by a Map of instances when this becomes stateful /** The shared UI instance for JCheckBoxes. */ - private static MetalCheckBoxUI instance = null; + private static MetalCheckBoxUI instance; /** * Constructs a new instance of MetalCheckBoxUI. diff --git a/javax/swing/plaf/metal/MetalComboBoxButton.java b/javax/swing/plaf/metal/MetalComboBoxButton.java index 3787a98c3..6a528de2b 100644 --- a/javax/swing/plaf/metal/MetalComboBoxButton.java +++ b/javax/swing/plaf/metal/MetalComboBoxButton.java @@ -256,9 +256,8 @@ public class MetalComboBoxButton { ListCellRenderer renderer = comboBox.getRenderer(); boolean pressed = this.getModel().isPressed(); - Component comp= renderer.getListCellRendererComponent(listBox, - comboBox.getSelectedItem(), - -1, false, false); + Component comp = renderer.getListCellRendererComponent(listBox, + comboBox.getSelectedItem(), -1, false, false); comp.setFont(rendererPane.getFont()); if (model.isArmed() && model.isPressed()) { diff --git a/javax/swing/plaf/metal/MetalComboBoxIcon.java b/javax/swing/plaf/metal/MetalComboBoxIcon.java index f21c5af61..944ce3944 100644 --- a/javax/swing/plaf/metal/MetalComboBoxIcon.java +++ b/javax/swing/plaf/metal/MetalComboBoxIcon.java @@ -48,7 +48,8 @@ import javax.swing.Icon; /** * An icon used by the {@link MetalComboBoxUI} class. */ -public class MetalComboBoxIcon implements Icon, Serializable { +public class MetalComboBoxIcon implements Icon, Serializable +{ /** * Creates a new icon. diff --git a/javax/swing/plaf/metal/MetalFileChooserUI.java b/javax/swing/plaf/metal/MetalFileChooserUI.java index cb94c87b8..1219ad9fd 100644 --- a/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -52,12 +52,13 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import java.text.NumberFormat; - import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; - import java.io.File; +import java.sql.Date; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.List; import javax.swing.AbstractAction; import javax.swing.AbstractListModel; @@ -79,7 +80,6 @@ import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JToggleButton; -import javax.swing.JViewport; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; @@ -94,12 +94,6 @@ import javax.swing.plaf.basic.BasicFileChooserUI; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; -import java.sql.Date; - -import java.text.DateFormat; - -import java.util.List; - /** * A UI delegate for the {@link JFileChooser} component. This class is only @@ -350,7 +344,7 @@ public class MetalFileChooserUI setDirectorySelected(false); File currentDirectory = filechooser.getCurrentDirectory(); setDirectory(currentDirectory); - boolean hasParent = (currentDirectory.getParentFile() != null); + boolean hasParent = currentDirectory.getParentFile() != null; getChangeToParentDirectoryAction().setEnabled(hasParent); } @@ -648,15 +642,15 @@ public class MetalFileChooserUI FileView v = getFileView(getFileChooser()); File f = (File) value; if (f != null) - { - setText(v.getName(f)); - setIcon(v.getIcon(f)); - } + { + setText(v.getName(f)); + setIcon(v.getIcon(f)); + } else - { - setText(""); - setIcon(null); - } + { + setText(""); + setIcon(null); + } setOpaque(true); if (isSelected) { @@ -962,10 +956,9 @@ public class MetalFileChooserUI { String text = editField.getText(); if (text != null && text != "" && !text.equals(fc.getName(editFile))) - if (editFile.renameTo - (fc.getFileSystemView().createFileObject - (fc.getCurrentDirectory(), text))) - rescanCurrentDirectory(fc); + if (editFile.renameTo(fc.getFileSystemView().createFileObject( + fc.getCurrentDirectory(), text))) + rescanCurrentDirectory(fc); list.remove(editField); } startEditing = false; @@ -1018,7 +1011,7 @@ public class MetalFileChooserUI JFileChooser fc; /** The last selected file. */ - Object lastSelected = null; + Object lastSelected; /** * Stores the current file that is being edited. @@ -1032,10 +1025,8 @@ public class MetalFileChooserUI /** * Creates a new listener. * - * @param table - * the directory/file table - * @param fc - * the JFileChooser + * @param table the directory/file table + * @param fc the JFileChooser */ public TableClickListener(JTable table, JFileChooser fc) { @@ -1051,8 +1042,7 @@ public class MetalFileChooserUI /** * Receives notification of a mouse click event. * - * @param e - * the event. + * @param e the event. */ public void mouseClicked(MouseEvent e) { @@ -1156,10 +1146,9 @@ public class MetalFileChooserUI { String text = editField.getText(); if (text != null && text != "" && !text.equals(fc.getName(editFile))) - if (editFile.renameTo - (fc.getFileSystemView().createFileObject - (fc.getCurrentDirectory(), text))) - rescanCurrentDirectory(fc); + if (editFile.renameTo(fc.getFileSystemView().createFileObject( + fc.getCurrentDirectory(), text))) + rescanCurrentDirectory(fc); table.remove(editField); } startEditing = false; @@ -1636,8 +1625,7 @@ public class MetalFileChooserUI /** * Formats bytes into the appropriate size. * - * @param bytes - - * the number of bytes to convert + * @param bytes the number of bytes to convert * @return a string representation of the size */ private String formatSize(long bytes) @@ -1838,7 +1826,7 @@ public class MetalFileChooserUI /** * Updates the current directory. * - * @param the file chooser to update. + * @param fc the file chooser to update. */ public void rescanCurrentDirectory(JFileChooser fc) { @@ -1966,7 +1954,8 @@ public class MetalFileChooserUI * * @param component the component. */ - public void removeLayoutComponent(Component component) { + public void removeLayoutComponent(Component component) + { // do nothing } } @@ -2072,7 +2061,8 @@ public class MetalFileChooserUI * * @param component the component. */ - public void removeLayoutComponent(Component component) { + public void removeLayoutComponent(Component component) + { // do nothing } } diff --git a/javax/swing/plaf/metal/MetalIconFactory.java b/javax/swing/plaf/metal/MetalIconFactory.java index d24a05262..4e4c863c9 100644 --- a/javax/swing/plaf/metal/MetalIconFactory.java +++ b/javax/swing/plaf/metal/MetalIconFactory.java @@ -617,7 +617,8 @@ public class MetalIconFactory implements Serializable * * @return The width of the icon. */ - public int getIconWidth() { + public int getIconWidth() + { return 16; } diff --git a/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java b/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java index f74828e56..dd0c48639 100644 --- a/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java +++ b/javax/swing/plaf/metal/MetalInternalFrameTitlePane.java @@ -95,7 +95,7 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane String propName = e.getPropertyName(); if (e.getPropertyName().equals(JInternalFrame.FRAME_ICON_PROPERTY)) { - title.setIcon( frame.getFrameIcon() ); + title.setIcon(frame.getFrameIcon()); } else if (propName.equals("JInternalFrame.isPalette")) { @@ -387,8 +387,8 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane paintPalette(g); else { - paintTitleBackground(g); - paintChildren(g); + paintTitleBackground(g); + paintChildren(g); Dimension d = getSize(); if (frame.isSelected()) g.setColor(MetalLookAndFeel.getPrimaryControlDarkShadow()); @@ -421,7 +421,8 @@ public class MetalInternalFrameTitlePane extends BasicInternalFrameTitlePane endX = Math.max(closeButton.getX(), endX); endX -= 7; if (endX > startX) - MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, getHeight() - 6, Color.white, Color.gray); + MetalUtils.fillMetalPattern(this, g, startX, 3, endX - startX, + getHeight() - 6, Color.white, Color.gray); } g.setColor(savedColor); } diff --git a/javax/swing/plaf/metal/MetalLookAndFeel.java b/javax/swing/plaf/metal/MetalLookAndFeel.java index d7cd9ab24..73b0a64bd 100644 --- a/javax/swing/plaf/metal/MetalLookAndFeel.java +++ b/javax/swing/plaf/metal/MetalLookAndFeel.java @@ -67,7 +67,7 @@ import javax.swing.plaf.basic.BasicLookAndFeel; * }</pre> */ public class MetalLookAndFeel extends BasicLookAndFeel -{ +{ private static final long serialVersionUID = 6680646159193457980L; /** The current theme. */ @@ -888,11 +888,9 @@ public class MetalLookAndFeel extends BasicLookAndFeel "CheckBox.font", new FontUIResource("Dialog", Font.BOLD, 12), "CheckBox.foreground", getControlTextColor(), "CheckBox.icon", - new UIDefaults.ProxyLazyValue - ("javax.swing.plaf.metal.MetalCheckBoxIcon"), + new UIDefaults.ProxyLazyValue("javax.swing.plaf.metal.MetalCheckBoxIcon"), "CheckBox.checkIcon", - new UIDefaults.ProxyLazyValue - ("javax.swing.plaf.metal.MetalCheckBoxIcon"), + new UIDefaults.ProxyLazyValue("javax.swing.plaf.metal.MetalCheckBoxIcon"), "Checkbox.select", getControlShadow(), "CheckBoxMenuItem.acceleratorFont", new FontUIResource("Dialog", Font.PLAIN, 10), @@ -964,7 +962,7 @@ public class MetalLookAndFeel extends BasicLookAndFeel "FileChooser.detailsViewIcon", MetalIconFactory.getFileChooserDetailViewIcon(), "FileChooser.fileNameLabelMnemonic", new Integer(78), - "FileChooser.filesOfTypeLabelMnemonic",new Integer(84), + "FileChooser.filesOfTypeLabelMnemonic", new Integer(84), "FileChooser.lookInLabelMnemonic", new Integer(73), "FileView.computerIcon", MetalIconFactory.getTreeComputerIcon(), "FileView.directoryIcon", MetalIconFactory.getTreeFolderIcon(), @@ -1273,6 +1271,8 @@ public class MetalLookAndFeel extends BasicLookAndFeel "ToolBar.light", getControlHighlight(), "ToolBar.shadow", getControlShadow(), "ToolBar.border", new MetalBorders.ToolBarBorder(), + "ToolBar.rolloverBorder", MetalBorders.getToolbarButtonBorder(), + "ToolBar.nonrolloverBorder", MetalBorders.getToolbarButtonBorder(), "ToolTip.background", getPrimaryControl(), "ToolTip.backgroundInactive", getControl(), diff --git a/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java b/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java index 44a2d3bcd..7c580f90f 100644 --- a/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java +++ b/javax/swing/plaf/metal/MetalPopupMenuSeparatorUI.java @@ -51,7 +51,7 @@ public class MetalPopupMenuSeparatorUI // FIXME: maybe replace by a Map of instances when this becomes stateful /** The shared UI instance for MetalPopupMenuSeparatorUIs */ - private static MetalPopupMenuSeparatorUI instance = null; + private static MetalPopupMenuSeparatorUI instance; /** * Constructs a new instance of <code>MetalPopupMenuSeparatorUI</code>. diff --git a/javax/swing/plaf/metal/MetalRadioButtonUI.java b/javax/swing/plaf/metal/MetalRadioButtonUI.java index 9fb960f68..046e4942e 100644 --- a/javax/swing/plaf/metal/MetalRadioButtonUI.java +++ b/javax/swing/plaf/metal/MetalRadioButtonUI.java @@ -1,5 +1,5 @@ /* MetalRadioButtonUI.java - Copyright (C) 2005 Free Software Foundation, Inc. + Copyright (C) 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -95,9 +95,10 @@ public class MetalRadioButtonUI public void installDefaults(AbstractButton b) { super.installDefaults(b); - disabledTextColor = UIManager.getColor("RadioButton.disabledText"); - focusColor = UIManager.getColor("RadioButton.focus"); - selectColor = UIManager.getColor("RadioButton.select"); + String prefix = getPropertyPrefix(); + disabledTextColor = UIManager.getColor(prefix + "disabledText"); + focusColor = UIManager.getColor(prefix + "focus"); + selectColor = UIManager.getColor(prefix + "select"); } /** diff --git a/javax/swing/plaf/metal/MetalRootPaneUI.java b/javax/swing/plaf/metal/MetalRootPaneUI.java index 6cabc7e86..eaee5bf92 100644 --- a/javax/swing/plaf/metal/MetalRootPaneUI.java +++ b/javax/swing/plaf/metal/MetalRootPaneUI.java @@ -958,7 +958,7 @@ public class MetalRootPaneUI /** * The shared UI instance for MetalRootPaneUIs. */ - private static MetalRootPaneUI instance = null; + private static MetalRootPaneUI instance; /** * Constructs a shared instance of <code>MetalRootPaneUI</code>. diff --git a/javax/swing/plaf/metal/MetalScrollBarUI.java b/javax/swing/plaf/metal/MetalScrollBarUI.java index c7dfd11e4..75f2750ae 100644 --- a/javax/swing/plaf/metal/MetalScrollBarUI.java +++ b/javax/swing/plaf/metal/MetalScrollBarUI.java @@ -90,14 +90,14 @@ public class MetalScrollBarUI extends BasicScrollBarUI if (e.getPropertyName().equals(FREE_STANDING_PROP)) { Boolean prop = (Boolean) e.getNewValue(); - isFreeStanding = (prop == null ? true : prop.booleanValue()); - if (increaseButton != null) - increaseButton.setFreeStanding(isFreeStanding); - if (decreaseButton != null) - decreaseButton.setFreeStanding(isFreeStanding); + isFreeStanding = prop == null ? true : prop.booleanValue(); + if (increaseButton != null) + increaseButton.setFreeStanding(isFreeStanding); + if (decreaseButton != null) + decreaseButton.setFreeStanding(isFreeStanding); } else - super.propertyChange(e); + super.propertyChange(e); } } @@ -167,7 +167,7 @@ public class MetalScrollBarUI extends BasicScrollBarUI // createDecreaseButton() are called (unless there is somewhere earlier // that we can do this). Boolean prop = (Boolean) scrollbar.getClientProperty(FREE_STANDING_PROP); - isFreeStanding = (prop == null ? true : prop.booleanValue()); + isFreeStanding = prop == null ? true : prop.booleanValue(); scrollBarShadowColor = UIManager.getColor("ScrollBar.shadow"); super.installDefaults(); } @@ -401,7 +401,7 @@ public class MetalScrollBarUI extends BasicScrollBarUI { g.drawLine(x, y, x + w - 1, y); g.drawLine(x, y, x, y + h - 1); - g.drawLine(x + w - 1, y, x + w - 1, y + h -1); + g.drawLine(x + w - 1, y, x + w - 1, y + h - 1); } // then the highlight diff --git a/javax/swing/plaf/metal/MetalSeparatorUI.java b/javax/swing/plaf/metal/MetalSeparatorUI.java index 1d48e9be2..6d7818f8b 100644 --- a/javax/swing/plaf/metal/MetalSeparatorUI.java +++ b/javax/swing/plaf/metal/MetalSeparatorUI.java @@ -58,7 +58,7 @@ public class MetalSeparatorUI // FIXME: maybe replace by a Map of instances when this becomes stateful /** The shared UI instance for MetalSeparatorUIs */ - private static MetalSeparatorUI instance = null; + private static MetalSeparatorUI instance; /** * Constructs a new instance of <code>MetalSeparatorUI</code>. diff --git a/javax/swing/plaf/metal/MetalSliderUI.java b/javax/swing/plaf/metal/MetalSliderUI.java index f97717f31..0f824418c 100644 --- a/javax/swing/plaf/metal/MetalSliderUI.java +++ b/javax/swing/plaf/metal/MetalSliderUI.java @@ -192,10 +192,13 @@ public class MetalSliderUI extends BasicSliderUI */ public void paintThumb(Graphics g) { + Color save = g.getColor(); + g.setColor(thumbColor); if (slider.getOrientation() == JSlider.HORIZONTAL) horizThumbIcon.paintIcon(slider, g, thumbRect.x, thumbRect.y); else vertThumbIcon.paintIcon(slider, g, thumbRect.x, thumbRect.y); + g.setColor(save); } /** @@ -229,9 +232,9 @@ public class MetalSliderUI extends BasicSliderUI if (slider.isEnabled()) { int xPos = xPositionForValue(slider.getValue()); - int x = (slider.getInverted() ? xPos : trackRect.x); - int w = (slider.getInverted() ? trackX + trackW - xPos - : xPos - trackRect.x); + int x = slider.getInverted() ? xPos : trackRect.x; + int w = slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x; g.setColor(MetalLookAndFeel.getWhite()); g.drawLine(x + 1, trackY + 1, x + w - 3, trackY + 1); g.setColor(UIManager.getColor("Slider.altTrackColor")); @@ -245,9 +248,9 @@ public class MetalSliderUI extends BasicSliderUI else if (filledSlider) { int xPos = xPositionForValue(slider.getValue()); - int x = (slider.getInverted() ? xPos : trackRect.x); - int w = (slider.getInverted() ? trackX + trackW - xPos - : xPos - trackRect.x); + int x = slider.getInverted() ? xPos : trackRect.x; + int w = slider.getInverted() ? trackX + trackW - xPos + : xPos - trackRect.x; g.setColor(MetalLookAndFeel.getControlShadow()); g.fillRect(x + 1, trackY + 1, w - 3, getTrackWidth() - 3); if (slider.isEnabled()) @@ -280,9 +283,9 @@ public class MetalSliderUI extends BasicSliderUI if (slider.isEnabled()) { int yPos = yPositionForValue(slider.getValue()); - int y = (slider.getInverted() ? trackY : yPos); - int h = (slider.getInverted() ? yPos - trackY - : trackY + trackH - yPos); + int y = slider.getInverted() ? trackY : yPos; + int h = slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos; g.setColor(MetalLookAndFeel.getWhite()); g.drawLine(trackX + 1, y + 1, trackX + 1, y + h - 3); @@ -297,9 +300,9 @@ public class MetalSliderUI extends BasicSliderUI else if (filledSlider) { int yPos = yPositionForValue(slider.getValue()); - int y = (slider.getInverted() ? trackY : yPos); - int h = (slider.getInverted() ? yPos - trackY - : trackY + trackH - yPos); + int y = slider.getInverted() ? trackY : yPos; + int h = slider.getInverted() ? yPos - trackY + : trackY + trackH - yPos; g.setColor(MetalLookAndFeel.getControlShadow()); g.fillRect(trackX + 1, y + 1, getTrackWidth() - 3, h - 3); if (slider.isEnabled()) @@ -323,7 +326,8 @@ public class MetalSliderUI extends BasicSliderUI */ public void paintFocus(Graphics g) { - // do nothing as focus is shown by different color on thumb control + thumbColor = getFocusColor(); + paintThumb(g); } /** @@ -368,8 +372,8 @@ public class MetalSliderUI extends BasicSliderUI */ protected int getTrackLength() { - return (slider.getOrientation() == JSlider.HORIZONTAL - ? tickRect.width : tickRect.height); + return slider.getOrientation() == JSlider.HORIZONTAL + ? tickRect.width : tickRect.height; } /** diff --git a/javax/swing/plaf/metal/MetalSplitPaneDivider.java b/javax/swing/plaf/metal/MetalSplitPaneDivider.java index 9c592bd51..ba4e314f3 100644 --- a/javax/swing/plaf/metal/MetalSplitPaneDivider.java +++ b/javax/swing/plaf/metal/MetalSplitPaneDivider.java @@ -42,7 +42,6 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; @@ -159,8 +158,8 @@ class MetalSplitPaneDivider extends BasicSplitPaneDivider if ((c1 instanceof BasicArrowButton) && (c2 instanceof BasicArrowButton)) { - lb = ((BasicArrowButton) c1); - rb = ((BasicArrowButton) c2); + lb = (BasicArrowButton) c1; + rb = (BasicArrowButton) c2; } } if (rb != null && lb != null) diff --git a/javax/swing/plaf/metal/MetalTabbedPaneUI.java b/javax/swing/plaf/metal/MetalTabbedPaneUI.java index 39dec3d66..c49abe832 100644 --- a/javax/swing/plaf/metal/MetalTabbedPaneUI.java +++ b/javax/swing/plaf/metal/MetalTabbedPaneUI.java @@ -607,11 +607,11 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI } else { - if (isOcean && tabIndex == tabPane.getSelectedIndex()+ 1) + if (isOcean && tabIndex == tabPane.getSelectedIndex() + 1) { g.setColor(oceanSelectedBorder); } - if (tabIndex != tabRuns[runCount- 1]) + if (tabIndex != tabRuns[runCount - 1]) { g.drawLine(0, 0, 0, bottom); } @@ -856,7 +856,7 @@ public class MetalTabbedPaneUI extends BasicTabbedPaneUI // run directly above the content or the selected tab is not visible, // then we draw an unbroken line. if (tabPlacement != TOP || selectedIndex < 0 - || rect.y + rect.height + 1 < y || rect.x < x ||rect.x > x + w) + || rect.y + rect.height + 1 < y || rect.x < x || rect.x > x + w) { g.drawLine(x, y, x + w - 2, y); if (isOcean && tabPlacement == TOP) diff --git a/javax/swing/plaf/metal/MetalToolTipUI.java b/javax/swing/plaf/metal/MetalToolTipUI.java index f183ed5a1..d1040347f 100644 --- a/javax/swing/plaf/metal/MetalToolTipUI.java +++ b/javax/swing/plaf/metal/MetalToolTipUI.java @@ -75,7 +75,7 @@ public class MetalToolTipUI public static final int padSpaceBetweenStrings = 12; /** The shared UI instance. */ - private static MetalToolTipUI instance = null; + private static MetalToolTipUI instance; /** A flag controlling the visibility of the accelerator (if there is one). */ private boolean isAcceleratorHidden; @@ -256,8 +256,8 @@ public class MetalToolTipUI g.setColor(acceleratorForeground); fm = t.getFontMetrics(acceleratorFont); int width = fm.stringWidth(acceleratorString); - g.drawString(acceleratorString, vr.x + vr.width - width - padSpaceBetweenStrings/2, - vr.y + vr.height - fm.getDescent()); + g.drawString(acceleratorString, vr.x + vr.width - width + - padSpaceBetweenStrings / 2, vr.y + vr.height - fm.getDescent()); } g.setColor(saved); diff --git a/javax/swing/plaf/metal/MetalUtils.java b/javax/swing/plaf/metal/MetalUtils.java index 03617aa40..72cbb34a6 100644 --- a/javax/swing/plaf/metal/MetalUtils.java +++ b/javax/swing/plaf/metal/MetalUtils.java @@ -104,7 +104,7 @@ class MetalUtils else g.setColor(dark); - for (int mX = x + (xOff); mX < (x + w); mX += 4) + for (int mX = x + xOff; mX < (x + w); mX += 4) { g.drawLine(mX, mY, mX, mY); } diff --git a/javax/swing/plaf/multi/MultiComboBoxUI.java b/javax/swing/plaf/multi/MultiComboBoxUI.java index 05279d7d6..33b432152 100644 --- a/javax/swing/plaf/multi/MultiComboBoxUI.java +++ b/javax/swing/plaf/multi/MultiComboBoxUI.java @@ -357,7 +357,8 @@ public class MultiComboBoxUI extends ComboBoxUI * @param c the component. * @param visible the visible state. */ - public void setPopupVisible(JComboBox c, boolean visible) { + public void setPopupVisible(JComboBox c, boolean visible) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -376,7 +377,8 @@ public class MultiComboBoxUI extends ComboBoxUI * * @return The result for the UI delegate from the primary look and feel. */ - public boolean isPopupVisible(JComboBox c) { + public boolean isPopupVisible(JComboBox c) + { boolean result = false; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -406,7 +408,8 @@ public class MultiComboBoxUI extends ComboBoxUI * UI delegate in the primary look and feel, and <code>false</code> * otherwise. */ - public boolean isFocusTraversable(JComboBox c) { + public boolean isFocusTraversable(JComboBox c) + { boolean result = false; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/plaf/multi/MultiFileChooserUI.java b/javax/swing/plaf/multi/MultiFileChooserUI.java index 6f8826010..719f04374 100644 --- a/javax/swing/plaf/multi/MultiFileChooserUI.java +++ b/javax/swing/plaf/multi/MultiFileChooserUI.java @@ -364,7 +364,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The filter returned by the UI delegate from the primary * look and feel. */ - public FileFilter getAcceptAllFileFilter(JFileChooser chooser) { + public FileFilter getAcceptAllFileFilter(JFileChooser chooser) + { FileFilter result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -393,7 +394,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The view returned by the UI delegate from the primary * look and feel. */ - public FileView getFileView(JFileChooser chooser) { + public FileView getFileView(JFileChooser chooser) + { FileView result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -422,7 +424,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The text returned by the UI delegate from the primary * look and feel. */ - public String getApproveButtonText(JFileChooser chooser) { + public String getApproveButtonText(JFileChooser chooser) + { String result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -451,7 +454,8 @@ public class MultiFileChooserUI extends FileChooserUI * @return The title returned by the UI delegate from the primary * look and feel. */ - public String getDialogTitle(JFileChooser chooser) { + public String getDialogTitle(JFileChooser chooser) + { String result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -476,7 +480,8 @@ public class MultiFileChooserUI extends FileChooserUI * * @param chooser the file chooser. */ - public void rescanCurrentDirectory(JFileChooser chooser) { + public void rescanCurrentDirectory(JFileChooser chooser) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -493,7 +498,8 @@ public class MultiFileChooserUI extends FileChooserUI * @param chooser the file chooser. * @param file the file. */ - public void ensureFileIsVisible(JFileChooser chooser, File file) { + public void ensureFileIsVisible(JFileChooser chooser, File file) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { diff --git a/javax/swing/plaf/multi/MultiListUI.java b/javax/swing/plaf/multi/MultiListUI.java index 7350b4541..78c22419f 100644 --- a/javax/swing/plaf/multi/MultiListUI.java +++ b/javax/swing/plaf/multi/MultiListUI.java @@ -364,7 +364,8 @@ public class MultiListUI extends ListUI * @return The index returned by the UI delegate from the primary * look and feel. */ - public int locationToIndex(JList list, Point location) { + public int locationToIndex(JList list, Point location) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -394,7 +395,8 @@ public class MultiListUI extends ListUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public Point indexToLocation(JList list, int index) { + public Point indexToLocation(JList list, int index) + { Point result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -425,7 +427,8 @@ public class MultiListUI extends ListUI * @return The bounds returned by the UI delegate from the primary * look and feel. */ - public Rectangle getCellBounds(JList list, int index1, int index2) { + public Rectangle getCellBounds(JList list, int index1, int index2) + { Rectangle result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/plaf/multi/MultiLookAndFeel.java b/javax/swing/plaf/multi/MultiLookAndFeel.java index 2bd358dd0..12351655a 100644 --- a/javax/swing/plaf/multi/MultiLookAndFeel.java +++ b/javax/swing/plaf/multi/MultiLookAndFeel.java @@ -49,7 +49,8 @@ import javax.swing.plaf.ComponentUI; * A look and feel that provides the ability to use auxiliary look and feels * in addition to the primary look and feel. */ -public class MultiLookAndFeel extends LookAndFeel { +public class MultiLookAndFeel extends LookAndFeel +{ /** * Creates a new instance of the look and feel. diff --git a/javax/swing/plaf/multi/MultiOptionPaneUI.java b/javax/swing/plaf/multi/MultiOptionPaneUI.java index c5cb913a0..8d6f3861c 100644 --- a/javax/swing/plaf/multi/MultiOptionPaneUI.java +++ b/javax/swing/plaf/multi/MultiOptionPaneUI.java @@ -356,7 +356,8 @@ public class MultiOptionPaneUI extends OptionPaneUI * * @param pane the option pane. */ - public void selectInitialValue(JOptionPane pane) { + public void selectInitialValue(JOptionPane pane) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -375,7 +376,8 @@ public class MultiOptionPaneUI extends OptionPaneUI * * @return The result for the UI delegate from the primary look and feel. */ - public boolean containsCustomComponents(JOptionPane pane) { + public boolean containsCustomComponents(JOptionPane pane) + { boolean result = false; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/plaf/multi/MultiSplitPaneUI.java b/javax/swing/plaf/multi/MultiSplitPaneUI.java index f481f8109..70ea4f13b 100644 --- a/javax/swing/plaf/multi/MultiSplitPaneUI.java +++ b/javax/swing/plaf/multi/MultiSplitPaneUI.java @@ -356,7 +356,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * * @param pane the component. */ - public void resetToPreferredSizes(JSplitPane pane) { + public void resetToPreferredSizes(JSplitPane pane) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -372,7 +373,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @param pane the component. * @param location the location. */ - public void setDividerLocation(JSplitPane pane, int location) { + public void setDividerLocation(JSplitPane pane, int location) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { @@ -392,7 +394,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public int getDividerLocation(JSplitPane pane) { + public int getDividerLocation(JSplitPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -421,7 +424,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public int getMinimumDividerLocation(JSplitPane pane) { + public int getMinimumDividerLocation(JSplitPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -450,7 +454,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @return The location returned by the UI delegate from the primary * look and feel. */ - public int getMaximumDividerLocation(JSplitPane pane) { + public int getMaximumDividerLocation(JSplitPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -476,7 +481,8 @@ public class MultiSplitPaneUI extends SplitPaneUI * @param pane the component. * @param g the graphics device. */ - public void finishedPaintingChildren(JSplitPane pane, Graphics g) { + public void finishedPaintingChildren(JSplitPane pane, Graphics g) + { Iterator iterator = uis.iterator(); while (iterator.hasNext()) { diff --git a/javax/swing/plaf/multi/MultiTabbedPaneUI.java b/javax/swing/plaf/multi/MultiTabbedPaneUI.java index 575de192a..2a2599bde 100644 --- a/javax/swing/plaf/multi/MultiTabbedPaneUI.java +++ b/javax/swing/plaf/multi/MultiTabbedPaneUI.java @@ -364,7 +364,8 @@ public class MultiTabbedPaneUI extends TabbedPaneUI * @return The tab index returned by the UI delegate from the primary * look and feel. */ - public int tabForCoordinate(JTabbedPane pane, int x, int y) { + public int tabForCoordinate(JTabbedPane pane, int x, int y) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -394,7 +395,8 @@ public class MultiTabbedPaneUI extends TabbedPaneUI * @return The bounds returned by the UI delegate from the primary * look and feel. */ - public Rectangle getTabBounds(JTabbedPane pane, int index) { + public Rectangle getTabBounds(JTabbedPane pane, int index) + { Rectangle result = null; Iterator iterator = uis.iterator(); // first UI delegate provides the return value @@ -423,7 +425,8 @@ public class MultiTabbedPaneUI extends TabbedPaneUI * @return The count returned by the UI delegate from the primary * look and feel. */ - public int getTabRunCount(JTabbedPane pane) { + public int getTabRunCount(JTabbedPane pane) + { int result = 0; Iterator iterator = uis.iterator(); // first UI delegate provides the return value diff --git a/javax/swing/table/AbstractTableModel.java b/javax/swing/table/AbstractTableModel.java index bda716ee7..66b6a0743 100644 --- a/javax/swing/table/AbstractTableModel.java +++ b/javax/swing/table/AbstractTableModel.java @@ -1,5 +1,5 @@ /* AbstractTableModel.java -- - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -83,7 +83,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable StringBuffer buffer = new StringBuffer(); while (columnIndex >= 0) { - buffer.insert (0, (char) ('A' + columnIndex % 26)); + buffer.insert(0, (char) ('A' + columnIndex % 26)); columnIndex = columnIndex / 26 - 1; } return buffer.toString(); @@ -221,7 +221,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @param firstRow the index of the first row. * @param lastRow the index of the last row. */ - public void fireTableRowsInserted (int firstRow, int lastRow) + public void fireTableRowsInserted(int firstRow, int lastRow) { fireTableChanged(new TableModelEvent(this, firstRow, lastRow, TableModelEvent.ALL_COLUMNS, @@ -235,7 +235,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @param firstRow the index of the first row. * @param lastRow the index of the last row. */ - public void fireTableRowsUpdated (int firstRow, int lastRow) + public void fireTableRowsUpdated(int firstRow, int lastRow) { fireTableChanged(new TableModelEvent(this, firstRow, lastRow, TableModelEvent.ALL_COLUMNS, @@ -263,7 +263,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * @param row the row index. * @param column the column index. */ - public void fireTableCellUpdated (int row, int column) + public void fireTableCellUpdated(int row, int column) { fireTableChanged(new TableModelEvent(this, row, row, column)); } @@ -282,7 +282,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable for (index = 0; index < list.length; index += 2) { listener = (TableModelListener) list [index + 1]; - listener.tableChanged (event); + listener.tableChanged(event); } } diff --git a/javax/swing/table/DefaultTableModel.java b/javax/swing/table/DefaultTableModel.java index 09be2f752..79285903c 100644 --- a/javax/swing/table/DefaultTableModel.java +++ b/javax/swing/table/DefaultTableModel.java @@ -1,5 +1,5 @@ /* DefaultTableModel.java -- - Copyright (C) 2002, 2004, 2005, Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2006, Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -249,7 +249,7 @@ public class DefaultTableModel extends AbstractTableModel public void setColumnIdentifiers(Vector columnIdentifiers) { this.columnIdentifiers = columnIdentifiers; - setColumnCount((columnIdentifiers == null ? 0 : columnIdentifiers.size())); + setColumnCount(columnIdentifiers == null ? 0 : columnIdentifiers.size()); } /** @@ -289,13 +289,13 @@ public class DefaultTableModel extends AbstractTableModel if (rowCount < existingRowCount) { dataVector.setSize(rowCount); - fireTableRowsDeleted(rowCount,existingRowCount-1); + fireTableRowsDeleted(rowCount, existingRowCount - 1); } else { int rowsToAdd = rowCount - existingRowCount; addExtraRows(rowsToAdd, columnIdentifiers.size()); - fireTableRowsInserted(existingRowCount,rowCount-1); + fireTableRowsInserted(existingRowCount, rowCount - 1); } } @@ -353,7 +353,8 @@ public class DefaultTableModel extends AbstractTableModel * @param columnName the column name (<code>null</code> permitted). * @param columnData the column data. */ - public void addColumn(Object columnName, Object[] columnData) { + public void addColumn(Object columnName, Object[] columnData) + { if (columnData != null) { // check columnData array for cases where the number of items @@ -384,7 +385,8 @@ public class DefaultTableModel extends AbstractTableModel * * @param rowData the row data (<code>null</code> permitted). */ - public void addRow(Vector rowData) { + public void addRow(Vector rowData) + { int rowIndex = dataVector.size(); dataVector.add(rowData); newRowsAdded(new TableModelEvent( @@ -398,7 +400,8 @@ public class DefaultTableModel extends AbstractTableModel * * @param rowData the row data (<code>null</code> permitted). */ - public void addRow(Object[] rowData) { + public void addRow(Object[] rowData) + { addRow(convertToVector(rowData)); } @@ -408,9 +411,10 @@ public class DefaultTableModel extends AbstractTableModel * @param row the row index. * @param rowData the row data. */ - public void insertRow(int row, Vector rowData) { + public void insertRow(int row, Vector rowData) + { dataVector.add(row, rowData); - fireTableRowsInserted(row,row); + fireTableRowsInserted(row, row); } /** @@ -419,7 +423,8 @@ public class DefaultTableModel extends AbstractTableModel * @param row the row index. * @param rowData the row data. */ - public void insertRow(int row, Object[] rowData) { + public void insertRow(int row, Object[] rowData) + { insertRow(row, convertToVector(rowData)); } @@ -431,7 +436,8 @@ public class DefaultTableModel extends AbstractTableModel * @param endIndex the end row. * @param toIndex the row to move to. */ - public void moveRow(int startIndex, int endIndex, int toIndex) { + public void moveRow(int startIndex, int endIndex, int toIndex) + { Vector removed = new Vector(); for (int i = endIndex; i >= startIndex; i--) { @@ -452,9 +458,10 @@ public class DefaultTableModel extends AbstractTableModel * * @param row the row index. */ - public void removeRow(int row) { + public void removeRow(int row) + { dataVector.remove(row); - fireTableRowsDeleted(row,row); + fireTableRowsDeleted(row, row); } /** @@ -462,7 +469,8 @@ public class DefaultTableModel extends AbstractTableModel * * @return The row count. */ - public int getRowCount() { + public int getRowCount() + { return dataVector.size(); } @@ -471,8 +479,9 @@ public class DefaultTableModel extends AbstractTableModel * * @return The column count. */ - public int getColumnCount() { - return (columnIdentifiers == null ? 0 : columnIdentifiers.size()); + public int getColumnCount() + { + return columnIdentifiers == null ? 0 : columnIdentifiers.size(); } /** @@ -485,7 +494,8 @@ public class DefaultTableModel extends AbstractTableModel * * @return The column name. */ - public String getColumnName(int column) { + public String getColumnName(int column) + { String result = ""; if (columnIdentifiers == null) result = super.getColumnName(column); @@ -516,7 +526,8 @@ public class DefaultTableModel extends AbstractTableModel * * @return <code>true</code> in all cases. */ - public boolean isCellEditable(int row, int column) { + public boolean isCellEditable(int row, int column) + { return true; } @@ -529,7 +540,8 @@ public class DefaultTableModel extends AbstractTableModel * @return The value (<code>Object</code>, possibly <code>null</code>) at * the specified cell in the table. */ - public Object getValueAt(int row, int column) { + public Object getValueAt(int row, int column) + { return ((Vector) dataVector.get(row)).get(column); } @@ -541,9 +553,10 @@ public class DefaultTableModel extends AbstractTableModel * @param row the row index. * @param column the column index. */ - public void setValueAt(Object value, int row, int column) { + public void setValueAt(Object value, int row, int column) + { ((Vector) dataVector.get(row)).set(column, value); - fireTableCellUpdated(row,column); + fireTableCellUpdated(row, column); } /** @@ -554,7 +567,8 @@ public class DefaultTableModel extends AbstractTableModel * @return A vector (or <code>null</code> if the data array * is <code>null</code>). */ - protected static Vector convertToVector(Object[] data) { + protected static Vector convertToVector(Object[] data) + { if (data == null) return null; Vector vector = new Vector(data.length); @@ -571,7 +585,8 @@ public class DefaultTableModel extends AbstractTableModel * @return A vector (or <code>null</code> if the data array * is <code>null</code>. */ - protected static Vector convertToVector(Object[][] data) { + protected static Vector convertToVector(Object[][] data) + { if (data == null) return null; Vector vector = new Vector(data.length); diff --git a/javax/swing/table/TableCellEditor.java b/javax/swing/table/TableCellEditor.java index b355311dc..15070a755 100644 --- a/javax/swing/table/TableCellEditor.java +++ b/javax/swing/table/TableCellEditor.java @@ -47,19 +47,19 @@ import javax.swing.JTable; * TableCellEditor public interface * @author Andrew Selkirk */ -public interface TableCellEditor extends CellEditor { +public interface TableCellEditor extends CellEditor +{ - /** - * Get table cell editor component - * @param table JTable - * @param value Value of cell - * @param isSelected Cell selected - * @param row Row of cell - * @param column Column of cell - * @returns Component - */ - Component getTableCellEditorComponent(JTable table, - Object value, boolean isSelected, int row, int column); + /** + * Get table cell editor component + * @param table JTable + * @param value Value of cell + * @param isSelected Cell selected + * @param row Row of cell + * @param column Column of cell + * @return Component + */ + Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, int row, int column); - -} // TableCellEditor +} diff --git a/javax/swing/table/TableCellRenderer.java b/javax/swing/table/TableCellRenderer.java index 639b4b9ad..6c1fecf56 100644 --- a/javax/swing/table/TableCellRenderer.java +++ b/javax/swing/table/TableCellRenderer.java @@ -46,21 +46,21 @@ import javax.swing.JTable; * TableCellRenderer public interface * @author Andrew Selkirk */ -public interface TableCellRenderer { +public interface TableCellRenderer +{ - /** - * Get table cell renderer component - * @param table JTable - * @param value Value of cell - * @param isSelected Cell selected - * @param hasFocus Cell has focus - * @param row Row of cell - * @param column Column of cell - * @returns Component - */ - Component getTableCellRendererComponent(JTable table, - Object value, boolean isSelected, boolean hasFocus, - int row, int column); + /** + * Get table cell renderer component + * @param table JTable + * @param value Value of cell + * @param isSelected Cell selected + * @param hasFocus Cell has focus + * @param row Row of cell + * @param column Column of cell + * @return Component + */ + Component getTableCellRendererComponent(JTable table, Object value, + boolean isSelected, boolean hasFocus, int row, int column); -} // TableCellRenderer +} diff --git a/javax/swing/text/AbstractWriter.java b/javax/swing/text/AbstractWriter.java index d5fc395e1..8d5a6075d 100644 --- a/javax/swing/text/AbstractWriter.java +++ b/javax/swing/text/AbstractWriter.java @@ -183,7 +183,8 @@ public abstract class AbstractWriter if (! elt.isLeaf()) throw new BadLocationException("Element is not a leaf", elt.getStartOffset()); - return document.getText(elt.getStartOffset(), elt.getEndOffset()); + return document.getText(elt.getStartOffset(), + elt.getEndOffset() - elt.getStartOffset()); } /** diff --git a/javax/swing/text/DefaultCaret.java b/javax/swing/text/DefaultCaret.java index 3bef80d9e..ce93cf56e 100644 --- a/javax/swing/text/DefaultCaret.java +++ b/javax/swing/text/DefaultCaret.java @@ -216,13 +216,26 @@ public class DefaultCaret extends Rectangle */ public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName().equals("document")) + String name = e.getPropertyName(); + + if (name.equals("document")) { Document oldDoc = (Document) e.getOldValue(); oldDoc.removeDocumentListener(documentListener); Document newDoc = (Document) e.getNewValue(); newDoc.addDocumentListener(documentListener); } + else if (name.equals("editable")) + { + active = (((Boolean) e.getNewValue()).booleanValue() + && textComponent.isEnabled()); + } + else if (name.equals("enabled")) + { + active = (((Boolean) e.getNewValue()).booleanValue() + && textComponent.isEditable()); + } + } } @@ -281,8 +294,10 @@ public class DefaultCaret extends Rectangle /** * The text component in which this caret is installed. + * + * (Package private to avoid synthetic accessor method.) */ - private JTextComponent textComponent; + JTextComponent textComponent; /** * Indicates if the selection should be visible or not. @@ -314,6 +329,12 @@ public class DefaultCaret extends Rectangle * package private to avoid an accessor method. */ boolean visible = false; + + /** Indicates whether the text component where the caret is installed is + * editable and enabled. If either of these properties is <code>false</code> + * the caret is not drawn. + */ + boolean active = true; /** * The current highlight entry. @@ -388,14 +409,23 @@ public class DefaultCaret extends Rectangle /** * Moves the caret position when the mouse is dragged over the text - * component, modifying the selection accordingly. + * component, modifying the selectiony. + * + * <p>When the text component where the caret is installed is disabled, + * the selection is not change but you can still scroll the text and + * update the caret's location.</p> * * @param event the <code>MouseEvent</code> describing the drag operation */ public void mouseDragged(MouseEvent event) { if (event.getButton() == MouseEvent.BUTTON1) - moveCaret(event); + { + if (textComponent.isEnabled()) + moveCaret(event); + else + positionCaret(event); + } } /** @@ -426,6 +456,10 @@ public class DefaultCaret extends Rectangle */ public void mouseClicked(MouseEvent event) { + // Do not modify selection if component is disabled. + if (!textComponent.isEnabled()) + return; + int count = event.getClickCount(); if (event.getButton() == MouseEvent.BUTTON1 && count >= 2) @@ -523,7 +557,7 @@ public class DefaultCaret extends Rectangle // implemented (in regard to text components): // - a left-click moves the caret // - a left-click when shift is held down expands the selection - // - a right-click or click with any additionaly mouse button + // - a right-click or click with any additional mouse button // on a text component is ignored // - a middle-click positions the caret and pastes the clipboard // contents. @@ -540,6 +574,7 @@ public class DefaultCaret extends Rectangle else { positionCaret(event); + textComponent.paste(); } else @@ -564,8 +599,11 @@ public class DefaultCaret extends Rectangle */ public void focusGained(FocusEvent event) { - setVisible(true); - updateTimerStatus(); + if (textComponent.isEditable()) + { + setVisible(true); + updateTimerStatus(); + } } /** @@ -575,9 +613,10 @@ public class DefaultCaret extends Rectangle */ public void focusLost(FocusEvent event) { - if (event.isTemporary() == false) + if (textComponent.isEditable() && event.isTemporary() == false) { setVisible(false); + // Stop the blinker, if running. if (blinkTimer != null && blinkTimer.isRunning()) blinkTimer.stop(); @@ -670,6 +709,7 @@ public class DefaultCaret extends Rectangle textComponent.addPropertyChangeListener(propertyChangeListener); documentListener = new DocumentHandler(); textComponent.getDocument().addDocumentListener(documentListener); + active = textComponent.isEditable() && textComponent.isEnabled(); repaint(); } @@ -872,7 +912,7 @@ public class DefaultCaret extends Rectangle } // Now draw the caret on the new position if visible. - if (visible) + if (visible && active) { g.setColor(textComponent.getCaretColor()); g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height - 1); @@ -1013,7 +1053,9 @@ public class DefaultCaret extends Rectangle this.dot = Math.max(this.dot, 0); handleHighlight(); + appear(); + adjustVisibility(this); } } @@ -1050,7 +1092,9 @@ public class DefaultCaret extends Rectangle this.mark = this.dot; clearHighlight(); + appear(); + adjustVisibility(this); } } @@ -1104,7 +1148,7 @@ public class DefaultCaret extends Rectangle */ public boolean isVisible() { - return visible; + return visible && active; } /** diff --git a/javax/swing/text/DefaultEditorKit.java b/javax/swing/text/DefaultEditorKit.java index 1b686182b..8602e69f8 100644 --- a/javax/swing/text/DefaultEditorKit.java +++ b/javax/swing/text/DefaultEditorKit.java @@ -52,6 +52,7 @@ import java.io.Reader; import java.io.Writer; import javax.swing.Action; +import javax.swing.SwingConstants; /** * The default implementation of {@link EditorKit}. This <code>EditorKit</code> @@ -60,6 +61,7 @@ import javax.swing.Action; * * @author original author unknown * @author Roman Kennke (roman@kennke.org) + * @author Robert Schuster (robertschuster@fsfe.org) */ public class DefaultEditorKit extends EditorKit { @@ -123,6 +125,122 @@ public class DefaultEditorKit extends EditorKit } } + static class SelectionBeginWordAction extends TextAction + { + SelectionBeginWordAction() + { + super(selectionBeginWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordStart(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.moveDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class SelectionEndWordAction extends TextAction + { + SelectionEndWordAction() + { + super(selectionEndWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordEnd(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.moveDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class BeginWordAction extends TextAction + { + BeginWordAction() + { + super(beginWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordStart(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class EndWordAction extends TextAction + { + EndWordAction() + { + super(endWordAction); + } + + public void actionPerformed(ActionEvent event) + { + try + { + JTextComponent t = getTextComponent(event); + + if (t != null) + { + int offs = Utilities.getWordEnd(t, t.getCaretPosition()); + + Caret c = t.getCaret(); + c.setDot(offs); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + static class PreviousWordAction extends TextAction { @@ -258,336 +376,260 @@ public class DefaultEditorKit extends EditorKit } } } - - static class SelectionEndLineAction - extends TextAction + + static class SelectionBeginLineAction + extends TextAction { - SelectionEndLineAction() + + SelectionBeginLineAction() { - super(selectionEndLineAction); + super(selectionBeginLineAction); } public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); - try - { - Point p = t.modelToView(t.getCaret().getDot()).getLocation(); - int cur = t.getCaretPosition(); - int y = p.y; - int length = t.getDocument().getLength(); - while (y == p.y && cur < length) - y = t.modelToView(++cur).getLocation().y; - if (cur != length) - cur--; - - Caret c = t.getCaret(); - c.moveDot(cur); - c.setMagicCaretPosition(t.modelToView(cur).getLocation()); - } - catch (BadLocationException ble) - { - // Nothing to do here - } + Caret c = t.getCaret(); + try + { + int offs = Utilities.getRowStart(t, c.getDot()); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } } - static class SelectionBeginLineAction + static class SelectionEndLineAction extends TextAction { - SelectionBeginLineAction() + SelectionEndLineAction() { - super(selectionBeginLineAction); + super(selectionEndLineAction); } public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); - + Caret c = t.getCaret(); try - { - // TODO: There is a more efficent solution, but - // viewToModel doesn't work properly. - Point p = t.modelToView(t.getCaret().getDot()).getLocation(); - - int cur = t.getCaretPosition(); - int y = p.y; - - while (y == p.y && cur > 0) - y = t.modelToView(--cur).getLocation().y; - if (cur != 0) - cur++; - - Caret c = t.getCaret(); - c.moveDot(cur); - c.setMagicCaretPosition(t.modelToView(cur).getLocation()); - } - catch (BadLocationException ble) - { - // Do nothing here. - } + { + int offs = Utilities.getRowEnd(t, c.getDot()); + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } } - - static class SelectionDownAction - extends TextAction + + static class SelectLineAction extends TextAction { - SelectionDownAction() + SelectLineAction() { - super(selectionDownAction); + super(selectLineAction); } - + public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); try { - if (t != null) - { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); - - if (pos > -1) - t.moveCaretPosition(pos); - } + int offs1 = Utilities.getRowStart(t, c.getDot()); + int offs2 = Utilities.getRowEnd(t, c.getDot()); + + c.setDot(offs2); + c.moveDot(offs1); + + c.setMagicCaretPosition(t.modelToView(offs2).getLocation()); } - catch(BadLocationException ble) + catch(BadLocationException ble) { - // FIXME: Swallowing allowed? + // Can't happen. } } } - - static class SelectionUpAction - extends TextAction + + static class SelectWordAction extends TextAction { - SelectionUpAction() + SelectWordAction() { - super(selectionUpAction); + super(selectWordAction); } - + public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); + int dot = c.getDot(); + try { - if (t != null) + int wordStart = Utilities.getWordStart(t, dot); + + if (dot == wordStart) { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); + // Current cursor position is on the first character in a word. + c.setDot(wordStart); + c.moveDot(Utilities.getWordEnd(t, wordStart)); + } + else + { + // Current cursor position is not on the first character + // in a word. + int nextWord = Utilities.getNextWord(t, dot); + int previousWord = Utilities.getPreviousWord(t, dot); + int previousWordEnd = Utilities.getWordEnd(t, previousWord); - if (pos > -1) - t.moveCaretPosition(pos); + // Cursor position is in the space between two words. In such a + // situation just select the space. + if (dot >= previousWordEnd && dot <= nextWord) + { + c.setDot(previousWordEnd); + c.moveDot(nextWord); + } + else + { + // Cursor position is inside a word. Just select it then. + c.setDot(previousWord); + c.moveDot(previousWordEnd); + } } + + // If the position was updated change the magic caret position + // as well. + if (c.getDot() != dot) + c.setMagicCaretPosition(t.modelToView(c.getDot()).getLocation()); + } - catch(BadLocationException ble) + catch(BadLocationException ble) { - // FIXME: Swallowing allowed? + // Can't happen. } } } + static class SelectionDownAction + extends TextAction.VerticalMovementAction + { + SelectionDownAction() + { + super(selectionDownAction, SwingConstants.SOUTH); + } + + protected void actionPerformedImpl(Caret c, int offs) + { + c.moveDot(offs); + } + + } + + static class SelectionUpAction + extends TextAction.VerticalMovementAction + { + SelectionUpAction() + { + super(selectionUpAction, SwingConstants.NORTH); + } + + protected void actionPerformedImpl(Caret c, int offs) + { + c.moveDot(offs); + } + + } + static class SelectionForwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { SelectionForwardAction() { - super(selectionForwardAction); + super(selectionForwardAction, SwingConstants.EAST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() + 1; - - if(offs <= t.getDocument().getLength()) - { - Caret c = t.getCaret(); - c.moveDot(offs); - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch(BadLocationException ble) - { - // Can't happen. - } - } - } + c.moveDot(offs); } } static class SelectionBackwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { SelectionBackwardAction() { - super(selectionBackwardAction); + super(selectionBackwardAction, SwingConstants.WEST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() - 1; - - if(offs >= 0) - { - Caret c = t.getCaret(); - c.moveDot(offs); - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch(BadLocationException ble) - { - // Can't happen. - } - } - } + c.moveDot(offs); } } static class DownAction - extends TextAction + extends TextAction.VerticalMovementAction { DownAction() { - super(downAction); + super(downAction, SwingConstants.SOUTH); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - try - { - if (t != null) - { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionBelow(t, t.getCaretPosition(), x); - - if (pos > -1) - t.setCaretPosition(pos); - } - } - catch(BadLocationException ble) - { - // FIXME: Swallowing allowed? - } + c.setDot(offs); } } static class UpAction - extends TextAction + extends TextAction.VerticalMovementAction { UpAction() { - super(upAction); + super(upAction, SwingConstants.NORTH); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - try - { - if (t != null) - { - Caret c = t.getCaret(); - // The magic caret position may be null when the caret - // has not moved yet. - Point mcp = c.getMagicCaretPosition(); - int x = (mcp != null) ? mcp.x : 0; - int pos = Utilities.getPositionAbove(t, t.getCaretPosition(), x); - - if (pos > -1) - t.setCaretPosition(pos); - } - } - catch(BadLocationException ble) - { - // FIXME: Swallowing allowed? - } + c.setDot(offs); } + } static class ForwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { ForwardAction() { - super(forwardAction); + super(forwardAction, SwingConstants.EAST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() + 1; - if (offs <= t.getDocument().getLength()) - { - Caret c = t.getCaret(); - c.setDot(offs); - - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch (BadLocationException ble) - { - // Should not happen. - } - } - } - + c.setDot(offs); } + } static class BackwardAction - extends TextAction + extends TextAction.HorizontalMovementAction { BackwardAction() { - super(backwardAction); + super(backwardAction, SwingConstants.WEST); } - public void actionPerformed(ActionEvent event) + protected void actionPerformedImpl(Caret c, int offs) { - JTextComponent t = getTextComponent(event); - if (t != null) - { - int offs = t.getCaretPosition() - 1; - if (offs >= 0) - { - Caret c = t.getCaret(); - c.setDot(offs); - - try - { - c.setMagicCaretPosition(t.modelToView(offs).getLocation()); - } - catch (BadLocationException ble) - { - // Should not happen. - } - } - } + c.setDot(offs); } + } static class DeletePrevCharAction @@ -720,6 +762,55 @@ public class DefaultEditorKit extends EditorKit } } + static class BeginAction extends TextAction + { + + BeginAction() + { + super(beginAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + Caret c = t.getCaret(); + c.setDot(0); + try + { + c.setMagicCaretPosition(t.modelToView(0).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + + static class EndAction extends TextAction + { + + EndAction() + { + super(endAction); + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + int offs = t.getDocument().getLength(); + Caret c = t.getCaret(); + c.setDot(offs); + try + { + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + catch(BadLocationException ble) + { + // Can't happen. + } + } + } + /** * Creates a beep on the PC speaker. * @@ -867,8 +958,8 @@ public class DefaultEditorKit extends EditorKit // first we filter the following events: // - control characters // - key events with the ALT modifier (FIXME: filter that too!) - char c = event.getActionCommand().charAt(0); - if (Character.isISOControl(c)) + int cp = event.getActionCommand().codePointAt(0); + if (Character.isISOControl(cp)) return; JTextComponent t = getTextComponent(event); @@ -1345,8 +1436,6 @@ public class DefaultEditorKit extends EditorKit * The <code>Action</code>s that are supported by the * <code>DefaultEditorKit</code>. */ - // TODO: All these inner classes look ugly. Maybe work out a better way - // to handle this. private static Action[] defaultActions = new Action[] { // These classes are public because they are so in the RI. @@ -1387,9 +1476,21 @@ public class DefaultEditorKit extends EditorKit new PreviousWordAction(), new SelectionPreviousWordAction(), + new BeginAction(), new SelectionBeginAction(), + + new EndAction(), new SelectionEndAction(), + + new BeginWordAction(), + new SelectionBeginWordAction(), + + new EndWordAction(), + new SelectionEndWordAction(), + new SelectAllAction(), + new SelectLineAction(), + new SelectWordAction() }; /** diff --git a/javax/swing/text/FieldView.java b/javax/swing/text/FieldView.java index 0c2f0fef1..f41f90130 100644 --- a/javax/swing/text/FieldView.java +++ b/javax/swing/text/FieldView.java @@ -50,6 +50,7 @@ import java.awt.event.ActionListener; import javax.swing.BoundedRangeModel; import javax.swing.JTextField; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; @@ -241,12 +242,29 @@ public class FieldView extends PlainView Shape newAlloc = adjustAllocation(s); - // Set a clip to prevent drawing outside of the allocation area. - // TODO: Is there a better way to achieve this? Shape clip = g.getClip(); - g.setClip(s); + if (clip != null) + { + // Reason for this: The allocation area is always determined by the + // size of the component (and its insets) regardless of whether + // parts of the component are invisible or not (e.g. when the + // component is part of a JScrollPane and partly moved out of + // the user-visible range). However the clip of the Graphics + // instance may be adjusted properly to that condition but + // does not handle insets. By calculating the intersection + // we get the correct clip to paint the text in all cases. + Rectangle r = s.getBounds(); + Rectangle cb = clip.getBounds(); + SwingUtilities.computeIntersection(r.x, r.y, r.width, r.height, cb); + + g.setClip(cb); + } + else + g.setClip(s); + super.paint(g, newAlloc); g.setClip(clip); + } public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf) diff --git a/javax/swing/text/GapContent.java b/javax/swing/text/GapContent.java index 219accb40..780297ce9 100644 --- a/javax/swing/text/GapContent.java +++ b/javax/swing/text/GapContent.java @@ -39,13 +39,10 @@ exception statement from your version. */ package javax.swing.text; import java.io.Serializable; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; -import java.util.ListIterator; +import java.util.Set; import java.util.Vector; +import java.util.WeakHashMap; import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CannotRedoException; @@ -60,8 +57,6 @@ import javax.swing.undo.UndoableEdit; * minimal (simple array access). The array only has to be shifted around when * the insertion point moves (then the gap also moves and one array copy is * necessary) or when the gap is filled up and the buffer has to be enlarged. - * - * TODO: Implement UndoableEdit support stuff */ public class GapContent implements AbstractDocument.Content, Serializable @@ -71,11 +66,14 @@ public class GapContent * A {@link Position} implementation for <code>GapContent</code>. */ private class GapContentPosition - implements Position, Comparable + implements Position { - /** The index within the buffer array. */ - int mark; + /** + * The index to the positionMarks array entry, which in turn holds the + * mark into the buffer array. + */ + int index; /** * Creates a new GapContentPosition object. @@ -84,33 +82,20 @@ public class GapContent */ GapContentPosition(int mark) { - this.mark = mark; - } - - /** - * Comparable interface implementation. This is used to store all - * positions in an ordered fashion. - * - * @param o the object to be compared to this - * - * @return a negative integer if this is less than <code>o</code>, zero - * if both are equal or a positive integer if this is greater than - * <code>o</code> - * - * @throws ClassCastException if <code>o</code> is not a - * GapContentPosition or Integer object - */ - public int compareTo(Object o) - { - if (o instanceof Integer) + // Try to find the mark in the positionMarks array, and store the index + // to it. + synchronized (GapContent.this) { - int otherMark = ((Integer) o).intValue(); - return mark - otherMark; - } - else - { - GapContentPosition other = (GapContentPosition) o; - return mark - other.mark; + int i = binarySearch(positionMarks, mark, numMarks); + if (i >= 0) // mark found + { + index = i; + } + else + { + index = -i - 1; + insertMark(index, mark); + } } } @@ -121,14 +106,19 @@ public class GapContent */ public int getOffset() { - // Check precondition. - assert mark <= gapStart || mark >= gapEnd : "mark: " + mark - + ", gapStart: " + gapStart - + ", gapEnd: " + gapEnd; - if (mark <= gapStart) - return mark; - else - return mark - (gapEnd - gapStart); + synchronized (GapContent.this) + { + // Fetch the actual mark. + int mark = positionMarks[index]; + // Check precondition. + assert mark <= gapStart || mark >= gapEnd : "mark: " + mark + + ", gapStart: " + gapStart + + ", gapEnd: " + gapEnd; + int res = mark; + if (mark > gapStart) + res -= (gapEnd - gapStart); + return res; + } } } @@ -209,40 +199,6 @@ public class GapContent } - /** - * Compares WeakReference objects in a List by comparing the referenced - * objects instead. - * - * @author Roman Kennke (kennke@aicas.com) - */ - private class WeakPositionComparator - implements Comparator - { - - /** - * Compares two objects of type WeakReference. The objects are compared - * using the referenced objects compareTo() method. - */ - public int compare(Object o1, Object o2) - { - // Unwrap references. - if (o1 instanceof WeakReference) - o1 = ((WeakReference) o1).get(); - if (o2 instanceof WeakReference) - o2 = ((WeakReference) o2).get(); - - GapContentPosition p1 = (GapContentPosition) o1; - GapContentPosition p2 = (GapContentPosition) o2; - - int retVal; - if (p1 == null || p2 == null) - retVal = -1; - else - retVal = p1.compareTo(p2); - return retVal; - } - } - /** The serialization UID (compatible with JDK1.5). */ private static final long serialVersionUID = -6226052713477823730L; @@ -267,12 +223,26 @@ public class GapContent */ int gapEnd; + // FIXME: We might want to track GC'ed GapContentPositions and remove their + // corresponding marks, or alternativly, perform some regular cleanup of + // the positionMarks array. + + /** + * Holds the marks for positions. These marks are referenced by the + * GapContentPosition instances by an index into this array. + */ + int[] positionMarks; + /** - * The positions generated by this GapContent. They are kept in an ordered - * fashion, so they can be looked up easily. The value objects will be - * WeakReference objects that in turn hold GapContentPosition objects. + * The number of elements in the positionMarks array. The positionMarks array + * might be bigger than the actual number of elements. */ - private ArrayList positions; + int numMarks; + + /** + * (Weakly) Stores the GapContentPosition instances. + */ + WeakHashMap positions; /** * Creates a new GapContent object. @@ -294,7 +264,9 @@ public class GapContent gapStart = 1; gapEnd = size; buffer[0] = '\n'; - positions = new ArrayList(); + positions = new WeakHashMap(); + positionMarks = new int[10]; + numMarks = 0; } /** @@ -483,26 +455,30 @@ public class GapContent */ public Position createPosition(final int offset) throws BadLocationException { - if (offset < 0 || offset > length()) - throw new BadLocationException("The offset was out of the bounds of this" - + " buffer", offset); - - clearPositionReferences(); - - // We store the actual array index in the GapContentPosition. The real - // offset is then calculated in the GapContentPosition. - int mark = offset; - if (offset >= gapStart) - mark += gapEnd - gapStart; - GapContentPosition pos = new GapContentPosition(mark); - WeakReference r = new WeakReference(pos); - - // Add this into our list in a sorted fashion. - int index = Collections.binarySearch(positions, r, - new WeakPositionComparator()); - if (index < 0) - index = -(index + 1); - positions.add(index, r); + // We try to find a GapContentPosition at the specified offset and return + // that. Otherwise we must create a new one. + GapContentPosition pos = null; + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + if (p.getOffset() == offset) + { + pos = p; + break; + } + } + + // If none was found, then create and return a new one. + if (pos == null) + { + int mark = offset; + if (mark >= gapStart) + mark += (gapEnd - gapStart); + pos = new GapContentPosition(mark); + positions.put(pos, null); + } + return pos; } @@ -542,7 +518,6 @@ public class GapContent { if (newGapStart == gapStart) return; - int newGapEnd = newGapStart + gapEnd - gapStart; if (newGapStart < gapStart) { @@ -583,7 +558,7 @@ public class GapContent assert newGapStart < gapStart : "The new gap start must be less than the " + "old gap start."; - setPositionsInRange(newGapStart, gapStart - newGapStart, gapStart); + setPositionsInRange(newGapStart, gapStart, false); gapStart = newGapStart; } @@ -602,7 +577,7 @@ public class GapContent assert newGapEnd > gapEnd : "The new gap end must be greater than the " + "old gap end."; - setPositionsInRange(gapEnd, newGapEnd - gapEnd, newGapEnd); + setPositionsInRange(gapEnd, newGapEnd, false); gapEnd = newGapEnd; } @@ -688,85 +663,79 @@ public class GapContent else res.clear(); - int endOffset = offset + length; - - int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset), - new WeakPositionComparator()); - if (index1 < 0) - index1 = -(index1 + 1); - - // Search the first index with the specified offset. The binarySearch does - // not necessarily find the first one. - while (index1 > 0) - { - WeakReference r = (WeakReference) positions.get(index1 - 1); - GapContentPosition p = (GapContentPosition) r.get(); - if (p != null && p.mark == offset || p == null) - index1--; - else - break; - } + int endOffs = offset + length; - for (ListIterator i = positions.listIterator(index1); i.hasNext();) + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) { - WeakReference r = (WeakReference) i.next(); - GapContentPosition p = (GapContentPosition) r.get(); - if (p == null) - continue; - - if (p.mark > endOffset) - break; - if (p.mark >= offset && p.mark <= endOffset) + GapContentPosition p = (GapContentPosition) i.next(); + int offs = p.getOffset(); + if (offs >= offset && offs < endOffs) res.add(p); } + return res; } /** - * Sets the mark of all <code>Position</code>s that are in the range - * specified by <code>offset</code> and </code>length</code> within - * the buffer array to <code>value</code> + * Crunches all positions in the specified range to either the start or + * end of that interval. The interval boundaries are meant to be inclusive + * [start, end]. * - * @param offset the start offset of the range to search - * @param length the length of the range to search - * @param value the new value for each mark + * @param start the start offset of the range + * @param end the end offset of the range + * @param toStart a boolean indicating if the positions should be crunched + * to the start (true) or to the end (false) */ - private void setPositionsInRange(int offset, int length, int value) + private void setPositionsInRange(int start, int end, boolean toStart) { - int endOffset = offset + length; - - int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset), - new WeakPositionComparator()); - if (index1 < 0) - index1 = -(index1 + 1); - - // Search the first index with the specified offset. The binarySearch does - // not necessarily find the first one. - while (index1 > 0) + // We slump together all the GapContentPositions to point to + // one mark. So this is implemented as follows: + // 1. Remove all the marks in the specified range. + // 2. Insert one new mark at the correct location. + // 3. Adjust all affected GapContentPosition instances to point to + // this new mark. + + synchronized (this) { - WeakReference r = (WeakReference) positions.get(index1 - 1); - GapContentPosition p = (GapContentPosition) r.get(); - if (p != null && p.mark == offset || p == null) - index1--; + int startIndex = binarySearch(positionMarks, start, numMarks); + if (startIndex < 0) // Translate to insertion index, if not found. + startIndex = - startIndex - 1; + int endIndex = binarySearch(positionMarks, end, numMarks); + if (endIndex < 0) // Translate to insertion index - 1, if not found. + endIndex = - endIndex - 2; + + // Update the marks. + // We have inclusive interval bounds, but let one element over for + // filling in the new value. + int removed = endIndex - startIndex; + if (removed <= 0) + return; + System.arraycopy(positionMarks, endIndex + 1, positionMarks, + startIndex + 1, positionMarks.length - endIndex - 1); + numMarks -= removed; + if (toStart) + { + positionMarks[startIndex] = start; + } else - break; - } - - for (ListIterator i = positions.listIterator(index1); i.hasNext();) - { - WeakReference r = (WeakReference) i.next(); - GapContentPosition p = (GapContentPosition) r.get(); - if (p == null) - continue; - - if (p.mark > endOffset) - break; - - if (p.mark >= offset && p.mark <= endOffset) - p.mark = value; - } + { + positionMarks[startIndex] = end; + } + + // Update all affected GapContentPositions to point to the new index + // and all GapContentPositions that come after the interval to + // have their index moved by -removed. + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + if (p.index > start || p.index <= end) + p.index = start; + else if (p.index > end) + p.index -= removed; + } + } } /** @@ -780,39 +749,44 @@ public class GapContent */ private void adjustPositionsInRange(int offset, int length, int incr) { - int endOffset = offset + length; + int endMark = offset + length; - int index1 = Collections.binarySearch(positions, - new GapContentPosition(offset), - new WeakPositionComparator()); - if (index1 < 0) - index1 = -(index1 + 1); - - // Search the first index with the specified offset. The binarySearch does - // not necessarily find the first one. - while (index1 > 0) + synchronized (this) { - WeakReference r = (WeakReference) positions.get(index1 - 1); - GapContentPosition p = (GapContentPosition) r.get(); - if (p != null && p.mark == offset || p == null) - index1--; - else - break; + // Find the start and end indices in the positionMarks array. + int startIndex = binarySearch(positionMarks, offset, numMarks); + if (startIndex < 0) // Translate to insertion index, if not found. + startIndex = - startIndex - 1; + int endIndex = binarySearch(positionMarks, endMark, numMarks); + if (endIndex < 0) // Translate to insertion index - 1, if not found. + endIndex = - endIndex - 2; + + // We must not change the order of the marks, this would have + // unpredictable results while binary-searching the marks. + assert (startIndex <= 0 + || positionMarks[startIndex - 1] + <= positionMarks [startIndex] + incr) + && (endIndex >= numMarks - 1 + || positionMarks[endIndex + 1] + >= positionMarks[endIndex] + incr) + : "Adjusting the marks must not change their order"; + + // Some debug helper output to determine if the start or end of the + // should ever be coalesced together with adjecent marks. + if (startIndex > 0 && positionMarks[startIndex - 1] + == positionMarks[startIndex] + incr) + System.err.println("DEBUG: We could coalesce the start of the region" + + " in GapContent.adjustPositionsInRange()"); + if (endIndex < numMarks - 1 && positionMarks[endIndex + 1] + == positionMarks[endIndex] + incr) + System.err.println("DEBUG: We could coalesce the end of the region" + + " in GapContent.adjustPositionsInRange()"); + + // Actually adjust the marks. + for (int i = startIndex; i <= endIndex; i++) + positionMarks[i] += incr; } - for (ListIterator i = positions.listIterator(index1); i.hasNext();) - { - WeakReference r = (WeakReference) i.next(); - GapContentPosition p = (GapContentPosition) r.get(); - if (p == null) - continue; - - if (p.mark > endOffset) - break; - - if (p.mark >= offset && p.mark <= endOffset) - p.mark += incr; - } } /** @@ -826,7 +800,7 @@ public class GapContent if (gapStart != 0) return; - setPositionsInRange(gapEnd, 0, 0); + positionMarks[0] = 0; } /** @@ -866,27 +840,94 @@ public class GapContent System.err.println(); } - private void dumpPositions() + /** + * Prints out the position marks. + */ + private void dumpMarks() + { + System.err.print("positionMarks: "); + for (int i = 0; i < positionMarks.length; i++) + System.err.print(positionMarks[i] + ", "); + System.err.println(); + } + + /** + * Inserts a mark into the positionMarks array. This must update all the + * GapContentPosition instances in positions that come after insertionPoint. + * + * This is package private to avoid synthetic accessor methods. + * + * @param insertionPoint the index at which to insert the mark + * @param mark the mark to insert + */ + void insertMark(int insertionPoint, int mark) { - for (Iterator i = positions.iterator(); i.hasNext();) + synchronized (this) { - WeakReference r = (WeakReference) i.next(); - GapContentPosition pos = (GapContentPosition) r.get(); - System.err.println("position at: " + pos.mark); + // Update the positions. + Set positionSet = positions.keySet(); + for (Iterator i = positionSet.iterator(); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + if (p.index >= insertionPoint) + p.index++; + } + + // Update the position marks. + if (positionMarks.length <= numMarks) + { + int[] newMarks = new int[positionMarks.length + 10]; + System.arraycopy(positionMarks, 0, newMarks, 0, insertionPoint); + newMarks[insertionPoint] = mark; + System.arraycopy(positionMarks, insertionPoint, newMarks, + insertionPoint + 1, + numMarks - insertionPoint); + positionMarks = newMarks; + } + else + { + System.arraycopy(positionMarks, insertionPoint, positionMarks, + insertionPoint + 1, + numMarks - insertionPoint); + positionMarks[insertionPoint] = mark; + } + numMarks++; } } /** - * Clears all GC'ed references in the positions array. + * An adaption of {@link java.util.Arrays#binarySearch(int[], int)} to + * specify a maximum index up to which the array is searched. This allows + * us to have some trailing entries that we ignore. + * + * This is package private to avoid synthetic accessor methods. + * + * @param a the array + * @param key the key to search for + * @param maxIndex the maximum index up to which the search is performed + * + * @return the index of the found entry, or (-(index)-1) for the + * insertion point when not found + * + * @see java.util.Arrays#binarySearch(int[], int) */ - private void clearPositionReferences() + int binarySearch(int[] a, int key, int maxIndex) { - Iterator i = positions.iterator(); - while (i.hasNext()) + int low = 0; + int hi = maxIndex - 1; + int mid = 0; + while (low <= hi) { - WeakReference r = (WeakReference) i.next(); - if (r.get() == null) - i.remove(); + mid = (low + hi) >> 1; + final int d = a[mid]; + if (d == key) + return mid; + else if (d > key) + hi = mid - 1; + else + // This gets the insertion point right on the last loop. + low = ++mid; } + return -mid - 1; } } diff --git a/javax/swing/text/JTextComponent.java b/javax/swing/text/JTextComponent.java index 1103de9b4..9de151dfb 100644 --- a/javax/swing/text/JTextComponent.java +++ b/javax/swing/text/JTextComponent.java @@ -38,6 +38,8 @@ exception statement from your version. */ package javax.swing.text; +import gnu.classpath.NotImplementedException; + import java.awt.AWTEvent; import java.awt.Color; import java.awt.Dimension; @@ -176,6 +178,7 @@ public abstract class JTextComponent extends JComponent * @param e - caret event */ public void caretUpdate(CaretEvent e) + throws NotImplementedException { // TODO: fire appropriate event. dot = e.getDot(); @@ -187,6 +190,7 @@ public abstract class JTextComponent extends JComponent * @return the accessible state set of this component */ public AccessibleStateSet getAccessibleStateSet() + throws NotImplementedException { AccessibleStateSet state = super.getAccessibleStateSet(); // TODO: Figure out what state must be added here to the super's state. @@ -237,6 +241,7 @@ public abstract class JTextComponent extends JComponent * @param e - document event */ public void insertUpdate(DocumentEvent e) + throws NotImplementedException { // TODO } @@ -248,6 +253,7 @@ public abstract class JTextComponent extends JComponent * @param e - document event */ public void removeUpdate(DocumentEvent e) + throws NotImplementedException { // TODO } @@ -259,6 +265,7 @@ public abstract class JTextComponent extends JComponent * @param e - document event */ public void changedUpdate(DocumentEvent e) + throws NotImplementedException { // TODO } @@ -271,6 +278,7 @@ public abstract class JTextComponent extends JComponent * @return the character index, or -1 */ public int getIndexAtPoint(Point p) + throws NotImplementedException { return 0; // TODO } @@ -289,6 +297,7 @@ public abstract class JTextComponent extends JComponent * @return the bounding box, may be empty or null. */ public Rectangle getCharacterBounds(int index) + throws NotImplementedException { return null; // TODO } @@ -311,6 +320,7 @@ public abstract class JTextComponent extends JComponent * @return the character's attributes */ public AttributeSet getCharacterAttribute(int index) + throws NotImplementedException { return null; // TODO } @@ -324,6 +334,7 @@ public abstract class JTextComponent extends JComponent * @return the selection of text at that index, or null */ public String getAtIndex(int part, int index) + throws NotImplementedException { return null; // TODO } @@ -337,6 +348,7 @@ public abstract class JTextComponent extends JComponent * @return the selection of text after that index, or null */ public String getAfterIndex(int part, int index) + throws NotImplementedException { return null; // TODO } @@ -350,6 +362,7 @@ public abstract class JTextComponent extends JComponent * @return the selection of text before that index, or null */ public String getBeforeIndex(int part, int index) + throws NotImplementedException { return null; // TODO } @@ -361,6 +374,7 @@ public abstract class JTextComponent extends JComponent * @return the 0-based number of actions */ public int getAccessibleActionCount() + throws NotImplementedException { return 0; // TODO } @@ -369,11 +383,11 @@ public abstract class JTextComponent extends JComponent * Get a description for the specified action. Returns null if out of * bounds. * - * @param i - * the action to describe, 0-based + * @param i the action to describe, 0-based * @return description of the action */ public String getAccessibleActionDescription(int i) + throws NotImplementedException { // TODO: Not implemented fully return super.getAccessibleDescription(); @@ -386,6 +400,7 @@ public abstract class JTextComponent extends JComponent * @return true if the action was performed */ public boolean doAccessibleAction(int i) + throws NotImplementedException { return false; // TODO } @@ -396,6 +411,7 @@ public abstract class JTextComponent extends JComponent * @param s the new text */ public void setTextContents(String s) + throws NotImplementedException { // TODO } @@ -407,6 +423,7 @@ public abstract class JTextComponent extends JComponent * @param s the new text */ public void insertTextAtIndex(int index, String s) + throws NotImplementedException { replaceText(index, index, s); } @@ -495,6 +512,7 @@ public abstract class JTextComponent extends JComponent * @param s the new attribute set for the range */ public void setAttributes(int start, int end, AttributeSet s) + throws NotImplementedException { // TODO } @@ -1365,7 +1383,7 @@ public abstract class JTextComponent extends JComponent { if (editable == newValue) return; - + boolean oldValue = editable; editable = newValue; firePropertyChange("editable", oldValue, newValue); @@ -1725,17 +1743,20 @@ public abstract class JTextComponent extends JComponent public void copy() { + if (isEnabled()) doTransferAction("copy", TransferHandler.getCopyAction()); } public void cut() { - doTransferAction("cut", TransferHandler.getCutAction()); + if (editable && isEnabled()) + doTransferAction("cut", TransferHandler.getCutAction()); } public void paste() { - doTransferAction("paste", TransferHandler.getPasteAction()); + if (editable && isEnabled()) + doTransferAction("paste", TransferHandler.getPasteAction()); } private void doTransferAction(String name, Action action) diff --git a/javax/swing/text/StyleContext.java b/javax/swing/text/StyleContext.java index 1c772e4cf..5150351dd 100644 --- a/javax/swing/text/StyleContext.java +++ b/javax/swing/text/StyleContext.java @@ -413,7 +413,7 @@ public class StyleContext /** * These attribute keys are handled specially in serialization. */ - private static HashSet staticAttributeKeys = new HashSet(); + private static Hashtable staticAttributeKeys = new Hashtable(); EventListenerList listenerList; Hashtable styleTable; @@ -708,44 +708,107 @@ public class StyleContext } } - - // FIXME: there's some sort of quasi-serialization stuff in here which I - // have left incomplete; I'm not sure I understand the intent properly. - + /** + * Gets the object previously registered with registerStaticAttributeKey. + * + * @param key - the key that was registered. + * @return the object previously registered with registerStaticAttributeKey. + */ public static Object getStaticAttribute(Object key) - throws NotImplementedException { - throw new InternalError("not implemented"); + if (key == null) + return null; + return staticAttributeKeys.get(key); } + /** + * Returns the String that key will be registered with + * registerStaticAttributeKey. + * + * @param key - the key that will be registered. + * @return the string the key will be registered with. + */ public static Object getStaticAttributeKey(Object key) - throws NotImplementedException { - throw new InternalError("not implemented"); + return key.getClass().getName() + "." + key.toString(); } + /** + * Reads a set of attributes from the given object input stream. This will + * attempt to restore keys that were static objects by considering only the + * keys that have were registered with registerStaticAttributeKey. The + * attributes retrieved will be placed into the given set. + * + * @param in - the stream to read from + * @param a - the set of attributes + * @throws ClassNotFoundException - may be encountered when reading from + * stream + * @throws IOException - any I/O error + */ public static void readAttributeSet(ObjectInputStream in, MutableAttributeSet a) - throws ClassNotFoundException, IOException, NotImplementedException + throws ClassNotFoundException, IOException { - throw new InternalError("not implemented"); + if (in == null || a == null) + return; + + Object key = in.readObject(); + Object val = in.readObject(); + while (key != null && val != null) + { + Object staticKey = staticAttributeKeys.get(key); + Object staticVal = staticAttributeKeys.get(val); + + if (staticKey != null) + key = staticKey; + if (staticVal != null) + val = staticVal; + + a.addAttribute(key, val); + key = in.readObject(); + val = in.readObject(); + } } + /** + * TODO: DOCUMENT ME! + * + * @param out - stream to write to + * @param a - the attribute set + * @throws IOException - any I/O error + */ public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a) throws IOException, NotImplementedException { - throw new InternalError("not implemented"); + // FIXME: Not implemented } + /** + * Handles reading in the attributes. + * @see #readAttributeSet(ObjectInputStream, MutableAttributeSet) + * + * @param in - the stream to read from + * @param a - the set of attributes + * @throws ClassNotFoundException - may be encountered when reading from stream + * @throws IOException - any I/O error + */ public void readAttributes(ObjectInputStream in, MutableAttributeSet a) - throws ClassNotFoundException, IOException, NotImplementedException + throws ClassNotFoundException, IOException { - throw new InternalError("not implemented"); + readAttributeSet(in, a); } + /** + * Handles writing of the given attributes. + * @see #writeAttributeSet(ObjectOutputStream, AttributeSet) + * + * @param out - stream to write to + * @param a - the attribute set + * @throws IOException - any I/O error + */ public void writeAttributes(ObjectOutputStream out, AttributeSet a) - throws IOException, NotImplementedException + throws IOException { - throw new InternalError("not implemented"); + writeAttributeSet(out, a); } /** @@ -760,6 +823,8 @@ public class StyleContext */ public static void registerStaticAttributeKey(Object key) { - staticAttributeKeys.add(key); + if (key != null) + staticAttributeKeys.put(key.getClass().getName() + "." + key.toString(), + key); } } diff --git a/javax/swing/text/TextAction.java b/javax/swing/text/TextAction.java index 3ba5100c5..28dbff00a 100644 --- a/javax/swing/text/TextAction.java +++ b/javax/swing/text/TextAction.java @@ -38,12 +38,14 @@ exception statement from your version. */ package javax.swing.text; +import java.awt.Point; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.HashSet; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.SwingConstants; /** * TextAction @@ -108,4 +110,106 @@ public abstract class TextAction extends AbstractAction { return null; // TODO } + + /** Abstract helper class which implements everything needed for an + * Action implementation in <code>DefaultEditorKit</code> which + * does horizontal movement (and selection). + */ + abstract static class HorizontalMovementAction extends TextAction + { + int dir; + + HorizontalMovementAction(String name, int direction) + { + super(name); + dir = direction; + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + int offs + = Utilities.getNextVisualPositionFrom(t, + t.getCaretPosition(), + dir); + + Caret c = t.getCaret(); + + actionPerformedImpl(c, offs); + + c.setMagicCaretPosition(t.modelToView(offs).getLocation()); + } + } + catch(BadLocationException ble) + { + throw + (InternalError) new InternalError("Illegal offset").initCause(ble); + } + + } + + protected abstract void actionPerformedImpl(Caret c, int offs) + throws BadLocationException; + } + + /** Abstract helper class which implements everything needed for an + * Action implementation in <code>DefaultEditorKit</code> which + * does vertical movement (and selection). + */ + abstract static class VerticalMovementAction extends TextAction + { + int dir; + + VerticalMovementAction(String name, int direction) + { + super(name); + dir = direction; + } + + public void actionPerformed(ActionEvent event) + { + JTextComponent t = getTextComponent(event); + try + { + if (t != null) + { + Caret c = t.getCaret(); + // The magic caret position may be null when the caret + // has not moved yet. + Point mcp = c.getMagicCaretPosition(); + + int pos; + if (mcp != null) + { + mcp.y = t.modelToView(c.getDot()).y; + pos = t.viewToModel(mcp); + } + else + pos = c.getDot(); + + pos = Utilities.getNextVisualPositionFrom(t, + t.getCaretPosition(), + dir); + + if (pos > -1) + actionPerformedImpl(c, pos); + } + } + catch(BadLocationException ble) + { + throw + (InternalError) new InternalError("Illegal offset").initCause(ble); + } + } + + protected abstract void actionPerformedImpl(Caret c, int offs) + throws BadLocationException; + + } + + } diff --git a/javax/swing/text/Utilities.java b/javax/swing/text/Utilities.java index f154e55aa..36361f497 100644 --- a/javax/swing/text/Utilities.java +++ b/javax/swing/text/Utilities.java @@ -43,6 +43,9 @@ import java.awt.Graphics; import java.awt.Point; import java.text.BreakIterator; +import javax.swing.SwingConstants; +import javax.swing.text.Position.Bias; + /** * A set of utilities to deal with text. This is used by several other classes * inside this package. @@ -337,7 +340,7 @@ public class Utilities // location or is not whitespace (meaning it is a number or // punctuation). The first case means that 'last' denotes the // beginning of a word while the second case means it is the start - // of some else. + // of something else. if (Character.isLetter(cp) || !Character.isWhitespace(cp)) return last; @@ -346,7 +349,7 @@ public class Utilities current = wb.next(); } - throw new BadLocationException("no more word", offs); + throw new BadLocationException("no more words", offs); } /** @@ -363,24 +366,36 @@ public class Utilities public static final int getPreviousWord(JTextComponent c, int offs) throws BadLocationException { - if (offs < 0 || offs > (c.getText().length() - 1)) - throw new BadLocationException("invalid offset specified", offs); String text = c.getText(); + + if (offs <= 0 || offs > text.length()) + throw new BadLocationException("invalid offset specified", offs); + BreakIterator wb = BreakIterator.getWordInstance(); wb.setText(text); int last = wb.preceding(offs); int current = wb.previous(); + int cp; while (current != BreakIterator.DONE) { for (int i = last; i < offs; i++) { - if (Character.isLetter(text.codePointAt(i))) + cp = text.codePointAt(i); + + // Return the last found bound if there is a letter at the current + // location or is not whitespace (meaning it is a number or + // punctuation). The first case means that 'last' denotes the + // beginning of a word while the second case means it is the start + // of some else. + if (Character.isLetter(cp) + || !Character.isWhitespace(cp)) return last; } last = current; current = wb.previous(); } + return 0; } @@ -394,14 +409,17 @@ public class Utilities public static final int getWordStart(JTextComponent c, int offs) throws BadLocationException { - if (offs < 0 || offs >= c.getText().length()) + String text = c.getText(); + + if (offs < 0 || offs > text.length()) throw new BadLocationException("invalid offset specified", offs); - String text = c.getText(); BreakIterator wb = BreakIterator.getWordInstance(); wb.setText(text); + if (wb.isBoundary(offs)) return offs; + return wb.preceding(offs); } @@ -674,4 +692,38 @@ public class Utilities else return offs+1; } + + /** This is an internal helper method which is used by the + * <code>javax.swing.text</code> package. It simply delegates the + * call to a method with the same name on the <code>NavigationFilter</code> + * of the provided <code>JTextComponent</code> (if it has one) or its UI. + * + * If the underlying method throws a <code>BadLocationException</code> it + * will be swallowed and the initial offset is returned. + */ + static int getNextVisualPositionFrom(JTextComponent t, int offset, int direction) + { + NavigationFilter nf = t.getNavigationFilter(); + + try + { + return (nf != null) + ? nf.getNextVisualPositionFrom(t, + offset, + Bias.Forward, + direction, + null) + : t.getUI().getNextVisualPositionFrom(t, + offset, + Bias.Forward, + direction, + null); + } + catch (BadLocationException ble) + { + return offset; + } + + } + } diff --git a/javax/swing/text/html/HTMLDocument.java b/javax/swing/text/html/HTMLDocument.java index 24f743ed2..c3d276178 100644 --- a/javax/swing/text/html/HTMLDocument.java +++ b/javax/swing/text/html/HTMLDocument.java @@ -40,14 +40,12 @@ package javax.swing.text.html; import gnu.classpath.NotImplementedException; +import gnu.javax.swing.text.html.CharacterAttributeTranslator; import java.io.IOException; import java.net.URL; import java.util.HashMap; import java.util.Stack; import java.util.Vector; - -import javax.swing.event.DocumentEvent; -import javax.swing.event.UndoableEditEvent; import javax.swing.text.AbstractDocument; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; @@ -131,21 +129,6 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Replaces the contents of the document with the given element - * specifications. This is called before insert if the loading is done - * in bursts. This is the only method called if loading the document - * entirely in one burst. - * - * @param data - the date that replaces the content of the document - */ - protected void create(DefaultStyledDocument.ElementSpec[] data) - { - // Once the super behaviour is properly implemented it should be sufficient - // to simply call super.create(data). - super.create(data); - } - - /** * This method creates a root element for the new document. * * @return the new default root @@ -216,41 +199,6 @@ public class HTMLDocument extends DefaultStyledDocument } /** - * Inserts new elements in bulk. This is how elements get created in the - * document. The parsing determines what structure is needed and creates the - * specification as a set of tokens that describe the edit while leaving the - * document free of a write-lock. This method can then be called in bursts by - * the reader to acquire a write-lock for a shorter duration (i.e. while the - * document is actually being altered). - * - * @param offset - the starting offset - * @param data - the element data - * @throws BadLocationException - if the given position does not - * represent a valid location in the associated document. - */ - protected void insert(int offset, DefaultStyledDocument.ElementSpec[] data) - throws BadLocationException - { - super.insert(offset, data); - } - - /** - * Updates document structure as a result of text insertion. This will happen - * within a write lock. This implementation simply parses the inserted content - * for line breaks and builds up a set of instructions for the element buffer. - * - * @param chng - a description of the document change - * @param attr - the attributes - */ - protected void insertUpdate(AbstractDocument.DefaultDocumentEvent chng, - AttributeSet attr) - { - // FIXME: Not implemented - System.out.println("insertUpdate not implemented"); - super.insertUpdate(chng, attr); - } - - /** * Returns the parser used by this HTMLDocument to insert HTML. * * @return the parser used by this HTMLDocument to insert HTML. @@ -414,6 +362,7 @@ public class HTMLDocument extends DefaultStyledDocument } public void processHTMLFrameHyperlinkEvent(HTMLFrameHyperlinkEvent event) + throws NotImplementedException { // TODO: Implement this properly. } @@ -646,12 +595,16 @@ public class HTMLDocument extends DefaultStyledDocument { // Put the old attribute set on the stack. pushCharacterStyle(); - - // And create the new one by adding the attributes in <code>a</code>. - if (a != null) - charAttr.addAttribute(t, a.copyAttributes()); + + // Translate tag.. return if succesful. + if(CharacterAttributeTranslator.translateTag(charAttr, t, a)) + return; + + // Just add the attributes in <code>a</code>. + if (a != null) + charAttr.addAttribute(t, a.copyAttributes()); } - + /** * Called when an end tag is seen for one of the types of tags associated * with this Action. @@ -745,7 +698,6 @@ public class HTMLDocument extends DefaultStyledDocument */ public void start(HTML.Tag t, MutableAttributeSet a) { - // FIXME: What else must be done here? blockOpen(t, a); } @@ -755,7 +707,6 @@ public class HTMLDocument extends DefaultStyledDocument */ public void end(HTML.Tag t) { - // FIXME: What else must be done here? blockClose(t); } } @@ -771,6 +722,7 @@ public class HTMLDocument extends DefaultStyledDocument { // FIXME: Implement. print ("PreAction.start not implemented"); + super.start(t, a); } /** @@ -782,6 +734,7 @@ public class HTMLDocument extends DefaultStyledDocument { // FIXME: Implement. print ("PreAction.end not implemented"); + super.end(t); } } @@ -1131,7 +1084,7 @@ public class HTMLDocument extends DefaultStyledDocument */ protected void pushCharacterStyle() { - charAttrStack.push(charAttr); + charAttrStack.push(charAttr.copyAttributes()); } /** @@ -1565,8 +1518,8 @@ public class HTMLDocument extends DefaultStyledDocument */ public Element getElement(String attrId) { - Element root = getDefaultRootElement(); - return getElement(root, HTML.getAttributeKey(attrId) , attrId); + return getElement(getDefaultRootElement(), HTML.getAttributeKey(attrId), + attrId); } /** @@ -1690,53 +1643,4 @@ public class HTMLDocument extends DefaultStyledDocument // FIXME: Not implemented fully, use InsertHTML* in HTMLEditorKit? System.out.println("insertAfterStart not implemented"); } - - /** - * This method sets the attributes associated with the paragraph containing - * offset. If replace is false, s is merged with existing attributes. The - * length argument determines how many characters are affected by the new - * attributes. This is often the entire paragraph. - * - * @param offset - - * the offset into the paragraph (must be at least 0) - * @param length - - * the number of characters affected (must be at least 0) - * @param s - - * the attributes - * @param replace - - * whether to replace existing attributes, or merge them - */ - public void setParagraphAttributes(int offset, int length, AttributeSet s, - boolean replace) - throws NotImplementedException - { - // FIXME: Not implemented. - System.out.println("setParagraphAttributes not implemented"); - super.setParagraphAttributes(offset, length, s, replace); - } - - /** - * This method flags a change in the document. - * - * @param e - the Document event - */ - protected void fireChangedUpdate(DocumentEvent e) - throws NotImplementedException - { - // FIXME: Not implemented. - System.out.println("fireChangedUpdate not implemented"); - super.fireChangedUpdate(e); - } - - /** - * This method fires an event intended to be caught by Undo listeners. It - * simply calls the super version inherited from DefaultStyledDocument. With - * this method, an HTML editor could easily provide undo support. - * - * @param e - the UndoableEditEvent - */ - protected void fireUndoableEditUpdate(UndoableEditEvent e) - { - super.fireUndoableEditUpdate(e); - } } diff --git a/javax/swing/text/html/MinimalHTMLWriter.java b/javax/swing/text/html/MinimalHTMLWriter.java new file mode 100644 index 000000000..4dc67298a --- /dev/null +++ b/javax/swing/text/html/MinimalHTMLWriter.java @@ -0,0 +1,452 @@ +/* MinimalHTMLWriter.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package javax.swing.text.html; + +import javax.swing.text.AttributeSet; +import javax.swing.text.AbstractWriter; +import javax.swing.text.BadLocationException; +import javax.swing.text.DefaultStyledDocument; +import javax.swing.text.Element; +import javax.swing.text.ElementIterator; +import javax.swing.text.StyleConstants; +import javax.swing.text.Style; +import javax.swing.text.StyledDocument; +import java.io.Writer; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Stack; +import java.awt.Color; + +/** + * MinimalHTMLWriter, + * A minimal AbstractWriter implementation for HTML. + * + * @author Sven de Marothy + */ +public class MinimalHTMLWriter extends AbstractWriter +{ + private StyledDocument doc; + private Stack tagStack; + private boolean inFontTag = false; + + /** + * Constructs a MinimalHTMLWriter. + * @param w - a Writer, for output. + * @param doc - the document + */ + public MinimalHTMLWriter(Writer w, StyledDocument doc) + { + super(w, doc); + this.doc = doc; + tagStack = new Stack(); + } + + /** + * Constructs a MinimalHTMLWriter. + * @param w - a Writer, for output. + * @param doc - the document + * @param pos - start position + * @param len - length + */ + public MinimalHTMLWriter(Writer w, StyledDocument doc, int pos, int len) + { + super(w, doc, pos, len); + this.doc = doc; + tagStack = new Stack(); + } + + /** + * Starts a span tag. + */ + protected void startFontTag(String style) throws IOException + { + if( inFontTag() ) + endOpenTags(); + writeStartTag("<span style=\""+style+"\">"); + inFontTag = true; + } + + /** + * Returns whether the writer is within two span tags. + */ + protected boolean inFontTag() + { + return inFontTag; + } + + /** + * Ends a span tag. + */ + protected void endFontTag() throws IOException + { + writeEndTag("</span>"); + inFontTag = false; + } + + /** + * Write the entire HTML document. + */ + public synchronized void write() throws IOException, BadLocationException + { + writeStartTag("<html>"); + writeHeader(); + writeBody(); + writeEndTag("</html>"); + } + + /** + * Write a start tag and increment the indent. + */ + protected void writeStartTag(String tag) throws IOException + { + indent(); + write(tag+NEWLINE); + incrIndent(); + } + + /** + * Write an ending tag and decrement the indent. + */ + protected void writeEndTag(String endTag) throws IOException + { + decrIndent(); + indent(); + write(endTag+NEWLINE); + } + + /** + * Write the HTML header. + */ + protected void writeHeader() throws IOException + { + writeStartTag("<head>"); + writeStartTag("<style>"); + writeStartTag("<!--"); + writeStyles(); + writeEndTag("-->"); + writeEndTag("</style>"); + writeEndTag("</head>"); + } + + /** + * Write a paragraph start tag. + */ + protected void writeStartParagraph(Element elem) throws IOException + { + indent(); + write("<p class=default>"+NEWLINE); // FIXME: Class value = ? + incrIndent(); + } + + /** + * Write a paragraph end tag, closes any other open tags. + */ + protected void writeEndParagraph() throws IOException + { + endOpenTags(); + writeEndTag("</p>"); + } + + /** + * Writes the body of the HTML document. + */ + protected void writeBody() throws IOException, BadLocationException + { + writeStartTag("<body>"); + + ElementIterator ei = getElementIterator(); + Element e = ei.first(); + boolean inParagraph = false; + do + { + if( e.isLeaf() ) + { + boolean hasNL = (getText(e).indexOf(NEWLINE) != -1); + if( !inParagraph && hasText( e ) ) + { + writeStartParagraph(e); + inParagraph = true; + } + + if( hasText( e ) ) + writeContent(e, true); + + if( hasNL && inParagraph ) + { + writeEndParagraph(); + inParagraph = false; + } + else + endOpenTags(); + } + } + while((e = ei.next()) != null); + + writeEndTag("</body>"); + } + + protected void text(Element elem) throws IOException, BadLocationException + { + write( getText(elem).trim() ); + } + + /** + * Write bold, indent and underline tags. + */ + protected void writeHTMLTags(AttributeSet attr) throws IOException + { + if(attr.getAttribute(StyleConstants.Bold) != null) + if(((Boolean)attr.getAttribute(StyleConstants.Bold)).booleanValue()) + { + write("<b>"); + tagStack.push("</b>"); + } + if(attr.getAttribute(StyleConstants.Italic) != null) + if(((Boolean)attr.getAttribute(StyleConstants.Italic)).booleanValue()) + { + write("<i>"); + tagStack.push("</i>"); + } + if(attr.getAttribute(StyleConstants.Underline) != null) + if(((Boolean)attr.getAttribute(StyleConstants.Underline)).booleanValue()) + { + write("<u>"); + tagStack.push("</u>"); + } + } + + /** + * Returns whether the element contains text or not. + */ + protected boolean isText(Element elem) + { + return (elem.getEndOffset() != elem.getStartOffset()); + } + + /** + * Writes the content of an element. + */ + protected void writeContent(Element elem, boolean needsIndenting) + throws IOException, BadLocationException + { + writeNonHTMLAttributes(elem.getAttributes()); + if(needsIndenting) + indent(); + writeHTMLTags(elem.getAttributes()); + if( isText(elem) ) + text(elem); + else + writeLeaf(elem); + + endOpenTags(); + } + + /** + * Writes a non-text leaf element. + */ + protected void writeLeaf(Element e) throws IOException + { + // NOTE: Haven't tested if this is correct. + if(e.getName().equals(StyleConstants.IconElementName)) + writeImage(e); + else + writeComponent(e); + } + + /** + * Write the HTML attributes which do not have tag equivalents, + * e.g. attributes other than bold/italic/underlined. + */ + protected void writeNonHTMLAttributes(AttributeSet attr) throws IOException + { + String style = ""; + + // Alignment? Background? + + if( StyleConstants.getForeground(attr) != null ) + style = style + "color: " + + getColor(StyleConstants.getForeground(attr)) + "; "; + + style = style + "font-size: "+StyleConstants.getFontSize(attr)+"pt; "; + style = style + "font-family: "+StyleConstants.getFontFamily(attr); + + startFontTag(style); + } + + /** + * Write the styles used. + */ + protected void writeStyles() throws IOException + { + if(doc instanceof DefaultStyledDocument) + { + Enumeration styles = ((DefaultStyledDocument)doc).getStyleNames(); + while(styles.hasMoreElements()) + writeStyle(doc.getStyle((String)styles.nextElement())); + } + else + { // What else to do here? + Style s = (Style)doc.getStyle("default"); + if(s != null) + writeStyle( s ); + } + } + + /** + * Write a set of attributes. + */ + protected void writeAttributes(AttributeSet attr) throws IOException + { + Enumeration attribs = attr.getAttributeNames(); + while(attribs.hasMoreElements()) + { + Object attribName = attribs.nextElement(); + String name = attribName.toString(); + String output = getAttribute(name, attr.getAttribute(attribName)); + if( output != null ) + { + indent(); + write( output + NEWLINE ); + } + } + } + + /** + * Deliberately unimplemented, handles component elements. + */ + protected void writeComponent(Element elem) + { + } + + /** + * Deliberately unimplemented. + * Writes StyleConstants.IconElementName elements. + */ + protected void writeImage(Element elem) + { + } + + // -------------------- Private methods. -------------------------------- + + /** + * Write a single style attribute + */ + private String getAttribute(String name, Object a) throws IOException + { + if(name.equals("foreground")) + return "foreground:"+getColor((Color)a)+";"; + if(name.equals("background")) + return "background:"+getColor((Color)a)+";"; + if(name.equals("italic")) + return "italic:"+(((Boolean)a).booleanValue() ? "italic;" : ";"); + if(name.equals("bold")) + return "bold:"+(((Boolean)a).booleanValue() ? "bold;" : "normal;"); + if(name.equals("family")) + return "family:" + a + ";"; + if(name.equals("size")) + { + int size = ((Integer)a).intValue(); + int htmlSize; + if( size > 24 ) + htmlSize = 7; + else if( size > 18 ) + htmlSize = 6; + else if( size > 14 ) + htmlSize = 5; + else if( size > 12 ) + htmlSize = 4; + else if( size > 10 ) + htmlSize = 3; + else if( size > 8 ) + htmlSize = 2; + else + htmlSize = 1; + + return "size:" + htmlSize + ";"; + } + + return null; + } + + /** + * Stupid that Color doesn't have a method for this. + */ + private String getColor(Color c) + { + String r = "00" + Integer.toHexString(c.getRed()); + r = r.substring(r.length() - 2); + String g = "00" + Integer.toHexString(c.getGreen()); + g = g.substring(g.length() - 2); + String b = "00" + Integer.toHexString(c.getBlue()); + b = b.substring(b.length() - 2); + return "#" + r + g + b; + } + + /** + * Empty the stack of open tags + */ + private void endOpenTags() throws IOException + { + while(!tagStack.empty()) + write((String)tagStack.pop()); + + if( inFontTag() ) + { + write(""+NEWLINE); + endFontTag(); + } + } + + /** + * Output a single style + */ + private void writeStyle(Style s) throws IOException + { + if( s == null ) + return; + + writeStartTag("p."+s.getName()+" {"); + writeAttributes(s); + writeEndTag("}"); + } + + private boolean hasText(Element e) throws BadLocationException + { + return (getText(e).trim().length() > 0); + } +} |